rhythia-api 187.0.0 → 189.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,79 @@
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 { getUserBySession } from "../utils/getUserBySession";
6
+ import { User } from "@supabase/supabase-js";
7
+ import short from "short-uuid";
8
+ import { error } from "console";
9
+
10
+ export const Schema = {
11
+ input: z.strictObject({
12
+ session: z.string(),
13
+ code: z.string(),
14
+ }),
15
+ output: z.object({
16
+ error: z.string().optional(),
17
+ }),
18
+ };
19
+
20
+ export async function POST(request: Request) {
21
+ return protectedApi({
22
+ request,
23
+ schema: Schema,
24
+ authorization: validUser,
25
+ activity: handler,
26
+ });
27
+ }
28
+
29
+ export async function handler(data: (typeof Schema)["input"]["_type"]) {
30
+ const user = (await getUserBySession(data.session)) as User;
31
+ let { data: queryUserData, error: userError } = await supabase
32
+ .from("profiles")
33
+ .select("*")
34
+ .eq("uid", user.id)
35
+ .single();
36
+
37
+ if (!queryUserData) {
38
+ return NextResponse.json({ error: "Can't find user" });
39
+ }
40
+
41
+ let { data: codeData } = await supabase
42
+ .from("invites")
43
+ .select("*")
44
+ .eq("code", data.code)
45
+ .single();
46
+
47
+ if (!codeData || (codeData && codeData.used)) {
48
+ return NextResponse.json({ error: "Can't find code, or used" });
49
+ }
50
+
51
+ if (codeData.type == "clan") {
52
+ if (queryUserData.clan) {
53
+ return NextResponse.json({
54
+ error: "You can't join another clan while being in a clan",
55
+ });
56
+ }
57
+
58
+ let { data: queryClanData, error: clanError } = await supabase
59
+ .from("clans")
60
+ .select("*")
61
+ .eq("id", Number(codeData.resourceId))
62
+ .single();
63
+
64
+ if (!queryClanData) {
65
+ return NextResponse.json({
66
+ error: "No such clan",
67
+ });
68
+ }
69
+
70
+ await supabase.from("profiles").upsert({
71
+ id: queryUserData.id,
72
+ clan: queryClanData?.id,
73
+ });
74
+
75
+ return NextResponse.json({});
76
+ }
77
+
78
+ return NextResponse.json({ error: "Unknown invite type" });
79
+ }
@@ -7,6 +7,8 @@ import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
7
7
  import { rateMap } from "../utils/star-calc";
8
8
  import { getUserBySession } from "../utils/getUserBySession";
9
9
  import { User } from "@supabase/supabase-js";
10
+ import { NodeHttpHandler } from "@aws-sdk/node-http-handler";
11
+
10
12
  const s3Client = new S3Client({
11
13
  region: "auto",
12
14
  endpoint: "https://s3.eu-central-003.backblazeb2.com",
@@ -14,8 +16,46 @@ const s3Client = new S3Client({
14
16
  secretAccessKey: process.env.SECRET_BUCKET || "",
15
17
  accessKeyId: process.env.ACCESS_BUCKET || "",
16
18
  },
19
+ requestChecksumCalculation: "WHEN_REQUIRED",
17
20
  });
18
21
 
22
+ // Remove ALL validation and checksum middleware
23
+ const middlewareToRemove = [
24
+ "build:checksum",
25
+ "build:content-checksum",
26
+ "build:content-md5",
27
+ "validate",
28
+ "validateChecksum",
29
+ ];
30
+
31
+ s3Client.middlewareStack.add(
32
+ (next) =>
33
+ async (args): Promise<any> => {
34
+ const request = args.request as RequestInit;
35
+
36
+ // Remove checksum headers
37
+ const headers = request.headers as Record<string, string>;
38
+ delete headers["x-amz-checksum-crc32"];
39
+ delete headers["x-amz-checksum-crc32c"];
40
+ delete headers["x-amz-checksum-sha1"];
41
+ delete headers["x-amz-checksum-sha256"];
42
+ request.headers = headers;
43
+
44
+ Object.entries(request.headers).forEach(
45
+ // @ts-ignore
46
+ ([key, value]: [string, string]): void => {
47
+ if (!request.headers) {
48
+ request.headers = {};
49
+ }
50
+ (request.headers as Record<string, string>)[key] = value;
51
+ }
52
+ );
53
+
54
+ return next(args);
55
+ },
56
+ { step: "build", name: "customHeaders" }
57
+ );
58
+
19
59
  export const Schema = {
20
60
  input: z.strictObject({
21
61
  url: z.string(),
@@ -0,0 +1,66 @@
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 { getUserBySession } from "../utils/getUserBySession";
6
+ import { User } from "@supabase/supabase-js";
7
+ import short from "short-uuid";
8
+
9
+ export const Schema = {
10
+ input: z.strictObject({
11
+ session: z.string(),
12
+ type: z.string(),
13
+ resourceId: z.string(),
14
+ }),
15
+ output: z.object({
16
+ code: z.string().optional(),
17
+ error: z.string().optional(),
18
+ }),
19
+ };
20
+
21
+ export async function POST(request: Request) {
22
+ return protectedApi({
23
+ request,
24
+ schema: Schema,
25
+ authorization: validUser,
26
+ activity: handler,
27
+ });
28
+ }
29
+
30
+ export async function handler(data: (typeof Schema)["input"]["_type"]) {
31
+ const user = (await getUserBySession(data.session)) as User;
32
+ let { data: queryUserData, error: userError } = await supabase
33
+ .from("profiles")
34
+ .select("*")
35
+ .eq("uid", user.id)
36
+ .single();
37
+
38
+ if (!queryUserData) {
39
+ return NextResponse.json({ error: "Can't find user" });
40
+ }
41
+
42
+ if (data.type !== "clan") {
43
+ return NextResponse.json({
44
+ error: "Invites can only be created for clans",
45
+ });
46
+ }
47
+
48
+ if (data.resourceId !== queryUserData.clan?.toString()) {
49
+ return NextResponse.json({
50
+ error: "You can't create invite for a clan that you aren't owner of.",
51
+ });
52
+ }
53
+
54
+ const invite = short.generate();
55
+
56
+ const upsertResult = await supabase
57
+ .from("invites")
58
+ .upsert({
59
+ code: invite,
60
+ type: "clan",
61
+ resourceId: data.resourceId,
62
+ })
63
+ .select();
64
+
65
+ return NextResponse.json({ code: invite });
66
+ }
@@ -0,0 +1,45 @@
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 { getUserBySession } from "../utils/getUserBySession";
6
+ import { User } from "@supabase/supabase-js";
7
+
8
+ export const Schema = {
9
+ input: z.strictObject({
10
+ page: z.number(),
11
+ session: z.any(),
12
+ }),
13
+ output: z.object({
14
+ clanData: z.array(
15
+ z.object({
16
+ id: z.number(),
17
+ name: z.string(),
18
+ acronym: z.string().nullable(),
19
+ avatar_url: z.string().nullable(),
20
+ description: z.string().nullable(),
21
+ member_count: z.number(),
22
+ total_skill_points: z.number(),
23
+ total_pages: z.number(),
24
+ })
25
+ ),
26
+ error: z.string().optional(),
27
+ }),
28
+ };
29
+
30
+ export async function POST(request: Request) {
31
+ return protectedApi({
32
+ request,
33
+ schema: Schema,
34
+ authorization: validUser,
35
+ activity: handler,
36
+ });
37
+ }
38
+
39
+ export async function handler(data: (typeof Schema)["input"]["_type"]) {
40
+ const { data: clanData, error } = await supabase.rpc("get_clan_leaderboard", {
41
+ page_number: data.page,
42
+ items_per_page: 25,
43
+ });
44
+ return NextResponse.json({ clanData, error });
45
+ }
@@ -42,6 +42,9 @@ export async function handler({
42
42
  if (!userData) return NextResponse.json({ error: "No user." });
43
43
  if (userData.ban !== "cool") return NextResponse.json({ error: "Error" });
44
44
 
45
+ if (content.length > 256)
46
+ return NextResponse.json({ error: "Comment exceeds length." });
47
+
45
48
  const upserted = await supabase
46
49
  .from("beatmapPageComments")
47
50
  .upsert({
@@ -198,7 +198,7 @@ export async function handler({
198
198
 
199
199
  if (
200
200
  beatmaps.starRating &&
201
- Math.abs(beatmaps.starRating - data.virtualStars) < 0.01
201
+ Math.abs(beatmaps.starRating - data.virtualStars) < 0.1
202
202
  ) {
203
203
  awarded_sp = calculatePerformancePoints(
204
204
  data.speed * beatmaps.starRating * multiplierMod,
package/index.ts CHANGED
@@ -1,5 +1,21 @@
1
1
  import { handleApi } from "./handleApi"
2
2
 
3
+ // ./api/acceptInvite.ts API
4
+
5
+ /*
6
+ export const Schema = {
7
+ input: z.strictObject({
8
+ session: z.string(),
9
+ code: z.string(),
10
+ }),
11
+ output: z.object({
12
+ error: z.string().optional(),
13
+ }),
14
+ };*/
15
+ import { Schema as AcceptInvite } from "./api/acceptInvite"
16
+ export { Schema as SchemaAcceptInvite } from "./api/acceptInvite"
17
+ export const acceptInvite = handleApi({url:"/api/acceptInvite",...AcceptInvite})
18
+
3
19
  // ./api/addCollectionMap.ts API
4
20
 
5
21
  /*
@@ -47,17 +63,7 @@ export const chartPublicStats = handleApi({url:"/api/chartPublicStats",...ChartP
47
63
  // ./api/createBeatmap.ts API
48
64
 
49
65
  /*
50
- export const Schema = {
51
- input: z.strictObject({
52
- url: z.string(),
53
- session: z.string(),
54
- updateFlag: z.boolean().optional(),
55
- }),
56
- output: z.strictObject({
57
- hash: z.string().optional(),
58
- error: z.string().optional(),
59
- }),
60
- };*/
66
+ */
61
67
  import { Schema as CreateBeatmap } from "./api/createBeatmap"
62
68
  export { Schema as SchemaCreateBeatmap } from "./api/createBeatmap"
63
69
  export const createBeatmap = handleApi({url:"/api/createBeatmap",...CreateBeatmap})
@@ -112,6 +118,24 @@ import { Schema as CreateCollection } from "./api/createCollection"
112
118
  export { Schema as SchemaCreateCollection } from "./api/createCollection"
113
119
  export const createCollection = handleApi({url:"/api/createCollection",...CreateCollection})
114
120
 
121
+ // ./api/createInvite.ts API
122
+
123
+ /*
124
+ export const Schema = {
125
+ input: z.strictObject({
126
+ session: z.string(),
127
+ type: z.string(),
128
+ resourceId: z.string(),
129
+ }),
130
+ output: z.object({
131
+ code: z.string().optional(),
132
+ error: z.string().optional(),
133
+ }),
134
+ };*/
135
+ import { Schema as CreateInvite } from "./api/createInvite"
136
+ export { Schema as SchemaCreateInvite } from "./api/createInvite"
137
+ export const createInvite = handleApi({url:"/api/createInvite",...CreateInvite})
138
+
115
139
  // ./api/deleteBeatmapPage.ts API
116
140
 
117
141
  /*
@@ -500,6 +524,34 @@ import { Schema as GetClan } from "./api/getClan"
500
524
  export { Schema as SchemaGetClan } from "./api/getClan"
501
525
  export const getClan = handleApi({url:"/api/getClan",...GetClan})
502
526
 
527
+ // ./api/getClans.ts API
528
+
529
+ /*
530
+ export const Schema = {
531
+ input: z.strictObject({
532
+ page: z.number(),
533
+ session: z.any(),
534
+ }),
535
+ output: z.object({
536
+ clanData: z.array(
537
+ z.object({
538
+ id: z.number(),
539
+ name: z.string(),
540
+ acronym: z.string().nullable(),
541
+ avatar_url: z.string().nullable(),
542
+ description: z.string().nullable(),
543
+ member_count: z.number(),
544
+ total_skill_points: z.number(),
545
+ total_pages: z.number(),
546
+ })
547
+ ),
548
+ error: z.string().optional(),
549
+ }),
550
+ };*/
551
+ import { Schema as GetClans } from "./api/getClans"
552
+ export { Schema as SchemaGetClans } from "./api/getClans"
553
+ export const getClans = handleApi({url:"/api/getClans",...GetClans})
554
+
503
555
  // ./api/getCollection.ts API
504
556
 
505
557
  /*
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rhythia-api",
3
- "version": "187.0.0",
3
+ "version": "189.0.0",
4
4
  "main": "index.ts",
5
5
  "author": "online-contributors",
6
6
  "scripts": {
@@ -15,6 +15,7 @@
15
15
  "dependencies": {
16
16
  "@2toad/profanity": "^3.0.0",
17
17
  "@aws-sdk/client-s3": "^3.637.0",
18
+ "@aws-sdk/node-http-handler": "^3.374.0",
18
19
  "@aws-sdk/s3-request-presigner": "^3.637.0",
19
20
  "@netlify/zip-it-and-ship-it": "^9.37.9",
20
21
  "@noble/ciphers": "^1.0.0",
@@ -40,10 +41,12 @@
40
41
  "osu-parsers": "^4.1.7",
41
42
  "osu-standard-stable": "^5.0.0",
42
43
  "sharp": "^0.33.5",
44
+ "short-uuid": "^5.2.0",
43
45
  "simple-git": "^3.25.0",
44
- "supabase": "^2.9.6",
46
+ "supabase": "^2.15.8",
45
47
  "tsx": "^4.17.0",
46
48
  "utf-8-validate": "^6.0.4",
49
+ "uuid": "^11.1.0",
47
50
  "validator": "^13.12.0",
48
51
  "zero-width": "^1.0.29",
49
52
  "zod": "^3.23.8"