rhythia-api 182.0.0 → 185.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/.prettierrc.json +6 -6
- package/api/addCollectionMap.ts +82 -82
- package/api/approveMap.ts +78 -78
- package/api/chartPublicStats.ts +32 -32
- package/api/createBeatmap.ts +168 -156
- package/api/createBeatmapPage.ts +64 -64
- package/api/createClan.ts +81 -81
- package/api/createCollection.ts +58 -58
- package/api/deleteBeatmapPage.ts +77 -72
- package/api/deleteCollection.ts +59 -59
- package/api/deleteCollectionMap.ts +71 -71
- package/api/editAboutMe.ts +91 -91
- package/api/editClan.ts +90 -90
- package/api/editCollection.ts +77 -77
- package/api/editProfile.ts +123 -123
- package/api/getAvatarUploadUrl.ts +85 -85
- package/api/getBadgedUsers.ts +56 -56
- package/api/getBeatmapComments.ts +57 -57
- package/api/getBeatmapPage.ts +106 -106
- package/api/getBeatmapPageById.ts +99 -99
- package/api/getBeatmapStarRating.ts +53 -53
- package/api/getBeatmaps.ts +159 -159
- package/api/getClan.ts +77 -77
- package/api/getCollection.ts +130 -130
- package/api/getCollections.ts +130 -126
- package/api/getLeaderboard.ts +136 -136
- package/api/getMapUploadUrl.ts +93 -93
- package/api/getPassToken.ts +55 -55
- package/api/getProfile.ts +146 -146
- package/api/getPublicStats.ts +180 -180
- package/api/getRawStarRating.ts +57 -57
- package/api/getScore.ts +85 -85
- package/api/getTimestamp.ts +23 -23
- package/api/getUserScores.ts +175 -175
- package/api/nominateMap.ts +82 -69
- package/api/postBeatmapComment.ts +59 -59
- package/api/rankMapsArchive.ts +64 -64
- package/api/searchUsers.ts +56 -56
- package/api/setPasskey.ts +59 -59
- package/api/submitScore.ts +433 -433
- package/api/updateBeatmapPage.ts +229 -229
- package/handleApi.ts +20 -20
- package/index.html +2 -2
- package/index.ts +866 -864
- package/package.json +2 -2
- package/types/database.ts +114 -1
- package/utils/getUserBySession.ts +48 -48
- package/utils/requestUtils.ts +87 -87
- package/utils/security.ts +20 -20
- package/utils/star-calc/index.ts +72 -72
- package/utils/star-calc/osuUtils.ts +53 -53
- package/utils/star-calc/sspmParser.ts +398 -398
- package/utils/star-calc/sspmv1Parser.ts +165 -165
- package/utils/supabase.ts +13 -13
- package/utils/test +4 -4
- package/utils/validateToken.ts +7 -7
- package/vercel.json +12 -12
- package/package-lock.json +0 -8913
package/.prettierrc.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
{
|
|
2
|
-
"trailingComma": "es5",
|
|
3
|
-
"tabWidth": 2,
|
|
4
|
-
"semi": true,
|
|
5
|
-
"singleQuote": false
|
|
6
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"trailingComma": "es5",
|
|
3
|
+
"tabWidth": 2,
|
|
4
|
+
"semi": true,
|
|
5
|
+
"singleQuote": false
|
|
6
|
+
}
|
package/api/addCollectionMap.ts
CHANGED
|
@@ -1,82 +1,82 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
import z from "zod";
|
|
3
|
-
import { protectedApi, validUser } from "../utils/requestUtils";
|
|
4
|
-
import { supabase } from "../utils/supabase";
|
|
5
|
-
import { getUserBySession } from "../utils/getUserBySession";
|
|
6
|
-
import { User } from "@supabase/supabase-js";
|
|
7
|
-
|
|
8
|
-
export const Schema = {
|
|
9
|
-
input: z.strictObject({
|
|
10
|
-
session: z.string(),
|
|
11
|
-
collection: z.number(),
|
|
12
|
-
beatmapPage: z.number(),
|
|
13
|
-
}),
|
|
14
|
-
output: z.object({
|
|
15
|
-
error: z.string().optional(),
|
|
16
|
-
}),
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export async function POST(request: Request) {
|
|
20
|
-
return protectedApi({
|
|
21
|
-
request,
|
|
22
|
-
schema: Schema,
|
|
23
|
-
authorization: validUser,
|
|
24
|
-
activity: handler,
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export async function handler(data: (typeof Schema)["input"]["_type"]) {
|
|
29
|
-
const user = (await getUserBySession(data.session)) as User;
|
|
30
|
-
let { data: queryUserData, error: userError } = await supabase
|
|
31
|
-
.from("profiles")
|
|
32
|
-
.select("*")
|
|
33
|
-
.eq("uid", user.id)
|
|
34
|
-
.single();
|
|
35
|
-
|
|
36
|
-
if (!queryUserData) {
|
|
37
|
-
return NextResponse.json({ error: "Can't find user" });
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
let { data: queryCollectionRelation, error: collectionRelationError } =
|
|
41
|
-
await supabase
|
|
42
|
-
.from("collectionRelations")
|
|
43
|
-
.select("*")
|
|
44
|
-
.eq("collection", data.collection)
|
|
45
|
-
.eq("beatmapPage", data.beatmapPage)
|
|
46
|
-
.single();
|
|
47
|
-
|
|
48
|
-
if (queryCollectionRelation) {
|
|
49
|
-
return NextResponse.json({ error: "Map already in collection" });
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
let { data: queryCollectionData, error: collectionError } = await supabase
|
|
53
|
-
.from("beatmapCollections")
|
|
54
|
-
.select("*")
|
|
55
|
-
.eq("id", data.collection)
|
|
56
|
-
.single();
|
|
57
|
-
|
|
58
|
-
let { data: queryBeatmapData, error: beatmapData } = await supabase
|
|
59
|
-
.from("beatmapPages")
|
|
60
|
-
.select("*")
|
|
61
|
-
.eq("id", data.beatmapPage)
|
|
62
|
-
.single();
|
|
63
|
-
|
|
64
|
-
if (!queryCollectionData) {
|
|
65
|
-
return NextResponse.json({ error: "Can't find collection" });
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (!queryBeatmapData) {
|
|
69
|
-
return NextResponse.json({ error: "Can't find beatmap page" });
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (queryCollectionData.owner !== queryUserData.id) {
|
|
73
|
-
return NextResponse.json({ error: "You can't update foreign collections" });
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
await supabase.from("collectionRelations").insert({
|
|
77
|
-
collection: data.collection,
|
|
78
|
-
beatmapPage: data.beatmapPage,
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
return NextResponse.json({});
|
|
82
|
-
}
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import z from "zod";
|
|
3
|
+
import { protectedApi, validUser } from "../utils/requestUtils";
|
|
4
|
+
import { supabase } from "../utils/supabase";
|
|
5
|
+
import { getUserBySession } from "../utils/getUserBySession";
|
|
6
|
+
import { User } from "@supabase/supabase-js";
|
|
7
|
+
|
|
8
|
+
export const Schema = {
|
|
9
|
+
input: z.strictObject({
|
|
10
|
+
session: z.string(),
|
|
11
|
+
collection: z.number(),
|
|
12
|
+
beatmapPage: z.number(),
|
|
13
|
+
}),
|
|
14
|
+
output: z.object({
|
|
15
|
+
error: z.string().optional(),
|
|
16
|
+
}),
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export async function POST(request: Request) {
|
|
20
|
+
return protectedApi({
|
|
21
|
+
request,
|
|
22
|
+
schema: Schema,
|
|
23
|
+
authorization: validUser,
|
|
24
|
+
activity: handler,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function handler(data: (typeof Schema)["input"]["_type"]) {
|
|
29
|
+
const user = (await getUserBySession(data.session)) as User;
|
|
30
|
+
let { data: queryUserData, error: userError } = await supabase
|
|
31
|
+
.from("profiles")
|
|
32
|
+
.select("*")
|
|
33
|
+
.eq("uid", user.id)
|
|
34
|
+
.single();
|
|
35
|
+
|
|
36
|
+
if (!queryUserData) {
|
|
37
|
+
return NextResponse.json({ error: "Can't find user" });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let { data: queryCollectionRelation, error: collectionRelationError } =
|
|
41
|
+
await supabase
|
|
42
|
+
.from("collectionRelations")
|
|
43
|
+
.select("*")
|
|
44
|
+
.eq("collection", data.collection)
|
|
45
|
+
.eq("beatmapPage", data.beatmapPage)
|
|
46
|
+
.single();
|
|
47
|
+
|
|
48
|
+
if (queryCollectionRelation) {
|
|
49
|
+
return NextResponse.json({ error: "Map already in collection" });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
let { data: queryCollectionData, error: collectionError } = await supabase
|
|
53
|
+
.from("beatmapCollections")
|
|
54
|
+
.select("*")
|
|
55
|
+
.eq("id", data.collection)
|
|
56
|
+
.single();
|
|
57
|
+
|
|
58
|
+
let { data: queryBeatmapData, error: beatmapData } = await supabase
|
|
59
|
+
.from("beatmapPages")
|
|
60
|
+
.select("*")
|
|
61
|
+
.eq("id", data.beatmapPage)
|
|
62
|
+
.single();
|
|
63
|
+
|
|
64
|
+
if (!queryCollectionData) {
|
|
65
|
+
return NextResponse.json({ error: "Can't find collection" });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!queryBeatmapData) {
|
|
69
|
+
return NextResponse.json({ error: "Can't find beatmap page" });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (queryCollectionData.owner !== queryUserData.id) {
|
|
73
|
+
return NextResponse.json({ error: "You can't update foreign collections" });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
await supabase.from("collectionRelations").insert({
|
|
77
|
+
collection: data.collection,
|
|
78
|
+
beatmapPage: data.beatmapPage,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return NextResponse.json({});
|
|
82
|
+
}
|
package/api/approveMap.ts
CHANGED
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
import z from "zod";
|
|
3
|
-
import { protectedApi, validUser } from "../utils/requestUtils";
|
|
4
|
-
import { supabase } from "../utils/supabase";
|
|
5
|
-
import { getUserBySession } from "../utils/getUserBySession";
|
|
6
|
-
import { User } from "@supabase/supabase-js";
|
|
7
|
-
|
|
8
|
-
export const Schema = {
|
|
9
|
-
input: z.strictObject({
|
|
10
|
-
session: z.string(),
|
|
11
|
-
mapId: z.number(),
|
|
12
|
-
}),
|
|
13
|
-
output: z.object({
|
|
14
|
-
error: z.string().optional(),
|
|
15
|
-
}),
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export async function POST(request: Request) {
|
|
19
|
-
return protectedApi({
|
|
20
|
-
request,
|
|
21
|
-
schema: Schema,
|
|
22
|
-
authorization: validUser,
|
|
23
|
-
activity: handler,
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export async function handler(data: (typeof Schema)["input"]["_type"]) {
|
|
28
|
-
const user = (await getUserBySession(data.session)) as User;
|
|
29
|
-
let { data: queryUserData, error: userError } = await supabase
|
|
30
|
-
.from("profiles")
|
|
31
|
-
.select("*")
|
|
32
|
-
.eq("uid", user.id)
|
|
33
|
-
.single();
|
|
34
|
-
|
|
35
|
-
if (!queryUserData) {
|
|
36
|
-
return NextResponse.json({ error: "Can't find user" });
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const tags = (queryUserData?.badges || []) as string[];
|
|
40
|
-
|
|
41
|
-
if (!tags.includes("MMT")) {
|
|
42
|
-
return NextResponse.json({ error: "Only MMTs can approve maps!" });
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const { data: mapData, error } = await supabase
|
|
46
|
-
.from("beatmapPages")
|
|
47
|
-
.select("id,nominations,owner")
|
|
48
|
-
.eq("id", data.mapId)
|
|
49
|
-
.single();
|
|
50
|
-
|
|
51
|
-
if (!mapData) {
|
|
52
|
-
return NextResponse.json({ error: "Bad map" });
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (mapData.owner == queryUserData.id) {
|
|
56
|
-
return NextResponse.json({ error: "Can't approve own map" });
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if ((mapData.nominations as number[])!.length < 2) {
|
|
60
|
-
return NextResponse.json({
|
|
61
|
-
error: "Maps can get approved only if they have 2 nominations",
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if ((mapData.nominations as number[]).includes(queryUserData.id)) {
|
|
66
|
-
return NextResponse.json({
|
|
67
|
-
error: "Can't nominate and approve",
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
await supabase.from("beatmapPages").upsert({
|
|
72
|
-
id: data.mapId,
|
|
73
|
-
status: "RANKED",
|
|
74
|
-
ranked_at: Date.now(),
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
return NextResponse.json({});
|
|
78
|
-
}
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import z from "zod";
|
|
3
|
+
import { protectedApi, validUser } from "../utils/requestUtils";
|
|
4
|
+
import { supabase } from "../utils/supabase";
|
|
5
|
+
import { getUserBySession } from "../utils/getUserBySession";
|
|
6
|
+
import { User } from "@supabase/supabase-js";
|
|
7
|
+
|
|
8
|
+
export const Schema = {
|
|
9
|
+
input: z.strictObject({
|
|
10
|
+
session: z.string(),
|
|
11
|
+
mapId: z.number(),
|
|
12
|
+
}),
|
|
13
|
+
output: z.object({
|
|
14
|
+
error: z.string().optional(),
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export async function POST(request: Request) {
|
|
19
|
+
return protectedApi({
|
|
20
|
+
request,
|
|
21
|
+
schema: Schema,
|
|
22
|
+
authorization: validUser,
|
|
23
|
+
activity: handler,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function handler(data: (typeof Schema)["input"]["_type"]) {
|
|
28
|
+
const user = (await getUserBySession(data.session)) as User;
|
|
29
|
+
let { data: queryUserData, error: userError } = await supabase
|
|
30
|
+
.from("profiles")
|
|
31
|
+
.select("*")
|
|
32
|
+
.eq("uid", user.id)
|
|
33
|
+
.single();
|
|
34
|
+
|
|
35
|
+
if (!queryUserData) {
|
|
36
|
+
return NextResponse.json({ error: "Can't find user" });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const tags = (queryUserData?.badges || []) as string[];
|
|
40
|
+
|
|
41
|
+
if (!tags.includes("MMT")) {
|
|
42
|
+
return NextResponse.json({ error: "Only MMTs can approve maps!" });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const { data: mapData, error } = await supabase
|
|
46
|
+
.from("beatmapPages")
|
|
47
|
+
.select("id,nominations,owner")
|
|
48
|
+
.eq("id", data.mapId)
|
|
49
|
+
.single();
|
|
50
|
+
|
|
51
|
+
if (!mapData) {
|
|
52
|
+
return NextResponse.json({ error: "Bad map" });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (mapData.owner == queryUserData.id) {
|
|
56
|
+
return NextResponse.json({ error: "Can't approve own map" });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if ((mapData.nominations as number[])!.length < 2) {
|
|
60
|
+
return NextResponse.json({
|
|
61
|
+
error: "Maps can get approved only if they have 2 nominations",
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if ((mapData.nominations as number[]).includes(queryUserData.id)) {
|
|
66
|
+
return NextResponse.json({
|
|
67
|
+
error: "Can't nominate and approve",
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
await supabase.from("beatmapPages").upsert({
|
|
72
|
+
id: data.mapId,
|
|
73
|
+
status: "RANKED",
|
|
74
|
+
ranked_at: Date.now(),
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
return NextResponse.json({});
|
|
78
|
+
}
|
package/api/chartPublicStats.ts
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
import { NextResponse } from "next/server";
|
|
2
|
-
import z from "zod";
|
|
3
|
-
import { protectedApi } from "../utils/requestUtils";
|
|
4
|
-
import { supabase } from "../utils/supabase";
|
|
5
|
-
|
|
6
|
-
export const Schema = {
|
|
7
|
-
input: z.strictObject({}),
|
|
8
|
-
output: z.object({}),
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export async function POST(request: Request) {
|
|
12
|
-
return protectedApi({
|
|
13
|
-
request,
|
|
14
|
-
schema: Schema,
|
|
15
|
-
authorization: () => {},
|
|
16
|
-
activity: handler,
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export async function handler(data: (typeof Schema)["input"]["_type"]) {
|
|
21
|
-
// 30 minutes activity
|
|
22
|
-
const countOnline = await supabase
|
|
23
|
-
.from("profileActivities")
|
|
24
|
-
.select("*", { count: "exact", head: true })
|
|
25
|
-
.gt("last_activity", Date.now() - 1800000);
|
|
26
|
-
|
|
27
|
-
await supabase.from("chartedValues").insert({
|
|
28
|
-
type: "online_players",
|
|
29
|
-
value: countOnline.count,
|
|
30
|
-
});
|
|
31
|
-
return NextResponse.json({});
|
|
32
|
-
}
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import z from "zod";
|
|
3
|
+
import { protectedApi } from "../utils/requestUtils";
|
|
4
|
+
import { supabase } from "../utils/supabase";
|
|
5
|
+
|
|
6
|
+
export const Schema = {
|
|
7
|
+
input: z.strictObject({}),
|
|
8
|
+
output: z.object({}),
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export async function POST(request: Request) {
|
|
12
|
+
return protectedApi({
|
|
13
|
+
request,
|
|
14
|
+
schema: Schema,
|
|
15
|
+
authorization: () => {},
|
|
16
|
+
activity: handler,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function handler(data: (typeof Schema)["input"]["_type"]) {
|
|
21
|
+
// 30 minutes activity
|
|
22
|
+
const countOnline = await supabase
|
|
23
|
+
.from("profileActivities")
|
|
24
|
+
.select("*", { count: "exact", head: true })
|
|
25
|
+
.gt("last_activity", Date.now() - 1800000);
|
|
26
|
+
|
|
27
|
+
await supabase.from("chartedValues").insert({
|
|
28
|
+
type: "online_players",
|
|
29
|
+
value: countOnline.count,
|
|
30
|
+
});
|
|
31
|
+
return NextResponse.json({});
|
|
32
|
+
}
|