rhythia-api 239.0.0 → 240.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/api/editProfile.ts +75 -13
- package/api/getProfile.ts +8 -0
- package/index.ts +8 -5
- package/package.json +2 -1
- package/types/database.ts +29 -0
package/api/editProfile.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { NextResponse } from "../utils/response";
|
|
2
2
|
import z from "zod";
|
|
3
3
|
import { Database } from "../types/database";
|
|
4
|
-
import { protectedApi, validUser } from "../utils/requestUtils";
|
|
4
|
+
import { protectedApi, validUser } from "../utils/requestUtils";
|
|
5
5
|
import { supabase } from "../utils/supabase";
|
|
6
6
|
import { getUserBySession } from "../utils/getUserBySession";
|
|
7
|
+
import { COUNTRY_LIST } from "../utils/countryList";
|
|
7
8
|
import { User } from "@supabase/supabase-js";
|
|
8
9
|
import validator from "validator";
|
|
9
10
|
import removeZeroWidth from "zero-width";
|
|
10
11
|
|
|
11
12
|
const USERNAME_CHANGE_COOLDOWN_ERROR =
|
|
12
13
|
"Username can only be changed once every 6 months";
|
|
14
|
+
const FLAG_CHANGE_ERROR = "Flag can only be changed once";
|
|
15
|
+
const countryCodes = new Set(COUNTRY_LIST);
|
|
13
16
|
|
|
14
17
|
function getNextUsernameChangeAt(
|
|
15
18
|
lastChangedAt: string | null | undefined
|
|
@@ -42,14 +45,16 @@ function isUsernameChangeLocked(
|
|
|
42
45
|
export const Schema = {
|
|
43
46
|
input: z.strictObject({
|
|
44
47
|
session: z.string(),
|
|
45
|
-
data: z.object({
|
|
46
|
-
avatar_url: z.string().optional(),
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
data: z.object({
|
|
49
|
+
avatar_url: z.string().optional(),
|
|
50
|
+
flag: z.string().optional(),
|
|
51
|
+
profile_image: z.string().optional(),
|
|
52
|
+
username: z.string().optional(),
|
|
53
|
+
}),
|
|
50
54
|
}),
|
|
51
55
|
output: z.object({
|
|
52
56
|
error: z.string().optional(),
|
|
57
|
+
can_change_flag: z.boolean().optional(),
|
|
53
58
|
next_username_change_at: z.string().nullable().optional(),
|
|
54
59
|
}),
|
|
55
60
|
};
|
|
@@ -95,18 +100,33 @@ export async function handler(
|
|
|
95
100
|
}
|
|
96
101
|
}
|
|
97
102
|
|
|
98
|
-
if (validator.trim(data.data.username || "") !== (data.data.username || "")) {
|
|
99
|
-
return NextResponse.json(
|
|
100
|
-
{
|
|
101
|
-
error: "Username can't start or end with spaces.",
|
|
102
|
-
},
|
|
103
|
+
if (validator.trim(data.data.username || "") !== (data.data.username || "")) {
|
|
104
|
+
return NextResponse.json(
|
|
105
|
+
{
|
|
106
|
+
error: "Username can't start or end with spaces.",
|
|
107
|
+
},
|
|
103
108
|
{ status: 404 }
|
|
104
109
|
);
|
|
105
110
|
}
|
|
106
111
|
|
|
107
112
|
data.data.username = removeZeroWidth(data.data.username || "");
|
|
108
|
-
|
|
109
|
-
|
|
113
|
+
|
|
114
|
+
if (data.data.flag !== undefined) {
|
|
115
|
+
const normalizedFlag = validator.trim(data.data.flag).toUpperCase();
|
|
116
|
+
|
|
117
|
+
if (!countryCodes.has(normalizedFlag as (typeof COUNTRY_LIST)[number])) {
|
|
118
|
+
return NextResponse.json(
|
|
119
|
+
{
|
|
120
|
+
error: "Flag must be a valid country code.",
|
|
121
|
+
},
|
|
122
|
+
{ status: 404 }
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
data.data.flag = normalizedFlag;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const user = (await getUserBySession(data.session)) as User;
|
|
110
130
|
|
|
111
131
|
let userData: Database["public"]["Tables"]["profiles"]["Update"];
|
|
112
132
|
|
|
@@ -144,8 +164,11 @@ export async function handler(
|
|
|
144
164
|
|
|
145
165
|
const usernameHasChanged =
|
|
146
166
|
data.data.username !== undefined && data.data.username !== userData.username;
|
|
167
|
+
const flagHasChanged =
|
|
168
|
+
data.data.flag !== undefined && data.data.flag !== userData.flag;
|
|
147
169
|
|
|
148
170
|
let nextUsernameChangeAt: string | null = null;
|
|
171
|
+
let canChangeFlag = true;
|
|
149
172
|
|
|
150
173
|
if (usernameHasChanged) {
|
|
151
174
|
const { data: usernameHistory, error: usernameHistoryError } = await supabase
|
|
@@ -180,6 +203,35 @@ export async function handler(
|
|
|
180
203
|
}
|
|
181
204
|
}
|
|
182
205
|
|
|
206
|
+
if (flagHasChanged) {
|
|
207
|
+
const { data: flagHistory, error: flagHistoryError } = await supabase
|
|
208
|
+
.from("profileFlags")
|
|
209
|
+
.select("id")
|
|
210
|
+
.eq("profile_id", userData.id!)
|
|
211
|
+
.limit(1);
|
|
212
|
+
|
|
213
|
+
if (flagHistoryError) {
|
|
214
|
+
return NextResponse.json(
|
|
215
|
+
{
|
|
216
|
+
error: "Could not verify flag change availability.",
|
|
217
|
+
},
|
|
218
|
+
{ status: 500 }
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
canChangeFlag = !flagHistory?.length;
|
|
223
|
+
|
|
224
|
+
if (!canChangeFlag) {
|
|
225
|
+
return NextResponse.json(
|
|
226
|
+
{
|
|
227
|
+
error: FLAG_CHANGE_ERROR,
|
|
228
|
+
can_change_flag: false,
|
|
229
|
+
},
|
|
230
|
+
{ status: 404 }
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
183
235
|
const upsertPayload: Database["public"]["Tables"]["profiles"]["Update"] = {
|
|
184
236
|
id: userData.id,
|
|
185
237
|
computedUsername: data.data.username?.toLowerCase(),
|
|
@@ -222,6 +274,16 @@ export async function handler(
|
|
|
222
274
|
);
|
|
223
275
|
}
|
|
224
276
|
|
|
277
|
+
if (flagHasChanged && upsertResult.error.message.includes(FLAG_CHANGE_ERROR)) {
|
|
278
|
+
return NextResponse.json(
|
|
279
|
+
{
|
|
280
|
+
error: FLAG_CHANGE_ERROR,
|
|
281
|
+
can_change_flag: false,
|
|
282
|
+
},
|
|
283
|
+
{ status: 404 }
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
225
287
|
return NextResponse.json(
|
|
226
288
|
{
|
|
227
289
|
error: "Can't update, username might be used by someone else!",
|
package/api/getProfile.ts
CHANGED
|
@@ -53,6 +53,7 @@ export const Schema = {
|
|
|
53
53
|
activity_status: z.enum(["active", "inactive"]),
|
|
54
54
|
is_online: z.boolean(),
|
|
55
55
|
last_active_timestamp: z.number().nullable(),
|
|
56
|
+
can_change_flag: z.boolean(),
|
|
56
57
|
next_username_change_at: z.string().nullable(),
|
|
57
58
|
previous_usernames: z.array(
|
|
58
59
|
z.object({
|
|
@@ -153,6 +154,12 @@ export async function handler(
|
|
|
153
154
|
.select("username,changed_at")
|
|
154
155
|
.eq("profile_id", user.id)
|
|
155
156
|
.order("changed_at", { ascending: false });
|
|
157
|
+
|
|
158
|
+
const { data: flagHistoryData } = await supabase
|
|
159
|
+
.from("profileFlags")
|
|
160
|
+
.select("id")
|
|
161
|
+
.eq("profile_id", user.id)
|
|
162
|
+
.limit(1);
|
|
156
163
|
|
|
157
164
|
//last 30 minutes
|
|
158
165
|
if (activityData && activityData.last_activity) {
|
|
@@ -214,6 +221,7 @@ export async function handler(
|
|
|
214
221
|
activity_status: activityStatus,
|
|
215
222
|
is_online: isOnline,
|
|
216
223
|
last_active_timestamp: activityData?.last_activity ?? null,
|
|
224
|
+
can_change_flag: !flagHistoryData?.length,
|
|
217
225
|
next_username_change_at: getNextUsernameChangeAt(latestUsernameChangeAt),
|
|
218
226
|
previous_usernames: previousUsernames,
|
|
219
227
|
},
|
package/index.ts
CHANGED
|
@@ -304,14 +304,16 @@ export const editCollection = handleApi({url:"/api/editCollection",...EditCollec
|
|
|
304
304
|
export const Schema = {
|
|
305
305
|
input: z.strictObject({
|
|
306
306
|
session: z.string(),
|
|
307
|
-
data: z.object({
|
|
308
|
-
avatar_url: z.string().optional(),
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
307
|
+
data: z.object({
|
|
308
|
+
avatar_url: z.string().optional(),
|
|
309
|
+
flag: z.string().optional(),
|
|
310
|
+
profile_image: z.string().optional(),
|
|
311
|
+
username: z.string().optional(),
|
|
312
|
+
}),
|
|
312
313
|
}),
|
|
313
314
|
output: z.object({
|
|
314
315
|
error: z.string().optional(),
|
|
316
|
+
can_change_flag: z.boolean().optional(),
|
|
315
317
|
next_username_change_at: z.string().nullable().optional(),
|
|
316
318
|
}),
|
|
317
319
|
};*/
|
|
@@ -993,6 +995,7 @@ export const Schema = {
|
|
|
993
995
|
activity_status: z.enum(["active", "inactive"]),
|
|
994
996
|
is_online: z.boolean(),
|
|
995
997
|
last_active_timestamp: z.number().nullable(),
|
|
998
|
+
can_change_flag: z.boolean(),
|
|
996
999
|
next_username_change_at: z.string().nullable(),
|
|
997
1000
|
previous_usernames: z.array(
|
|
998
1001
|
z.object({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rhythia-api",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "240.0.0",
|
|
4
4
|
"main": "index.ts",
|
|
5
5
|
"author": "online-contributors-cunev",
|
|
6
6
|
"scripts": {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"test": "tsx ./scripts/test.ts",
|
|
11
11
|
"cache:clear-user-scores": "bun run scripts/clear-user-score-cache.ts",
|
|
12
12
|
"db:optimize-user-scores": "bun run scripts/optimize-user-scores-indexes.ts",
|
|
13
|
+
"db:create-profile-flags": "node scripts/create-profile-flags-table.ts",
|
|
13
14
|
"db:create-profile-reports": "node scripts/create-profile-reports-table.ts",
|
|
14
15
|
"query-pull": "bun run scripts/pull-queries.ts",
|
|
15
16
|
"query-push": "bun run scripts/deploy-queries.ts",
|
package/types/database.ts
CHANGED
|
@@ -558,6 +558,35 @@ export type Database = {
|
|
|
558
558
|
},
|
|
559
559
|
]
|
|
560
560
|
}
|
|
561
|
+
profileFlags: {
|
|
562
|
+
Row: {
|
|
563
|
+
changed_at: string
|
|
564
|
+
flag: string | null
|
|
565
|
+
id: number
|
|
566
|
+
profile_id: number
|
|
567
|
+
}
|
|
568
|
+
Insert: {
|
|
569
|
+
changed_at?: string
|
|
570
|
+
flag?: string | null
|
|
571
|
+
id?: number
|
|
572
|
+
profile_id: number
|
|
573
|
+
}
|
|
574
|
+
Update: {
|
|
575
|
+
changed_at?: string
|
|
576
|
+
flag?: string | null
|
|
577
|
+
id?: number
|
|
578
|
+
profile_id?: number
|
|
579
|
+
}
|
|
580
|
+
Relationships: [
|
|
581
|
+
{
|
|
582
|
+
foreignKeyName: "profileFlags_profile_id_fkey"
|
|
583
|
+
columns: ["profile_id"]
|
|
584
|
+
isOneToOne: false
|
|
585
|
+
referencedRelation: "profiles"
|
|
586
|
+
referencedColumns: ["id"]
|
|
587
|
+
},
|
|
588
|
+
]
|
|
589
|
+
}
|
|
561
590
|
profileUsernames: {
|
|
562
591
|
Row: {
|
|
563
592
|
changed_at: string
|