From 7c29a02e491a7872d8993943fdfdc171d9565f39 Mon Sep 17 00:00:00 2001 From: Taevas <67872932+TTTaevas@users.noreply.github.com> Date: Sun, 31 Mar 2024 01:05:46 +0100 Subject: [PATCH] Add forum tests, change getRoomLeaderboard() to return user_score --- lib/forum.ts | 1 + lib/index.ts | 2 +- lib/multiplayer.ts | 40 +++++++++++++++++++++--------------- lib/tests/test_authorized.ts | 33 ++++++++++++++++++----------- lib/user.ts | 2 +- yarn.lock | 6 +++--- 6 files changed, 50 insertions(+), 34 deletions(-) diff --git a/lib/forum.ts b/lib/forum.ts index 1459c5a..dfb4d70 100644 --- a/lib/forum.ts +++ b/lib/forum.ts @@ -126,6 +126,7 @@ export namespace Forum { * @param topic The topic or the id of the topic you're making your reply in * @param text Your reply! Your message! * @returns The reply you've made, as a Forum.Post! + * @remarks Replying when the last post was made by the authorized user will likely cause the server to return a 403 */ export async function reply(this: API, topic: Topic["id"] | Topic, text: string): Promise { return await this.request("post", `forums/topics/${getId(topic)}/reply`, {body: text}) diff --git a/lib/index.ts b/lib/index.ts index 08022e8..cdbb8ea 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -633,7 +633,7 @@ export class API { readonly getRooms = Multiplayer.Room.getMultiple /** {@inheritDoc Multiplayer.Room.getOne} @group Multiplayer Functions */ - readonly getRoomLeaderboard = Multiplayer.Room.getLeaderboard + readonly getRoomLeaderboard = Multiplayer.Room.Leader.getMultiple /** {@inheritDoc Multiplayer.Room.getOne} @group Multiplayer Functions */ readonly getPlaylistItemScores = Multiplayer.Room.PlaylistItem.getScores diff --git a/lib/multiplayer.ts b/lib/multiplayer.ts index 6e18bcc..81638df 100644 --- a/lib/multiplayer.ts +++ b/lib/multiplayer.ts @@ -15,7 +15,7 @@ export namespace Multiplayer { max_attempts: number | null name: string participant_count: number - playlist: Multiplayer.Room.PlaylistItem[] + playlist: Room.PlaylistItem[] queue_mode: string recent_participants: User[] starts_at: Date @@ -99,11 +99,27 @@ export namespace Multiplayer { user: User.WithCountry } + export namespace Leader { + export interface WithPosition extends Leader { + position: number + } + + /** + * Get the room stats of all the users of that room! + * @scope {@link Scope"public"} + * @param room The room or the id of the room in question + * @returns An object with the leaderboard, and the score and position of the authorized user under `user_score` + */ + export async function getMultiple(this: API, room: number | Room): Promise<{leaderboard: Leader[], user_score: Leader.WithPosition | null}> { + return await this.request("get", `rooms/${getId(room)}/leaderboard`) + } + } + /** * Get data about a lazer multiplayer room (realtime or playlists)! * @param room The room or the id of the room, can be found at the end of its URL (after `/multiplayer/rooms/`) */ - export async function getOne(this: API, room: number | Multiplayer.Room): Promise { + export async function getOne(this: API, room: number | Room): Promise { return await this.request("get", `rooms/${getId(room)}`) } @@ -116,19 +132,9 @@ export namespace Multiplayer { * @param sort Sort (where most recent is first) by creation date or end date, defaults to the creation date */ export async function getMultiple(this: API, type: "playlists" | "realtime", mode: "active" | "all" | "ended" | "participated" | "owned", - limit: number = 10, sort: "ended" | "created" = "created"): Promise { + limit: number = 10, sort: "ended" | "created" = "created"): Promise { return await this.request("get", "rooms", {type_group: type, mode, limit, sort}) } - - /** - * Get the room stats of all the users of that room! - * @scope {@link Scope"public"} - * @param room The room or the id of the room in question - */ - export async function getLeaderboard(this: API, room: number | Multiplayer.Room): Promise { - const response = await this.request("get", `rooms/${getId(room)}/leaderboard`) - return response.leaderboard - } } /** @obtainableFrom {@link API.getMatch} */ @@ -177,8 +183,8 @@ export namespace Multiplayer { * Get data of a multiplayer lobby from the stable (non-lazer) client that have URLs with `community/matches` or `mp` * @param match The id of a match can be found at the end of its URL */ - export async function getOne(this: API, match: Match.Info["id"] | Match.Info): Promise { - const response = await this.request("get", `matches/${getId(match)}`) as Multiplayer.Match + export async function getOne(this: API, match: Info["id"] | Info): Promise { + const response = await this.request("get", `matches/${getId(match)}`) as Match // Fix `events[i].game.scores[e].perfect` being a number instead of a boolean for (let i = 0; i < response.events.length; i++) { for (let e = 0; e < Number(response.events[i].game?.scores.length); e++) { @@ -198,12 +204,12 @@ export namespace Multiplayer { * @remarks You can use this argument differently to get all matches before/after (depending of `query.sort`) a certain match, * by adding +1/-1 to its id! So if you want all matches after match_id 10 with sorting is_desc, just have this argument be 10 + 1, or 11! */ - first_match_in_array?: Match.Info["id"] | Match.Info + first_match_in_array?: Info["id"] | Info /** The maximum amount of elements returned in the array (defaults to **50**) */ limit?: number /** "id_desc" has the biggest id (most recent start_time) at the beginning of the array, "id_asc" is the opposite (defaults to **id_desc**) */ sort?: "id_desc" | "id_asc" - }): Promise { + }): Promise { // `first_match_in_array` is a cool way to use the endpoint's cursor const cursor = query?.first_match_in_array ? {match_id: getId(query.first_match_in_array) + (query?.sort === "id_asc" ? -1 : 1)} : undefined const response = await this.request("get", "matches", {cursor, limit: query?.limit, sort: query?.sort}) diff --git a/lib/tests/test_authorized.ts b/lib/tests/test_authorized.ts index 525b97e..e619ad3 100644 --- a/lib/tests/test_authorized.ts +++ b/lib/tests/test_authorized.ts @@ -90,7 +90,6 @@ function validate(object: unknown, schemaName: string): boolean { const testChat = async (): Promise => { let okay = true console.log("\n===> CHAT") - if (server === "https://osu.ppy.sh") console.warn("⚠️ DOING THE TESTS ON THE ACTUAL OSU SERVER") const a = await attempt(api.getChatChannels) if (!isOk(a, !a || (validate(a, "Chat.Channel")))) okay = false @@ -127,15 +126,23 @@ const testChat = async (): Promise => { return okay } -// const testForum = async (): Promise => { -// let okay = true -// console.log("\n===> FORUM") - -// const a = await attempt(api.getSpotlights) -// if (!isOk(a, !a || (a.length >= 132 && validate(a, "Spotlight")))) okay = false +const testForum = async (): Promise => { + let okay = true + console.log("\n===> FORUM") + const a = await attempt(api.createForumTopic, 85, "osu-api-v2-js test post", `Please ignore this forum post +It was automatically made for the sole purpose of testing [url=https://github.com/TTTaevas/osu-api-v2-js]osu-api-v2-js[/url]`, + {title: "test poll", options: ["yes", "maybe", "no"], length_days: 14, vote_change: true}) + if (!isOk(a, !a || (validate(a.topic, "Forum.Topic") && validate(a.post, "Forum.Post")))) okay = false + + if (a) { + const b = await attempt(api.editForumTopicTitle, a.topic, "osu-api-v2-js test post!") + if (!isOk(b, !b || (b.title === "osu-api-v2-js test post!" && validate(b, "Forum.Topic")))) okay = false + const c = await attempt(api.editForumPost, a.post, a.post.body.raw + " <3") + if (!isOk(c, !c || (c.body.raw === a.post.body.raw + " <3" && validate(c, "Forum.Post")))) okay = false + } -// return okay -// } + return okay +} const testMultiplayer = async (): Promise => { let okay = true @@ -148,11 +155,11 @@ const testMultiplayer = async (): Promise => { if (a1 && a1.length) { const b1 = await attempt(api.getRoomLeaderboard, a1[0]) - if (!isOk(b1, !b1 || (validate(b1, "Multiplayer.Room.Leader")))) okay = false + if (!isOk(b1, !b1 || (validate(b1.leaderboard, "Multiplayer.Room.Leader")))) okay = false } if (a2 && a2.length) { const b2 = await attempt(api.getRoomLeaderboard, a2[0]) - if (!isOk(b2, !b2 || (validate(b2, "Multiplayer.Room.Leader")))) okay = false + if (!isOk(b2, !b2 || (validate(b2.leaderboard, "Multiplayer.Room.Leader")))) okay = false } return okay @@ -185,6 +192,8 @@ const testUser = async (): Promise => { } const test = async (id: number | string | undefined, secret: string | undefined, redirect_uri: string | undefined): Promise => { + if (server === "https://osu.ppy.sh") console.warn("⚠️ DOING THE TESTS ON THE ACTUAL OSU SERVER") + if (id === undefined) {throw new Error("no ID env var")} if (secret === undefined) {throw new Error("no SECRET env var")} if (redirect_uri === undefined) {throw new Error("no REDIRECT_URI env var")} @@ -197,7 +206,7 @@ const test = async (id: number | string | undefined, secret: string | undefined, const tests = [ testChat, - // testForum, + testForum, testMultiplayer, testScore, testUser diff --git a/lib/user.ts b/lib/user.ts index 75922a5..97ce787 100644 --- a/lib/user.ts +++ b/lib/user.ts @@ -266,7 +266,7 @@ export namespace User { export async function getMultiple(this: API, users: Array): Promise { const ids = users.map((user) => getId(user)) const response = await this.request("get", "users", {ids}) - return response.users + return response.users // It's the only property } /** diff --git a/yarn.lock b/yarn.lock index 83eb838..1db68f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8,9 +8,9 @@ integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== "@types/node@*", "@types/node@^20.8.10": - version "20.11.30" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.30.tgz#9c33467fc23167a347e73834f788f4b9f399d66f" - integrity sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw== + version "20.12.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.2.tgz#9facdd11102f38b21b4ebedd9d7999663343d72e" + integrity sha512-zQ0NYO87hyN6Xrclcqp7f8ZbXNbRfoGWNcMvHTPQp9UUrwI0mI7XBz+cu7/W6/VClYo2g63B0cjull/srU7LgQ== dependencies: undici-types "~5.26.4"