Skip to content

Commit

Permalink
Update beatmapset discussion functions, plus some documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
TTTaevas committed Mar 26, 2024
1 parent 3f8e51c commit 6cf0214
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 36 deletions.
56 changes: 38 additions & 18 deletions lib/beatmapset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,21 @@ export namespace Beatmapset {
}

export namespace Discussion {
/**
* An interface to tell the API how the returned Array should be like
* @group Parameter Object Interfaces
*/
export interface Config {
/** The maximum amount of elements to get */
limit?: number
/** "id_asc" to have the oldest element first, "id_desc" to have the newest instead */
sort?: "id_desc" | "id_asc"
/** Which page of the results to get */
page?: number
/** A cursor_string provided by a previous request */
cursor_string?: string
}

export interface WithStartingpost extends Discussion {
starting_post: Post
}
Expand All @@ -254,18 +269,17 @@ export namespace Beatmapset {
* Get complex data about the posts of a beatmapset's discussion or of a user!
* @param from From where/who are the posts coming from? A specific discussion, a specific user?
* @param types What kind of posts?
* @param cursor_stuff How many results maximum to get, which page of those results, a cursor_string if you have that...
* @param sort (defaults to "id_desc") "id_asc" to have the oldest recent post first, "id_desc" to have the newest instead
* @param config How many results maximum, how to sort them, which page of those, maybe a cursor_string...
* @returns Relevant posts and info about them
* @remarks (2024-03-11) For months now, the API's documentation says the response is likely to change, so beware
*/
export async function getMultiple(this: API, from?: {discussion?: Discussion["id"] | Discussion, user?: User["id"] | User},
types?: ("first" | "reply" | "system")[], cursor_stuff?: {page?: number, limit?: number, cursor_string?: string}, sort: "id_desc" | "id_asc" = "id_desc"):
types?: ("first" | "reply" | "system")[], config?: Config):
Promise<{beatmapsets: Beatmapset.WithHype[], posts: Post[], users: User[], cursor_string: string | null}> {
const discussion = from?.discussion ? getId(from.discussion) : undefined
const user = from?.user ? getId(from.user) : undefined
return await this.request("get", "beatmapsets/discussions/posts", {beatmapset_discussion_id: discussion, limit: cursor_stuff?.limit,
page: cursor_stuff?.page, sort, types, user, cursor_string: cursor_stuff?.cursor_string})
return await this.request("get", "beatmapsets/discussions/posts", {beatmapset_discussion_id: discussion, limit: config?.limit,
page: config?.page, sort: config?.sort, types, user, cursor_string: config?.cursor_string})
}
}

Expand All @@ -283,45 +297,43 @@ export namespace Beatmapset {
* Get complex data about the votes of a beatmapset's discussions or/and received/given by a specific user!
* @param from The discussion with the votes, the user who voted, the user who's gotten the votes...
* @param score An upvote (1) or a downvote (-1)
* @param cursor_stuff How many results maximum to get, which page of those results, a cursor_string if you have that...
* @param sort "id_asc" to have the oldest recent vote first, "id_desc" to have the newest instead (defaults to **id_desc**)
* @param config How many results maximum, how to sort them, which page of those, maybe a cursor_string...
* @returns Relevant votes and info about them
* @remarks (2024-03-11) For months now, the API's documentation says the response is likely to change, so beware
*/
export async function getMultiple(this: API, from?: {discussion?: Discussion["id"] | Discussion, vote_giver?: User["id"] | User,
vote_receiver?: User["id"] | User}, score?: 1 | -1, cursor_stuff?: {page?: number, limit?: number, cursor_string?: string},
sort: "id_desc" | "id_asc" = "id_desc"): Promise<{votes: Vote[], discussions: Discussion[], users: User.WithGroups[], cursor_string: string | null}> {
vote_receiver?: User["id"] | User}, score?: 1 | -1, config?: Config):
Promise<{votes: Vote[], discussions: Discussion[], users: User.WithGroups[], cursor_string: string | null}> {
const discussion = from?.discussion ? getId(from.discussion) : undefined
const user = from?.vote_giver ? getId(from.vote_giver) : undefined
const receiver = from?.vote_receiver ? getId(from.vote_receiver) : undefined

return await this.request("get", "beatmapsets/discussions/votes", {beatmapset_discussion_id: discussion, limit: cursor_stuff?.limit,
page: cursor_stuff?.page, receiver, score, sort, user, cursor_string: cursor_stuff?.cursor_string})
return await this.request("get", "beatmapsets/discussions/votes", {beatmapset_discussion_id: discussion, limit: config?.limit,
page: config?.page, receiver, score, sort: config?.sort, user, cursor_string: config?.cursor_string})
}
}

/**
* Get complex data about the discussion page of any beatmapet that you want!
* @param from From where/who are the discussions coming from? Maybe only qualified sets?
* @param filter Should those discussions only be unresolved problems, for example?
* @param cursor_stuff How many results maximum to get, which page of those results, a cursor_string if you have that...
* @param sort "id_asc" to have the oldest recent discussion first, "id_desc" to have the newest instead (defaults to **id_desc**)
* @param config How many results maximum, how to sort them, which page of those, maybe a cursor_string...
* @returns Relevant discussions and info about them
* @remarks (2024-03-11) For months now, the API's documentation says the response is likely to change, so beware
* @privateRemarks I don't allow setting `beatmap_id` because my testing has led me to believe it does nothing (and is therefore misleading)
*/
export async function getMultiple(this: API, from?: {beatmapset?: Beatmapset["id"] | Beatmapset, user?: User["id"] | User,
status?: "all" | "ranked" | "qualified" | "disqualified" | "never_qualified"}, filter?: {types?: Beatmapset.Discussion["message_type"][],
only_unresolved?: boolean}, cursor_stuff?: {page?: number, limit?: number, cursor_string?: string}, sort: "id_desc" | "id_asc" = "id_desc"):
only_unresolved?: boolean}, config?: Config):
Promise<{beatmaps: Beatmap.Extended[], beatmapsets: Beatmapset.Extended[], discussions: Beatmapset.Discussion.WithStartingpost[]
included_discussions: Beatmapset.Discussion.WithStartingpost[], reviews_config: {max_blocks: number}, users: User.WithGroups[],
cursor_string: string | null}> {
const beatmapset = from?.beatmapset ? getId(from.beatmapset) : undefined
const user = from?.user ? getId(from.user) : undefined

return await this.request("get", "beatmapsets/discussions", {beatmapset_id: beatmapset, beatmapset_status: from?.status,
limit: cursor_stuff?.limit, message_types: filter?.types, only_unresolved: filter?.only_unresolved, page: cursor_stuff?.page, sort,
user, cursor_string: cursor_stuff?.cursor_string})
limit: config?.limit, message_types: filter?.types, only_unresolved: filter?.only_unresolved, page: config?.page, sort: config?.sort,
user, cursor_string: config?.cursor_string})
}
}

Expand All @@ -344,9 +356,17 @@ export namespace Beatmapset {
categories?: "Any" | "Ranked" | "Qualified" | "Loved" | "Favourites" | "Pending" | "WIP" | "Graveyard" | "My Maps",
/** Use this to hide all sets that are marked as explicit */
hide_explicit_content?: true,
/** Specify the musical genre of the music of the beatmapsets you're searching for */
/**
* Specify the musical genre of the music of the beatmapsets you're searching for (don't specify to get any genre)
* @remarks "Any"/0 actually looks up sets that specifically have the Genre "Any" such as `5947`, it's excluded because it's counter-intuitive
* and near useless (but you can do something like `1-1` if you actually want that!)
*/
genre?: Exclude<Genres, 0>,
/** Specify the spoken language of the music of the beatmapsets you're searching for */
/**
* Specify the spoken language of the music of the beatmapsets you're searching for (don't specify to get any language)
* @remarks "Any"/0 actually looks up sets that specifically have the Language "Any" (and no set has that), it's excluded because it's counter-intuitive
* and near useless (but you can do something like `1-1` if you actually want that!)
*/
language?: Exclude<Languages, 0>,
/** Should all sets have a video, a storyboard, maybe both at once? */
extra?: ("must_have_video" | "must_have_storyboard")[],
Expand Down
6 changes: 3 additions & 3 deletions lib/changelog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export namespace Changelog {
const max_id = typeof range?.to === "number" ? range.to : undefined

const response = await this.request("get", "changelog", {from, to, max_id, stream, message_formats})
return response.builds
return response.builds // NOT the only property; `streams` is irrelevant while `search` is useless
}
}

Expand Down Expand Up @@ -140,8 +140,8 @@ export namespace Changelog {
* ```
*/
export async function getAll(this: API): Promise<Changelog.UpdateStream.WithLatestbuildUsercount[]> {
const response = await this.request("get", "changelog", {max_id: 0})
return response.streams
const response = await this.request("get", "changelog", {max_id: 0}) // Limit how many `builds` we receive, for the sake of speed
return response.streams // NOT the only property; both `builds` and `search` are irrelevant
}
}
}
10 changes: 5 additions & 5 deletions lib/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ export namespace Chat {
/**
* Get a ChatChannel, and the users in it if it is a private channel!
* @scope {@link Scope"chat.read"}
* @remarks Will 404 if the user has not joined the channel (use `joinChatChannel` for that)
* @param channel The channel in question
* @remarks Will 404 if the user has not joined the channel (use `joinChatChannel` for that)
*/
export async function getOne(this: API, channel: Channel["channel_id"] | Channel): Promise<Channel.WithDetails> {
const response = await this.request("get", `chat/channels/${getId(channel, "channel_id")}`)
return response.channel
return response.channel // NOT the only property; `users` is already provided within `channel` so it is useless
}

/**
Expand Down Expand Up @@ -92,11 +92,11 @@ export namespace Chat {
/**
* Create a new announcement!
* @scope {@link Scope"chat.write_manage"}
* @remarks From my understanding, this WILL 403 unless the user is kinda special
* @param channel Details of the channel you're creating
* @param user_targets The people that will receive your message
* @param message The message to send with the announcement
* @returns The newly created channel!
* @remarks From my understanding, this WILL 403 unless the user is kinda special
*/
export async function createAnnouncement(this: API, channel: {name: string, description: string}, user_targets: Array<User["id"] | User>, message: string):
Promise<Channel> {
Expand Down Expand Up @@ -177,12 +177,12 @@ export namespace Chat {
/**
* Send a private message to someone!
* @scope {@link Scope"chat.write"}
* @remarks You don't need to use `createChatPrivateChannel` before sending a message
* @param user_target The User you wanna send your message to!
* @param message The message you wanna send
* @param is_action Is it a command? Like `/me dances` (defaults to **false**)
* @param uuid A client-side message identifier
* @returns The message you sent
* @remarks You don't need to use `createChatPrivateChannel` before sending a message
*/
export async function sendPrivate(this: API, user_target: User["id"] | User, message: string, is_action: boolean = false, uuid?: string):
Promise<{channel: Channel, message: Message}> {
Expand All @@ -197,7 +197,7 @@ export namespace Chat {
* @returns A list of recent silences
* @remarks Every 30 seconds is a good idea
*/
export async function keepAlive(this: API, since?: {user_silence?: UserSilence["id"]| UserSilence, message?: Message["message_id"] | Message}):
export async function keepAlive(this: API, since?: {user_silence?: UserSilence["id"] | UserSilence, message?: Message["message_id"] | Message}):
Promise<UserSilence[]> {
const history_since = since?.user_silence ? getId(since.user_silence) : undefined
const message_since = since?.message ? getId(since.message, "message_id") : undefined
Expand Down
16 changes: 8 additions & 8 deletions lib/forum.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { API } from "./index.js"
import { API, User } from "./index.js"
import { getId } from "./misc.js"

export namespace Forum {
Expand All @@ -16,8 +16,8 @@ export namespace Forum {
edited_by_id: number | null
forum_id: number
id: number
topic_id: number
user_id: number
topic_id: Topic["id"]
user_id: User["id"]
body: {
/** Post content in HTML format */
html: string
Expand Down Expand Up @@ -48,7 +48,7 @@ export namespace Forum {
export interface Topic {
created_at: Date
deleted_at: Date | null
first_post_id: number
first_post_id: Post["id"]
forum_id: number
id: number
is_locked: boolean
Expand All @@ -57,7 +57,7 @@ export namespace Forum {
title: string
type: "normal" | "sticky" | "announcement"
updated_at: Date
user_id: number
user_id: User["id"]
poll: {
allow_vote_change: boolean
/** @remarks Can be in the future */
Expand Down Expand Up @@ -87,12 +87,12 @@ export namespace Forum {
/**
* Create a new ForumTopic in the forum of your choice!
* @scope {@link Scope"forum.write"}
* @remarks Some users may not be allowed to do that, such as newly registered users, so this can 403 even with the right scopes
* @param forum_id The id of the forum you're creating your topic in
* @param title The topic's title
* @param text The first post's content/message
* @param poll If you want to make a poll, specify the parameters of that poll!
* @returns An object with the topic you've made, and its first initial post (which uses your `text`)
* @remarks Some users may not be allowed to do that, such as newly registered users, so this can 403 even with the right scopes
*/
export async function create(this: API, forum_id: number, title: string, text: string, poll?: {
title: string
Expand Down Expand Up @@ -134,10 +134,10 @@ export namespace Forum {
/**
* Edit the title of a Forum.Topic!
* @scope {@link Scope"forum.write"}
* @remarks Use `editForumPost` if you wanna edit the post at the top of the topic
* @param topic The topic or the id of the topic in question
* @param new_title The new title of the topic
* @returns The edited ForumTopic
* @remarks Use `editForumPost` if you wanna edit the post at the top of the topic
*/
export async function editTitle(this: API, topic: Topic["id"] | Topic, new_title: string): Promise<Topic> {
return await this.request("put", `forums/topics/${getId(topic)}`, {forum_topic: {topic_title: new_title}})
Expand All @@ -146,9 +146,9 @@ export namespace Forum {

/**
* Get a forum topic, as well as its main post (content) and the posts that were sent in it!
* @remarks The oldest post of a topic is the text of a topic
* @param topic An object with the id of the topic in question
* @param config How many results maximum, how to sort them, etc...
* @remarks The oldest post of a topic is the text of a topic
*/
export async function getTopicAndPosts(this: API, topic: Topic["id"] | Topic, config?: {
/** The id (or the post itself) of the first post to be returned in `posts` (irrelevant if using a `cursor_string`) */
Expand Down
2 changes: 1 addition & 1 deletion lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export { Comment } from "./comment.js"
function correctType(x: any): any {
const bannedProperties = [
"name", "artist", "title", "location", "interests", "occupation", "twitter",
"discord", "version", "author", "raw", "bbcode", "title", "message"
"discord", "version", "author", "raw", "bbcode", "title", "message", "creator"
]

if (typeof x === "boolean") {
Expand Down
2 changes: 1 addition & 1 deletion lib/news.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ export namespace NewsPost {

/**
* Get all the NewsPosts of a specific year!
* @remarks If the specified year is invalid/has no news, it fallbacks to the default year
* @param year The year the posts were made (defaults to **current year**)
* @privateRemarks Because the only filter is the year, everything but `news_sidebar.news_posts` is actually completely useless!
* You could maybe make a case for `years` being useful, but I don't believe it's useful enough to sacrifice the simplicity
* @remarks If the specified year is invalid/has no news, it fallbacks to the default year
*/
export async function getMultiple(this: API, year?: number): Promise<NewsPost[]> {
const response = await this.request("get", "news", {year, limit: 0}) // Put the limit at minimum because it's about stuff we're filtering out anyway
Expand Down

0 comments on commit 6cf0214

Please sign in to comment.