Skip to content

Commit a5787e0

Browse files
committed
chore(web-scraper): bump Retrack component version
1 parent 35ee0f3 commit a5787e0

13 files changed

Lines changed: 82 additions & 38 deletions

File tree

2 Bytes
Loading
0 Bytes
Loading
0 Bytes
Loading
1 Byte
Loading
1 Byte
Loading

e2e/tests/user_termination_retrack_cleanup.spec.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ interface RetrackTracker {
1616
tags: string[];
1717
}
1818

19+
interface RetrackTrackersPage {
20+
items: RetrackTracker[];
21+
total: number;
22+
}
23+
1924
async function getRetrackTracker(page: Page, id: string): Promise<RetrackTracker | null> {
2025
const response = await page.request.get(`${RETRACK_URL}/api/trackers/${id}`);
2126
if (response.status() === 404) {
@@ -26,9 +31,11 @@ async function getRetrackTracker(page: Page, id: string): Promise<RetrackTracker
2631
}
2732

2833
async function listRetrackTrackersByTag(page: Page, tag: string): Promise<RetrackTracker[]> {
29-
const response = await page.request.get(`${RETRACK_URL}/api/trackers?tag=${encodeURIComponent(tag)}`);
34+
const response = await page.request.get(`${RETRACK_URL}/api/trackers?tag=${encodeURIComponent(tag)}&pageSize=100`);
3035
expect(response.ok()).toBeTruthy();
31-
return (await response.json()) as RetrackTracker[];
36+
const trackersPage = (await response.json()) as RetrackTrackersPage;
37+
expect(trackersPage.items.length).toBeLessThanOrEqual(trackersPage.total);
38+
return trackersPage.items;
3239
}
3340

3441
test.describe('User termination cleans up Retrack trackers', () => {

src/retrack/api_ext.rs

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
};
77
use anyhow::{Context, bail};
88
use retrack_types::trackers::{
9-
Tracker, TrackerCreateParams, TrackerDataRevision, TrackerDataRevisionImportParams,
9+
Page, Tracker, TrackerCreateParams, TrackerDataRevision, TrackerDataRevisionImportParams,
1010
TrackerDataRevisionImportResult, TrackerDebugParams, TrackerExecutionLog,
1111
TrackerListRevisionsParams, TrackerUpdateParams,
1212
};
@@ -21,6 +21,8 @@ pub struct RetrackApi<'a, DR: DnsResolver, ET: EmailTransport> {
2121
}
2222

2323
impl<'a, DR: DnsResolver, ET: EmailTransport> RetrackApi<'a, DR, ET> {
24+
const LIST_TRACKERS_PAGE_SIZE: usize = 100;
25+
2426
/// Creates Retrack API.
2527
pub fn new(api: &'a Api<DR, ET>) -> Self {
2628
Self { api }
@@ -31,26 +33,46 @@ impl<'a, DR: DnsResolver, ET: EmailTransport> RetrackApi<'a, DR, ET> {
3133
&self,
3234
tags: &[Tag],
3335
) -> anyhow::Result<Vec<Tracker>> {
34-
// Construct tags query string.
35-
let tags_query = prepare_tags(tags)
36+
let prepared_tags = prepare_tags(tags);
37+
let tags_query = prepared_tags
3638
.iter()
3739
.map(|tag| format!("tag={}", urlencoding::encode(tag)))
3840
.collect::<Vec<_>>()
3941
.join("&");
40-
let endpoint = format!("{}api/trackers?{tags_query}", self.api.config.retrack.host);
42+
let mut trackers = vec![];
43+
let mut page_index = 0;
44+
45+
loop {
46+
let page_query = format!(
47+
"page={page_index}&pageSize={}{}{}",
48+
Self::LIST_TRACKERS_PAGE_SIZE,
49+
if tags_query.is_empty() { "" } else { "&" },
50+
tags_query
51+
);
52+
let endpoint = format!("{}api/trackers?{page_query}", self.api.config.retrack.host);
53+
let response = self
54+
.api
55+
.network
56+
.http_client
57+
.get(&endpoint)
58+
.send()
59+
.await
60+
.with_context(|| format!("Cannot query trackers ({page_query})."))?;
61+
let mut page = response
62+
.json::<Page<Tracker>>()
63+
.await
64+
.context(format!("Cannot deserialize trackers ({page_query})."))?;
4165

42-
let response = self
43-
.api
44-
.network
45-
.http_client
46-
.get(&endpoint)
47-
.send()
48-
.await
49-
.with_context(|| format!("Cannot query trackers ({tags_query})."))?;
50-
response
51-
.json()
52-
.await
53-
.context(format!("Cannot deserialize trackers ({tags_query})."))
66+
let total = page.total.max(0) as usize;
67+
let is_last_page = page.items.is_empty() || trackers.len() + page.items.len() >= total;
68+
trackers.append(&mut page.items);
69+
if is_last_page {
70+
break;
71+
}
72+
page_index += 1;
73+
}
74+
75+
Ok(trackers)
5476
}
5577

5678
/// Retrieves Retrack trackers with the specified IDs.

src/security/api_ext.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,7 @@ mod tests {
598598
use httpmock::MockServer;
599599
use insta::assert_debug_snapshot;
600600
use jsonwebtoken::{EncodingKey, Header, encode};
601+
use retrack_types::trackers::{Page, Tracker};
601602
use serde_json::json;
602603
use sqlx::PgPool;
603604
use std::collections::HashSet;
@@ -1127,7 +1128,7 @@ mod tests {
11271128
when.method(httpmock::Method::GET).path("/api/trackers");
11281129
then.status(200)
11291130
.header("Content-Type", "application/json")
1130-
.json_body(json!([]));
1131+
.json_body_obj(&Page::new(Vec::<Tracker>::new(), 0));
11311132
});
11321133
config.retrack.host = Url::parse(&retrack_server.base_url())?;
11331134
let api = mock_api_with_config(pool, config).await?;

src/server/handlers/security_users_clone.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ mod tests {
374374
};
375375
use actix_web::{body::MessageBody, http::StatusCode};
376376
use httpmock::MockServer;
377+
use retrack_types::trackers::{Page, Tracker};
377378
use serde_json::{Value, json};
378379
use sqlx::PgPool;
379380
use std::{sync::Arc, time::Duration};
@@ -706,13 +707,13 @@ mod tests {
706707
.json_body(identity_json(destination_id, destination_email));
707708
});
708709
// Retrack tracker-list call made by `clone_data` -> `generate_export`. Returning an
709-
// empty array lets clone_data succeed, so the failure mode under test (recovery-link
710+
// empty page lets clone_data succeed, so the failure mode under test (recovery-link
710711
// minting) is the one that actually trips the rollback.
711712
server.mock(|when, then| {
712713
when.method(httpmock::Method::GET).path("/api/trackers");
713714
then.status(200)
714715
.header("Content-Type", "application/json")
715-
.json_body(json!([]));
716+
.json_body_obj(&Page::new(Vec::<Tracker>::new(), 0));
716717
});
717718
// Rollback's `terminate` bulk-removes the user's Retrack trackers (none here).
718719
server.mock(|when, then| {
@@ -782,12 +783,12 @@ mod tests {
782783
.json_body(identity_json(destination_id, destination_email));
783784
});
784785
// Retrack tracker-list call made by `clone_data` -> `generate_export`. Source user
785-
// has no trackers so an empty array is the correct response.
786+
// has no trackers so an empty page is the correct response.
786787
server.mock(|when, then| {
787788
when.method(httpmock::Method::GET).path("/api/trackers");
788789
then.status(200)
789790
.header("Content-Type", "application/json")
790-
.json_body(json!([]));
791+
.json_body_obj(&Page::new(Vec::<Tracker>::new(), 0));
791792
});
792793
let recovery_mock = server.mock(|when, then| {
793794
when.method(httpmock::Method::POST)

0 commit comments

Comments
 (0)