rhythia-api 145.0.0 → 147.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/index.ts +24 -1610
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -11,68 +11,7 @@ export const Schema = {
|
|
|
11
11
|
output: z.object({
|
|
12
12
|
error: z.string().optional(),
|
|
13
13
|
}),
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export async function POST(request: Request) {
|
|
17
|
-
return protectedApi({
|
|
18
|
-
request,
|
|
19
|
-
schema: Schema,
|
|
20
|
-
authorization: validUser,
|
|
21
|
-
activity: handler,
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export async function handler(data: (typeof Schema)["input"]["_type"]) {
|
|
26
|
-
const user = (await supabase.auth.getUser(data.session)).data.user!;
|
|
27
|
-
let { data: queryUserData, error: userError } = await supabase
|
|
28
|
-
.from("profiles")
|
|
29
|
-
.select("*")
|
|
30
|
-
.eq("uid", user.id)
|
|
31
|
-
.single();
|
|
32
|
-
|
|
33
|
-
if (!queryUserData) {
|
|
34
|
-
return NextResponse.json({ error: "Can't find user" });
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const tags = (queryUserData?.badges || []) as string[];
|
|
38
|
-
|
|
39
|
-
if (!tags.includes("MMT")) {
|
|
40
|
-
return NextResponse.json({ error: "Only MMTs can approve maps!" });
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const { data: mapData, error } = await supabase
|
|
44
|
-
.from("beatmapPages")
|
|
45
|
-
.select("id,nominations,owner")
|
|
46
|
-
.eq("id", data.mapId)
|
|
47
|
-
.single();
|
|
48
|
-
|
|
49
|
-
if (!mapData) {
|
|
50
|
-
return NextResponse.json({ error: "Bad map" });
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (mapData.owner == queryUserData.id) {
|
|
54
|
-
return NextResponse.json({ error: "Can't approve own map" });
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if ((mapData.nominations as number[])!.length < 2) {
|
|
58
|
-
return NextResponse.json({
|
|
59
|
-
error: "Maps can get approved only if they have 2 nominations",
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if ((mapData.nominations as number[]).includes(queryUserData.id)) {
|
|
64
|
-
return NextResponse.json({
|
|
65
|
-
error: "Can't nominate and approve",
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
await supabase.from("beatmapPages").upsert({
|
|
70
|
-
id: data.mapId,
|
|
71
|
-
status: "RANKED",
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
return NextResponse.json({});
|
|
75
|
-
}
|
|
14
|
+
*/
|
|
76
15
|
import { Schema as ApproveMap } from "./api/approveMap"
|
|
77
16
|
export { Schema as SchemaApproveMap } from "./api/approveMap"
|
|
78
17
|
export const approveMap = handleApi({url:"/api/approveMap",...ApproveMap})
|
|
@@ -90,110 +29,7 @@ export const Schema = {
|
|
|
90
29
|
hash: z.string().optional(),
|
|
91
30
|
error: z.string().optional(),
|
|
92
31
|
}),
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
export async function POST(request: Request): Promise<NextResponse> {
|
|
96
|
-
return protectedApi({
|
|
97
|
-
request,
|
|
98
|
-
schema: Schema,
|
|
99
|
-
authorization: validUser,
|
|
100
|
-
activity: handler,
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export async function handler({
|
|
105
|
-
url,
|
|
106
|
-
session,
|
|
107
|
-
updateFlag,
|
|
108
|
-
}: (typeof Schema)["input"]["_type"]): Promise<
|
|
109
|
-
NextResponse<(typeof Schema)["output"]["_type"]>
|
|
110
|
-
> {
|
|
111
|
-
if (!url.startsWith(`https://static.rhythia.com/`))
|
|
112
|
-
return NextResponse.json({ error: "Invalid url" });
|
|
113
|
-
|
|
114
|
-
const request = await fetch(url);
|
|
115
|
-
const bytes = await request.arrayBuffer();
|
|
116
|
-
const parser = new SSPMParser(Buffer.from(bytes));
|
|
117
|
-
|
|
118
|
-
const parsedData = parser.parse();
|
|
119
|
-
const digested = parsedData.strings.mapID;
|
|
120
|
-
|
|
121
|
-
const user = (await supabase.auth.getUser(session)).data.user!;
|
|
122
|
-
let { data: userData, error: userError } = await supabase
|
|
123
|
-
.from("profiles")
|
|
124
|
-
.select("*")
|
|
125
|
-
.eq("uid", user.id)
|
|
126
|
-
.single();
|
|
127
|
-
|
|
128
|
-
if (!userData) {
|
|
129
|
-
return NextResponse.json({ error: "Bad user" });
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (
|
|
133
|
-
userData.ban == "excluded" ||
|
|
134
|
-
userData.ban == "restricted" ||
|
|
135
|
-
userData.ban == "silenced"
|
|
136
|
-
) {
|
|
137
|
-
return NextResponse.json(
|
|
138
|
-
{
|
|
139
|
-
error:
|
|
140
|
-
"Silenced, restricted or excluded players can't update their profile.",
|
|
141
|
-
},
|
|
142
|
-
{ status: 404 }
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
let { data: beatmapPage, error: errorlast } = await supabase
|
|
147
|
-
.from("beatmapPages")
|
|
148
|
-
.select(`*`)
|
|
149
|
-
.eq("latestBeatmapHash", digested)
|
|
150
|
-
.single();
|
|
151
|
-
|
|
152
|
-
if (beatmapPage) {
|
|
153
|
-
if (!updateFlag) {
|
|
154
|
-
return NextResponse.json({ error: "Already Exists" });
|
|
155
|
-
} else if (beatmapPage.owner !== userData.id) {
|
|
156
|
-
return NextResponse.json({ error: "Already Exists" });
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const imgkey = `beatmap-img-${Date.now()}-${digested}`;
|
|
161
|
-
|
|
162
|
-
let buffer = Buffer.from([]);
|
|
163
|
-
try {
|
|
164
|
-
buffer = await require("sharp")(parsedData.cover)
|
|
165
|
-
.resize(250)
|
|
166
|
-
.jpeg({ mozjpeg: true })
|
|
167
|
-
.toBuffer();
|
|
168
|
-
} catch (error) {}
|
|
169
|
-
|
|
170
|
-
const command = new PutObjectCommand({
|
|
171
|
-
Bucket: "rhthia-avatars",
|
|
172
|
-
Key: imgkey,
|
|
173
|
-
Body: buffer,
|
|
174
|
-
ContentType: "image/jpeg",
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
await s3Client.send(command);
|
|
178
|
-
const markers = parsedData.markers.sort((a, b) => a.position - b.position);
|
|
179
|
-
|
|
180
|
-
const upserted = await supabase.from("beatmaps").upsert({
|
|
181
|
-
beatmapHash: digested,
|
|
182
|
-
title: parsedData.strings.mapName,
|
|
183
|
-
playcount: 0,
|
|
184
|
-
difficulty: parsedData.metadata.difficulty,
|
|
185
|
-
noteCount: parsedData.metadata.noteCount,
|
|
186
|
-
length: markers[markers.length - 1].position,
|
|
187
|
-
beatmapFile: url,
|
|
188
|
-
image: `https://static.rhythia.com/${imgkey}`,
|
|
189
|
-
starRating: rateMap(parsedData),
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
if (upserted.error?.message.length) {
|
|
193
|
-
return NextResponse.json({ error: upserted.error.message });
|
|
194
|
-
}
|
|
195
|
-
return NextResponse.json({ hash: digested });
|
|
196
|
-
}
|
|
32
|
+
*/
|
|
197
33
|
import { Schema as CreateBeatmap } from "./api/createBeatmap"
|
|
198
34
|
export { Schema as SchemaCreateBeatmap } from "./api/createBeatmap"
|
|
199
35
|
export const createBeatmap = handleApi({url:"/api/createBeatmap",...CreateBeatmap})
|
|
@@ -209,54 +45,7 @@ export const Schema = {
|
|
|
209
45
|
error: z.string().optional(),
|
|
210
46
|
id: z.number().optional(),
|
|
211
47
|
}),
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
export async function POST(request: Request): Promise<NextResponse> {
|
|
215
|
-
return protectedApi({
|
|
216
|
-
request,
|
|
217
|
-
schema: Schema,
|
|
218
|
-
authorization: validUser,
|
|
219
|
-
activity: handler,
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
export async function handler({
|
|
224
|
-
session,
|
|
225
|
-
}: (typeof Schema)["input"]["_type"]): Promise<
|
|
226
|
-
NextResponse<(typeof Schema)["output"]["_type"]>
|
|
227
|
-
> {
|
|
228
|
-
const user = (await supabase.auth.getUser(session)).data.user!;
|
|
229
|
-
let { data: userData, error: userError } = await supabase
|
|
230
|
-
.from("profiles")
|
|
231
|
-
.select("*")
|
|
232
|
-
.eq("uid", user.id)
|
|
233
|
-
.single();
|
|
234
|
-
|
|
235
|
-
if (!userData) return NextResponse.json({ error: "No user." });
|
|
236
|
-
|
|
237
|
-
if (
|
|
238
|
-
userData.ban == "excluded" ||
|
|
239
|
-
userData.ban == "restricted" ||
|
|
240
|
-
userData.ban == "silenced"
|
|
241
|
-
) {
|
|
242
|
-
return NextResponse.json(
|
|
243
|
-
{
|
|
244
|
-
error:
|
|
245
|
-
"Silenced, restricted or excluded players can't update their profile.",
|
|
246
|
-
},
|
|
247
|
-
{ status: 404 }
|
|
248
|
-
);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const upserted = await supabase
|
|
252
|
-
.from("beatmapPages")
|
|
253
|
-
.upsert({
|
|
254
|
-
owner: userData.id,
|
|
255
|
-
})
|
|
256
|
-
.select("*")
|
|
257
|
-
.single();
|
|
258
|
-
return NextResponse.json({ id: upserted.data?.id });
|
|
259
|
-
}
|
|
48
|
+
*/
|
|
260
49
|
import { Schema as CreateBeatmapPage } from "./api/createBeatmapPage"
|
|
261
50
|
export { Schema as SchemaCreateBeatmapPage } from "./api/createBeatmapPage"
|
|
262
51
|
export const createBeatmapPage = handleApi({url:"/api/createBeatmapPage",...CreateBeatmapPage})
|
|
@@ -272,62 +61,7 @@ export const Schema = {
|
|
|
272
61
|
output: z.strictObject({
|
|
273
62
|
error: z.string().optional(),
|
|
274
63
|
}),
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
export async function POST(request: Request): Promise<NextResponse> {
|
|
278
|
-
return protectedApi({
|
|
279
|
-
request,
|
|
280
|
-
schema: Schema,
|
|
281
|
-
authorization: validUser,
|
|
282
|
-
activity: handler,
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
export async function handler({
|
|
287
|
-
session,
|
|
288
|
-
id,
|
|
289
|
-
}: (typeof Schema)["input"]["_type"]): Promise<
|
|
290
|
-
NextResponse<(typeof Schema)["output"]["_type"]>
|
|
291
|
-
> {
|
|
292
|
-
const user = (await supabase.auth.getUser(session)).data.user!;
|
|
293
|
-
let { data: userData, error: userError } = await supabase
|
|
294
|
-
.from("profiles")
|
|
295
|
-
.select("*")
|
|
296
|
-
.eq("uid", user.id)
|
|
297
|
-
.single();
|
|
298
|
-
|
|
299
|
-
let { data: pageData, error: pageError } = await supabase
|
|
300
|
-
.from("beatmapPages")
|
|
301
|
-
.select("*")
|
|
302
|
-
.eq("id", id)
|
|
303
|
-
.single();
|
|
304
|
-
|
|
305
|
-
if (!pageData) return NextResponse.json({ error: "No beatmap." });
|
|
306
|
-
|
|
307
|
-
let { data: beatmapData, error: bmPageError } = await supabase
|
|
308
|
-
.from("beatmaps")
|
|
309
|
-
.select("*")
|
|
310
|
-
.eq("beatmapHash", pageData.latestBeatmapHash || "-1-1-1-1")
|
|
311
|
-
.single();
|
|
312
|
-
|
|
313
|
-
if (!userData) return NextResponse.json({ error: "No user." });
|
|
314
|
-
if (!beatmapData) return NextResponse.json({ error: "No beatmap." });
|
|
315
|
-
|
|
316
|
-
if (userData.id !== pageData.owner)
|
|
317
|
-
return NextResponse.json({ error: "Non-authz user." });
|
|
318
|
-
|
|
319
|
-
if (pageData.status !== "UNRANKED")
|
|
320
|
-
return NextResponse.json({ error: "Only unranked maps can be updated" });
|
|
321
|
-
|
|
322
|
-
await supabase.from("beatmapPageComments").delete().eq("beatmapPage", id);
|
|
323
|
-
await supabase.from("beatmapPages").delete().eq("id", id);
|
|
324
|
-
await supabase
|
|
325
|
-
.from("beatmaps")
|
|
326
|
-
.delete()
|
|
327
|
-
.eq("beatmapHash", beatmapData.beatmapHash);
|
|
328
|
-
|
|
329
|
-
return NextResponse.json({});
|
|
330
|
-
}
|
|
64
|
+
*/
|
|
331
65
|
import { Schema as DeleteBeatmapPage } from "./api/deleteBeatmapPage"
|
|
332
66
|
export { Schema as SchemaDeleteBeatmapPage } from "./api/deleteBeatmapPage"
|
|
333
67
|
export const deleteBeatmapPage = handleApi({url:"/api/deleteBeatmapPage",...DeleteBeatmapPage})
|
|
@@ -345,80 +79,7 @@ export const Schema = {
|
|
|
345
79
|
output: z.object({
|
|
346
80
|
error: z.string().optional(),
|
|
347
81
|
}),
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
export async function POST(request: Request): Promise<NextResponse> {
|
|
351
|
-
return protectedApi({
|
|
352
|
-
request,
|
|
353
|
-
schema: Schema,
|
|
354
|
-
authorization: validUser,
|
|
355
|
-
activity: handler,
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
export async function handler(
|
|
360
|
-
data: (typeof Schema)["input"]["_type"]
|
|
361
|
-
): Promise<NextResponse<(typeof Schema)["output"]["_type"]>> {
|
|
362
|
-
if (!data.data.about_me) {
|
|
363
|
-
return NextResponse.json(
|
|
364
|
-
{
|
|
365
|
-
error: "Missing body.",
|
|
366
|
-
},
|
|
367
|
-
{ status: 404 }
|
|
368
|
-
);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
if (data.data.about_me.length > 10000) {
|
|
372
|
-
return NextResponse.json(
|
|
373
|
-
{
|
|
374
|
-
error: "Too long.",
|
|
375
|
-
},
|
|
376
|
-
{ status: 404 }
|
|
377
|
-
);
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
const user = (await supabase.auth.getUser(data.session)).data.user!;
|
|
381
|
-
let userData: Database["public"]["Tables"]["profiles"]["Update"];
|
|
382
|
-
|
|
383
|
-
// Find user's entry
|
|
384
|
-
{
|
|
385
|
-
let { data: queryUserData, error } = await supabase
|
|
386
|
-
.from("profiles")
|
|
387
|
-
.select("*")
|
|
388
|
-
.eq("uid", user.id);
|
|
389
|
-
|
|
390
|
-
if (!queryUserData?.length) {
|
|
391
|
-
return NextResponse.json(
|
|
392
|
-
{
|
|
393
|
-
error: "User cannot be retrieved from session",
|
|
394
|
-
},
|
|
395
|
-
{ status: 404 }
|
|
396
|
-
);
|
|
397
|
-
}
|
|
398
|
-
userData = queryUserData[0];
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
const upsertPayload: Database["public"]["Tables"]["profiles"]["Update"] = {
|
|
402
|
-
id: userData.id,
|
|
403
|
-
about_me: data.data.about_me,
|
|
404
|
-
};
|
|
405
|
-
|
|
406
|
-
const upsertResult = await supabase
|
|
407
|
-
.from("profiles")
|
|
408
|
-
.upsert(upsertPayload)
|
|
409
|
-
.select();
|
|
410
|
-
|
|
411
|
-
if (upsertResult.error) {
|
|
412
|
-
return NextResponse.json(
|
|
413
|
-
{
|
|
414
|
-
error: "Can't update..",
|
|
415
|
-
},
|
|
416
|
-
{ status: 404 }
|
|
417
|
-
);
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
return NextResponse.json({});
|
|
421
|
-
}
|
|
82
|
+
*/
|
|
422
83
|
import { Schema as EditAboutMe } from "./api/editAboutMe"
|
|
423
84
|
export { Schema as SchemaEditAboutMe } from "./api/editAboutMe"
|
|
424
85
|
export const editAboutMe = handleApi({url:"/api/editAboutMe",...EditAboutMe})
|
|
@@ -437,96 +98,7 @@ export const Schema = {
|
|
|
437
98
|
output: z.object({
|
|
438
99
|
error: z.string().optional(),
|
|
439
100
|
}),
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
export async function POST(request: Request): Promise<NextResponse> {
|
|
443
|
-
return protectedApi({
|
|
444
|
-
request,
|
|
445
|
-
schema: Schema,
|
|
446
|
-
authorization: validUser,
|
|
447
|
-
activity: handler,
|
|
448
|
-
});
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
export async function handler(
|
|
452
|
-
data: (typeof Schema)["input"]["_type"]
|
|
453
|
-
): Promise<NextResponse<(typeof Schema)["output"]["_type"]>> {
|
|
454
|
-
if (data.data.username !== undefined && data.data.username.length === 0) {
|
|
455
|
-
return NextResponse.json(
|
|
456
|
-
{
|
|
457
|
-
error: "Username can't be empty",
|
|
458
|
-
},
|
|
459
|
-
{ status: 404 }
|
|
460
|
-
);
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
if (data.data.username && data.data.username.length > 20) {
|
|
464
|
-
return NextResponse.json(
|
|
465
|
-
{
|
|
466
|
-
error: "Username too long.",
|
|
467
|
-
},
|
|
468
|
-
{ status: 404 }
|
|
469
|
-
);
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
const user = (await supabase.auth.getUser(data.session)).data.user!;
|
|
473
|
-
|
|
474
|
-
let userData: Database["public"]["Tables"]["profiles"]["Update"];
|
|
475
|
-
|
|
476
|
-
// Find user's entry
|
|
477
|
-
{
|
|
478
|
-
let { data: queryUserData, error } = await supabase
|
|
479
|
-
.from("profiles")
|
|
480
|
-
.select("*")
|
|
481
|
-
.eq("uid", user.id);
|
|
482
|
-
|
|
483
|
-
if (!queryUserData?.length) {
|
|
484
|
-
return NextResponse.json(
|
|
485
|
-
{
|
|
486
|
-
error: "User cannot be retrieved from session",
|
|
487
|
-
},
|
|
488
|
-
{ status: 404 }
|
|
489
|
-
);
|
|
490
|
-
}
|
|
491
|
-
userData = queryUserData[0];
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
if (
|
|
495
|
-
userData.ban == "excluded" ||
|
|
496
|
-
userData.ban == "restricted" ||
|
|
497
|
-
userData.ban == "silenced"
|
|
498
|
-
) {
|
|
499
|
-
return NextResponse.json(
|
|
500
|
-
{
|
|
501
|
-
error:
|
|
502
|
-
"Silenced, restricted or excluded players can't update their profile.",
|
|
503
|
-
},
|
|
504
|
-
{ status: 404 }
|
|
505
|
-
);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
const upsertPayload: Database["public"]["Tables"]["profiles"]["Update"] = {
|
|
509
|
-
id: userData.id,
|
|
510
|
-
computedUsername: data.data.username?.toLowerCase(),
|
|
511
|
-
...data.data,
|
|
512
|
-
};
|
|
513
|
-
|
|
514
|
-
const upsertResult = await supabase
|
|
515
|
-
.from("profiles")
|
|
516
|
-
.upsert(upsertPayload)
|
|
517
|
-
.select();
|
|
518
|
-
|
|
519
|
-
if (upsertResult.error) {
|
|
520
|
-
return NextResponse.json(
|
|
521
|
-
{
|
|
522
|
-
error: "Can't update, username might be used by someone else!",
|
|
523
|
-
},
|
|
524
|
-
{ status: 404 }
|
|
525
|
-
);
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
return NextResponse.json({});
|
|
529
|
-
}
|
|
101
|
+
*/
|
|
530
102
|
import { Schema as EditProfile } from "./api/editProfile"
|
|
531
103
|
export { Schema as SchemaEditProfile } from "./api/editProfile"
|
|
532
104
|
export const editProfile = handleApi({url:"/api/editProfile",...EditProfile})
|
|
@@ -546,55 +118,7 @@ export const Schema = {
|
|
|
546
118
|
url: z.string().optional(),
|
|
547
119
|
objectKey: z.string().optional(),
|
|
548
120
|
}),
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
export async function POST(request: Request): Promise<NextResponse> {
|
|
552
|
-
return protectedApi({
|
|
553
|
-
request,
|
|
554
|
-
schema: Schema,
|
|
555
|
-
authorization: validUser,
|
|
556
|
-
activity: handler,
|
|
557
|
-
});
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
export async function handler({
|
|
561
|
-
session,
|
|
562
|
-
contentLength,
|
|
563
|
-
contentType,
|
|
564
|
-
intrinsicToken,
|
|
565
|
-
}: (typeof Schema)["input"]["_type"]): Promise<
|
|
566
|
-
NextResponse<(typeof Schema)["output"]["_type"]>
|
|
567
|
-
> {
|
|
568
|
-
const user = (await supabase.auth.getUser(session)).data.user!;
|
|
569
|
-
|
|
570
|
-
if (!validateIntrinsicToken(intrinsicToken)) {
|
|
571
|
-
return NextResponse.json({
|
|
572
|
-
error: "Invalid intrinsic token",
|
|
573
|
-
});
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
if (contentLength > 5000000) {
|
|
577
|
-
return NextResponse.json({
|
|
578
|
-
error: "Max content length exceeded.",
|
|
579
|
-
});
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
const key = `user-avatar-${Date.now()}-${user.id}`;
|
|
583
|
-
const command = new PutObjectCommand({
|
|
584
|
-
Bucket: "rhthia-avatars",
|
|
585
|
-
Key: key,
|
|
586
|
-
ContentLength: contentLength,
|
|
587
|
-
ContentType: contentType,
|
|
588
|
-
});
|
|
589
|
-
|
|
590
|
-
const presigned = await getSignedUrl(s3Client, command, {
|
|
591
|
-
expiresIn: 3600,
|
|
592
|
-
});
|
|
593
|
-
return NextResponse.json({
|
|
594
|
-
url: presigned,
|
|
595
|
-
objectKey: key,
|
|
596
|
-
});
|
|
597
|
-
}
|
|
121
|
+
*/
|
|
598
122
|
import { Schema as GetAvatarUploadUrl } from "./api/getAvatarUploadUrl"
|
|
599
123
|
export { Schema as SchemaGetAvatarUploadUrl } from "./api/getAvatarUploadUrl"
|
|
600
124
|
export const getAvatarUploadUrl = handleApi({url:"/api/getAvatarUploadUrl",...GetAvatarUploadUrl})
|
|
@@ -618,41 +142,7 @@ export const Schema = {
|
|
|
618
142
|
)
|
|
619
143
|
.optional(),
|
|
620
144
|
}),
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
export async function POST(request: Request): Promise<NextResponse> {
|
|
624
|
-
return protectedApi({
|
|
625
|
-
request,
|
|
626
|
-
schema: Schema,
|
|
627
|
-
authorization: () => {},
|
|
628
|
-
activity: handler,
|
|
629
|
-
});
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
export async function handler(
|
|
633
|
-
data: (typeof Schema)["input"]["_type"]
|
|
634
|
-
): Promise<NextResponse<(typeof Schema)["output"]["_type"]>> {
|
|
635
|
-
const result = await getLeaderboard(data.badge);
|
|
636
|
-
return NextResponse.json(result);
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
export async function getLeaderboard(badge: string) {
|
|
640
|
-
let { data: queryData, error } = await supabase
|
|
641
|
-
.from("profiles")
|
|
642
|
-
.select("flag,id,username,badges");
|
|
643
|
-
|
|
644
|
-
const users = queryData?.filter((e) =>
|
|
645
|
-
((e.badges || []) as string[]).includes(badge)
|
|
646
|
-
);
|
|
647
|
-
|
|
648
|
-
return {
|
|
649
|
-
leaderboard: users?.map((user) => ({
|
|
650
|
-
flag: user.flag,
|
|
651
|
-
id: user.id,
|
|
652
|
-
username: user.username,
|
|
653
|
-
})),
|
|
654
|
-
};
|
|
655
|
-
}
|
|
145
|
+
*/
|
|
656
146
|
import { Schema as GetBadgedUsers } from "./api/getBadgedUsers"
|
|
657
147
|
export { Schema as SchemaGetBadgedUsers } from "./api/getBadgedUsers"
|
|
658
148
|
export const getBadgedUsers = handleApi({url:"/api/getBadgedUsers",...GetBadgedUsers})
|
|
@@ -680,38 +170,7 @@ export const Schema = {
|
|
|
680
170
|
})
|
|
681
171
|
),
|
|
682
172
|
}),
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
export async function POST(request: Request): Promise<NextResponse> {
|
|
686
|
-
return protectedApi({
|
|
687
|
-
request,
|
|
688
|
-
schema: Schema,
|
|
689
|
-
authorization: () => {},
|
|
690
|
-
activity: handler,
|
|
691
|
-
});
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
export async function handler({
|
|
695
|
-
page,
|
|
696
|
-
}: (typeof Schema)["input"]["_type"]): Promise<
|
|
697
|
-
NextResponse<(typeof Schema)["output"]["_type"]>
|
|
698
|
-
> {
|
|
699
|
-
let { data: userData, error: userError } = await supabase
|
|
700
|
-
.from("beatmapPageComments")
|
|
701
|
-
.select(
|
|
702
|
-
`
|
|
703
|
-
*,
|
|
704
|
-
profiles!inner(
|
|
705
|
-
username,
|
|
706
|
-
avatar_url,
|
|
707
|
-
badges
|
|
708
|
-
)
|
|
709
|
-
`
|
|
710
|
-
)
|
|
711
|
-
.eq("beatmapPage", page);
|
|
712
|
-
|
|
713
|
-
return NextResponse.json({ comments: userData! });
|
|
714
|
-
}
|
|
173
|
+
*/
|
|
715
174
|
import { Schema as GetBeatmapComments } from "./api/getBeatmapComments"
|
|
716
175
|
export { Schema as SchemaGetBeatmapComments } from "./api/getBeatmapComments"
|
|
717
176
|
export const getBeatmapComments = handleApi({url:"/api/getBeatmapComments",...GetBeatmapComments})
|
|
@@ -747,70 +206,7 @@ export const Schema = {
|
|
|
747
206
|
})
|
|
748
207
|
.optional(),
|
|
749
208
|
}),
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
export async function POST(request: Request): Promise<NextResponse> {
|
|
753
|
-
return protectedApi({
|
|
754
|
-
request,
|
|
755
|
-
schema: Schema,
|
|
756
|
-
authorization: () => {},
|
|
757
|
-
activity: handler,
|
|
758
|
-
});
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
export async function handler(
|
|
762
|
-
data: (typeof Schema)["input"]["_type"],
|
|
763
|
-
req: Request
|
|
764
|
-
): Promise<NextResponse<(typeof Schema)["output"]["_type"]>> {
|
|
765
|
-
let { data: beatmapPage, error: errorlast } = await supabase
|
|
766
|
-
.from("beatmapPages")
|
|
767
|
-
.select(
|
|
768
|
-
`
|
|
769
|
-
*,
|
|
770
|
-
beatmaps (
|
|
771
|
-
created_at,
|
|
772
|
-
playcount,
|
|
773
|
-
length,
|
|
774
|
-
ranked,
|
|
775
|
-
beatmapFile,
|
|
776
|
-
image,
|
|
777
|
-
starRating,
|
|
778
|
-
difficulty,
|
|
779
|
-
noteCount,
|
|
780
|
-
title
|
|
781
|
-
),
|
|
782
|
-
profiles (
|
|
783
|
-
username,
|
|
784
|
-
avatar_url
|
|
785
|
-
)
|
|
786
|
-
`
|
|
787
|
-
)
|
|
788
|
-
.eq("id", data.id)
|
|
789
|
-
.single();
|
|
790
|
-
|
|
791
|
-
if (!beatmapPage) return NextResponse.json({});
|
|
792
|
-
|
|
793
|
-
return NextResponse.json({
|
|
794
|
-
beatmap: {
|
|
795
|
-
playcount: beatmapPage.beatmaps?.playcount,
|
|
796
|
-
created_at: beatmapPage.created_at,
|
|
797
|
-
difficulty: beatmapPage.beatmaps?.difficulty,
|
|
798
|
-
noteCount: beatmapPage.beatmaps?.noteCount,
|
|
799
|
-
length: beatmapPage.beatmaps?.length,
|
|
800
|
-
title: beatmapPage.beatmaps?.title,
|
|
801
|
-
ranked: beatmapPage.beatmaps?.ranked,
|
|
802
|
-
beatmapFile: beatmapPage.beatmaps?.beatmapFile,
|
|
803
|
-
image: beatmapPage.beatmaps?.image,
|
|
804
|
-
starRating: beatmapPage.beatmaps?.starRating,
|
|
805
|
-
owner: beatmapPage.owner,
|
|
806
|
-
ownerUsername: beatmapPage.profiles?.username,
|
|
807
|
-
ownerAvatar: beatmapPage.profiles?.avatar_url,
|
|
808
|
-
id: beatmapPage.id,
|
|
809
|
-
status: beatmapPage.status,
|
|
810
|
-
nominations: beatmapPage.nominations as number[],
|
|
811
|
-
},
|
|
812
|
-
});
|
|
813
|
-
}
|
|
209
|
+
*/
|
|
814
210
|
import { Schema as GetBeatmapPage } from "./api/getBeatmapPage"
|
|
815
211
|
export { Schema as SchemaGetBeatmapPage } from "./api/getBeatmapPage"
|
|
816
212
|
export const getBeatmapPage = handleApi({url:"/api/getBeatmapPage",...GetBeatmapPage})
|
|
@@ -846,70 +242,7 @@ export const Schema = {
|
|
|
846
242
|
})
|
|
847
243
|
.optional(),
|
|
848
244
|
}),
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
export async function POST(request: Request): Promise<NextResponse> {
|
|
852
|
-
return protectedApi({
|
|
853
|
-
request,
|
|
854
|
-
schema: Schema,
|
|
855
|
-
authorization: () => {},
|
|
856
|
-
activity: handler,
|
|
857
|
-
});
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
export async function handler(
|
|
861
|
-
data: (typeof Schema)["input"]["_type"],
|
|
862
|
-
req: Request
|
|
863
|
-
): Promise<NextResponse<(typeof Schema)["output"]["_type"]>> {
|
|
864
|
-
let { data: beatmapPage, error: errorlast } = await supabase
|
|
865
|
-
.from("beatmapPages")
|
|
866
|
-
.select(
|
|
867
|
-
`
|
|
868
|
-
*,
|
|
869
|
-
beatmaps (
|
|
870
|
-
created_at,
|
|
871
|
-
playcount,
|
|
872
|
-
length,
|
|
873
|
-
ranked,
|
|
874
|
-
beatmapFile,
|
|
875
|
-
image,
|
|
876
|
-
starRating,
|
|
877
|
-
difficulty,
|
|
878
|
-
noteCount,
|
|
879
|
-
title
|
|
880
|
-
),
|
|
881
|
-
profiles (
|
|
882
|
-
username,
|
|
883
|
-
avatar_url
|
|
884
|
-
)
|
|
885
|
-
`
|
|
886
|
-
)
|
|
887
|
-
.eq("latestBeatmapHash", data.mapId)
|
|
888
|
-
.single();
|
|
889
|
-
|
|
890
|
-
if (!beatmapPage) return NextResponse.json({});
|
|
891
|
-
|
|
892
|
-
return NextResponse.json({
|
|
893
|
-
beatmap: {
|
|
894
|
-
playcount: beatmapPage.beatmaps?.playcount,
|
|
895
|
-
created_at: beatmapPage.created_at,
|
|
896
|
-
difficulty: beatmapPage.beatmaps?.difficulty,
|
|
897
|
-
noteCount: beatmapPage.beatmaps?.noteCount,
|
|
898
|
-
length: beatmapPage.beatmaps?.length,
|
|
899
|
-
title: beatmapPage.beatmaps?.title,
|
|
900
|
-
ranked: beatmapPage.beatmaps?.ranked,
|
|
901
|
-
beatmapFile: beatmapPage.beatmaps?.beatmapFile,
|
|
902
|
-
image: beatmapPage.beatmaps?.image,
|
|
903
|
-
starRating: beatmapPage.beatmaps?.starRating,
|
|
904
|
-
owner: beatmapPage.owner,
|
|
905
|
-
ownerUsername: beatmapPage.profiles?.username,
|
|
906
|
-
ownerAvatar: beatmapPage.profiles?.avatar_url,
|
|
907
|
-
id: beatmapPage.id,
|
|
908
|
-
status: beatmapPage.status,
|
|
909
|
-
nominations: beatmapPage.nominations as number[],
|
|
910
|
-
},
|
|
911
|
-
});
|
|
912
|
-
}
|
|
245
|
+
*/
|
|
913
246
|
import { Schema as GetBeatmapPageById } from "./api/getBeatmapPageById"
|
|
914
247
|
export { Schema as SchemaGetBeatmapPageById } from "./api/getBeatmapPageById"
|
|
915
248
|
export const getBeatmapPageById = handleApi({url:"/api/getBeatmapPageById",...GetBeatmapPageById})
|
|
@@ -959,118 +292,7 @@ export const Schema = {
|
|
|
959
292
|
)
|
|
960
293
|
.optional(),
|
|
961
294
|
}),
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
export async function POST(request: Request): Promise<NextResponse> {
|
|
965
|
-
return protectedApi({
|
|
966
|
-
request,
|
|
967
|
-
schema: Schema,
|
|
968
|
-
authorization: () => {},
|
|
969
|
-
activity: handler,
|
|
970
|
-
});
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
export async function handler(
|
|
974
|
-
data: (typeof Schema)["input"]["_type"]
|
|
975
|
-
): Promise<NextResponse<(typeof Schema)["output"]["_type"]>> {
|
|
976
|
-
const result = await getBeatmaps(data);
|
|
977
|
-
return NextResponse.json(result);
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
const VIEW_PER_PAGE = 50;
|
|
981
|
-
|
|
982
|
-
export async function getBeatmaps(data: (typeof Schema)["input"]["_type"]) {
|
|
983
|
-
const startPage = (data.page - 1) * VIEW_PER_PAGE;
|
|
984
|
-
const endPage = startPage + VIEW_PER_PAGE - 1;
|
|
985
|
-
const countQuery = await supabase
|
|
986
|
-
.from("beatmapPages")
|
|
987
|
-
.select("id", { count: "exact", head: true });
|
|
988
|
-
|
|
989
|
-
let qry = supabase
|
|
990
|
-
.from("beatmapPages")
|
|
991
|
-
.select(
|
|
992
|
-
`
|
|
993
|
-
owner,
|
|
994
|
-
created_at,
|
|
995
|
-
id,
|
|
996
|
-
status,
|
|
997
|
-
tags,
|
|
998
|
-
beatmaps!inner(
|
|
999
|
-
playcount,
|
|
1000
|
-
ranked,
|
|
1001
|
-
beatmapFile,
|
|
1002
|
-
image,
|
|
1003
|
-
starRating,
|
|
1004
|
-
difficulty,
|
|
1005
|
-
length,
|
|
1006
|
-
title
|
|
1007
|
-
),
|
|
1008
|
-
profiles!inner(
|
|
1009
|
-
username
|
|
1010
|
-
)`
|
|
1011
|
-
)
|
|
1012
|
-
.order("created_at", { ascending: false });
|
|
1013
|
-
|
|
1014
|
-
if (data.textFilter) {
|
|
1015
|
-
qry = qry.ilike("beatmaps.title", `%${data.textFilter}%`);
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
|
-
if (data.authorFilter) {
|
|
1019
|
-
qry = qry.ilike("profiles.username", `%${data.authorFilter}%`);
|
|
1020
|
-
}
|
|
1021
|
-
|
|
1022
|
-
if (data.tagsFilter) {
|
|
1023
|
-
qry = qry.ilike("tags", `%${data.tagsFilter}%`);
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
if (data.minStars) {
|
|
1027
|
-
qry = qry.gt("beatmaps.starRating", data.minStars);
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1030
|
-
if (data.maxStars) {
|
|
1031
|
-
qry = qry.lt("beatmaps.starRating", data.maxStars);
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
|
-
if (data.minLength) {
|
|
1035
|
-
qry = qry.gt("beatmaps.length", data.minLength);
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
|
-
if (data.maxLength) {
|
|
1039
|
-
qry = qry.lt("beatmaps.length", data.maxLength);
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
if (data.status) {
|
|
1043
|
-
qry = qry.eq("status", data.status);
|
|
1044
|
-
}
|
|
1045
|
-
|
|
1046
|
-
if (data.creator !== undefined) {
|
|
1047
|
-
qry = qry.eq("owner", data.creator);
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
let queryData = await qry.range(startPage, endPage);
|
|
1051
|
-
|
|
1052
|
-
return {
|
|
1053
|
-
total: countQuery.count || 0,
|
|
1054
|
-
viewPerPage: VIEW_PER_PAGE,
|
|
1055
|
-
currentPage: data.page,
|
|
1056
|
-
beatmaps: queryData.data?.map((beatmapPage) => ({
|
|
1057
|
-
id: beatmapPage.id,
|
|
1058
|
-
tags: beatmapPage.tags,
|
|
1059
|
-
playcount: beatmapPage.beatmaps?.playcount,
|
|
1060
|
-
created_at: beatmapPage.created_at,
|
|
1061
|
-
difficulty: beatmapPage.beatmaps?.difficulty,
|
|
1062
|
-
title: beatmapPage.beatmaps?.title,
|
|
1063
|
-
ranked: beatmapPage.beatmaps?.ranked,
|
|
1064
|
-
length: beatmapPage.beatmaps?.length,
|
|
1065
|
-
beatmapFile: beatmapPage.beatmaps?.beatmapFile,
|
|
1066
|
-
image: beatmapPage.beatmaps?.image,
|
|
1067
|
-
starRating: beatmapPage.beatmaps?.starRating,
|
|
1068
|
-
owner: beatmapPage.owner,
|
|
1069
|
-
status: beatmapPage.status,
|
|
1070
|
-
ownerUsername: beatmapPage.profiles?.username,
|
|
1071
|
-
})),
|
|
1072
|
-
};
|
|
1073
|
-
}
|
|
295
|
+
*/
|
|
1074
296
|
import { Schema as GetBeatmaps } from "./api/getBeatmaps"
|
|
1075
297
|
export { Schema as SchemaGetBeatmaps } from "./api/getBeatmaps"
|
|
1076
298
|
export const getBeatmaps = handleApi({url:"/api/getBeatmaps",...GetBeatmaps})
|
|
@@ -1102,77 +324,7 @@ export const Schema = {
|
|
|
1102
324
|
)
|
|
1103
325
|
.optional(),
|
|
1104
326
|
}),
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
export async function POST(request: Request): Promise<NextResponse> {
|
|
1108
|
-
return protectedApi({
|
|
1109
|
-
request,
|
|
1110
|
-
schema: Schema,
|
|
1111
|
-
authorization: () => {},
|
|
1112
|
-
activity: handler,
|
|
1113
|
-
});
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
export async function handler(
|
|
1117
|
-
data: (typeof Schema)["input"]["_type"]
|
|
1118
|
-
): Promise<NextResponse<(typeof Schema)["output"]["_type"]>> {
|
|
1119
|
-
const result = await getLeaderboard(data.page, data.session);
|
|
1120
|
-
return NextResponse.json(result);
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
const VIEW_PER_PAGE = 50;
|
|
1124
|
-
|
|
1125
|
-
export async function getLeaderboard(page = 1, session: string) {
|
|
1126
|
-
const getUserData = await getUser({ session });
|
|
1127
|
-
|
|
1128
|
-
let leaderPosition = 0;
|
|
1129
|
-
|
|
1130
|
-
if (getUserData) {
|
|
1131
|
-
let { data: queryData, error } = await supabase
|
|
1132
|
-
.from("profiles")
|
|
1133
|
-
.select("*")
|
|
1134
|
-
.eq("uid", getUserData.data.user.id)
|
|
1135
|
-
.single();
|
|
1136
|
-
|
|
1137
|
-
if (queryData) {
|
|
1138
|
-
const { count: playersWithMorePoints, error: rankError } = await supabase
|
|
1139
|
-
.from("profiles")
|
|
1140
|
-
.select("*", { count: "exact", head: true })
|
|
1141
|
-
.gt("skill_points", queryData.skill_points);
|
|
1142
|
-
|
|
1143
|
-
leaderPosition = (playersWithMorePoints || 0) + 1;
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
const startPage = (page - 1) * VIEW_PER_PAGE;
|
|
1148
|
-
const endPage = startPage + VIEW_PER_PAGE - 1;
|
|
1149
|
-
const countQuery = await supabase
|
|
1150
|
-
.from("profiles")
|
|
1151
|
-
.select("ban", { count: "exact", head: true })
|
|
1152
|
-
.neq("ban", "excluded");
|
|
1153
|
-
|
|
1154
|
-
let { data: queryData, error } = await supabase
|
|
1155
|
-
.from("profiles")
|
|
1156
|
-
.select("*")
|
|
1157
|
-
.neq("ban", "excluded")
|
|
1158
|
-
.order("skill_points", { ascending: false })
|
|
1159
|
-
.range(startPage, endPage);
|
|
1160
|
-
|
|
1161
|
-
return {
|
|
1162
|
-
total: countQuery.count || 0,
|
|
1163
|
-
viewPerPage: VIEW_PER_PAGE,
|
|
1164
|
-
currentPage: page,
|
|
1165
|
-
userPosition: leaderPosition,
|
|
1166
|
-
leaderboard: queryData?.map((user) => ({
|
|
1167
|
-
flag: user.flag,
|
|
1168
|
-
id: user.id,
|
|
1169
|
-
play_count: user.play_count,
|
|
1170
|
-
skill_points: user.skill_points,
|
|
1171
|
-
total_score: user.total_score,
|
|
1172
|
-
username: user.username,
|
|
1173
|
-
})),
|
|
1174
|
-
};
|
|
1175
|
-
}
|
|
327
|
+
*/
|
|
1176
328
|
import { Schema as GetLeaderboard } from "./api/getLeaderboard"
|
|
1177
329
|
export { Schema as SchemaGetLeaderboard } from "./api/getLeaderboard"
|
|
1178
330
|
export const getLeaderboard = handleApi({url:"/api/getLeaderboard",...GetLeaderboard})
|
|
@@ -1193,62 +345,7 @@ export const Schema = {
|
|
|
1193
345
|
url: z.string().optional(),
|
|
1194
346
|
objectKey: z.string().optional(),
|
|
1195
347
|
}),
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
export async function POST(request: Request): Promise<NextResponse> {
|
|
1199
|
-
return protectedApi({
|
|
1200
|
-
request,
|
|
1201
|
-
schema: Schema,
|
|
1202
|
-
authorization: validUser,
|
|
1203
|
-
activity: handler,
|
|
1204
|
-
});
|
|
1205
|
-
}
|
|
1206
|
-
|
|
1207
|
-
export async function handler({
|
|
1208
|
-
mapName,
|
|
1209
|
-
session,
|
|
1210
|
-
contentLength,
|
|
1211
|
-
contentType,
|
|
1212
|
-
intrinsicToken,
|
|
1213
|
-
}: (typeof Schema)["input"]["_type"]): Promise<
|
|
1214
|
-
NextResponse<(typeof Schema)["output"]["_type"]>
|
|
1215
|
-
> {
|
|
1216
|
-
const user = (await supabase.auth.getUser(session)).data.user!;
|
|
1217
|
-
|
|
1218
|
-
if (!validateIntrinsicToken(intrinsicToken)) {
|
|
1219
|
-
return NextResponse.json({
|
|
1220
|
-
error: "Invalid intrinsic token",
|
|
1221
|
-
});
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
|
-
if (contentLength > 50000000) {
|
|
1225
|
-
return NextResponse.json({
|
|
1226
|
-
error: "Max content length exceeded.",
|
|
1227
|
-
});
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
|
-
if (contentType !== "application/octet-stream") {
|
|
1231
|
-
return NextResponse.json({
|
|
1232
|
-
error: "Unnacceptable format",
|
|
1233
|
-
});
|
|
1234
|
-
}
|
|
1235
|
-
|
|
1236
|
-
const key = `rhythia-${mapName ? mapName : user.id}-${Date.now()}.sspm`;
|
|
1237
|
-
const command = new PutObjectCommand({
|
|
1238
|
-
Bucket: "rhthia-avatars",
|
|
1239
|
-
Key: key,
|
|
1240
|
-
ContentLength: contentLength,
|
|
1241
|
-
ContentType: contentType,
|
|
1242
|
-
});
|
|
1243
|
-
|
|
1244
|
-
const presigned = await getSignedUrl(s3Client, command, {
|
|
1245
|
-
expiresIn: 3600,
|
|
1246
|
-
});
|
|
1247
|
-
return NextResponse.json({
|
|
1248
|
-
url: presigned,
|
|
1249
|
-
objectKey: key,
|
|
1250
|
-
});
|
|
1251
|
-
}
|
|
348
|
+
*/
|
|
1252
349
|
import { Schema as GetMapUploadUrl } from "./api/getMapUploadUrl"
|
|
1253
350
|
export { Schema as SchemaGetMapUploadUrl } from "./api/getMapUploadUrl"
|
|
1254
351
|
export const getMapUploadUrl = handleApi({url:"/api/getMapUploadUrl",...GetMapUploadUrl})
|
|
@@ -1284,97 +381,7 @@ export const Schema = {
|
|
|
1284
381
|
})
|
|
1285
382
|
.optional(),
|
|
1286
383
|
}),
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
export async function POST(request: Request): Promise<NextResponse> {
|
|
1290
|
-
return protectedApi({
|
|
1291
|
-
request,
|
|
1292
|
-
schema: Schema,
|
|
1293
|
-
authorization: () => {},
|
|
1294
|
-
activity: handler,
|
|
1295
|
-
});
|
|
1296
|
-
}
|
|
1297
|
-
|
|
1298
|
-
export async function handler(
|
|
1299
|
-
data: (typeof Schema)["input"]["_type"],
|
|
1300
|
-
req: Request
|
|
1301
|
-
): Promise<NextResponse<(typeof Schema)["output"]["_type"]>> {
|
|
1302
|
-
let profiles: Database["public"]["Tables"]["profiles"]["Row"][] = [];
|
|
1303
|
-
|
|
1304
|
-
// Fetch by id
|
|
1305
|
-
if (data.id !== undefined && data.id !== null) {
|
|
1306
|
-
let { data: queryData, error } = await supabase
|
|
1307
|
-
.from("profiles")
|
|
1308
|
-
.select("*")
|
|
1309
|
-
.eq("id", data.id);
|
|
1310
|
-
|
|
1311
|
-
console.log(profiles, error);
|
|
1312
|
-
|
|
1313
|
-
if (!queryData?.length) {
|
|
1314
|
-
return NextResponse.json(
|
|
1315
|
-
{
|
|
1316
|
-
error: "User not found",
|
|
1317
|
-
},
|
|
1318
|
-
{ status: 404 }
|
|
1319
|
-
);
|
|
1320
|
-
}
|
|
1321
|
-
|
|
1322
|
-
profiles = queryData;
|
|
1323
|
-
} else {
|
|
1324
|
-
// Fetch by session id
|
|
1325
|
-
const user = (await supabase.auth.getUser(data.session)).data.user;
|
|
1326
|
-
|
|
1327
|
-
if (user) {
|
|
1328
|
-
let { data: queryData, error } = await supabase
|
|
1329
|
-
.from("profiles")
|
|
1330
|
-
.select("*")
|
|
1331
|
-
.eq("uid", user.id);
|
|
1332
|
-
|
|
1333
|
-
if (!queryData?.length) {
|
|
1334
|
-
const geo = geolocation(req);
|
|
1335
|
-
const data = await supabase
|
|
1336
|
-
.from("profiles")
|
|
1337
|
-
.upsert({
|
|
1338
|
-
uid: user.id,
|
|
1339
|
-
about_me: "",
|
|
1340
|
-
avatar_url:
|
|
1341
|
-
"https://rhthia-avatars.s3.eu-central-003.backblazeb2.com/user-avatar-1725309193296-72002e6b-321c-4f60-a692-568e0e75147d",
|
|
1342
|
-
badges: [],
|
|
1343
|
-
username: `${user.user_metadata.full_name.slice(0, 20)}${Math.round(
|
|
1344
|
-
Math.random() * 900000 + 100000
|
|
1345
|
-
)}`,
|
|
1346
|
-
computedUsername: `${user.user_metadata.full_name.slice(
|
|
1347
|
-
0,
|
|
1348
|
-
20
|
|
1349
|
-
)}${Math.round(Math.random() * 900000 + 100000)}`.toLowerCase(),
|
|
1350
|
-
flag: (geo.country || "US").toUpperCase(),
|
|
1351
|
-
created_at: Date.now(),
|
|
1352
|
-
})
|
|
1353
|
-
.select();
|
|
1354
|
-
|
|
1355
|
-
profiles = data.data!;
|
|
1356
|
-
} else {
|
|
1357
|
-
profiles = queryData;
|
|
1358
|
-
}
|
|
1359
|
-
}
|
|
1360
|
-
}
|
|
1361
|
-
|
|
1362
|
-
const user = profiles[0];
|
|
1363
|
-
|
|
1364
|
-
// Query to count how many players have more skill points than the specific player
|
|
1365
|
-
const { count: playersWithMorePoints, error: rankError } = await supabase
|
|
1366
|
-
.from("profiles")
|
|
1367
|
-
.select("*", { count: "exact", head: true })
|
|
1368
|
-
.neq("ban", "excluded")
|
|
1369
|
-
.gt("skill_points", user.skill_points);
|
|
1370
|
-
|
|
1371
|
-
return NextResponse.json({
|
|
1372
|
-
user: {
|
|
1373
|
-
...user,
|
|
1374
|
-
position: (playersWithMorePoints || 0) + 1,
|
|
1375
|
-
},
|
|
1376
|
-
});
|
|
1377
|
-
}
|
|
384
|
+
*/
|
|
1378
385
|
import { Schema as GetProfile } from "./api/getProfile"
|
|
1379
386
|
export { Schema as SchemaGetProfile } from "./api/getProfile"
|
|
1380
387
|
export const getProfile = handleApi({url:"/api/getProfile",...GetProfile})
|
|
@@ -1389,36 +396,7 @@ export const Schema = {
|
|
|
1389
396
|
beatmaps: z.number(),
|
|
1390
397
|
scores: z.number(),
|
|
1391
398
|
}),
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
export async function POST(request: Request) {
|
|
1395
|
-
return protectedApi({
|
|
1396
|
-
request,
|
|
1397
|
-
schema: Schema,
|
|
1398
|
-
authorization: () => {},
|
|
1399
|
-
activity: handler,
|
|
1400
|
-
});
|
|
1401
|
-
}
|
|
1402
|
-
|
|
1403
|
-
export async function handler(data: (typeof Schema)["input"]["_type"]) {
|
|
1404
|
-
const countProfilesQuery = await supabase
|
|
1405
|
-
.from("profiles")
|
|
1406
|
-
.select("*", { count: "exact", head: true });
|
|
1407
|
-
|
|
1408
|
-
const countBeatmapsQuery = await supabase
|
|
1409
|
-
.from("beatmaps")
|
|
1410
|
-
.select("*", { count: "exact", head: true });
|
|
1411
|
-
|
|
1412
|
-
const countScoresQuery = await supabase
|
|
1413
|
-
.from("scores")
|
|
1414
|
-
.select("*", { count: "exact", head: true });
|
|
1415
|
-
|
|
1416
|
-
return NextResponse.json({
|
|
1417
|
-
beatmaps: countBeatmapsQuery.count,
|
|
1418
|
-
profiles: countProfilesQuery.count,
|
|
1419
|
-
scores: countScoresQuery.count,
|
|
1420
|
-
});
|
|
1421
|
-
}
|
|
399
|
+
*/
|
|
1422
400
|
import { Schema as GetPublicStats } from "./api/getPublicStats"
|
|
1423
401
|
export { Schema as SchemaGetPublicStats } from "./api/getPublicStats"
|
|
1424
402
|
export const getPublicStats = handleApi({url:"/api/getPublicStats",...GetPublicStats})
|
|
@@ -1451,59 +429,7 @@ export const Schema = {
|
|
|
1451
429
|
})
|
|
1452
430
|
.optional(),
|
|
1453
431
|
}),
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
export async function POST(request: Request): Promise<NextResponse> {
|
|
1457
|
-
return protectedApi({
|
|
1458
|
-
request,
|
|
1459
|
-
schema: Schema,
|
|
1460
|
-
authorization: () => {},
|
|
1461
|
-
activity: handler,
|
|
1462
|
-
});
|
|
1463
|
-
}
|
|
1464
|
-
|
|
1465
|
-
export async function handler(
|
|
1466
|
-
data: (typeof Schema)["input"]["_type"],
|
|
1467
|
-
req: Request
|
|
1468
|
-
): Promise<NextResponse<(typeof Schema)["output"]["_type"]>> {
|
|
1469
|
-
let { data: score, error: errorlast } = await supabase
|
|
1470
|
-
.from("scores")
|
|
1471
|
-
.select(
|
|
1472
|
-
`
|
|
1473
|
-
*,
|
|
1474
|
-
beatmaps (
|
|
1475
|
-
difficulty,
|
|
1476
|
-
noteCount,
|
|
1477
|
-
title
|
|
1478
|
-
),
|
|
1479
|
-
profiles (
|
|
1480
|
-
username
|
|
1481
|
-
)
|
|
1482
|
-
`
|
|
1483
|
-
)
|
|
1484
|
-
.eq("id", data.id)
|
|
1485
|
-
.single();
|
|
1486
|
-
|
|
1487
|
-
if (!score) return NextResponse.json({});
|
|
1488
|
-
|
|
1489
|
-
return NextResponse.json({
|
|
1490
|
-
score: {
|
|
1491
|
-
created_at: score.created_at,
|
|
1492
|
-
id: score.id,
|
|
1493
|
-
passed: score.passed,
|
|
1494
|
-
userId: score.userId,
|
|
1495
|
-
awarded_sp: score.awarded_sp,
|
|
1496
|
-
beatmapHash: score.beatmapHash,
|
|
1497
|
-
misses: score.misses,
|
|
1498
|
-
songId: score.songId,
|
|
1499
|
-
beatmapDifficulty: score.beatmaps?.difficulty,
|
|
1500
|
-
beatmapNotes: score.beatmaps?.noteCount,
|
|
1501
|
-
beatmapTitle: score.beatmaps?.title,
|
|
1502
|
-
username: score.profiles?.username,
|
|
1503
|
-
speed: score.speed,
|
|
1504
|
-
},
|
|
1505
|
-
});
|
|
1506
|
-
}
|
|
432
|
+
*/
|
|
1507
433
|
import { Schema as GetScore } from "./api/getScore"
|
|
1508
434
|
export { Schema as SchemaGetScore } from "./api/getScore"
|
|
1509
435
|
export const getScore = handleApi({url:"/api/getScore",...GetScore})
|
|
@@ -1556,107 +482,7 @@ export const Schema = {
|
|
|
1556
482
|
)
|
|
1557
483
|
.optional(),
|
|
1558
484
|
}),
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
export async function POST(request: Request): Promise<NextResponse> {
|
|
1562
|
-
return protectedApi({
|
|
1563
|
-
request,
|
|
1564
|
-
schema: Schema,
|
|
1565
|
-
authorization: () => {},
|
|
1566
|
-
activity: handler,
|
|
1567
|
-
});
|
|
1568
|
-
}
|
|
1569
|
-
|
|
1570
|
-
export async function handler(
|
|
1571
|
-
data: (typeof Schema)["input"]["_type"],
|
|
1572
|
-
req: Request
|
|
1573
|
-
): Promise<NextResponse<(typeof Schema)["output"]["_type"]>> {
|
|
1574
|
-
let { data: scores1, error: errorlast } = await supabase
|
|
1575
|
-
.from("scores")
|
|
1576
|
-
.select(
|
|
1577
|
-
`
|
|
1578
|
-
*,
|
|
1579
|
-
beatmaps (
|
|
1580
|
-
difficulty,
|
|
1581
|
-
noteCount,
|
|
1582
|
-
title
|
|
1583
|
-
)
|
|
1584
|
-
`
|
|
1585
|
-
)
|
|
1586
|
-
.eq("userId", data.id)
|
|
1587
|
-
.eq("passed", true)
|
|
1588
|
-
.order("created_at", { ascending: false })
|
|
1589
|
-
.limit(10);
|
|
1590
|
-
|
|
1591
|
-
let { data: scores2, error: errorsp } = await supabase
|
|
1592
|
-
.from("scores")
|
|
1593
|
-
.select(
|
|
1594
|
-
`
|
|
1595
|
-
*,
|
|
1596
|
-
beatmaps (
|
|
1597
|
-
difficulty,
|
|
1598
|
-
noteCount,
|
|
1599
|
-
title
|
|
1600
|
-
)
|
|
1601
|
-
`
|
|
1602
|
-
)
|
|
1603
|
-
.eq("userId", data.id)
|
|
1604
|
-
.neq("awarded_sp", 0)
|
|
1605
|
-
.eq("passed", true)
|
|
1606
|
-
.order("awarded_sp", { ascending: false });
|
|
1607
|
-
|
|
1608
|
-
if (scores2 == null) return NextResponse.json({ error: "No scores" });
|
|
1609
|
-
|
|
1610
|
-
let hashMap: Record<string, { awarded_sp: number; score: any }> = {};
|
|
1611
|
-
|
|
1612
|
-
for (const score of scores2) {
|
|
1613
|
-
const { beatmapHash, awarded_sp } = score;
|
|
1614
|
-
|
|
1615
|
-
if (!beatmapHash || !awarded_sp) continue;
|
|
1616
|
-
|
|
1617
|
-
if (!hashMap[beatmapHash] || hashMap[beatmapHash].awarded_sp < awarded_sp) {
|
|
1618
|
-
hashMap[beatmapHash] = { awarded_sp, score };
|
|
1619
|
-
}
|
|
1620
|
-
}
|
|
1621
|
-
|
|
1622
|
-
const values = Object.values(hashMap);
|
|
1623
|
-
let vals = values
|
|
1624
|
-
.sort((a, b) => b.awarded_sp - a.awarded_sp)
|
|
1625
|
-
.slice(0, 10)
|
|
1626
|
-
.map((e) => e.score);
|
|
1627
|
-
|
|
1628
|
-
return NextResponse.json({
|
|
1629
|
-
lastDay: scores1?.map((s) => ({
|
|
1630
|
-
created_at: s.created_at,
|
|
1631
|
-
id: s.id,
|
|
1632
|
-
passed: s.passed,
|
|
1633
|
-
userId: s.userId,
|
|
1634
|
-
awarded_sp: s.awarded_sp,
|
|
1635
|
-
beatmapHash: s.beatmapHash,
|
|
1636
|
-
misses: s.misses,
|
|
1637
|
-
songId: s.songId,
|
|
1638
|
-
beatmapDifficulty: s.beatmaps?.difficulty,
|
|
1639
|
-
beatmapNotes: s.beatmaps?.noteCount,
|
|
1640
|
-
beatmapTitle: s.beatmaps?.title,
|
|
1641
|
-
speed: s.speed,
|
|
1642
|
-
})),
|
|
1643
|
-
top: vals?.map((s) => ({
|
|
1644
|
-
created_at: s.created_at,
|
|
1645
|
-
id: s.id,
|
|
1646
|
-
passed: s.passed,
|
|
1647
|
-
userId: s.userId,
|
|
1648
|
-
awarded_sp: s.awarded_sp,
|
|
1649
|
-
beatmapHash: s.beatmapHash,
|
|
1650
|
-
misses: s.misses,
|
|
1651
|
-
rank: s.rank,
|
|
1652
|
-
songId: s.songId,
|
|
1653
|
-
beatmapDifficulty: s.beatmaps?.difficulty,
|
|
1654
|
-
beatmapNotes: s.beatmaps?.noteCount,
|
|
1655
|
-
beatmapTitle: s.beatmaps?.title,
|
|
1656
|
-
speed: s.speed,
|
|
1657
|
-
})),
|
|
1658
|
-
});
|
|
1659
|
-
}
|
|
485
|
+
*/
|
|
1660
486
|
import { Schema as GetUserScores } from "./api/getUserScores"
|
|
1661
487
|
export { Schema as SchemaGetUserScores } from "./api/getUserScores"
|
|
1662
488
|
export const getUserScores = handleApi({url:"/api/getUserScores",...GetUserScores})
|
|
@@ -1672,60 +498,7 @@ export const Schema = {
|
|
|
1672
498
|
output: z.object({
|
|
1673
499
|
error: z.string().optional(),
|
|
1674
500
|
}),
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
export async function POST(request: Request) {
|
|
1678
|
-
return protectedApi({
|
|
1679
|
-
request,
|
|
1680
|
-
schema: Schema,
|
|
1681
|
-
authorization: validUser,
|
|
1682
|
-
activity: handler,
|
|
1683
|
-
});
|
|
1684
|
-
}
|
|
1685
|
-
|
|
1686
|
-
export async function handler(data: (typeof Schema)["input"]["_type"]) {
|
|
1687
|
-
const user = (await supabase.auth.getUser(data.session)).data.user!;
|
|
1688
|
-
let { data: queryUserData, error: userError } = await supabase
|
|
1689
|
-
.from("profiles")
|
|
1690
|
-
.select("*")
|
|
1691
|
-
.eq("uid", user.id)
|
|
1692
|
-
.single();
|
|
1693
|
-
|
|
1694
|
-
if (!queryUserData) {
|
|
1695
|
-
return NextResponse.json({ error: "Can't find user" });
|
|
1696
|
-
}
|
|
1697
|
-
|
|
1698
|
-
const tags = (queryUserData?.badges || []) as string[];
|
|
1699
|
-
|
|
1700
|
-
if (!tags.includes("RCT")) {
|
|
1701
|
-
return NextResponse.json({ error: "Only RCTs can nominate maps!" });
|
|
1702
|
-
}
|
|
1703
|
-
|
|
1704
|
-
const { data: mapData, error } = await supabase
|
|
1705
|
-
.from("beatmapPages")
|
|
1706
|
-
.select("id,nominations,owner")
|
|
1707
|
-
.eq("id", data.mapId)
|
|
1708
|
-
.single();
|
|
1709
|
-
|
|
1710
|
-
if (!mapData) {
|
|
1711
|
-
return NextResponse.json({ error: "Bad map" });
|
|
1712
|
-
}
|
|
1713
|
-
|
|
1714
|
-
if (mapData.owner == queryUserData.id) {
|
|
1715
|
-
return NextResponse.json({ error: "Can't nominate own map" });
|
|
1716
|
-
}
|
|
1717
|
-
|
|
1718
|
-
if ((mapData.nominations as number[]).includes(queryUserData.id)) {
|
|
1719
|
-
return NextResponse.json({ error: "Already nominated" });
|
|
1720
|
-
}
|
|
1721
|
-
|
|
1722
|
-
await supabase.from("beatmapPages").upsert({
|
|
1723
|
-
id: data.mapId,
|
|
1724
|
-
nominations: [...(mapData.nominations! as number[]), queryUserData.id],
|
|
1725
|
-
});
|
|
1726
|
-
|
|
1727
|
-
return NextResponse.json({});
|
|
1728
|
-
}
|
|
501
|
+
*/
|
|
1729
502
|
import { Schema as NominateMap } from "./api/nominateMap"
|
|
1730
503
|
export { Schema as SchemaNominateMap } from "./api/nominateMap"
|
|
1731
504
|
export const nominateMap = handleApi({url:"/api/nominateMap",...NominateMap})
|
|
@@ -1742,48 +515,7 @@ export const Schema = {
|
|
|
1742
515
|
output: z.strictObject({
|
|
1743
516
|
error: z.string().optional(),
|
|
1744
517
|
}),
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
export async function POST(request: Request): Promise<NextResponse> {
|
|
1748
|
-
return protectedApi({
|
|
1749
|
-
request,
|
|
1750
|
-
schema: Schema,
|
|
1751
|
-
authorization: validUser,
|
|
1752
|
-
activity: handler,
|
|
1753
|
-
});
|
|
1754
|
-
}
|
|
1755
|
-
|
|
1756
|
-
export async function handler({
|
|
1757
|
-
session,
|
|
1758
|
-
page,
|
|
1759
|
-
content,
|
|
1760
|
-
}: (typeof Schema)["input"]["_type"]): Promise<
|
|
1761
|
-
NextResponse<(typeof Schema)["output"]["_type"]>
|
|
1762
|
-
> {
|
|
1763
|
-
const user = (await supabase.auth.getUser(session)).data.user!;
|
|
1764
|
-
let { data: userData, error: userError } = await supabase
|
|
1765
|
-
.from("profiles")
|
|
1766
|
-
.select("*")
|
|
1767
|
-
.eq("uid", user.id)
|
|
1768
|
-
.single();
|
|
1769
|
-
|
|
1770
|
-
if (!userData) return NextResponse.json({ error: "No user." });
|
|
1771
|
-
|
|
1772
|
-
const upserted = await supabase
|
|
1773
|
-
.from("beatmapPageComments")
|
|
1774
|
-
.upsert({
|
|
1775
|
-
beatmapPage: page,
|
|
1776
|
-
owner: userData.id,
|
|
1777
|
-
content,
|
|
1778
|
-
})
|
|
1779
|
-
.select("*")
|
|
1780
|
-
.single();
|
|
1781
|
-
|
|
1782
|
-
if (upserted.error?.message.length) {
|
|
1783
|
-
return NextResponse.json({ error: upserted.error.message });
|
|
1784
|
-
}
|
|
1785
|
-
return NextResponse.json({});
|
|
1786
|
-
}
|
|
518
|
+
*/
|
|
1787
519
|
import { Schema as PostBeatmapComment } from "./api/postBeatmapComment"
|
|
1788
520
|
export { Schema as SchemaPostBeatmapComment } from "./api/postBeatmapComment"
|
|
1789
521
|
export const postBeatmapComment = handleApi({url:"/api/postBeatmapComment",...PostBeatmapComment})
|
|
@@ -1799,55 +531,7 @@ export const Schema = {
|
|
|
1799
531
|
output: z.object({
|
|
1800
532
|
error: z.string().optional(),
|
|
1801
533
|
}),
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
export async function POST(request: Request) {
|
|
1805
|
-
return protectedApi({
|
|
1806
|
-
request,
|
|
1807
|
-
schema: Schema,
|
|
1808
|
-
authorization: validUser,
|
|
1809
|
-
activity: handler,
|
|
1810
|
-
});
|
|
1811
|
-
}
|
|
1812
|
-
|
|
1813
|
-
export async function handler(data: (typeof Schema)["input"]["_type"]) {
|
|
1814
|
-
const user = (await supabase.auth.getUser(data.session)).data.user!;
|
|
1815
|
-
let { data: queryUserData, error: userError } = await supabase
|
|
1816
|
-
.from("profiles")
|
|
1817
|
-
.select("*")
|
|
1818
|
-
.eq("uid", user.id)
|
|
1819
|
-
.single();
|
|
1820
|
-
|
|
1821
|
-
if (!queryUserData) {
|
|
1822
|
-
return NextResponse.json({ error: "Can't find user" });
|
|
1823
|
-
}
|
|
1824
|
-
|
|
1825
|
-
const tags = (queryUserData?.badges || []) as string[];
|
|
1826
|
-
|
|
1827
|
-
if (!tags.includes("Bot")) {
|
|
1828
|
-
return NextResponse.json({ error: "Only Bots can force-rank maps!" });
|
|
1829
|
-
}
|
|
1830
|
-
|
|
1831
|
-
const { data: mapData, error } = await supabase
|
|
1832
|
-
.from("beatmapPages")
|
|
1833
|
-
.select("id,nominations,owner,status")
|
|
1834
|
-
.eq("owner", user.id)
|
|
1835
|
-
.eq("status", "UNRANKED");
|
|
1836
|
-
|
|
1837
|
-
if (!mapData) {
|
|
1838
|
-
return NextResponse.json({ error: "Bad map" });
|
|
1839
|
-
}
|
|
1840
|
-
|
|
1841
|
-
for (const element of mapData) {
|
|
1842
|
-
await supabase.from("beatmapPages").upsert({
|
|
1843
|
-
id: element.id,
|
|
1844
|
-
nominations: [queryUserData.id, queryUserData.id],
|
|
1845
|
-
status: "RANKED",
|
|
1846
|
-
});
|
|
1847
|
-
}
|
|
1848
|
-
|
|
1849
|
-
return NextResponse.json({});
|
|
1850
|
-
}
|
|
534
|
+
*/
|
|
1851
535
|
import { Schema as RankMapsArchive } from "./api/rankMapsArchive"
|
|
1852
536
|
export { Schema as SchemaRankMapsArchive } from "./api/rankMapsArchive"
|
|
1853
537
|
export const rankMapsArchive = handleApi({url:"/api/rankMapsArchive",...RankMapsArchive})
|
|
@@ -1870,28 +554,7 @@ export const Schema = {
|
|
|
1870
554
|
)
|
|
1871
555
|
.optional(),
|
|
1872
556
|
}),
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
export async function POST(request: Request) {
|
|
1876
|
-
return protectedApi({
|
|
1877
|
-
request,
|
|
1878
|
-
schema: Schema,
|
|
1879
|
-
authorization: () => {},
|
|
1880
|
-
activity: handler,
|
|
1881
|
-
});
|
|
1882
|
-
}
|
|
1883
|
-
|
|
1884
|
-
export async function handler(data: (typeof Schema)["input"]["_type"]) {
|
|
1885
|
-
const { data: searchData, error } = await supabase
|
|
1886
|
-
.from("profiles")
|
|
1887
|
-
.select("id,username")
|
|
1888
|
-
.neq("ban", "excluded")
|
|
1889
|
-
.ilike("username", `%${data.text}%`)
|
|
1890
|
-
.limit(10);
|
|
1891
|
-
return NextResponse.json({
|
|
1892
|
-
results: searchData || [],
|
|
1893
|
-
});
|
|
1894
|
-
}
|
|
557
|
+
*/
|
|
1895
558
|
import { Schema as SearchUsers } from "./api/searchUsers"
|
|
1896
559
|
export { Schema as SchemaSearchUsers } from "./api/searchUsers"
|
|
1897
560
|
export const searchUsers = handleApi({url:"/api/searchUsers",...SearchUsers})
|
|
@@ -1916,188 +579,7 @@ export const Schema = {
|
|
|
1916
579
|
output: z.object({
|
|
1917
580
|
error: z.string().optional(),
|
|
1918
581
|
}),
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
function easeInExpoDeq(x: number) {
|
|
1922
|
-
return x === 0 ? 0 : Math.pow(2, 50 * x - 50);
|
|
1923
|
-
}
|
|
1924
|
-
|
|
1925
|
-
export function calculatePerformancePoints(
|
|
1926
|
-
starRating: number,
|
|
1927
|
-
accuracy: number
|
|
1928
|
-
) {
|
|
1929
|
-
return Math.round(
|
|
1930
|
-
Math.pow((starRating * easeInExpoDeq(accuracy) * 100) / 2, 2) / 1000
|
|
1931
|
-
);
|
|
1932
|
-
}
|
|
1933
|
-
|
|
1934
|
-
export async function POST(request: Request): Promise<NextResponse> {
|
|
1935
|
-
return protectedApi({
|
|
1936
|
-
request,
|
|
1937
|
-
schema: Schema,
|
|
1938
|
-
authorization: validUser,
|
|
1939
|
-
activity: handler,
|
|
1940
|
-
});
|
|
1941
|
-
}
|
|
1942
|
-
|
|
1943
|
-
export async function handler({
|
|
1944
|
-
data,
|
|
1945
|
-
session,
|
|
1946
|
-
}: (typeof Schema)["input"]["_type"]): Promise<
|
|
1947
|
-
NextResponse<(typeof Schema)["output"]["_type"]>
|
|
1948
|
-
> {
|
|
1949
|
-
return NextResponse.json(
|
|
1950
|
-
{
|
|
1951
|
-
error: "Disabled",
|
|
1952
|
-
},
|
|
1953
|
-
{ status: 500 }
|
|
1954
|
-
);
|
|
1955
|
-
const user = (await supabase.auth.getUser(session)).data.user!;
|
|
1956
|
-
|
|
1957
|
-
let { data: userData, error: userError } = await supabase
|
|
1958
|
-
.from("profiles")
|
|
1959
|
-
.select("*")
|
|
1960
|
-
.eq("uid", user.id)
|
|
1961
|
-
.single();
|
|
1962
|
-
|
|
1963
|
-
if (!userData)
|
|
1964
|
-
return NextResponse.json(
|
|
1965
|
-
{
|
|
1966
|
-
error: "User doesn't exist",
|
|
1967
|
-
},
|
|
1968
|
-
{ status: 500 }
|
|
1969
|
-
);
|
|
1970
|
-
|
|
1971
|
-
console.log(userData);
|
|
1972
|
-
let { data: beatmaps, error } = await supabase
|
|
1973
|
-
.from("beatmaps")
|
|
1974
|
-
.select("*")
|
|
1975
|
-
.eq("beatmapHash", data.mapHash)
|
|
1976
|
-
.single();
|
|
1977
|
-
|
|
1978
|
-
let { data: beatmapPages, error: bpError } = await supabase
|
|
1979
|
-
.from("beatmapPages")
|
|
1980
|
-
.select("*")
|
|
1981
|
-
.eq("latestBeatmapHash", data.mapHash)
|
|
1982
|
-
.single();
|
|
1983
|
-
|
|
1984
|
-
if (!beatmapPages) {
|
|
1985
|
-
return NextResponse.json(
|
|
1986
|
-
{
|
|
1987
|
-
error: "Map not submitted",
|
|
1988
|
-
},
|
|
1989
|
-
{ status: 500 }
|
|
1990
|
-
);
|
|
1991
|
-
}
|
|
1992
|
-
|
|
1993
|
-
if (!beatmaps) {
|
|
1994
|
-
return NextResponse.json(
|
|
1995
|
-
{
|
|
1996
|
-
error: "Map not submitted",
|
|
1997
|
-
},
|
|
1998
|
-
{ status: 500 }
|
|
1999
|
-
);
|
|
2000
|
-
}
|
|
2001
|
-
|
|
2002
|
-
if (beatmaps.noteCount !== data.mapNoteCount) {
|
|
2003
|
-
return NextResponse.json(
|
|
2004
|
-
{
|
|
2005
|
-
error: "Wrong map",
|
|
2006
|
-
},
|
|
2007
|
-
{ status: 500 }
|
|
2008
|
-
);
|
|
2009
|
-
}
|
|
2010
|
-
|
|
2011
|
-
await supabase.from("beatmaps").upsert({
|
|
2012
|
-
beatmapHash: data.mapHash,
|
|
2013
|
-
playcount: (beatmaps.playcount || 1) + 1,
|
|
2014
|
-
});
|
|
2015
|
-
|
|
2016
|
-
let passed = true;
|
|
2017
|
-
|
|
2018
|
-
// Pass invalidation
|
|
2019
|
-
if (data.misses + data.hits !== beatmaps.noteCount) {
|
|
2020
|
-
passed = false;
|
|
2021
|
-
}
|
|
2022
|
-
|
|
2023
|
-
const accurracy = data.hits / beatmaps.noteCount;
|
|
2024
|
-
let awarded_sp = 0;
|
|
2025
|
-
|
|
2026
|
-
console.log(
|
|
2027
|
-
data.misses + data.hits == beatmaps.noteCount,
|
|
2028
|
-
data.misses + data.hits,
|
|
2029
|
-
beatmaps.noteCount
|
|
2030
|
-
);
|
|
2031
|
-
|
|
2032
|
-
if (beatmaps.starRating) {
|
|
2033
|
-
awarded_sp = calculatePerformancePoints(
|
|
2034
|
-
data.speed * beatmaps.starRating,
|
|
2035
|
-
accurracy
|
|
2036
|
-
);
|
|
2037
|
-
}
|
|
2038
|
-
|
|
2039
|
-
if (beatmapPages.status == "UNRANKED") {
|
|
2040
|
-
awarded_sp = 0;
|
|
2041
|
-
}
|
|
2042
|
-
|
|
2043
|
-
console.log("p1");
|
|
2044
|
-
await supabase.from("scores").upsert({
|
|
2045
|
-
beatmapHash: data.mapHash,
|
|
2046
|
-
replayHwid: data.relayHwid,
|
|
2047
|
-
songId: data.songId,
|
|
2048
|
-
userId: userData.id,
|
|
2049
|
-
passed,
|
|
2050
|
-
misses: data.misses,
|
|
2051
|
-
awarded_sp: Math.round(awarded_sp * 100) / 100,
|
|
2052
|
-
speed: data.speed,
|
|
2053
|
-
});
|
|
2054
|
-
console.log("p2");
|
|
2055
|
-
|
|
2056
|
-
let totalSp = 0;
|
|
2057
|
-
let { data: scores2, error: errorsp } = await supabase
|
|
2058
|
-
.from("scores")
|
|
2059
|
-
.select(`awarded_sp,beatmapHash`)
|
|
2060
|
-
.eq("userId", userData.id)
|
|
2061
|
-
.neq("awarded_sp", 0)
|
|
2062
|
-
.eq("passed", true)
|
|
2063
|
-
.order("awarded_sp", { ascending: false });
|
|
2064
|
-
|
|
2065
|
-
if (scores2 == null) return NextResponse.json({ error: "No scores" });
|
|
2066
|
-
|
|
2067
|
-
let hashMap: Record<string, number> = {};
|
|
2068
|
-
|
|
2069
|
-
for (const score of scores2) {
|
|
2070
|
-
const { beatmapHash, awarded_sp } = score;
|
|
2071
|
-
|
|
2072
|
-
if (!beatmapHash || !awarded_sp) continue;
|
|
2073
|
-
|
|
2074
|
-
if (!hashMap[beatmapHash] || hashMap[beatmapHash] < awarded_sp) {
|
|
2075
|
-
hashMap[beatmapHash] = awarded_sp;
|
|
2076
|
-
}
|
|
2077
|
-
}
|
|
2078
|
-
let weight = 100;
|
|
2079
|
-
const values = Object.values(hashMap);
|
|
2080
|
-
values.sort((a, b) => b - a);
|
|
2081
|
-
|
|
2082
|
-
for (const score of values) {
|
|
2083
|
-
totalSp += ((score || 0) * weight) / 100;
|
|
2084
|
-
weight -= 1;
|
|
2085
|
-
|
|
2086
|
-
if (weight == 0) {
|
|
2087
|
-
break;
|
|
2088
|
-
}
|
|
2089
|
-
}
|
|
2090
|
-
|
|
2091
|
-
await supabase.from("profiles").upsert({
|
|
2092
|
-
id: userData.id,
|
|
2093
|
-
play_count: (userData.play_count || 0) + 1,
|
|
2094
|
-
skill_points: Math.round(totalSp * 100) / 100,
|
|
2095
|
-
squares_hit: (userData.squares_hit || 0) + data.hits,
|
|
2096
|
-
});
|
|
2097
|
-
console.log("p3");
|
|
2098
|
-
|
|
2099
|
-
return NextResponse.json({});
|
|
2100
|
-
}
|
|
582
|
+
*/
|
|
2101
583
|
import { Schema as SubmitScore } from "./api/submitScore"
|
|
2102
584
|
export { Schema as SchemaSubmitScore } from "./api/submitScore"
|
|
2103
585
|
export const submitScore = handleApi({url:"/api/submitScore",...SubmitScore})
|
|
@@ -2116,75 +598,7 @@ export const Schema = {
|
|
|
2116
598
|
output: z.strictObject({
|
|
2117
599
|
error: z.string().optional(),
|
|
2118
600
|
}),
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
export async function POST(request: Request): Promise<NextResponse> {
|
|
2122
|
-
return protectedApi({
|
|
2123
|
-
request,
|
|
2124
|
-
schema: Schema,
|
|
2125
|
-
authorization: validUser,
|
|
2126
|
-
activity: handler,
|
|
2127
|
-
});
|
|
2128
|
-
}
|
|
2129
|
-
|
|
2130
|
-
export async function handler({
|
|
2131
|
-
session,
|
|
2132
|
-
beatmapHash,
|
|
2133
|
-
id,
|
|
2134
|
-
description,
|
|
2135
|
-
tags,
|
|
2136
|
-
}: (typeof Schema)["input"]["_type"]): Promise<
|
|
2137
|
-
NextResponse<(typeof Schema)["output"]["_type"]>
|
|
2138
|
-
> {
|
|
2139
|
-
const user = (await supabase.auth.getUser(session)).data.user!;
|
|
2140
|
-
let { data: userData, error: userError } = await supabase
|
|
2141
|
-
.from("profiles")
|
|
2142
|
-
.select("*")
|
|
2143
|
-
.eq("uid", user.id)
|
|
2144
|
-
.single();
|
|
2145
|
-
|
|
2146
|
-
let { data: pageData, error: pageError } = await supabase
|
|
2147
|
-
.from("beatmapPages")
|
|
2148
|
-
.select("*")
|
|
2149
|
-
.eq("id", id)
|
|
2150
|
-
.single();
|
|
2151
|
-
|
|
2152
|
-
let { data: beatmapData, error: bmPageError } = await supabase
|
|
2153
|
-
.from("beatmaps")
|
|
2154
|
-
.select("*")
|
|
2155
|
-
.eq("beatmapHash", beatmapHash)
|
|
2156
|
-
.single();
|
|
2157
|
-
|
|
2158
|
-
if (!userData) return NextResponse.json({ error: "No user." });
|
|
2159
|
-
if (!beatmapData) return NextResponse.json({ error: "No beatmap." });
|
|
2160
|
-
|
|
2161
|
-
if (userData.id !== pageData?.owner)
|
|
2162
|
-
return NextResponse.json({ error: "Non-authz user." });
|
|
2163
|
-
|
|
2164
|
-
if (pageData?.status !== "UNRANKED")
|
|
2165
|
-
return NextResponse.json({ error: "Only unranked maps can be updated" });
|
|
2166
|
-
|
|
2167
|
-
const upserted = await supabase
|
|
2168
|
-
.from("beatmapPages")
|
|
2169
|
-
.upsert({
|
|
2170
|
-
id,
|
|
2171
|
-
latestBeatmapHash: beatmapHash,
|
|
2172
|
-
genre: "",
|
|
2173
|
-
title: beatmapData.title,
|
|
2174
|
-
status: "UNRANKED",
|
|
2175
|
-
owner: userData.id,
|
|
2176
|
-
description,
|
|
2177
|
-
tags,
|
|
2178
|
-
nominations: [],
|
|
2179
|
-
})
|
|
2180
|
-
.select("*")
|
|
2181
|
-
.single();
|
|
2182
|
-
|
|
2183
|
-
if (upserted.error?.message.length) {
|
|
2184
|
-
return NextResponse.json({ error: upserted.error.message });
|
|
2185
|
-
}
|
|
2186
|
-
return NextResponse.json({});
|
|
2187
|
-
}
|
|
601
|
+
*/
|
|
2188
602
|
import { Schema as UpdateBeatmapPage } from "./api/updateBeatmapPage"
|
|
2189
603
|
export { Schema as SchemaUpdateBeatmapPage } from "./api/updateBeatmapPage"
|
|
2190
604
|
export const updateBeatmapPage = handleApi({url:"/api/updateBeatmapPage",...UpdateBeatmapPage})
|