rhythia-api 193.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.
@@ -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
+ }
@@ -120,6 +120,7 @@ export async function handler(
120
120
  userId: score.userid,
121
121
  username: score.username,
122
122
  avatar_url: score.avatar_url,
123
+ accuracy: score.accuracy,
123
124
  })),
124
125
  beatmap: {
125
126
  playcount: beatmapPage.beatmaps?.playcount,
@@ -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
- .from("beatmapPages")
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
- .order("created_at", { ascending: false });
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,
@@ -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 (!tags.includes("Bot")) {
42
- return NextResponse.json({ error: "Only Bots can force-rank maps!" });
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("owner", user.id)
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(),
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "rhythia-api",
3
- "version": "193.0.0",
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.15.8",
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.23.8"
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
  }