rhythia-api 120.0.0 → 122.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,65 @@
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
+
6
+ export const Schema = {
7
+ input: z.strictObject({
8
+ session: z.string(),
9
+ mapId: z.number(),
10
+ }),
11
+ output: z.object({
12
+ error: z.string().optional(),
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")
46
+ .eq("id", data.mapId)
47
+ .single();
48
+
49
+ if (!mapData) {
50
+ return NextResponse.json({ error: "Bad map" });
51
+ }
52
+
53
+ if (mapData.nominations! < 2) {
54
+ return NextResponse.json({
55
+ error: "Maps can get approved only if they have 2 approvals",
56
+ });
57
+ }
58
+
59
+ await supabase.from("beatmapPages").upsert({
60
+ id: data.mapId,
61
+ status: "RANKED",
62
+ });
63
+
64
+ return NextResponse.json({});
65
+ }
@@ -64,28 +64,26 @@ export async function getBeatmaps(data: (typeof Schema)["input"]["_type"]) {
64
64
  const endPage = startPage + VIEW_PER_PAGE - 1;
65
65
  const countQuery = await supabase
66
66
  .from("beatmapPages")
67
- .select("*", { count: "exact", head: true });
67
+ .select("id", { count: "exact", head: true });
68
68
 
69
69
  let qry = supabase
70
70
  .from("beatmapPages")
71
71
  .select(
72
72
  `
73
- *,
73
+ owner,
74
+ created_at,
75
+ id,
74
76
  beatmaps!inner(
75
- created_at,
76
77
  playcount,
77
- length,
78
78
  ranked,
79
79
  beatmapFile,
80
80
  image,
81
81
  starRating,
82
82
  difficulty,
83
- noteCount,
84
83
  title
85
84
  ),
86
85
  profiles!inner(
87
- username,
88
- avatar_url
86
+ username
89
87
  )`
90
88
  )
91
89
  .order("created_at", { ascending: false });
@@ -105,7 +103,7 @@ export async function getBeatmaps(data: (typeof Schema)["input"]["_type"]) {
105
103
  qry = qry.eq("status", data.status);
106
104
  }
107
105
 
108
- if (data.creator) {
106
+ if (data.creator !== undefined) {
109
107
  qry = qry.eq("owner", data.creator);
110
108
  }
111
109
 
@@ -120,8 +118,6 @@ export async function getBeatmaps(data: (typeof Schema)["input"]["_type"]) {
120
118
  playcount: beatmapPage.beatmaps?.playcount,
121
119
  created_at: beatmapPage.created_at,
122
120
  difficulty: beatmapPage.beatmaps?.difficulty,
123
- noteCount: beatmapPage.beatmaps?.noteCount,
124
- length: beatmapPage.beatmaps?.length,
125
121
  title: beatmapPage.beatmaps?.title,
126
122
  ranked: beatmapPage.beatmaps?.ranked,
127
123
  beatmapFile: beatmapPage.beatmaps?.beatmapFile,
@@ -129,7 +125,6 @@ export async function getBeatmaps(data: (typeof Schema)["input"]["_type"]) {
129
125
  starRating: beatmapPage.beatmaps?.starRating,
130
126
  owner: beatmapPage.owner,
131
127
  ownerUsername: beatmapPage.profiles?.username,
132
- ownerAvatar: beatmapPage.profiles?.avatar_url,
133
128
  })),
134
129
  };
135
130
  }
@@ -73,7 +73,7 @@ export async function getLeaderboard(page = 1, session: string) {
73
73
  const endPage = startPage + VIEW_PER_PAGE - 1;
74
74
  const countQuery = await supabase
75
75
  .from("profiles")
76
- .select("*", { count: "exact", head: true })
76
+ .select("ban", { count: "exact", head: true })
77
77
  .neq("ban", "excluded");
78
78
 
79
79
  let { data: queryData, error } = await supabase
package/api/getScore.ts CHANGED
@@ -24,6 +24,7 @@ export const Schema = {
24
24
  beatmapNotes: z.number().optional().nullable(),
25
25
  beatmapTitle: z.string().optional().nullable(),
26
26
  username: z.string().optional().nullable(),
27
+ speed: z.number().optional().nullable(),
27
28
  })
28
29
  .optional(),
29
30
  }),
@@ -76,6 +77,7 @@ export async function handler(
76
77
  beatmapNotes: score.beatmaps?.noteCount,
77
78
  beatmapTitle: score.beatmaps?.title,
78
79
  username: score.profiles?.username,
80
+ speed: score.speed,
79
81
  },
80
82
  });
81
83
  }
@@ -24,6 +24,7 @@ export const Schema = {
24
24
  beatmapDifficulty: z.number().optional().nullable(),
25
25
  beatmapNotes: z.number().optional().nullable(),
26
26
  beatmapTitle: z.string().optional().nullable(),
27
+ speed: z.number().optional().nullable(),
27
28
  })
28
29
  )
29
30
  .optional(),
@@ -42,6 +43,7 @@ export const Schema = {
42
43
  beatmapDifficulty: z.number().optional().nullable(),
43
44
  beatmapNotes: z.number().optional().nullable(),
44
45
  beatmapTitle: z.string().optional().nullable(),
46
+ speed: z.number().optional().nullable(),
45
47
  })
46
48
  )
47
49
  .optional(),
@@ -128,6 +130,7 @@ export async function handler(
128
130
  beatmapDifficulty: s.beatmaps?.difficulty,
129
131
  beatmapNotes: s.beatmaps?.noteCount,
130
132
  beatmapTitle: s.beatmaps?.title,
133
+ speed: s.speed,
131
134
  })),
132
135
  top: vals?.map((s) => ({
133
136
  created_at: s.created_at,
@@ -142,6 +145,7 @@ export async function handler(
142
145
  beatmapDifficulty: s.beatmaps?.difficulty,
143
146
  beatmapNotes: s.beatmaps?.noteCount,
144
147
  beatmapTitle: s.beatmaps?.title,
148
+ speed: s.speed,
145
149
  })),
146
150
  });
147
151
  }
@@ -0,0 +1,59 @@
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
+
6
+ export const Schema = {
7
+ input: z.strictObject({
8
+ session: z.string(),
9
+ mapId: z.number(),
10
+ }),
11
+ output: z.object({
12
+ error: z.string().optional(),
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("RCT")) {
40
+ return NextResponse.json({ error: "Only RCTs can nominate maps!" });
41
+ }
42
+
43
+ const { data: mapData, error } = await supabase
44
+ .from("beatmapPages")
45
+ .select("id,nominations")
46
+ .eq("id", data.mapId)
47
+ .single();
48
+
49
+ if (!mapData) {
50
+ return NextResponse.json({ error: "Bad map" });
51
+ }
52
+
53
+ await supabase.from("beatmapPages").upsert({
54
+ id: data.mapId,
55
+ nominations: mapData.nominations! + 1,
56
+ });
57
+
58
+ return NextResponse.json({});
59
+ }
package/index.ts CHANGED
@@ -1,5 +1,10 @@
1
1
  import { handleApi } from "./handleApi"
2
2
 
3
+ // ./api/approveMap.ts API
4
+ import { Schema as ApproveMap } from "./api/approveMap"
5
+ export { Schema as SchemaApproveMap } from "./api/approveMap"
6
+ export const approveMap = handleApi({url:"/api/approveMap",...ApproveMap})
7
+
3
8
  // ./api/createBeatmap.ts API
4
9
  import { Schema as CreateBeatmap } from "./api/createBeatmap"
5
10
  export { Schema as SchemaCreateBeatmap } from "./api/createBeatmap"
@@ -65,6 +70,11 @@ import { Schema as GetUserScores } from "./api/getUserScores"
65
70
  export { Schema as SchemaGetUserScores } from "./api/getUserScores"
66
71
  export const getUserScores = handleApi({url:"/api/getUserScores",...GetUserScores})
67
72
 
73
+ // ./api/nominateMap.ts API
74
+ import { Schema as NominateMap } from "./api/nominateMap"
75
+ export { Schema as SchemaNominateMap } from "./api/nominateMap"
76
+ export const nominateMap = handleApi({url:"/api/nominateMap",...NominateMap})
77
+
68
78
  // ./api/searchUsers.ts API
69
79
  import { Schema as SearchUsers } from "./api/searchUsers"
70
80
  export { Schema as SchemaSearchUsers } from "./api/searchUsers"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rhythia-api",
3
- "version": "120.0.0",
3
+ "version": "122.0.0",
4
4
  "main": "index.ts",
5
5
  "scripts": {
6
6
  "update": "bun ./scripts/update.ts",
@@ -33,7 +33,7 @@
33
33
  "osu-parsers": "^4.1.7",
34
34
  "osu-standard-stable": "^5.0.0",
35
35
  "simple-git": "^3.25.0",
36
- "supabase": "^1.192.5",
36
+ "supabase": "^1.204.3",
37
37
  "tsx": "^4.17.0",
38
38
  "utf-8-validate": "^6.0.4",
39
39
  "zod": "^3.23.8"
package/types/database.ts CHANGED
@@ -15,6 +15,7 @@ export type Database = {
15
15
  genre: string | null
16
16
  id: number
17
17
  latestBeatmapHash: string | null
18
+ nominations: number | null
18
19
  owner: number | null
19
20
  status: string | null
20
21
  title: string | null
@@ -24,6 +25,7 @@ export type Database = {
24
25
  genre?: string | null
25
26
  id?: number
26
27
  latestBeatmapHash?: string | null
28
+ nominations?: number | null
27
29
  owner?: number | null
28
30
  status?: string | null
29
31
  title?: string | null
@@ -33,6 +35,7 @@ export type Database = {
33
35
  genre?: string | null
34
36
  id?: number
35
37
  latestBeatmapHash?: string | null
38
+ nominations?: number | null
36
39
  owner?: number | null
37
40
  status?: string | null
38
41
  title?: string | null
@@ -174,6 +177,7 @@ export type Database = {
174
177
  passed: boolean | null
175
178
  replayHwid: string | null
176
179
  songId: string | null
180
+ speed: number | null
177
181
  userId: number | null
178
182
  }
179
183
  Insert: {
@@ -185,6 +189,7 @@ export type Database = {
185
189
  passed?: boolean | null
186
190
  replayHwid?: string | null
187
191
  songId?: string | null
192
+ speed?: number | null
188
193
  userId?: number | null
189
194
  }
190
195
  Update: {
@@ -196,6 +201,7 @@ export type Database = {
196
201
  passed?: boolean | null
197
202
  replayHwid?: string | null
198
203
  songId?: string | null
204
+ speed?: number | null
199
205
  userId?: number | null
200
206
  }
201
207
  Relationships: [