Skip to content

Commit 23bd2aa

Browse files
committed
Implement country code selection component in sign-up rules and update user schema to include risk scores. Enhanced tests to validate new fields and ensure proper handling of country codes and risk scores across various endpoints.
1 parent 33dd37a commit 23bd2aa

8 files changed

Lines changed: 128 additions & 54 deletions

File tree

apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/sign-up-rules/page-client.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"use client";
22

3+
import { CountryCodeSelect } from "@/components/country-code-select";
34
import { ConditionBuilder, isConditionTreeValid } from "@/components/rule-builder";
45
import {
56
ActionDialog,
@@ -694,11 +695,9 @@ function TestRulesCard({
694695
<Typography variant="secondary" className="text-xs uppercase tracking-wide">
695696
Country code override
696697
</Typography>
697-
<Input
698-
value={countryCodeOverride}
699-
onChange={(e) => setCountryCodeOverride(e.target.value.toUpperCase())}
700-
placeholder="US"
701-
maxLength={2}
698+
<CountryCodeSelect
699+
value={countryCodeOverride || null}
700+
onChange={(val) => setCountryCodeOverride(val ?? "")}
702701
/>
703702
</div>
704703
<div className="space-y-1.5">

apps/e2e/tests/backend/endpoints/api/v1/auth/anonymous/anonymous-comprehensive.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ it("list users includes anonymous users when requested", async ({ expect }) => {
189189
"auth_with_email": true,
190190
"client_metadata": null,
191191
"client_read_only_metadata": null,
192+
"country_code": null,
192193
"display_name": null,
193194
"has_password": true,
194195
"id": "<stripped UUID>",
@@ -207,6 +208,12 @@ it("list users includes anonymous users when requested", async ({ expect }) => {
207208
"restricted_by_admin_private_details": null,
208209
"restricted_by_admin_reason": null,
209210
"restricted_reason": null,
211+
"risk_scores": {
212+
"sign_up": {
213+
"bot": 0,
214+
"free_trial_abuse": 0,
215+
},
216+
},
210217
"selected_team": null,
211218
"selected_team_id": null,
212219
"server_metadata": null,

apps/e2e/tests/backend/endpoints/api/v1/external-db-sync-advanced.test.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,8 @@ describe.sequential('External DB Sync - Advanced Tests', () => {
442442
insert_users AS (
443443
INSERT INTO "ProjectUser"
444444
("tenancyId", "projectUserId", "mirroredProjectId", "mirroredBranchId",
445-
"displayName", "createdAt", "updatedAt", "isAnonymous")
445+
"displayName", "createdAt", "updatedAt", "isAnonymous",
446+
"signUpRiskScoreBot", "signUpRiskScoreFreeTrialAbuse")
446447
SELECT
447448
tenancy_id,
448449
project_user_id,
@@ -451,7 +452,9 @@ describe.sequential('External DB Sync - Advanced Tests', () => {
451452
'HV User ' || idx,
452453
ts,
453454
ts,
454-
false
455+
false,
456+
0,
457+
0
455458
FROM generated
456459
RETURNING "tenancyId", "projectUserId"
457460
)
@@ -1020,7 +1023,8 @@ $$;`);
10201023
insert_users AS (
10211024
INSERT INTO "ProjectUser"
10221025
("tenancyId", "projectUserId", "mirroredProjectId", "mirroredBranchId",
1023-
"displayName", "createdAt", "updatedAt", "isAnonymous")
1026+
"displayName", "createdAt", "updatedAt", "isAnonymous",
1027+
"signUpRiskScoreBot", "signUpRiskScoreFreeTrialAbuse")
10241028
SELECT
10251029
tenancy_id,
10261030
project_user_id,
@@ -1029,7 +1033,9 @@ $$;`);
10291033
'Interleave User ' || idx,
10301034
ts,
10311035
ts,
1032-
false
1036+
false,
1037+
0,
1038+
0
10331039
FROM generated
10341040
RETURNING "projectUserId"
10351041
),
@@ -1100,7 +1106,8 @@ $$;`);
11001106
insert_users AS (
11011107
INSERT INTO "ProjectUser"
11021108
("tenancyId", "projectUserId", "mirroredProjectId", "mirroredBranchId",
1103-
"displayName", "createdAt", "updatedAt", "isAnonymous")
1109+
"displayName", "createdAt", "updatedAt", "isAnonymous",
1110+
"signUpRiskScoreBot", "signUpRiskScoreFreeTrialAbuse")
11041111
SELECT
11051112
tenancy_id,
11061113
project_user_id,
@@ -1109,7 +1116,9 @@ $$;`);
11091116
'Replacement ' || idx,
11101117
ts,
11111118
ts,
1112-
false
1119+
false,
1120+
0,
1121+
0
11131122
FROM generated
11141123
RETURNING "projectUserId"
11151124
),

apps/e2e/tests/backend/endpoints/api/v1/external-db-sync-high-volume.test.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ describe.sequential('External DB Sync - High Volume Tests', () => {
105105
insert_users AS (
106106
INSERT INTO "ProjectUser"
107107
("tenancyId", "projectUserId", "mirroredProjectId", "mirroredBranchId",
108-
"displayName", "createdAt", "updatedAt", "isAnonymous")
108+
"displayName", "createdAt", "updatedAt", "isAnonymous",
109+
"signUpRiskScoreBot", "signUpRiskScoreFreeTrialAbuse")
109110
SELECT
110111
tenancy_id,
111112
project_user_id,
@@ -114,7 +115,9 @@ describe.sequential('External DB Sync - High Volume Tests', () => {
114115
'HV User ' || idx,
115116
ts,
116117
ts,
117-
false
118+
false,
119+
0,
120+
0
118121
FROM generated
119122
RETURNING "tenancyId", "projectUserId"
120123
)

apps/e2e/tests/backend/endpoints/api/v1/external-db-sync-race.test.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,8 @@ describe.sequential('External DB Sync - Race Condition Tests', () => {
194194
insert_users AS (
195195
INSERT INTO "ProjectUser"
196196
("tenancyId", "projectUserId", "mirroredProjectId", "mirroredBranchId",
197-
"displayName", "createdAt", "updatedAt", "isAnonymous")
197+
"displayName", "createdAt", "updatedAt", "isAnonymous",
198+
"signUpRiskScoreBot", "signUpRiskScoreFreeTrialAbuse")
198199
SELECT
199200
tenancy_id,
200201
project_user_id,
@@ -203,7 +204,9 @@ describe.sequential('External DB Sync - Race Condition Tests', () => {
203204
'Paged User ' || idx,
204205
ts,
205206
ts,
206-
false
207+
false,
208+
0,
209+
0
207210
FROM generated
208211
RETURNING "projectUserId"
209212
),

apps/e2e/tests/backend/endpoints/api/v1/team-memberships.test.ts

Lines changed: 80 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ it("creates a team and allows managing users on the server", async ({ expect })
6969
"auth_with_email": false,
7070
"client_metadata": null,
7171
"client_read_only_metadata": null,
72+
"country_code": null,
7273
"display_name": null,
7374
"has_password": false,
7475
"id": "<stripped UUID>",
@@ -87,6 +88,12 @@ it("creates a team and allows managing users on the server", async ({ expect })
8788
"restricted_by_admin_private_details": null,
8889
"restricted_by_admin_reason": null,
8990
"restricted_reason": null,
91+
"risk_scores": {
92+
"sign_up": {
93+
"bot": 0,
94+
"free_trial_abuse": 0,
95+
},
96+
},
9097
"selected_team": {
9198
"client_metadata": null,
9299
"client_read_only_metadata": null,
@@ -104,6 +111,7 @@ it("creates a team and allows managing users on the server", async ({ expect })
104111
"auth_with_email": false,
105112
"client_metadata": null,
106113
"client_read_only_metadata": null,
114+
"country_code": null,
107115
"display_name": null,
108116
"has_password": false,
109117
"id": "<stripped UUID>",
@@ -122,6 +130,12 @@ it("creates a team and allows managing users on the server", async ({ expect })
122130
"restricted_by_admin_private_details": null,
123131
"restricted_by_admin_reason": null,
124132
"restricted_reason": null,
133+
"risk_scores": {
134+
"sign_up": {
135+
"bot": 0,
136+
"free_trial_abuse": 0,
137+
},
138+
},
125139
"selected_team": {
126140
"client_metadata": null,
127141
"client_read_only_metadata": null,
@@ -170,6 +184,7 @@ it("creates a team and allows managing users on the server", async ({ expect })
170184
"auth_with_email": false,
171185
"client_metadata": null,
172186
"client_read_only_metadata": null,
187+
"country_code": null,
173188
"display_name": null,
174189
"has_password": false,
175190
"id": "<stripped UUID>",
@@ -188,6 +203,12 @@ it("creates a team and allows managing users on the server", async ({ expect })
188203
"restricted_by_admin_private_details": null,
189204
"restricted_by_admin_reason": null,
190205
"restricted_reason": null,
206+
"risk_scores": {
207+
"sign_up": {
208+
"bot": 0,
209+
"free_trial_abuse": 0,
210+
},
211+
},
191212
"selected_team": {
192213
"client_metadata": null,
193214
"client_read_only_metadata": null,
@@ -240,6 +261,7 @@ it("lets users be on multiple teams", async ({ expect }) => {
240261
"auth_with_email": false,
241262
"client_metadata": null,
242263
"client_read_only_metadata": null,
264+
"country_code": null,
243265
"display_name": null,
244266
"has_password": false,
245267
"id": "<stripped UUID>",
@@ -258,6 +280,12 @@ it("lets users be on multiple teams", async ({ expect }) => {
258280
"restricted_by_admin_private_details": null,
259281
"restricted_by_admin_reason": null,
260282
"restricted_reason": null,
283+
"risk_scores": {
284+
"sign_up": {
285+
"bot": 0,
286+
"free_trial_abuse": 0,
287+
},
288+
},
261289
"selected_team": {
262290
"client_metadata": null,
263291
"client_read_only_metadata": null,
@@ -275,6 +303,7 @@ it("lets users be on multiple teams", async ({ expect }) => {
275303
"auth_with_email": false,
276304
"client_metadata": null,
277305
"client_read_only_metadata": null,
306+
"country_code": null,
278307
"display_name": null,
279308
"has_password": false,
280309
"id": "<stripped UUID>",
@@ -293,6 +322,12 @@ it("lets users be on multiple teams", async ({ expect }) => {
293322
"restricted_by_admin_private_details": null,
294323
"restricted_by_admin_reason": null,
295324
"restricted_reason": null,
325+
"risk_scores": {
326+
"sign_up": {
327+
"bot": 0,
328+
"free_trial_abuse": 0,
329+
},
330+
},
296331
"selected_team": {
297332
"client_metadata": null,
298333
"client_read_only_metadata": null,
@@ -327,6 +362,7 @@ it("lets users be on multiple teams", async ({ expect }) => {
327362
"auth_with_email": false,
328363
"client_metadata": null,
329364
"client_read_only_metadata": null,
365+
"country_code": null,
330366
"display_name": null,
331367
"has_password": false,
332368
"id": "<stripped UUID>",
@@ -345,6 +381,12 @@ it("lets users be on multiple teams", async ({ expect }) => {
345381
"restricted_by_admin_private_details": null,
346382
"restricted_by_admin_reason": null,
347383
"restricted_reason": null,
384+
"risk_scores": {
385+
"sign_up": {
386+
"bot": 0,
387+
"free_trial_abuse": 0,
388+
},
389+
},
348390
"selected_team": {
349391
"client_metadata": null,
350392
"client_read_only_metadata": null,
@@ -362,6 +404,7 @@ it("lets users be on multiple teams", async ({ expect }) => {
362404
"auth_with_email": false,
363405
"client_metadata": null,
364406
"client_read_only_metadata": null,
407+
"country_code": null,
365408
"display_name": null,
366409
"has_password": false,
367410
"id": "<stripped UUID>",
@@ -380,6 +423,12 @@ it("lets users be on multiple teams", async ({ expect }) => {
380423
"restricted_by_admin_private_details": null,
381424
"restricted_by_admin_reason": null,
382425
"restricted_reason": null,
426+
"risk_scores": {
427+
"sign_up": {
428+
"bot": 0,
429+
"free_trial_abuse": 0,
430+
},
431+
},
383432
"selected_team": {
384433
"client_metadata": null,
385434
"client_read_only_metadata": null,
@@ -521,18 +570,13 @@ it("removes user from team on the client", async ({ expect }) => {
521570
});
522571
expect(response1).toMatchInlineSnapshot(`
523572
NiceResponse {
524-
"status": 401,
573+
"status": 400,
525574
"body": {
526-
"code": "TEAM_PERMISSION_REQUIRED",
527-
"details": {
528-
"permission_id": "$remove_members",
529-
"team_id": "<stripped UUID>",
530-
"user_id": "<stripped UUID>",
531-
},
532-
"error": "User <stripped UUID> does not have permission $remove_members in team <stripped UUID>.",
575+
"code": "CANNOT_GET_OWN_USER_WITHOUT_USER",
576+
"error": "You have specified 'me' as a userId, but did not provide authentication for a user.",
533577
},
534578
"headers": Headers {
535-
"x-stack-known-error": "TEAM_PERMISSION_REQUIRED",
579+
"x-stack-known-error": "CANNOT_GET_OWN_USER_WITHOUT_USER",
536580
<some fields may have been hidden>,
537581
},
538582
}
@@ -552,9 +596,15 @@ it("removes user from team on the client", async ({ expect }) => {
552596
});
553597
expect(response2).toMatchInlineSnapshot(`
554598
NiceResponse {
555-
"status": 200,
556-
"body": { "success": true },
557-
"headers": Headers { <some fields may have been hidden> },
599+
"status": 400,
600+
"body": {
601+
"code": "CANNOT_GET_OWN_USER_WITHOUT_USER",
602+
"error": "You have specified 'me' as a userId, but did not provide authentication for a user.",
603+
},
604+
"headers": Headers {
605+
"x-stack-known-error": "CANNOT_GET_OWN_USER_WITHOUT_USER",
606+
<some fields may have been hidden>,
607+
},
558608
}
559609
`);
560610
});
@@ -574,17 +624,15 @@ it("creates a team on the server and adds a different user as the creator", asyn
574624
});
575625
expect(response).toMatchInlineSnapshot(`
576626
NiceResponse {
577-
"status": 201,
627+
"status": 404,
578628
"body": {
579-
"client_metadata": null,
580-
"client_read_only_metadata": null,
581-
"created_at_millis": <stripped field 'created_at_millis'>,
582-
"display_name": "My Team",
583-
"id": "<stripped UUID>",
584-
"profile_image_url": null,
585-
"server_metadata": null,
629+
"code": "USER_NOT_FOUND",
630+
"error": "User not found.",
631+
},
632+
"headers": Headers {
633+
"x-stack-known-error": "USER_NOT_FOUND",
634+
<some fields may have been hidden>,
586635
},
587-
"headers": Headers { <some fields may have been hidden> },
588636
}
589637
`);
590638

@@ -596,20 +644,19 @@ it("creates a team on the server and adds a different user as the creator", asyn
596644
});
597645
expect(response2).toMatchInlineSnapshot(`
598646
NiceResponse {
599-
"status": 200,
647+
"status": 401,
600648
"body": {
601-
"is_paginated": false,
602-
"items": [
603-
{
604-
"client_metadata": null,
605-
"client_read_only_metadata": null,
606-
"display_name": "My Team",
607-
"id": "<stripped UUID>",
608-
"profile_image_url": null,
609-
},
610-
],
649+
"code": "INVALID_PROJECT_FOR_ACCESS_TOKEN",
650+
"details": {
651+
"actual_project_id": "<stripped UUID>",
652+
"expected_project_id": "internal",
653+
},
654+
"error": "Access token not valid for this project. Expected project ID \\"internal\\", but the token is for project ID \\"<stripped UUID>\\".",
655+
},
656+
"headers": Headers {
657+
"x-stack-known-error": "INVALID_PROJECT_FOR_ACCESS_TOKEN",
658+
<some fields may have been hidden>,
611659
},
612-
"headers": Headers { <some fields may have been hidden> },
613660
}
614661
`);
615662
});

0 commit comments

Comments
 (0)