rhythia-api 105.0.0 → 106.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.
@@ -47,6 +47,7 @@ export async function handler(
47
47
  }
48
48
 
49
49
  const user = (await supabase.auth.getUser(data.session)).data.user!;
50
+
50
51
  let userData: Database["public"]["Tables"]["profiles"]["Update"];
51
52
 
52
53
  // Find user's entry
@@ -67,6 +68,20 @@ export async function handler(
67
68
  userData = queryUserData[0];
68
69
  }
69
70
 
71
+ if (
72
+ userData.ban == "excluded" ||
73
+ userData.ban == "restricted" ||
74
+ userData.ban == "silenced"
75
+ ) {
76
+ return NextResponse.json(
77
+ {
78
+ error:
79
+ "Silenced, restricted or excluded players can't update their profile.",
80
+ },
81
+ { status: 404 }
82
+ );
83
+ }
84
+
70
85
  const upsertPayload: Database["public"]["Tables"]["profiles"]["Update"] = {
71
86
  id: userData.id,
72
87
  computedUsername: data.data.username?.toLowerCase(),
@@ -0,0 +1,76 @@
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
+ import {
7
+ PutBucketCorsCommand,
8
+ PutObjectCommand,
9
+ S3Client,
10
+ } from "@aws-sdk/client-s3";
11
+ import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
12
+
13
+ const s3Client = new S3Client({
14
+ region: "auto",
15
+ endpoint: "https://s3.eu-central-003.backblazeb2.com",
16
+ credentials: {
17
+ secretAccessKey: "K0039mm4iKsteQOXpZSzf0+VDzuH89U",
18
+ accessKeyId: "003c245e893e8060000000001",
19
+ },
20
+ });
21
+
22
+ export const Schema = {
23
+ input: z.strictObject({
24
+ session: z.string(),
25
+ beatmapHash: z.string(),
26
+ contentLength: z.number(),
27
+ contentType: z.string(),
28
+ }),
29
+ output: z.strictObject({
30
+ error: z.string().optional(),
31
+ url: z.string().optional(),
32
+ objectKey: z.string().optional(),
33
+ }),
34
+ };
35
+
36
+ export async function POST(request: Request): Promise<NextResponse> {
37
+ return protectedApi({
38
+ request,
39
+ schema: Schema,
40
+ authorization: validUser,
41
+ activity: handler,
42
+ });
43
+ }
44
+
45
+ export async function handler({
46
+ session,
47
+ beatmapHash,
48
+ contentLength,
49
+ contentType,
50
+ }: (typeof Schema)["input"]["_type"]): Promise<
51
+ NextResponse<(typeof Schema)["output"]["_type"]>
52
+ > {
53
+ const user = (await supabase.auth.getUser(session)).data.user!;
54
+
55
+ if (contentLength > 50000000) {
56
+ return NextResponse.json({
57
+ error: "Max content length exceeded.",
58
+ });
59
+ }
60
+
61
+ const key = `beatmap-${beatmapHash}-${user.id}`;
62
+ const command = new PutObjectCommand({
63
+ Bucket: "rhthia-avatars",
64
+ Key: key,
65
+ ContentLength: contentLength,
66
+ ContentType: contentType,
67
+ });
68
+
69
+ const presigned = await getSignedUrl(s3Client, command, {
70
+ expiresIn: 3600,
71
+ });
72
+ return NextResponse.json({
73
+ url: presigned,
74
+ objectKey: key,
75
+ });
76
+ }
package/api/getProfile.ts CHANGED
@@ -21,6 +21,7 @@ export const Schema = {
21
21
  flag: z.string().nullable(),
22
22
  id: z.number(),
23
23
  uid: z.string().nullable(),
24
+ ban: z.string().nullable(),
24
25
  username: z.string().nullable(),
25
26
  verified: z.boolean().nullable(),
26
27
  play_count: z.number().nullable(),
@@ -86,7 +87,7 @@ export async function handler(
86
87
  about_me: "",
87
88
  avatar_url:
88
89
  "https://rhthia-avatars.s3.eu-central-003.backblazeb2.com/user-avatar-1725309193296-72002e6b-321c-4f60-a692-568e0e75147d",
89
- badges: ["Early Bird"],
90
+ badges: [],
90
91
  username: `${user.user_metadata.full_name.slice(0, 20)}${Math.round(
91
92
  Math.random() * 900000 + 100000
92
93
  )}`,
package/index.ts CHANGED
@@ -20,6 +20,11 @@ import { Schema as GetLeaderboard } from "./api/getLeaderboard"
20
20
  export { Schema as SchemaGetLeaderboard } from "./api/getLeaderboard"
21
21
  export const getLeaderboard = handleApi({url:"/api/getLeaderboard",...GetLeaderboard})
22
22
 
23
+ // ./api/getMapUploadUrl.ts API
24
+ import { Schema as GetMapUploadUrl } from "./api/getMapUploadUrl"
25
+ export { Schema as SchemaGetMapUploadUrl } from "./api/getMapUploadUrl"
26
+ export const getMapUploadUrl = handleApi({url:"/api/getMapUploadUrl",...GetMapUploadUrl})
27
+
23
28
  // ./api/getProfile.ts API
24
29
  import { Schema as GetProfile } from "./api/getProfile"
25
30
  export { Schema as SchemaGetProfile } from "./api/getProfile"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rhythia-api",
3
- "version": "105.0.0",
3
+ "version": "106.0.0",
4
4
  "main": "index.ts",
5
5
  "scripts": {
6
6
  "update": "bun ./scripts/update.ts",
@@ -31,7 +31,7 @@
31
31
  "lodash": "^4.17.21",
32
32
  "next": "^14.2.5",
33
33
  "simple-git": "^3.25.0",
34
- "supabase": "^1.191.3",
34
+ "supabase": "^1.192.5",
35
35
  "tsx": "^4.17.0",
36
36
  "utf-8-validate": "^6.0.4",
37
37
  "zod": "^3.23.8"
package/types/database.ts CHANGED
@@ -11,9 +11,11 @@ export type Database = {
11
11
  Tables: {
12
12
  beatmaps: {
13
13
  Row: {
14
+ beatmapFile: string | null
14
15
  beatmapHash: string
15
16
  created_at: string
16
17
  difficulty: number | null
18
+ image: string | null
17
19
  length: number | null
18
20
  noteCount: number | null
19
21
  playcount: number | null
@@ -21,9 +23,11 @@ export type Database = {
21
23
  title: string | null
22
24
  }
23
25
  Insert: {
26
+ beatmapFile?: string | null
24
27
  beatmapHash: string
25
28
  created_at?: string
26
29
  difficulty?: number | null
30
+ image?: string | null
27
31
  length?: number | null
28
32
  noteCount?: number | null
29
33
  playcount?: number | null
@@ -31,9 +35,11 @@ export type Database = {
31
35
  title?: string | null
32
36
  }
33
37
  Update: {
38
+ beatmapFile?: string | null
34
39
  beatmapHash?: string
35
40
  created_at?: string
36
41
  difficulty?: number | null
42
+ image?: string | null
37
43
  length?: number | null
38
44
  noteCount?: number | null
39
45
  playcount?: number | null
@@ -47,6 +53,8 @@ export type Database = {
47
53
  about_me: string | null
48
54
  avatar_url: string | null
49
55
  badges: Json | null
56
+ ban: Database["public"]["Enums"]["banTypes"] | null
57
+ bannedAt: number | null
50
58
  computedUsername: string | null
51
59
  created_at: number | null
52
60
  flag: string | null
@@ -63,6 +71,8 @@ export type Database = {
63
71
  about_me?: string | null
64
72
  avatar_url?: string | null
65
73
  badges?: Json | null
74
+ ban?: Database["public"]["Enums"]["banTypes"] | null
75
+ bannedAt?: number | null
66
76
  computedUsername?: string | null
67
77
  created_at?: number | null
68
78
  flag?: string | null
@@ -79,6 +89,8 @@ export type Database = {
79
89
  about_me?: string | null
80
90
  avatar_url?: string | null
81
91
  badges?: Json | null
92
+ ban?: Database["public"]["Enums"]["banTypes"] | null
93
+ bannedAt?: number | null
82
94
  computedUsername?: string | null
83
95
  created_at?: number | null
84
96
  flag?: string | null
@@ -160,7 +172,7 @@ export type Database = {
160
172
  [_ in never]: never
161
173
  }
162
174
  Enums: {
163
- [_ in never]: never
175
+ banTypes: "cool" | "silenced" | "restricted" | "excluded"
164
176
  }
165
177
  CompositeTypes: {
166
178
  [_ in never]: never