rhythia-api 192.0.0 → 194.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/createSupporter.ts +145 -0
- package/api/getBeatmapPage.ts +1 -0
- package/api/getBeatmaps.ts +10 -6
- package/api/getProfile.ts +11 -0
- package/api/getUserScores.ts +2 -0
- package/api/rankMapsArchive.ts +11 -4
- package/index.ts +48 -0
- package/package.json +4 -4
- package/types/database.ts +31 -0
|
@@ -0,0 +1,145 @@
|
|
|
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
|
+
type: z.enum([
|
|
9
|
+
"membership.started",
|
|
10
|
+
"membership.ended",
|
|
11
|
+
"membership.updated",
|
|
12
|
+
]),
|
|
13
|
+
live_mode: z.boolean(),
|
|
14
|
+
attempt: z.number().nullable(),
|
|
15
|
+
created: z.number().nullable(),
|
|
16
|
+
event_id: z.number().nullable(),
|
|
17
|
+
data: z.object({
|
|
18
|
+
id: z.number().nullable(),
|
|
19
|
+
amount: z.number().nullable(),
|
|
20
|
+
object: z.enum(["membership"]).nullable(),
|
|
21
|
+
paused: z.enum(["true", "false"]).nullable(),
|
|
22
|
+
status: z.enum(["active", "inactive"]).nullable(),
|
|
23
|
+
canceled: z.enum(["true", "false"]).nullable(),
|
|
24
|
+
currency: z.string().nullable(),
|
|
25
|
+
psp_id: z.string().nullable(),
|
|
26
|
+
duration_type: z.enum(["month", "year"]).nullable(),
|
|
27
|
+
membership_level_id: z.number().nullable(),
|
|
28
|
+
membership_level_name: z.string().nullable(),
|
|
29
|
+
started_at: z.number().nullable(),
|
|
30
|
+
canceled_at: z.string().nullable(),
|
|
31
|
+
note_hidden: z.boolean().nullable(),
|
|
32
|
+
support_note: z.string().nullable(),
|
|
33
|
+
supporter_name: z.string().nullable(),
|
|
34
|
+
supporter_id: z.number().nullable(),
|
|
35
|
+
supporter_email: z.string().nullable(),
|
|
36
|
+
current_period_end: z.number().nullable(),
|
|
37
|
+
current_period_start: z.number().nullable(),
|
|
38
|
+
supporter_feedback: z.any(),
|
|
39
|
+
}),
|
|
40
|
+
}),
|
|
41
|
+
output: z.object({
|
|
42
|
+
error: z.string().optional(),
|
|
43
|
+
}),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export async function POST(request: Request): Promise<NextResponse> {
|
|
47
|
+
const sig = request.url.split("key=")[1];
|
|
48
|
+
if (process.env.BUY_SECRET !== sig) {
|
|
49
|
+
return NextResponse.json({
|
|
50
|
+
error: "Invalid Signature",
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return protectedApi({
|
|
54
|
+
request,
|
|
55
|
+
schema: Schema,
|
|
56
|
+
authorization: () => {},
|
|
57
|
+
activity: handler,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function handler(
|
|
62
|
+
data: (typeof Schema)["input"]["_type"],
|
|
63
|
+
request: Request
|
|
64
|
+
): Promise<NextResponse<(typeof Schema)["output"]["_type"]>> {
|
|
65
|
+
let user: any;
|
|
66
|
+
if (
|
|
67
|
+
!(data.type === "membership.started" || data.type === "membership.updated")
|
|
68
|
+
) {
|
|
69
|
+
return NextResponse.json({
|
|
70
|
+
error: "Invalid type",
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (data.data.status !== "active") {
|
|
75
|
+
return NextResponse.json({
|
|
76
|
+
error: "Inactive",
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (data.data.supporter_email) {
|
|
81
|
+
const emlRes = await supabase.rpc("get_user_by_email", {
|
|
82
|
+
email_address: data.data.supporter_email,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
if (emlRes.data) {
|
|
86
|
+
let { data: queryData, error } = await supabase
|
|
87
|
+
.from("profiles")
|
|
88
|
+
.select("*")
|
|
89
|
+
.eq("uid", (emlRes.data as any).id)
|
|
90
|
+
.single();
|
|
91
|
+
if (queryData) {
|
|
92
|
+
user = queryData;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (data.data.support_note) {
|
|
98
|
+
let { data: queryData, error } = await supabase
|
|
99
|
+
.from("profiles")
|
|
100
|
+
.select("*")
|
|
101
|
+
.eq("computedUsername", data.data.support_note)
|
|
102
|
+
.single();
|
|
103
|
+
|
|
104
|
+
if (queryData) {
|
|
105
|
+
user = queryData;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (data.data.supporter_name) {
|
|
110
|
+
let { data: queryData, error } = await supabase
|
|
111
|
+
.from("profiles")
|
|
112
|
+
.select("*")
|
|
113
|
+
.eq("computedUsername", data.data.supporter_name)
|
|
114
|
+
.single();
|
|
115
|
+
|
|
116
|
+
if (queryData) {
|
|
117
|
+
user = queryData;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (data.data.membership_level_name !== "Supporter") {
|
|
122
|
+
return NextResponse.json({
|
|
123
|
+
error: "Invalid membership",
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const endDate = (data.data.current_period_end || 0) * 1000;
|
|
128
|
+
|
|
129
|
+
if (!user) {
|
|
130
|
+
return NextResponse.json({
|
|
131
|
+
error: "No such player",
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const upsertResult = await supabase
|
|
136
|
+
.from("profiles")
|
|
137
|
+
.upsert({
|
|
138
|
+
id: user.id,
|
|
139
|
+
verificationDeadline: endDate,
|
|
140
|
+
verified: true,
|
|
141
|
+
})
|
|
142
|
+
.select();
|
|
143
|
+
|
|
144
|
+
return NextResponse.json({});
|
|
145
|
+
}
|
package/api/getBeatmapPage.ts
CHANGED
package/api/getBeatmaps.ts
CHANGED
|
@@ -72,15 +72,14 @@ export async function getBeatmaps(data: (typeof Schema)["input"]["_type"]) {
|
|
|
72
72
|
.from("beatmapPages")
|
|
73
73
|
.select("id", { count: "exact", head: true });
|
|
74
74
|
|
|
75
|
-
let qry = supabase
|
|
76
|
-
|
|
77
|
-
.select(
|
|
78
|
-
`
|
|
75
|
+
let qry = supabase.from("beatmapPages").select(
|
|
76
|
+
`
|
|
79
77
|
owner,
|
|
80
78
|
created_at,
|
|
81
79
|
id,
|
|
82
80
|
status,
|
|
83
81
|
tags,
|
|
82
|
+
ranked_at,
|
|
84
83
|
beatmaps!inner(
|
|
85
84
|
playcount,
|
|
86
85
|
ranked,
|
|
@@ -94,8 +93,13 @@ export async function getBeatmaps(data: (typeof Schema)["input"]["_type"]) {
|
|
|
94
93
|
profiles!inner(
|
|
95
94
|
username
|
|
96
95
|
)`
|
|
97
|
-
|
|
98
|
-
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
if (data.status == "RANKED") {
|
|
99
|
+
qry = qry.order("ranked_at", { ascending: false });
|
|
100
|
+
} else {
|
|
101
|
+
qry = qry.order("created_at", { ascending: false });
|
|
102
|
+
}
|
|
99
103
|
|
|
100
104
|
if (data.textFilter) {
|
|
101
105
|
qry = qry.ilike("beatmaps.title", `%${data.textFilter}%`);
|
package/api/getProfile.ts
CHANGED
|
@@ -27,6 +27,7 @@ export const Schema = {
|
|
|
27
27
|
ban: z.string().nullable(),
|
|
28
28
|
username: z.string().nullable(),
|
|
29
29
|
verified: z.boolean().nullable(),
|
|
30
|
+
verificationDeadline: z.number().nullable(),
|
|
30
31
|
play_count: z.number().nullable(),
|
|
31
32
|
skill_points: z.number().nullable(),
|
|
32
33
|
squares_hit: z.number().nullable(),
|
|
@@ -136,6 +137,16 @@ export async function handler(
|
|
|
136
137
|
.neq("ban", "excluded")
|
|
137
138
|
.gt("skill_points", user.skill_points);
|
|
138
139
|
|
|
140
|
+
if (user.verificationDeadline < Date.now()) {
|
|
141
|
+
await supabase
|
|
142
|
+
.from("profiles")
|
|
143
|
+
.upsert({
|
|
144
|
+
id: user.id,
|
|
145
|
+
verified: false,
|
|
146
|
+
})
|
|
147
|
+
.select();
|
|
148
|
+
}
|
|
149
|
+
|
|
139
150
|
return NextResponse.json({
|
|
140
151
|
user: {
|
|
141
152
|
...user,
|
package/api/getUserScores.ts
CHANGED
|
@@ -45,6 +45,7 @@ export const Schema = {
|
|
|
45
45
|
beatmapHash: z.string().nullable(), // Add beatmapHash to the schema
|
|
46
46
|
beatmapTitle: z.string().nullable(),
|
|
47
47
|
difficulty: z.number().nullable(),
|
|
48
|
+
beatmapNotes: z.number().optional().nullable(),
|
|
48
49
|
})
|
|
49
50
|
)
|
|
50
51
|
.optional(),
|
|
@@ -190,6 +191,7 @@ export async function handler(
|
|
|
190
191
|
spin: s.spin,
|
|
191
192
|
beatmapHash: s.beatmaphash,
|
|
192
193
|
beatmapTitle: s.beatmaptitle,
|
|
194
|
+
beatmapNotes: s.notes,
|
|
193
195
|
difficulty: s.difficulty,
|
|
194
196
|
})),
|
|
195
197
|
top: vals?.map((s) => ({
|
package/api/rankMapsArchive.ts
CHANGED
|
@@ -38,15 +38,21 @@ export async function handler(data: (typeof Schema)["input"]["_type"]) {
|
|
|
38
38
|
|
|
39
39
|
const tags = (queryUserData?.badges || []) as string[];
|
|
40
40
|
|
|
41
|
-
if (
|
|
42
|
-
|
|
41
|
+
if (
|
|
42
|
+
!(
|
|
43
|
+
tags.includes("Bot") ||
|
|
44
|
+
tags.includes("Admin") ||
|
|
45
|
+
tags.includes("MMT") ||
|
|
46
|
+
tags.includes("Developer")
|
|
47
|
+
)
|
|
48
|
+
) {
|
|
49
|
+
return NextResponse.json({ error: "Only management can force-rank maps!" });
|
|
43
50
|
}
|
|
44
51
|
|
|
45
52
|
const { data: mapData, error } = await supabase
|
|
46
53
|
.from("beatmapPages")
|
|
47
54
|
.select("id,nominations,owner,status")
|
|
48
|
-
.eq("
|
|
49
|
-
.eq("status", "UNRANKED");
|
|
55
|
+
.eq("id", data.mapId);
|
|
50
56
|
|
|
51
57
|
if (!mapData) {
|
|
52
58
|
return NextResponse.json({ error: "Bad map" });
|
|
@@ -57,6 +63,7 @@ export async function handler(data: (typeof Schema)["input"]["_type"]) {
|
|
|
57
63
|
id: element.id,
|
|
58
64
|
nominations: [queryUserData.id, queryUserData.id],
|
|
59
65
|
status: "RANKED",
|
|
66
|
+
ranked_at: Date.now(),
|
|
60
67
|
});
|
|
61
68
|
}
|
|
62
69
|
|
package/index.ts
CHANGED
|
@@ -136,6 +136,52 @@ import { Schema as CreateInvite } from "./api/createInvite"
|
|
|
136
136
|
export { Schema as SchemaCreateInvite } from "./api/createInvite"
|
|
137
137
|
export const createInvite = handleApi({url:"/api/createInvite",...CreateInvite})
|
|
138
138
|
|
|
139
|
+
// ./api/createSupporter.ts API
|
|
140
|
+
|
|
141
|
+
/*
|
|
142
|
+
export const Schema = {
|
|
143
|
+
input: z.strictObject({
|
|
144
|
+
type: z.enum([
|
|
145
|
+
"membership.started",
|
|
146
|
+
"membership.ended",
|
|
147
|
+
"membership.updated",
|
|
148
|
+
]),
|
|
149
|
+
live_mode: z.boolean(),
|
|
150
|
+
attempt: z.number().nullable(),
|
|
151
|
+
created: z.number().nullable(),
|
|
152
|
+
event_id: z.number().nullable(),
|
|
153
|
+
data: z.object({
|
|
154
|
+
id: z.number().nullable(),
|
|
155
|
+
amount: z.number().nullable(),
|
|
156
|
+
object: z.enum(["membership"]).nullable(),
|
|
157
|
+
paused: z.enum(["true", "false"]).nullable(),
|
|
158
|
+
status: z.enum(["active", "inactive"]).nullable(),
|
|
159
|
+
canceled: z.enum(["true", "false"]).nullable(),
|
|
160
|
+
currency: z.string().nullable(),
|
|
161
|
+
psp_id: z.string().nullable(),
|
|
162
|
+
duration_type: z.enum(["month", "year"]).nullable(),
|
|
163
|
+
membership_level_id: z.number().nullable(),
|
|
164
|
+
membership_level_name: z.string().nullable(),
|
|
165
|
+
started_at: z.number().nullable(),
|
|
166
|
+
canceled_at: z.string().nullable(),
|
|
167
|
+
note_hidden: z.boolean().nullable(),
|
|
168
|
+
support_note: z.string().nullable(),
|
|
169
|
+
supporter_name: z.string().nullable(),
|
|
170
|
+
supporter_id: z.number().nullable(),
|
|
171
|
+
supporter_email: z.string().nullable(),
|
|
172
|
+
current_period_end: z.number().nullable(),
|
|
173
|
+
current_period_start: z.number().nullable(),
|
|
174
|
+
supporter_feedback: z.any(),
|
|
175
|
+
}),
|
|
176
|
+
}),
|
|
177
|
+
output: z.object({
|
|
178
|
+
error: z.string().optional(),
|
|
179
|
+
}),
|
|
180
|
+
};*/
|
|
181
|
+
import { Schema as CreateSupporter } from "./api/createSupporter"
|
|
182
|
+
export { Schema as SchemaCreateSupporter } from "./api/createSupporter"
|
|
183
|
+
export const createSupporter = handleApi({url:"/api/createSupporter",...CreateSupporter})
|
|
184
|
+
|
|
139
185
|
// ./api/deleteBeatmapPage.ts API
|
|
140
186
|
|
|
141
187
|
/*
|
|
@@ -776,6 +822,7 @@ export const Schema = {
|
|
|
776
822
|
ban: z.string().nullable(),
|
|
777
823
|
username: z.string().nullable(),
|
|
778
824
|
verified: z.boolean().nullable(),
|
|
825
|
+
verificationDeadline: z.number().nullable(),
|
|
779
826
|
play_count: z.number().nullable(),
|
|
780
827
|
skill_points: z.number().nullable(),
|
|
781
828
|
squares_hit: z.number().nullable(),
|
|
@@ -969,6 +1016,7 @@ export const Schema = {
|
|
|
969
1016
|
beatmapHash: z.string().nullable(), // Add beatmapHash to the schema
|
|
970
1017
|
beatmapTitle: z.string().nullable(),
|
|
971
1018
|
difficulty: z.number().nullable(),
|
|
1019
|
+
beatmapNotes: z.number().optional().nullable(),
|
|
972
1020
|
})
|
|
973
1021
|
)
|
|
974
1022
|
.optional(),
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rhythia-api",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "194.0.0",
|
|
4
4
|
"main": "index.ts",
|
|
5
|
-
"author": "online-contributors",
|
|
5
|
+
"author": "online-contributors-cunev",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"update": "bun ./scripts/update.ts",
|
|
8
8
|
"ci-deploy": "tsx ./scripts/ci-deploy.ts",
|
|
@@ -43,12 +43,12 @@
|
|
|
43
43
|
"sharp": "^0.33.5",
|
|
44
44
|
"short-uuid": "^5.2.0",
|
|
45
45
|
"simple-git": "^3.25.0",
|
|
46
|
-
"supabase": "^2.
|
|
46
|
+
"supabase": "^2.19.7",
|
|
47
47
|
"tsx": "^4.17.0",
|
|
48
48
|
"utf-8-validate": "^6.0.4",
|
|
49
49
|
"uuid": "^11.1.0",
|
|
50
50
|
"validator": "^13.12.0",
|
|
51
51
|
"zero-width": "^1.0.29",
|
|
52
|
-
"zod": "^3.
|
|
52
|
+
"zod": "^3.24.2"
|
|
53
53
|
}
|
|
54
54
|
}
|
package/types/database.ts
CHANGED
|
@@ -412,6 +412,7 @@ export type Database = {
|
|
|
412
412
|
total_score: number | null
|
|
413
413
|
uid: string | null
|
|
414
414
|
username: string | null
|
|
415
|
+
verificationDeadline: number
|
|
415
416
|
verified: boolean | null
|
|
416
417
|
}
|
|
417
418
|
Insert: {
|
|
@@ -435,6 +436,7 @@ export type Database = {
|
|
|
435
436
|
total_score?: number | null
|
|
436
437
|
uid?: string | null
|
|
437
438
|
username?: string | null
|
|
439
|
+
verificationDeadline?: number
|
|
438
440
|
verified?: boolean | null
|
|
439
441
|
}
|
|
440
442
|
Update: {
|
|
@@ -458,6 +460,7 @@ export type Database = {
|
|
|
458
460
|
total_score?: number | null
|
|
459
461
|
uid?: string | null
|
|
460
462
|
username?: string | null
|
|
463
|
+
verificationDeadline?: number
|
|
461
464
|
verified?: boolean | null
|
|
462
465
|
}
|
|
463
466
|
Relationships: [
|
|
@@ -754,6 +757,33 @@ export type Database = {
|
|
|
754
757
|
avatar_url: string
|
|
755
758
|
}[]
|
|
756
759
|
}
|
|
760
|
+
get_top_scores_for_beatmap2: {
|
|
761
|
+
Args: {
|
|
762
|
+
beatmap_hash: string
|
|
763
|
+
}
|
|
764
|
+
Returns: {
|
|
765
|
+
id: number
|
|
766
|
+
awarded_sp: number
|
|
767
|
+
created_at: string
|
|
768
|
+
misses: number
|
|
769
|
+
mods: Json
|
|
770
|
+
passed: boolean
|
|
771
|
+
replayhwid: string
|
|
772
|
+
songid: string
|
|
773
|
+
speed: number
|
|
774
|
+
spin: boolean
|
|
775
|
+
userid: number
|
|
776
|
+
username: string
|
|
777
|
+
avatar_url: string
|
|
778
|
+
accuracy: number
|
|
779
|
+
}[]
|
|
780
|
+
}
|
|
781
|
+
get_user_by_email: {
|
|
782
|
+
Args: {
|
|
783
|
+
email_address: string
|
|
784
|
+
}
|
|
785
|
+
Returns: Json
|
|
786
|
+
}
|
|
757
787
|
get_user_reigning_scores:
|
|
758
788
|
| {
|
|
759
789
|
Args: {
|
|
@@ -792,6 +822,7 @@ export type Database = {
|
|
|
792
822
|
beatmaphash: string
|
|
793
823
|
beatmaptitle: string
|
|
794
824
|
difficulty: number
|
|
825
|
+
notes: number
|
|
795
826
|
}[]
|
|
796
827
|
}
|
|
797
828
|
}
|