Skip to content

Commit 8564557

Browse files
committed
feat: Update error messages for duplicate ID checks and enhance ID mappings functionality
1 parent 8c4d163 commit 8564557

File tree

3 files changed

+198
-7
lines changed

3 files changed

+198
-7
lines changed

cloudflare-worker/src/routes/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ const testerRoutes = (router: Router, env: Env) => {
127127
return new Response(
128128
JSON.stringify({
129129
success: false,
130-
error: "ID already exists for another tester",
130+
error: "ID already exists in the database",
131131
}),
132132
{
133133
status: 409,
@@ -227,7 +227,7 @@ const testerRoutes = (router: Router, env: Env) => {
227227
return new Response(
228228
JSON.stringify({
229229
success: false,
230-
error: "ID already exists for another tester",
230+
error: "ID already exists in the database",
231231
}),
232232
{
233233
status: 409,

cloudflare-worker/src/routes/mockDb.ts

Lines changed: 174 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ import { v4 as uuidv4 } from "uuid";
2828

2929
import { Feedback, Publication, Purchase, Refund, Tester } from "../types/data";
3030

31+
/**
32+
* Interface for the OAuth ID to tester UUID mapping
33+
*/
34+
interface IdMapping {
35+
id: string; // OAuth ID (primary key)
36+
testerUuid: string; // Reference to tester UUID
37+
}
38+
3139
// Sample data collections
3240
const testersData: Tester[] = [
3341
{
@@ -42,6 +50,20 @@ const testersData: Tester[] = [
4250
},
4351
];
4452

53+
/**
54+
* ID mappings table - simulates a separate table for ID lookups
55+
*/
56+
const idMappingsData: IdMapping[] = [
57+
{
58+
id: "auth0|1234567890",
59+
testerUuid: "45f9830a-309b-4cda-95ec-71e000b78f7d",
60+
},
61+
{
62+
id: "auth0|0987654321",
63+
testerUuid: "cc97a5cc-c4ba-4804-98b5-90532f09bd83",
64+
},
65+
];
66+
4567
const purchasesData: Purchase[] = [
4668
{
4769
id: "d5726cf2-36f6-41d8-bd37-f349314561b4",
@@ -126,6 +148,100 @@ const refundsData: Refund[] = [
126148
* Provides CRUD-like operations for all data types
127149
*/
128150
export const mockDb = {
151+
/**
152+
* ID mappings operations
153+
*/
154+
idMappings: {
155+
/**
156+
* Check if an ID exists in the database
157+
* @param {string} id - The OAuth ID to check
158+
* @returns {boolean} True if the ID exists, false otherwise
159+
*/
160+
exists: (id: string): boolean => {
161+
return idMappingsData.some((mapping) => mapping.id === id);
162+
},
163+
164+
/**
165+
* Check if multiple IDs exist in the database
166+
* @param {string[]} ids - Array of OAuth IDs to check
167+
* @returns {string[]} Array of IDs that already exist
168+
*/
169+
existsMultiple: (ids: string[]): string[] => {
170+
return ids.filter((id) =>
171+
idMappingsData.some((mapping) => mapping.id === id),
172+
);
173+
},
174+
175+
/**
176+
* Get the tester UUID associated with an ID
177+
* @param {string} id - The OAuth ID to look up
178+
* @returns {string|undefined} The associated tester UUID if found
179+
*/
180+
getTesterUuid: (id: string): string | undefined => {
181+
const mapping = idMappingsData.find((mapping) => mapping.id === id);
182+
183+
return mapping?.testerUuid;
184+
},
185+
186+
/**
187+
* Add a new ID to tester mapping
188+
* @param {string} id - The OAuth ID
189+
* @param {string} testerUuid - The associated tester UUID
190+
* @returns {boolean} True if successful, false if ID already exists
191+
*/
192+
put: (id: string, testerUuid: string): boolean => {
193+
if (idMappingsData.some((mapping) => mapping.id === id)) {
194+
return false; // ID already exists
195+
}
196+
197+
idMappingsData.push({ id, testerUuid });
198+
199+
return true;
200+
},
201+
202+
/**
203+
* Add multiple ID to tester mappings
204+
* @param {string[]} ids - Array of OAuth IDs
205+
* @param {string} testerUuid - The associated tester UUID
206+
* @returns {string[]} Array of IDs that were successfully added
207+
*/
208+
putMultiple: (ids: string[], testerUuid: string): string[] => {
209+
const addedIds: string[] = [];
210+
211+
for (const id of ids) {
212+
if (!idMappingsData.some((mapping) => mapping.id === id)) {
213+
idMappingsData.push({ id, testerUuid });
214+
addedIds.push(id);
215+
}
216+
}
217+
218+
return addedIds;
219+
},
220+
221+
/**
222+
* Delete an ID mapping
223+
* @param {string} id - The OAuth ID to delete
224+
* @returns {boolean} True if successful, false if ID not found
225+
*/
226+
delete: (id: string): boolean => {
227+
const index = idMappingsData.findIndex((mapping) => mapping.id === id);
228+
229+
if (index >= 0) {
230+
idMappingsData.splice(index, 1);
231+
232+
return true;
233+
}
234+
235+
return false;
236+
},
237+
238+
/**
239+
* Get all ID mappings
240+
* @returns {IdMapping[]} Copy of all ID mappings
241+
*/
242+
getAll: () => [...idMappingsData],
243+
},
244+
129245
/**
130246
* Tester-related database operations
131247
*/
@@ -156,6 +272,24 @@ export const mockDb = {
156272

157273
if (index >= 0) {
158274
// Update existing tester
275+
const oldIds = testersData[index].ids;
276+
const newIds = newTester.ids;
277+
278+
// Remove old ID mappings that are no longer in the tester's ID list
279+
for (const oldId of oldIds) {
280+
if (!newIds.includes(oldId)) {
281+
mockDb.idMappings.delete(oldId);
282+
}
283+
}
284+
285+
// Add new ID mappings
286+
for (const newId of newIds) {
287+
if (!oldIds.includes(newId)) {
288+
mockDb.idMappings.put(newId, newTester.uuid);
289+
}
290+
}
291+
292+
// Update the tester
159293
testersData[index] = newTester;
160294

161295
return newTester.ids;
@@ -164,6 +298,11 @@ export const mockDb = {
164298
if (!newTester.uuid) {
165299
newTester.uuid = uuidv4();
166300
}
301+
302+
// Add ID mappings for all IDs in the new tester
303+
mockDb.idMappings.putMultiple(newTester.ids, newTester.uuid);
304+
305+
// Add the tester
167306
testersData.push(newTester);
168307

169308
return newTester.ids;
@@ -177,12 +316,17 @@ export const mockDb = {
177316
getAll: () => [...testersData],
178317

179318
/**
180-
* Find a tester by their authentication ID
319+
* Find a tester by their authentication ID (efficient lookup using ID mappings)
181320
* @param {string} id - Authentication ID to search for
182321
* @returns {Tester|undefined} The matching tester or undefined if not found
183322
*/
184-
getTesterWithId: (id: string) =>
185-
testersData.find((tester) => tester.ids.includes(id)),
323+
getTesterWithId: (id: string) => {
324+
const testerUuid = mockDb.idMappings.getTesterUuid(id);
325+
326+
if (!testerUuid) return undefined;
327+
328+
return testersData.find((tester) => tester.uuid === testerUuid);
329+
},
186330

187331
/**
188332
* Find a tester by their UUID
@@ -191,6 +335,33 @@ export const mockDb = {
191335
*/
192336
getTesterWithUuid: (uuid: string) =>
193337
testersData.find((tester) => tester.uuid === uuid),
338+
339+
/**
340+
* Add IDs to an existing tester
341+
* @param {string} uuid - UUID of the tester to update
342+
* @param {string[]} ids - IDs to add to the tester
343+
* @returns {string[]|undefined} Updated list of IDs if successful, undefined if tester not found
344+
*/
345+
addIds: (uuid: string, ids: string[]): string[] | undefined => {
346+
const index = testersData.findIndex((tester) => tester.uuid === uuid);
347+
348+
if (index < 0) return undefined;
349+
350+
// Get existing IDs
351+
const existingIds = testersData[index].ids;
352+
// Check which IDs don't already exist in the mappings table
353+
const newIds = ids.filter((id) => !mockDb.idMappings.exists(id));
354+
355+
// Add new ID mappings
356+
mockDb.idMappings.putMultiple(newIds, uuid);
357+
358+
// Update tester with all IDs (existing + new)
359+
const allIds = [...existingIds, ...newIds];
360+
361+
testersData[index].ids = allIds;
362+
363+
return allIds;
364+
},
194365
},
195366

196367
/**

cloudflare-worker/test/basic.api.test.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ const api = {
4141
headers: {
4242
'Content-Type': 'application/json',
4343
'Authorization': `Bearer ${AUTH0_TOKEN}`
44+
},
45+
validateStatus: function (status) {
46+
return status < 500; // la requête résout tant que le code de sa réponse est
47+
// inférieur à 500
4448
}
4549
});
4650
},
@@ -49,6 +53,10 @@ const api = {
4953
headers: {
5054
'Content-Type': 'application/json',
5155
'Authorization': `Bearer ${AUTH0_TOKEN}`
56+
},
57+
validateStatus: function (status) {
58+
return status < 500; // la requête résout tant que le code de sa réponse est
59+
// inférieur à 500
5260
}
5361
});
5462
},
@@ -121,9 +129,21 @@ describe('Feedback Flow API', () => {
121129
name: 'TESTER',
122130
id: testerId
123131
});
124-
expect(response.status).toBe(209);
132+
133+
expect(response.status).toBe(409);
134+
expect(response.data.success).toBe(false);
135+
expect(response.data.error).toBe('ID already exists in the database');
136+
});
137+
138+
test('45. Should not add a duplicate OAuth ID owned by another tester', async () => {
139+
const response = await api.post('/tester/ids', {
140+
name: 'TESTER',
141+
id: 'auth0|0987654321' /* Owned by Jane Doe */
142+
});
143+
144+
expect(response.status).toBe(409);
125145
expect(response.data.success).toBe(false);
126-
expect(response.data.message).toBe('ID already exists for this tester');
146+
expect(response.data.error).toBe('ID already exists in the database');
127147
});
128148

129149
test('50. Should create a purchase', async () => {

0 commit comments

Comments
 (0)