rhythia-api 106.0.0 → 107.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,47 @@
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 {
6
+ SSPMParsedMap,
7
+ SSPMParser,
8
+ } from "rhythia-star-calculator/src/sspmParser";
9
+
10
+ export const Schema = {
11
+ input: z.strictObject({
12
+ url: z.string(),
13
+ }),
14
+ output: z.strictObject({
15
+ hash: z.string().optional(),
16
+ error: z.string().optional(),
17
+ }),
18
+ };
19
+
20
+ export async function POST(request: Request): Promise<NextResponse> {
21
+ return protectedApi({
22
+ request,
23
+ schema: Schema,
24
+ authorization: validUser,
25
+ activity: handler,
26
+ });
27
+ }
28
+
29
+ export async function handler({
30
+ url,
31
+ }: (typeof Schema)["input"]["_type"]): Promise<
32
+ NextResponse<(typeof Schema)["output"]["_type"]>
33
+ > {
34
+ if (
35
+ !url.startsWith(`https://rhthia-avatars.s3.eu-central-003.backblazeb2.com/`)
36
+ )
37
+ return NextResponse.json({ error: "Invalid url" });
38
+
39
+ const request = await fetch(url);
40
+ const bytes = await request.arrayBuffer();
41
+ const parser = new SSPMParser(Buffer.from(bytes));
42
+
43
+ const parsedData = parser.parse();
44
+
45
+ console.log(parsedData);
46
+ return NextResponse.json({});
47
+ }
@@ -0,0 +1,47 @@
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
+ }),
10
+ output: z.strictObject({
11
+ error: z.string().optional(),
12
+ id: z.number().optional(),
13
+ }),
14
+ };
15
+
16
+ export async function POST(request: Request): Promise<NextResponse> {
17
+ return protectedApi({
18
+ request,
19
+ schema: Schema,
20
+ authorization: validUser,
21
+ activity: handler,
22
+ });
23
+ }
24
+
25
+ export async function handler({
26
+ session,
27
+ }: (typeof Schema)["input"]["_type"]): Promise<
28
+ NextResponse<(typeof Schema)["output"]["_type"]>
29
+ > {
30
+ const user = (await supabase.auth.getUser(session)).data.user!;
31
+ let { data: userData, error: userError } = await supabase
32
+ .from("profiles")
33
+ .select("*")
34
+ .eq("uid", user.id)
35
+ .single();
36
+
37
+ if (!userData) return NextResponse.json({ error: "No user." });
38
+
39
+ const upserted = await supabase
40
+ .from("beatmapPages")
41
+ .upsert({
42
+ owner: userData.id,
43
+ })
44
+ .select("*")
45
+ .single();
46
+ return NextResponse.json({ id: upserted.data?.id });
47
+ }
@@ -74,11 +74,13 @@ export async function getLeaderboard(page = 1, session: string) {
74
74
  console.log(startPage, endPage);
75
75
  const countQuery = await supabase
76
76
  .from("profiles")
77
- .select("*", { count: "exact", head: true });
77
+ .select("*", { count: "exact", head: true })
78
+ .neq("ban", "excluded");
78
79
 
79
80
  let { data: queryData, error } = await supabase
80
81
  .from("profiles")
81
82
  .select("*")
83
+ .neq("ban", "excluded")
82
84
  .order("skill_points", { ascending: false })
83
85
  .range(startPage, endPage);
84
86
 
@@ -22,7 +22,6 @@ const s3Client = new S3Client({
22
22
  export const Schema = {
23
23
  input: z.strictObject({
24
24
  session: z.string(),
25
- beatmapHash: z.string(),
26
25
  contentLength: z.number(),
27
26
  contentType: z.string(),
28
27
  }),
@@ -44,7 +43,6 @@ export async function POST(request: Request): Promise<NextResponse> {
44
43
 
45
44
  export async function handler({
46
45
  session,
47
- beatmapHash,
48
46
  contentLength,
49
47
  contentType,
50
48
  }: (typeof Schema)["input"]["_type"]): Promise<
@@ -58,7 +56,7 @@ export async function handler({
58
56
  });
59
57
  }
60
58
 
61
- const key = `beatmap-${beatmapHash}-${user.id}`;
59
+ const key = `beatmap-${Date.now()}-${user.id}`;
62
60
  const command = new PutObjectCommand({
63
61
  Bucket: "rhthia-avatars",
64
62
  Key: key,
package/api/getProfile.ts CHANGED
@@ -113,6 +113,7 @@ export async function handler(
113
113
  const { count: playersWithMorePoints, error: rankError } = await supabase
114
114
  .from("profiles")
115
115
  .select("*", { count: "exact", head: true })
116
+ .neq("ban", "excluded")
116
117
  .gt("skill_points", user.skill_points);
117
118
 
118
119
  return NextResponse.json({
@@ -33,6 +33,7 @@ export async function handler(data: (typeof Schema)["input"]["_type"]) {
33
33
  const { data: searchData, error } = await supabase
34
34
  .from("profiles")
35
35
  .select("id,username")
36
+ .neq("ban", "excluded")
36
37
  .ilike("username", `%${data.text}%`)
37
38
  .limit(10);
38
39
  return NextResponse.json({
@@ -0,0 +1,64 @@
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
+ id: z.number(),
10
+ beatmapHash: z.string(),
11
+ }),
12
+ output: z.strictObject({
13
+ error: z.string().optional(),
14
+ }),
15
+ };
16
+
17
+ export async function POST(request: Request): Promise<NextResponse> {
18
+ return protectedApi({
19
+ request,
20
+ schema: Schema,
21
+ authorization: validUser,
22
+ activity: handler,
23
+ });
24
+ }
25
+
26
+ export async function handler({
27
+ session,
28
+ beatmapHash,
29
+ id,
30
+ }: (typeof Schema)["input"]["_type"]): Promise<
31
+ NextResponse<(typeof Schema)["output"]["_type"]>
32
+ > {
33
+ const user = (await supabase.auth.getUser(session)).data.user!;
34
+ let { data: userData, error: userError } = await supabase
35
+ .from("profiles")
36
+ .select("*")
37
+ .eq("uid", user.id)
38
+ .single();
39
+
40
+ let { data: pageData, error: pageError } = await supabase
41
+ .from("beatmapPages")
42
+ .select("*")
43
+ .eq("id", id)
44
+ .single();
45
+
46
+ if (!userData) return NextResponse.json({ error: "No user." });
47
+ if (userData.id !== pageData?.owner)
48
+ return NextResponse.json({ error: "Non-authz user." });
49
+
50
+ const upserted = await supabase
51
+ .from("beatmapPages")
52
+ .upsert({
53
+ id,
54
+ latestBeatmapHash: beatmapHash,
55
+ owner: userData.id,
56
+ })
57
+ .select("*")
58
+ .single();
59
+
60
+ if (upserted.error) {
61
+ return NextResponse.json({ error: upserted.error.message });
62
+ }
63
+ return NextResponse.json({});
64
+ }
package/index.ts CHANGED
@@ -1,5 +1,15 @@
1
1
  import { handleApi } from "./handleApi"
2
2
 
3
+ // ./api/createBeatmap.ts API
4
+ import { Schema as CreateBeatmap } from "./api/createBeatmap"
5
+ export { Schema as SchemaCreateBeatmap } from "./api/createBeatmap"
6
+ export const createBeatmap = handleApi({url:"/api/createBeatmap",...CreateBeatmap})
7
+
8
+ // ./api/createBeatmapPage.ts API
9
+ import { Schema as CreateBeatmapPage } from "./api/createBeatmapPage"
10
+ export { Schema as SchemaCreateBeatmapPage } from "./api/createBeatmapPage"
11
+ export const createBeatmapPage = handleApi({url:"/api/createBeatmapPage",...CreateBeatmapPage})
12
+
3
13
  // ./api/editAboutMe.ts API
4
14
  import { Schema as EditAboutMe } from "./api/editAboutMe"
5
15
  export { Schema as SchemaEditAboutMe } from "./api/editAboutMe"
@@ -54,4 +64,9 @@ export const searchUsers = handleApi({url:"/api/searchUsers",...SearchUsers})
54
64
  import { Schema as SubmitScore } from "./api/submitScore"
55
65
  export { Schema as SchemaSubmitScore } from "./api/submitScore"
56
66
  export const submitScore = handleApi({url:"/api/submitScore",...SubmitScore})
67
+
68
+ // ./api/updateBeatmapPage.ts API
69
+ import { Schema as UpdateBeatmapPage } from "./api/updateBeatmapPage"
70
+ export { Schema as SchemaUpdateBeatmapPage } from "./api/updateBeatmapPage"
71
+ export const updateBeatmapPage = handleApi({url:"/api/updateBeatmapPage",...UpdateBeatmapPage})
57
72
  export { handleApi } from "./handleApi"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rhythia-api",
3
- "version": "106.0.0",
3
+ "version": "107.0.0",
4
4
  "main": "index.ts",
5
5
  "scripts": {
6
6
  "update": "bun ./scripts/update.ts",
@@ -30,6 +30,7 @@
30
30
  "isomorphic-git": "^1.27.1",
31
31
  "lodash": "^4.17.21",
32
32
  "next": "^14.2.5",
33
+ "rhythia-star-calculator": "^1.0.4",
33
34
  "simple-git": "^3.25.0",
34
35
  "supabase": "^1.192.5",
35
36
  "tsx": "^4.17.0",
@@ -0,0 +1,31 @@
1
+ import { createClient } from "@supabase/supabase-js";
2
+ import { Database } from "../types/database";
3
+
4
+ export const supabase = createClient<Database>(
5
+ `https://pfkajngbllcbdzoylrvp.supabase.co`,
6
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBma2FqbmdibGxjYmR6b3lscnZwIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTcxODU3NjA3MCwiZXhwIjoyMDM0MTUyMDcwfQ.XKUlQWvzmcYyirM-Zi4nwhiEKcpx1xLS97QUyuR3MoY",
7
+ {
8
+ auth: {
9
+ autoRefreshToken: false,
10
+ persistSession: false,
11
+ },
12
+ }
13
+ );
14
+
15
+ async function main() {
16
+ const countQuery = await supabase
17
+ .from("profiles")
18
+ .select("*", { count: "exact", head: true })
19
+ .neq("ban", "excluded");
20
+
21
+ let { data: queryData, error } = await supabase
22
+ .from("profiles")
23
+ .select("*")
24
+ .neq("ban", "excluded")
25
+ .order("skill_points", { ascending: false })
26
+ .range(0, 50);
27
+
28
+ console.log(queryData);
29
+ }
30
+
31
+ main();
package/types/database.ts CHANGED
@@ -9,6 +9,42 @@ export type Json =
9
9
  export type Database = {
10
10
  public: {
11
11
  Tables: {
12
+ beatmapPages: {
13
+ Row: {
14
+ created_at: string
15
+ id: number
16
+ latestBeatmapHash: string | null
17
+ owner: number | null
18
+ }
19
+ Insert: {
20
+ created_at?: string
21
+ id?: number
22
+ latestBeatmapHash?: string | null
23
+ owner?: number | null
24
+ }
25
+ Update: {
26
+ created_at?: string
27
+ id?: number
28
+ latestBeatmapHash?: string | null
29
+ owner?: number | null
30
+ }
31
+ Relationships: [
32
+ {
33
+ foreignKeyName: "beatmapPages_latestBeatmapHash_fkey"
34
+ columns: ["latestBeatmapHash"]
35
+ isOneToOne: false
36
+ referencedRelation: "beatmaps"
37
+ referencedColumns: ["beatmapHash"]
38
+ },
39
+ {
40
+ foreignKeyName: "beatmapPages_owner_fkey"
41
+ columns: ["owner"]
42
+ isOneToOne: false
43
+ referencedRelation: "profiles"
44
+ referencedColumns: ["id"]
45
+ },
46
+ ]
47
+ }
12
48
  beatmaps: {
13
49
  Row: {
14
50
  beatmapFile: string | null