diff --git a/README.md b/README.md index 8fdef71..156cae7 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,9 @@ An official module for interacting with the Top.gg API # Introduction -The base client is Topgg.Api, and it takes your Top.gg token and provides you with plenty of methods to interact with the API. +The base client is Topgg.Api, and it takes your Top.gg token and provides you with plenty of methods to interact with the API. -Your Top.gg token can be found at `top.gg/bot/(BOT_ID)/webhooks` and copying the token. +See [this tutorial](https://github.com/top-gg/rust-sdk/assets/60427892/d2df5bd3-bc48-464c-b878-a04121727bff) on how to retrieve your API token. You can also setup webhooks via Topgg.Webhook, look down below at the examples for how to do so! @@ -58,5 +58,5 @@ app.post( app.listen(3000); // your port ``` -With this example, your webhook dashboard should look like this: -![](https://i.imgur.com/wFlp4Hg.png) +With this example, your webhook dashboard (`https://top.gg/bot/{your bot's id}/webhooks`) should look like this: +![](https://i.imgur.com/cZfZgK5.png) diff --git a/src/structs/Api.ts b/src/structs/Api.ts index 90f7ba5..74aaf73 100644 --- a/src/structs/Api.ts +++ b/src/structs/Api.ts @@ -30,6 +30,7 @@ import { */ export class Api extends EventEmitter { private options: APIOptions; + /** * Create Top.gg API instance * @@ -38,8 +39,25 @@ export class Api extends EventEmitter { */ constructor(token: string, options: APIOptions = {}) { super(); + + const tokenSegments = token.split("."); + + if (tokenSegments.length !== 3) { + throw new Error("Got a malformed API token."); + } + + const tokenData = atob(tokenSegments[1]); + + try { + JSON.parse(tokenData).id; + } catch { + throw new Error( + "Invalid API token state, this should not happen! Please report!" + ); + } + this.options = { - token: token, + token, ...options, }; } @@ -64,6 +82,7 @@ export class Api extends EventEmitter { }); let responseBody; + if ( (response.headers["content-type"] as string)?.startsWith( "application/json" @@ -92,24 +111,19 @@ export class Api extends EventEmitter { * ```js * await api.postStats({ * serverCount: 28199, - * shardCount: 1, * }); * ``` * * @param {object} stats Stats object * @param {number} stats.serverCount Server count - * @param {number} [stats.shardCount] Shard count - * @param {number} [stats.shardId] Posting shard (useful for process sharding) * @returns {BotStats} Passed object */ public async postStats(stats: BotStats): Promise { - if (!stats?.serverCount) throw new Error("Missing Server Count"); + if ((stats?.serverCount ?? 0) <= 0) throw new Error("Missing server count"); /* eslint-disable camelcase */ await this._request("POST", "/bots/stats", { server_count: stats.serverCount, - shard_id: stats.shardId, - shard_count: stats.shardCount, }); /* eslint-enable camelcase */ @@ -117,29 +131,31 @@ export class Api extends EventEmitter { } /** - * Get a bots stats + * Get your bot's stats * * @example * ```js - * await api.getStats("461521980492087297"); + * await api.getStats(); * // => * { * serverCount: 28199, - * shardCount 1, + * shardCount: null, * shards: [] * } * ``` * - * @param {Snowflake} id Bot ID - * @returns {BotStats} Stats of bot requested + * @returns {BotStats} Your bot's stats */ - public async getStats(id: Snowflake): Promise { - if (!id) throw new Error("ID missing"); - const result = await this._request("GET", `/bots/${id}/stats`); + public async getStats(_id?: Snowflake): Promise { + if (_id) + console.warn( + "[DeprecationWarning] getStats() no longer needs an ID argument" + ); + const result = await this._request("GET", "/bots/stats"); return { serverCount: result.server_count, - shardCount: result.shard_count, - shards: result.shards, + shardCount: null, + shards: [], }; } @@ -160,6 +176,8 @@ export class Api extends EventEmitter { } /** + * @deprecated No longer supported by Top.gg API v0. + * * Get user info * * @example @@ -173,7 +191,10 @@ export class Api extends EventEmitter { * @returns {UserInfo} Info for user */ public async getUser(id: Snowflake): Promise { - if (!id) throw new Error("ID Missing"); + console.warn( + "[DeprecationWarning] getUser is no longer supported by Top.gg API v0." + ); + return this._request("GET", `/users/${id}`); } @@ -185,18 +206,15 @@ export class Api extends EventEmitter { * // Finding by properties * await api.getBots({ * search: { - * username: "shiro", - * certifiedBot: true, + * username: "shiro" * }, * }); * // => * { * results: [ * { - * id: '461521980492087297', - * username: 'Shiro', - * discriminator: '8764', - * lib: 'discord.js', + * id: "461521980492087297", + * username: "Shiro", * ...rest of bot object * } * ...other shiro knockoffs B) @@ -243,7 +261,7 @@ export class Api extends EventEmitter { } /** - * Get users who've voted + * Get recent unique users who've voted * * @example * ```js @@ -253,22 +271,22 @@ export class Api extends EventEmitter { * { * username: 'Xignotic', * id: '205680187394752512', - * avatar: '3b9335670c7213b3a2d4e990081900c7' + * avatar: 'https://cdn.discordapp.com/avatars/1026525568344264724/cd70e62e41f691f1c05c8455d8c31e23.png' * }, * { * username: 'iara', * id: '395526710101278721', - * avatar: '3d1477390b8d7c3cec717ac5c778f5f4' + * avatar: 'https://cdn.discordapp.com/avatars/1026525568344264724/cd70e62e41f691f1c05c8455d8c31e23.png' * } * ...more * ] * ``` * - * @returns {ShortUser[]} Array of users who've voted + * @param {number} [page] The page number. Each page can only have at most 100 voters. + * @returns {ShortUser[]} Array of unique users who've voted */ - public async getVotes(): Promise { - if (!this.options.token) throw new Error("Missing token"); - return this._request("GET", "/bots/votes"); + public async getVotes(page?: number): Promise { + return this._request("GET", "/bots/votes", { page: page ?? 1 }); } /** diff --git a/src/typings.ts b/src/typings.ts index d0c8eca..f891c54 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -7,22 +7,36 @@ export interface APIOptions { export type Snowflake = string; export interface BotInfo { - /** The id of the bot */ + /** The Top.gg ID of the bot */ id: Snowflake; + /** The Discord ID of the bot */ + clientid: Snowflake; /** The username of the bot */ username: string; - /** The discriminator of the bot */ + /** + * The discriminator of the bot + * + * @deprecated No longer supported by Top.gg API v0. + */ discriminator: string; - /** The avatar hash of the bot's avatar */ - avatar?: string; - /** The cdn hash of the bot's avatar if the bot has none */ + /** The bot's avatar */ + avatar: string; + /** + * The cdn hash of the bot's avatar if the bot has none + * + * @deprecated No longer supported by Top.gg API v0. + */ defAvatar: string; - /** The URL for the banner image */ + /** + * The URL for the banner image + * + * @deprecated No longer supported by Top.gg API v0. + */ bannerUrl?: string; /** * The library of the bot * - * @deprecated + * @deprecated No longer supported by Top.gg API v0. */ lib: string; /** The prefix of the bot */ @@ -30,33 +44,54 @@ export interface BotInfo { /** The short description of the bot */ shortdesc: string; /** The long description of the bot. Can contain HTML and/or Markdown */ - longdesc: string; + longdesc?: string; /** The tags of the bot */ tags: string[]; /** The website url of the bot */ website?: string; - /** The support server invite code of the bot */ + /** The support url of the bot */ support?: string; /** The link to the github repo of the bot */ github?: string; /** The owners of the bot. First one in the array is the main owner */ owners: Snowflake[]; - /** The guilds featured on the bot page */ + /** + * The guilds featured on the bot page + * + * @deprecated No longer supported by Top.gg API v0. + */ guilds: Snowflake[]; /** The custom bot invite url of the bot */ invite?: string; - /** The date when the bot was approved (in ISO 8601) */ + /** The date when the bot was submitted (in ISO 8601) */ date: string; - /** The certified status of the bot */ + /** + * The certified status of the bot + * + * @deprecated No longer supported by Top.gg API v0. + */ certifiedBot: boolean; /** The vanity url of the bot */ vanity?: string; - /** The amount of upvotes the bot has */ + /** The amount of votes the bot has */ points: number; - /** The amount of upvotes the bot has this month */ + /** The amount of votes the bot has this month */ monthlyPoints: number; - /** The guild id for the donatebot setup */ + /** + * The guild id for the donatebot setup + * + * @deprecated No longer supported by Top.gg API v0. + */ donatebotguildid: Snowflake; + /** The amount of servers the bot is in based on posted stats */ + server_count?: number; + /** The bot's reviews on Top.gg */ + reviews: { + /** This bot's average review score out of 5 */ + averageScore: number; + /** This bot's review count */ + count: number; + }; } export interface BotStats { @@ -65,14 +100,27 @@ export interface BotStats { /** * The amount of servers the bot is in per shard. Always present but can be * empty. (Only when receiving stats) + * + * @deprecated No longer supported by Top.gg API v0. */ shards?: number[]; - /** The shard ID to post as (only when posting) */ + /** + * The shard ID to post as (only when posting) + * + * @deprecated No longer supported by Top.gg API v0. + */ shardId?: number; - /** The amount of shards a bot has */ - shardCount?: number; + /** + * The amount of shards a bot has + * + * @deprecated No longer supported by Top.gg API v0. + */ + shardCount?: number | null; } +/** + * @deprecated No longer supported by Top.gg API v0. + */ export interface UserInfo { /** The id of the user */ id: Snowflake; @@ -80,8 +128,8 @@ export interface UserInfo { username: string; /** The discriminator of the user */ discriminator: string; - /** The avatar hash of the user's avatar */ - avatar?: string; + /** The user's avatar url */ + avatar: string; /** The cdn hash of the user's avatar if the user has none */ defAvatar: string; /** The bio of the user */ @@ -126,8 +174,8 @@ export interface BotsQuery { [key in keyof BotInfo]: string; } | string; - /** The field to sort by. Prefix with "-"" to reverse the order */ - sort?: string; + /** Sorts results from a specific criteria. Results will always be descending. */ + sort?: "monthlyPoints" | "id" | "date"; /** A list of fields to show. */ fields?: string[] | string; } @@ -153,10 +201,10 @@ export interface ShortUser { /** * User's discriminator * - * @deprecated + * @deprecated No longer supported by Top.gg API v0. */ discriminator: string; - /** User's avatar hash */ + /** User's avatar url */ avatar: string; } diff --git a/tests/Api.test.ts b/tests/Api.test.ts index 04000db..f163b42 100644 --- a/tests/Api.test.ts +++ b/tests/Api.test.ts @@ -1,143 +1,68 @@ import { Api } from '../src/index'; import ApiError from '../src/utils/ApiError'; -import { BOT, BOT_STATS, USER, VOTES } from './mocks/data'; +import { BOT, BOT_STATS, VOTES } from './mocks/data'; -const is_owner = new Api('owner_token'); -const not_owner = new Api('not_owner_token'); -const no_token = new Api(''); +/* mock token */ +const client = new Api('.eyJpZCI6IjEwMjY1MjU1NjgzNDQyNjQ3MjQiLCJib3QiOnRydWV9.'); describe('API postStats test', () => { - it('postStats should return 401 when no token is provided', async() => { - await expect(no_token.postStats({serverCount: 1, shardCount: 0})).rejects.toThrowError(ApiError); - }) it('postStats without server count should throw error', async () => { - await expect(is_owner.postStats({shardCount: 0})).rejects.toThrowError(Error); - }) - it('postStats should return 401 when no token is provided', async () => { - await expect(no_token.postStats({serverCount: 1, shardCount: 0})).rejects.toThrowError(ApiError); - }) - - /* - TODO: Check for this is not added in code and api returns 400 - it('postStats with invalid negative server count should throw error', () => { - expect(is_owner.postStats({serverCount: -1, shardCount: 0})).rejects.toThrowError(Error); - }) - - TODO: Check for negative shardId is not added - it('postStats with invalid negative shardId should throw error', () => { - expect(is_owner.postStats({serverCount: 1, shardCount: 0, shardId: -1})).rejects.toThrowError(Error); - }) - - TODO: ShardId cannot be greater or equal to shardCount - it('postStats with shardId greater than shardCount should throw error', () => { - expect(is_owner.postStats({serverCount: 1, shardCount: 0, shardId: 1})).rejects.toThrowError(Error); - }) - - TODO: Check for negative shardCount is not added - it('postStats with invalid negative shardCount should throw error', () => { - expect(is_owner.postStats({serverCount: 1, shardCount: -1})).rejects.toThrowError(Error); - }) - - TODO: Check if shardCount is greater than 10000 - it('postStats with invalid shardCount should throw error', () => { - expect(is_owner.postStats({serverCount: 1, shardCount: 10001})).rejects.toThrowError(Error); - }) - */ - - it('postStats should return 403 when token is not owner of bot', async () => { - await expect(not_owner.postStats({serverCount: 1, shardCount: 0})).rejects.toThrowError(ApiError); - }) - - it('postStats should return 200 when token is owner of bot', async () => { - await expect(is_owner.postStats({serverCount: 1, shardCount: 1})).resolves.toBeInstanceOf(Object); - }) -}) + await expect(client.postStats({ shardCount: 0 })).rejects.toThrow(Error); + }); + + it('postStats with invalid negative server count should throw error', () => { + expect(client.postStats({ serverCount: -1 })).rejects.toThrow(Error); + }); + + it('postStats should return 200', async () => { + await expect(client.postStats({ serverCount: 1 })).resolves.toBeInstanceOf( + Object + ); + }); +}); describe('API getStats test', () => { - it('getStats should return 401 when no token is provided', () => { - expect(no_token.getStats('1')).rejects.toThrowError(ApiError); - }) - - it('getStats should return 404 when bot is not found', async() => { - await expect(is_owner.getStats('0')).rejects.toThrowError(ApiError); - }) - it('getStats should return 200 when bot is found', async () => { - expect(is_owner.getStats('1')).resolves.toStrictEqual({ + expect(client.getStats('1')).resolves.toStrictEqual({ serverCount: BOT_STATS.server_count, - shardCount: BOT_STATS.shard_count, - shards: BOT_STATS.shards - }); - }) - - it('getStats should throw when no id is provided', () => { - expect(is_owner.getStats('')).rejects.toThrowError(Error); - }) -}) - + shardCount: BOT_STATS.shard_count, + shards: BOT_STATS.shards + }); + }); +}); describe('API getBot test', () => { - it('getBot should return 401 when no token is provided', () => { - expect(no_token.getBot('1')).rejects.toThrowError(ApiError); - }) it('getBot should return 404 when bot is not found', () => { - expect(is_owner.getBot('0')).rejects.toThrowError(ApiError); - }) - - it('getBot should return 200 when bot is found', async () => { - expect(is_owner.getBot('1')).resolves.toStrictEqual(BOT); - }) - - it('getBot should throw when no id is provided', () => { - expect(is_owner.getBot('')).rejects.toThrowError(Error); - }) - -}) -describe('API getUser test', () => { - it('getUser should return 401 when no token is provided', () => { - expect(no_token.getUser('1')).rejects.toThrowError(ApiError); - }) + expect(client.getBot('0')).rejects.toThrow(ApiError); + }); - it('getUser should return 404 when user is not found', () => { - expect(is_owner.getUser('0')).rejects.toThrowError(ApiError); - }) - - it('getUser should return 200 when user is found', async () => { - expect(is_owner.getUser('1')).resolves.toStrictEqual(USER); - }) - - it('getUser should throw when no id is provided', () => { - expect(is_owner.getUser('')).rejects.toThrowError(Error); - }) -}) + it('getBot should return 200 when bot is found', async () => { + expect(client.getBot('1')).resolves.toStrictEqual(BOT); + }); + it('getBot should throw when no id is provided', () => { + expect(client.getBot('')).rejects.toThrow(Error); + }); +}); describe('API getVotes test', () => { - it('getVotes should return throw error when no token is provided', () => { - expect(no_token.getVotes()).rejects.toThrowError(Error); - }) - it('getVotes should return 200 when token is provided', () => { - expect(is_owner.getVotes()).resolves.toEqual(VOTES); - }) + expect(client.getVotes()).resolves.toEqual(VOTES); + }); }); describe('API hasVoted test', () => { - it('hasVoted should throw error when no token is provided', () => { - expect(no_token.hasVoted('1')).rejects.toThrowError(Error); - }) - it('hasVoted should return 200 when token is provided', () => { - expect(is_owner.hasVoted('1')).resolves.toBe(true); - }) + expect(client.hasVoted('1')).resolves.toBe(true); + }); it('hasVoted should throw error when no id is provided', () => { - expect(is_owner.hasVoted('')).rejects.toThrowError(Error); - }) -}) + expect(client.hasVoted('')).rejects.toThrow(Error); + }); +}); describe('API isWeekend tests', () => { it('isWeekend should return true', async () => { - expect(is_owner.isWeekend()).resolves.toBe(true) - }) -}); \ No newline at end of file + expect(client.isWeekend()).resolves.toBe(true); + }); +}); diff --git a/tests/jest.setup.ts b/tests/jest.setup.ts index 7145c22..7d4db81 100644 --- a/tests/jest.setup.ts +++ b/tests/jest.setup.ts @@ -11,44 +11,35 @@ interface IOptions { export const getIdInPath = (pattern: string, url: string) => { const regex = new RegExp(`^${pattern.replace(/:[^/]+/g, '([^/]+)')}$`); const match = url.match(regex); - + return match ? match[1] : null; -} +}; export const isMatchingPath = (pattern: string, url: string) => { // Remove query params - url = url.split("?")[0] + url = url.split("?")[0]; if (pattern === url) { return true; } // Check if there is an exact match - if(endpoints.some(({ pattern }) => pattern === url)) { - return false - }; + if (endpoints.some(({ pattern }) => pattern === url)) { + return false; + } return getIdInPath(pattern, url) !== null; -} +}; beforeEach(() => { - const mockAgent = new MockAgent() + const mockAgent = new MockAgent(); mockAgent.disableNetConnect(); const client = mockAgent.get('https://top.gg'); - - + const generateResponse = (request: MockInterceptor.MockResponseCallbackOptions, statusCode: number, data: any, headers = {}, options: IOptions) => { - const requestHeaders = request.headers as any; - - // Check if token is avaliable - if (options.requireAuth && (!requestHeaders['authorization'] || requestHeaders['authorization'] == '')) return { statusCode: 401 }; - - // Check that user is owner of bot - if (options.requireAuth && requestHeaders['authorization'] !== 'owner_token') return { statusCode: 403 } - const error = options.validate?.(request); if (error) return error; - + return { statusCode, data: JSON.stringify(data), @@ -57,12 +48,12 @@ beforeEach(() => { } } } - + endpoints.forEach(({ pattern, method, data, requireAuth, validate }) => { client.intercept({ path: (path) => isMatchingPath(pattern, path), method, - }).reply((request) => {return generateResponse(request, 200, data, {}, { pattern, requireAuth, validate: validate })}); + }).reply((request) => {return generateResponse(request, 200, data, {}, { pattern, requireAuth, validate })}); }) client.intercept({ @@ -71,6 +62,6 @@ beforeEach(() => { }).reply((request) => { throw Error(`No endpoint found for ${request.method} ${request.path}`) }) - + setGlobalDispatcher(mockAgent); -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/tests/mocks/data.ts b/tests/mocks/data.ts index fc3bd6b..65ec229 100644 --- a/tests/mocks/data.ts +++ b/tests/mocks/data.ts @@ -1,29 +1,25 @@ // https://docs.top.gg/api/bot/#find-one-bot export const BOT = { - "defAvatar": "6debd47ed13483642cf09e832ed0bc1b", - "invite": "", - "website": "https://discordbots.org", - "support": "KYZsaFb", - "github": "https://github.com/DiscordBotList/Luca", - "longdesc": "Luca only works in the **Discord Bot List** server. \r\nPrepend commands with the prefix `-` or `@Luca#1375`. \r\n**Please refrain from using these commands in non testing channels.**\r\n- `botinfo @bot` Shows bot info, title redirects to site listing.\r\n- `bots @user`* Shows all bots of that user, includes bots in the queue.\r\n- `owner / -owners @bot`* Shows all owners of that bot.\r\n- `prefix @bot`* Shows the prefix of that bot.\r\n* Mobile friendly version exists. Just add `noembed` to the end of the command.\r\n", - "shortdesc": "Luca is a bot for managing and informing members of the server", - "prefix": "- or @Luca#1375", - "lib": "discord.js", - "clientid": "264811613708746752", - "avatar": "7edcc4c6fbb0b23762455ca139f0e1c9", - "id": "264811613708746752", - "discriminator": "1375", - "username": "Luca", - "date": "2017-04-26T18:08:17.125Z", - "server_count": 2, - "guilds": ["417723229721853963", "264445053596991498"], - "shards": [], - "monthlyPoints": 19, - "points": 397, - "certifiedBot": false, - "owners": ["129908908096487424"], - "tags": ["Moderation", "Role Management", "Logging"], - "donatebotguildid": "" + invite: "https://top.gg/discord", + support: "https://discord.gg/dbl", + github: "https://github.com/top-gg", + longdesc: + "A bot to grant API access to our Library Developers on the Top.gg site without them needing to submit a bot to pass verification just to be able to access the API. \n" + + "\n" + + "Access to this bot's team can be requested by contacting a Community Manager in [our Discord server](https://top.gg/discord).", + shortdesc: "API access for Top.gg Library Developers", + prefix: "/", + clientid: "1026525568344264724", + avatar: "https://cdn.discordapp.com/avatars/1026525568344264724/cd70e62e41f691f1c05c8455d8c31e23.png", + id: "1026525568344264724", + username: "Top.gg Lib Dev API Access", + date: "2022-10-03T16:08:55.000Z", + server_count: 2, + monthlyPoints: 4, + points: 18, + owners: ["491002268401926145"], + tags: ["api", "library", "topgg"], + reviews: { averageScore: 5, count: 2 } } // https://docs.top.gg/api/bot/#search-bots @@ -38,45 +34,25 @@ export const BOTS = { // https://docs.top.gg/api/bot/#last-1000-votes export const VOTES = [ { - "username": "Xetera", - "id": "140862798832861184", - "avatar": "a_1241439d430def25c100dd28add2d42f" + username: "Xetera", + id: "140862798832861184", + avatar: "https://cdn.discordapp.com/avatars/1026525568344264724/cd70e62e41f691f1c05c8455d8c31e23.png" } ] // https://docs.top.gg/api/bot/#bot-stats export const BOT_STATS = { server_count: 0, - shards: ['200'], - shard_count: 1 + shards: [], + shard_count: null } // https://docs.top.gg/api/bot/#individual-user-vote export const USER_VOTE = { - "voted": 1 -} - -// https://docs.top.gg/api/user/#structure -export const USER = { - "discriminator": "0001", - "avatar": "a_1241439d430def25c100dd28add2d42f", - "id": "140862798832861184", - "username": "Xetera", - "defAvatar": "322c936a8c8be1b803cd94861bdfa868", - "admin": true, - "webMod": true, - "mod": true, - "certifiedDev": false, - "supporter": false, - "social": {} -} - -export const USER_VOTE_CHECK = { - voted: 1 + voted: 1 } // Undocumented 😢 export const WEEKEND = { is_weekend: true } - diff --git a/tests/mocks/endpoints.ts b/tests/mocks/endpoints.ts index 1919c0a..ce1fca9 100644 --- a/tests/mocks/endpoints.ts +++ b/tests/mocks/endpoints.ts @@ -1,5 +1,5 @@ import { MockInterceptor } from 'undici/types/mock-interceptor'; -import { BOT, BOTS, BOT_STATS, USER, USER_VOTE, USER_VOTE_CHECK, VOTES, WEEKEND } from './data'; +import { BOT, BOTS, BOT_STATS, USER_VOTE, VOTES, WEEKEND } from './data'; import { getIdInPath } from '../jest.setup'; export const endpoints = [ @@ -17,41 +17,25 @@ export const endpoints = [ validate: (request: MockInterceptor.MockResponseCallbackOptions) => { const bot_id = getIdInPath('/api/bots/:bot_id', request.path); if (Number(bot_id) === 0) return { statusCode: 404 }; - return null - }, - }, - { - pattern: '/api/bots/:bot_id/votes', - method: 'GET', - data: VOTES, - requireAuth: true + return null; + } }, { pattern: '/api/bots/votes', method: 'GET', data: VOTES, requireAuth: true - }, // Undocumented - { - pattern: '/api/bots/:bot_id/stats', - method: 'GET', - data: BOT_STATS, - requireAuth: true, - validate: (request: MockInterceptor.MockResponseCallbackOptions) => { - const bot_id = getIdInPath('/api/bots/:bot_id/stats', request.path); - if (Number(bot_id) === 0) return { statusCode: 404 }; - return null - }, }, { - pattern: '/api/bots/:bot_id/check', + pattern: '/api/bots/check', method: 'GET', data: USER_VOTE, requireAuth: true }, { - pattern: '/api/bots/:bot_id/stats', - method: 'POST', + pattern: '/api/bots/stats', + method: 'GET', + data: BOT_STATS, requireAuth: true }, { @@ -59,28 +43,11 @@ export const endpoints = [ method: 'POST', data: {}, requireAuth: true - }, // Undocumented - { - pattern: '/api/users/:user_id', - method: 'GET', - data: USER, - requireAuth: true, - validate: (request: MockInterceptor.MockResponseCallbackOptions) => { - const bot_id = getIdInPath('/api/users/:user_id', request.path); - if (Number(bot_id) === 0) return { statusCode: 404 }; - return null - }, }, { - pattern: '/api/bots/check', + pattern: '/api/weekend', method: 'GET', - data: USER_VOTE_CHECK, + data: WEEKEND, requireAuth: true - }, - { - pattern: '/api/weekend', - method: 'GET', - data: WEEKEND, - requireAuth: true - }, -]; \ No newline at end of file + } +] \ No newline at end of file