import * as v from 'valibot'; import { adminAccountSchema, adminAnnouncementSchema, adminCanonicalEmailBlockSchema, adminCohortSchema, adminCustomEmojiSchema, adminDimensionSchema, adminDomainAllowSchema, adminDomainBlockSchema, adminDomainSchema, adminEmailDomainBlockSchema, adminIpBlockSchema, adminMeasureSchema, adminModerationLogEntrySchema, adminRelaySchema, adminReportSchema, adminRuleSchema, adminTagSchema, pleromaConfigSchema, statusSchema, statusSourceSchema, trendsLinkSchema, } from '@/entities'; import { filteredArray } from '@/entities/utils'; import { GOTOSOCIAL, MITRA, PLEROMA } from '../features'; import type { PaginatedResponse } from '../responses'; import type { PlApiBaseClient } from '@/client-base'; import type { AdminAccount, AdminAnnouncement, AdminModerationLogEntry, AdminReport, PleromaConfig, Status, } from '@/entities'; import type { AdminAccountAction, AdminCreateAccountParams, AdminCreateAnnouncementParams, AdminCreateCustomEmojiParams, AdminCreateDomainBlockParams, AdminCreateDomainParams, AdminCreateIpBlockParams, AdminCreateRuleParams, AdminDimensionKey, AdminGetAccountsParams, AdminGetAnnouncementsParams, AdminGetCanonicalEmailBlocks, AdminGetCustomEmojisParams, AdminGetDimensionsParams, AdminGetDomainAllowsParams, AdminGetDomainBlocksParams, AdminGetEmailDomainBlocksParams, AdminGetIpBlocksParams, AdminGetMeasuresParams, AdminGetModerationLogParams, AdminGetReportsParams, AdminGetStatusesParams, AdminMeasureKey, AdminPerformAccountActionParams, AdminUpdateAnnouncementParams, AdminUpdateCustomEmojiParams, AdminUpdateDomainBlockParams, AdminUpdateReportParams, AdminUpdateRuleParams, AdminUpdateStatusParams, } from '@/params/admin'; import type { EditStatusParams } from '@/params/statuses'; import type { EmptyObject } from '@/utils/types'; const paginatedPleromaAccounts = async ( client: PlApiBaseClient, params: { query?: string; filters?: string; page?: number; page_size: number; tags?: Array; actor_types?: Array; name?: string; email?: string; }, ): Promise> => { const response = await client.request('/api/v1/pleroma/admin/users', { params }); const adminAccounts = v.parse(filteredArray(adminAccountSchema), response.json?.users); return { previous: params.page ? () => paginatedPleromaAccounts(client, { ...params, page: params.page! - 1 }) : null, next: response.json?.count > params.page_size * ((params.page || 1) - 1) + response.json?.users?.length ? () => paginatedPleromaAccounts(client, { ...params, page: (params.page || 0) + 1 }) : null, items: adminAccounts, partial: response.status === 206, total: response.json?.count, }; }; const paginatedPleromaReports = async ( client: PlApiBaseClient, params: { state?: 'open' | 'closed' | 'resolved'; limit?: number; page?: number; page_size: number; }, ): Promise> => { const response = await client.request('/api/v1/pleroma/admin/reports', { params }); return { previous: params.page ? () => paginatedPleromaReports(client, { ...params, page: params.page! - 1 }) : null, next: response.json?.total > params.page_size * ((params.page || 1) - 1) + response.json?.reports?.length ? () => paginatedPleromaReports(client, { ...params, page: (params.page || 0) + 1 }) : null, items: v.parse(filteredArray(adminReportSchema), response.json?.reports), partial: response.status === 206, total: response.json?.total, }; }; const paginatedPleromaStatuses = async ( client: PlApiBaseClient, params: { page_size?: number; local_only?: boolean; godmode?: boolean; with_reblogs?: boolean; page?: number; }, ): Promise> => { const response = await client.request('/api/v1/pleroma/admin/statuses', { params }); return { previous: params.page ? () => paginatedPleromaStatuses(client, { ...params, page: params.page! - 1 }) : null, next: response.json?.length ? () => paginatedPleromaStatuses(client, { ...params, page: (params.page || 0) + 1 }) : null, items: v.parse(filteredArray(statusSchema), response.json), partial: response.status === 206, }; }; const admin = (client: PlApiBaseClient) => { const category = { /** Perform moderation actions with accounts. */ accounts: { /** * View accounts * View all accounts, optionally matching certain criteria for filtering, up to 100 at a time. * @see {@link https://docs.joinmastodon.org/methods/admin/accounts/#v2} */ getAccounts: (params?: AdminGetAccountsParams) => { if (client.features.mastodonAdminV2) { return client.paginatedGet('/api/v2/admin/accounts', { params }, adminAccountSchema); } return paginatedPleromaAccounts( client, params ? { query: params.username, name: params.display_name, email: params.email, filters: [ params.origin === 'local' && 'local', params.origin === 'remote' && 'external', params.status === 'active' && 'active', params.status === 'pending' && 'need_approval', params.status === 'disabled' && 'deactivated', params.permissions === 'staff' && 'is_admin', params.permissions === 'staff' && 'is_moderator', ] .filter((filter) => filter) .join(','), page_size: 100, } : { page_size: 100 }, ); }, /** * View a specific account * View admin-level information about the given account. * @see {@link https://docs.joinmastodon.org/methods/admin/accounts/#get-one} */ getAccount: async (accountId: string) => { let response; if (client.features.mastodonAdmin) { response = await client.request(`/api/v1/admin/accounts/${accountId}`); } else { response = await client.request(`/api/v1/pleroma/admin/users/${accountId}`); } return v.parse(adminAccountSchema, response.json); }, /** * Approve a pending account * Approve the given local account if it is currently pending approval. * @see {@link https://docs.joinmastodon.org/methods/admin/accounts/#approve} */ approveAccount: async (accountId: string) => { let response; if (client.features.mastodonAdmin) { response = await client.request(`/api/v1/admin/accounts/${accountId}/approve`, { method: 'POST', }); } else { const account = await category.accounts.getAccount(accountId)!; response = await client.request('/api/v1/pleroma/admin/users/approve', { method: 'PATCH', body: { nicknames: [account.username] }, }); response.json = response.json?.users?.[0]; } return v.parse(adminAccountSchema, response.json); }, /** * Reject a pending account * Reject the given local account if it is currently pending approval. * @see {@link https://docs.joinmastodon.org/methods/admin/accounts/#reject} */ rejectAccount: async (accountId: string) => { let response; if (client.features.mastodonAdmin) { response = await client.request(`/api/v1/admin/accounts/${accountId}/reject`, { method: 'POST', }); } else { const account = await category.accounts.getAccount(accountId)!; response = await client.request('/api/v1/pleroma/admin/users', { method: 'DELETE', body: { nicknames: [account.username], }, }); } return v.safeParse(adminAccountSchema, response.json).output || {}; }, /** * Requires features{@link Features.pleromaAdminAccounts}. */ createAccount: async (params: AdminCreateAccountParams) => { const response = await client.request('/api/v1/pleroma/admin/users', { method: 'POST', body: { users: [params] }, }); return v.parse( v.object({ nickname: v.string(), email: v.string(), }), response.json[0]?.data, ); }, /** * Delete an account * Permanently delete data for a suspended accountusers * @see {@link https://docs.joinmastodon.org/methods/admin/accounts/#delete} */ deleteAccount: async (accountId: string) => { let response; if (client.features.mastodonAdmin || client.features.version.software === MITRA) { response = await client.request(`/api/v1/admin/accounts/${accountId}`, { method: 'DELETE', }); } else { const account = await category.accounts.getAccount(accountId)!; response = await client.request('/api/v1/pleroma/admin/users', { method: 'DELETE', body: { nicknames: [account.username], }, }); } return v.safeParse(adminAccountSchema, response.json).output || {}; }, /** * Perform an action against an account * Perform an action against an account and log this action in the moderation history. Also resolves any open reports against this account. * @see {@link https://docs.joinmastodon.org/methods/admin/accounts/#action} */ performAccountAction: async ( accountId: string, type: AdminAccountAction, params?: AdminPerformAccountActionParams, ) => { let response; if (client.features.mastodonAdmin) { response = await client.request(`/api/v1/admin/accounts/${accountId}/action`, { body: { ...params, type }, }); } else { const account = await category.accounts.getAccount(accountId)!; switch (type) { case 'disable': case 'suspend': response = await client.request( '/api/v1/pleroma/admin/users/deactivate', { body: { nicknames: [account.username] }, }, ); break; default: response = { json: {} }; break; } if (params?.report_id) await category.reports.resolveReport(params.report_id); } return response.json; }, /** * Enable a currently disabled account * Re-enable a local account whose login is currently disabled. * @see {@link https://docs.joinmastodon.org/methods/admin/accounts/#enable} */ enableAccount: async (accountId: string) => { let response; if (client.features.mastodonAdmin) { response = await client.request(`/api/v1/admin/accounts/${accountId}/enable`, { method: 'POST', }); } else { const account = await category.accounts.getAccount(accountId)!; response = await client.request('/api/v1/pleroma/admin/users/activate', { method: 'PATCH', body: { nicknames: [account.username] }, }); response.json = response.json?.users?.[0]; } return v.parse(adminAccountSchema, response.json); }, /** * Unsilence an account * Unsilence an account if it is currently silenced. * @see {@link https://docs.joinmastodon.org/methods/admin/accounts/#unsilence} */ unsilenceAccount: async (accountId: string) => { const response = await client.request(`/api/v1/admin/accounts/${accountId}/unsilence`, { method: 'POST', }); return v.parse(adminAccountSchema, response.json); }, /** * Unsuspend an account * Unsuspend a currently suspended account. * @see {@link https://docs.joinmastodon.org/methods/admin/accounts/#unsuspend} */ unsuspendAccount: async (accountId: string) => { let response; if (client.features.mastodonAdmin) { response = await client.request(`/api/v1/admin/accounts/${accountId}/unsuspend`, { method: 'POST', }); } else { const { account } = await category.accounts.getAccount(accountId)!; response = await client.request('/api/v1/pleroma/admin/users/activate', { method: 'PATCH', body: { nicknames: [account!.acct] }, }); response.json = response.json?.users?.[0]; } return v.parse(adminAccountSchema, response.json); }, /** * Unmark an account as sensitive * Stops marking an account’s posts as sensitive, if it was previously flagged as sensitive. * @see {@link https://docs.joinmastodon.org/methods/admin/accounts/#unsensitive} */ unsensitiveAccount: async (accountId: string) => { const response = await client.request(`/api/v1/admin/accounts/${accountId}/unsensitive`, { method: 'POST', }); return v.parse(adminAccountSchema, response.json); }, /** * Requires features{@link Features.pleromaAdminAccounts}. */ promoteToAdmin: async (accountId: string) => { const { account } = await category.accounts.getAccount(accountId)!; await client.request( '/api/v1/pleroma/admin/users/permission_group/moderator', { method: 'DELETE', body: { nicknames: [account!.acct] }, }, ); const response = await client.request( '/api/v1/pleroma/admin/users/permission_group/admin', { method: 'POST', body: { nicknames: [account!.acct] }, }, ); return response.json; }, /** * Requires features{@link Features.pleromaAdminAccounts}. */ promoteToModerator: async (accountId: string) => { const { account } = await category.accounts.getAccount(accountId)!; await client.request('/api/v1/pleroma/admin/users/permission_group/admin', { method: 'DELETE', body: { nicknames: [account!.acct] }, }); const response = await client.request( '/api/v1/pleroma/admin/users/permission_group/moderator', { method: 'POST', body: { nicknames: [account!.acct] }, }, ); return response.json; }, /** * Requires features{@link Features.pleromaAdminAccounts}. */ demoteToUser: async (accountId: string) => { const { account } = await category.accounts.getAccount(accountId)!; await client.request( '/api/v1/pleroma/admin/users/permission_group/moderator', { method: 'DELETE', body: { nicknames: [account!.acct] }, }, ); const response = await client.request( '/api/v1/pleroma/admin/users/permission_group/admin', { method: 'DELETE', body: { nicknames: [account!.acct] }, }, ); return response.json; }, /** * Tag a user. * * Requires features{@link Features.pleromaAdminAccounts}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#patch-apiv1pleromaadminuserssuggest} */ suggestUser: async (accountId: string) => { const { account } = await category.accounts.getAccount(accountId)!; const response = await client.request('/api/v1/pleroma/admin/users/suggest', { method: 'PATCH', body: { nicknames: [account!.acct] }, }); return response.json; }, /** * Untag a user. * * Requires features{@link Features.pleromaAdminAccounts}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#patch-apiv1pleromaadminusersunsuggest} */ unsuggestUser: async (accountId: string) => { const { account } = await category.accounts.getAccount(accountId)!; const response = await client.request( '/api/v1/pleroma/admin/users/unsuggest', { method: 'PATCH', body: { nicknames: [account!.acct] }, }, ); return response.json; }, /** * Tag a user. * * Requires features{@link Features.pleromaAdminAccounts}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#put-apiv1pleromaadminuserstag} */ tagUser: async (accountId: string, tags: Array) => { const { account } = await category.accounts.getAccount(accountId)!; const response = await client.request('/api/v1/pleroma/admin/users/tag', { method: 'PUT', body: { nicknames: [account!.acct], tags }, }); return response.json; }, /** * Untag a user. * * Requires features{@link Features.pleromaAdminAccounts}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#delete-apiv1pleromaadminuserstag} */ untagUser: async (accountId: string, tags: Array) => { const { account } = await category.accounts.getAccount(accountId)!; const response = await client.request('/api/v1/pleroma/admin/users/tag', { method: 'DELETE', body: { nicknames: [account!.acct], tags }, }); return response.json; }, }, /** Disallow certain domains to federate. */ domainBlocks: { /** * List all blocked domains * Show information about all blocked domains. * @see {@link https://docs.joinmastodon.org/methods/admin/domain_blocks/#get} */ getDomainBlocks: (params?: AdminGetDomainBlocksParams) => client.paginatedGet('/api/v1/admin/domain_blocks', { params }, adminDomainBlockSchema), /** * Get a single blocked domain * Show information about a single blocked domain. * @see {@link https://docs.joinmastodon.org/methods/admin/domain_blocks/#get-one} */ getDomainBlock: async (domainBlockId: string) => { const response = await client.request(`/api/v1/admin/domain_blocks/${domainBlockId}`); return v.parse(adminDomainBlockSchema, response.json); }, /** * Block a domain from federating * Add a domain to the list of domains blocked from federating. * @see {@link https://docs.joinmastodon.org/methods/admin/domain_blocks/#create} */ createDomainBlock: async (domain: string, params?: AdminCreateDomainBlockParams) => { const response = await client.request('/api/v1/admin/domain_blocks', { method: 'POST', body: { ...params, domain }, }); return v.parse(adminDomainBlockSchema, response.json); }, /** * Update a domain block * Change parameters for an existing domain block. * @see {@link https://docs.joinmastodon.org/methods/admin/domain_blocks/#update} */ updateDomainBlock: async (domainBlockId: string, params?: AdminUpdateDomainBlockParams) => { const response = await client.request(`/api/v1/admin/domain_blocks/${domainBlockId}`, { method: 'PUT', body: params, }); return v.parse(adminDomainBlockSchema, response.json); }, /** * Remove a domain block * Lift a block against a domain. * @see {@link https://docs.joinmastodon.org/methods/admin/domain_blocks/#delete} */ deleteDomainBlock: async (domainBlockId: string) => { const response = await client.request( `/api/v1/admin/domain_blocks/${domainBlockId}`, { method: 'DELETE', }, ); return response.json; }, }, /** Perform moderation actions with reports. */ reports: { /** * View all reports * View information about all reports. * @see {@link https://docs.joinmastodon.org/methods/admin/reports/#get} */ getReports: (params?: AdminGetReportsParams) => { if (client.features.mastodonAdmin) { if ( params?.resolved === undefined && (client.features.version.software === GOTOSOCIAL || client.features.version.software === PLEROMA) ) { if (!params) params = {}; params.resolved = false; } return client.paginatedGet('/api/v1/admin/reports', { params }, adminReportSchema); } return paginatedPleromaReports(client, { state: params?.resolved === true ? 'resolved' : 'open', page_size: params?.limit || 100, }); }, /** * View a single report * @see {@link https://docs.joinmastodon.org/methods/admin/reports/#get-one} */ getReport: async (reportId: string) => { let response; if (client.features.mastodonAdmin) { response = await client.request(`/api/v1/admin/reports/${reportId}`); } else { response = await client.request(`/api/v1/pleroma/admin/reports/${reportId}`); } return v.parse(adminReportSchema, response.json); }, /** * Update a report * Change metadata for a report. * @see {@link https://docs.joinmastodon.org/methods/admin/reports/#update} */ updateReport: async (reportId: string, params: AdminUpdateReportParams) => { const response = await client.request(`/api/v1/admin/reports/${reportId}`, { method: 'PUT', body: params, }); return v.parse(adminReportSchema, response.json); }, /** * Assign report to self * Claim the handling of this report to yourcategory. * @see {@link https://docs.joinmastodon.org/methods/admin/reports/#assign_tocategory} */ assignReportToSelf: async (reportId: string) => { const response = await client.request( `/api/v1/admin/reports/${reportId}/assign_tocategory`, { method: 'POST', }, ); return v.parse(adminReportSchema, response.json); }, /** * Unassign report * Unassign a report so that someone else can claim it. * @see {@link https://docs.joinmastodon.org/methods/admin/reports/#unassign} */ unassignReport: async (reportId: string) => { const response = await client.request(`/api/v1/admin/reports/${reportId}/unassign`, { method: 'POST', }); return v.parse(adminReportSchema, response.json); }, /** * Mark report as resolved * * Mark a report as resolved with no further action taken. * * `action_taken_comment` param requires features{@link Features.mastodonAdminResolveReportWithComment}. * @param action_taken_comment Optional admin comment on the action taken in response to this report. Supported by GoToSocial only. * @see {@link https://docs.joinmastodon.org/methods/admin/reports/#resolve} */ resolveReport: async (reportId: string, action_taken_comment?: string) => { let response; if (client.features.mastodonAdmin) { response = await client.request(`/api/v1/admin/reports/${reportId}/resolve`, { method: 'POST', body: { action_taken_comment }, }); } else { response = await client.request(`/api/v1/pleroma/admin/reports/${reportId}`, { method: 'PATCH', body: { reports: [{ id: reportId, state: 'resolved' }] }, }); } return v.parse(adminReportSchema, response.json); }, /** * Reopen a closed report * Reopen a currently closed report, if it is closed. * @see {@link https://docs.joinmastodon.org/methods/admin/reports/#reopen} */ reopenReport: async (reportId: string) => { let response; if (client.features.mastodonAdmin) { response = await client.request(`/api/v1/admin/reports/${reportId}/reopen`, { method: 'POST', }); } else { response = await client.request(`/api/v1/pleroma/admin/reports/${reportId}`, { method: 'PATCH', body: { reports: [{ id: reportId, state: 'open' }] }, }); } return v.parse(adminReportSchema, response.json); }, }, statuses: { /** * @param params Retrieves all latest statuses * * The params are subject to change in case Mastodon implements alike route. * * Requires features{@link Features.pleromaAdminStatuses}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#get-apiv1pleromaadminstatuses} */ getStatuses: (params?: AdminGetStatusesParams) => paginatedPleromaStatuses(client, { page_size: params?.limit || 100, page: 1, local_only: params?.local_only, with_reblogs: params?.with_reblogs, godmode: params?.with_private, }), /** * Show status by id * * Requires features{@link Features.pleromaAdminStatuses}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#get-apiv1pleromaadminstatusesid} */ getStatus: async (statusId: string) => { const response = await client.request(`/api/v1/pleroma/admin/statuses/${statusId}`); return v.parse(statusSchema, response.json); }, /** * Change the scope of an individual reported status * * Requires features{@link Features.pleromaAdminStatuses}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#put-apiv1pleromaadminstatusesid} */ updateStatus: async (statusId: string, params: AdminUpdateStatusParams) => { const response = await client.request(`/api/v1/pleroma/admin/statuses/${statusId}`, { method: 'PUT', body: params, }); return v.parse(statusSchema, response.json); }, /** * Delete an individual reported status * * Requires features{@link Features.pleromaAdminStatuses}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#delete-apiv1pleromaadminstatusesid} */ deleteStatus: async (statusId: string) => { let response; if (client.features.version.software === MITRA) { response = await client.request(`/api/v1/admin/posts/${statusId}`, { method: 'DELETE', }); } else { response = await client.request( `/api/v1/pleroma/admin/statuses/${statusId}`, { method: 'DELETE', }, ); } return response.json; }, /** * Requires features{@link Features.pleromaAdminStatusesRedact} */ redactStatus: async ( statusId: string, params: EditStatusParams & { overwrite?: boolean }, ) => { const response = await client.request(`/api/v1/pleroma/admin/statuses/${statusId}/redact`, { method: 'PATCH', body: params, }); return v.parse(statusSchema, response.json); }, /** * Requires features{@link Features.pleromaAdminStatusesRedact} */ getStatusSource: async (statusId: string) => { const response = await client.request(`/api/v1/pleroma/admin/statuses/${statusId}/source`); return v.parse(statusSourceSchema, response.json); }, }, trends: { /** * View trending links * Links that have been shared more than others, including unapproved and unreviewed links. * @see {@link https://docs.joinmastodon.org/methods/admin/trends/#links} */ getTrendingLinks: async () => { const response = await client.request('/api/v1/admin/trends/links'); return v.parse(filteredArray(trendsLinkSchema), response.json); }, /** * View trending statuses * Statuses that have been interacted with more than others, including unapproved and unreviewed statuses. * @see {@link https://docs.joinmastodon.org/methods/admin/trends/#statuses} */ getTrendingStatuses: async () => { const response = await client.request('/api/v1/admin/trends/statuses'); return v.parse(filteredArray(statusSchema), response.json); }, /** * View trending tags * Tags that are being used more frequently within the past week, including unapproved and unreviewed tags. * @see {@link https://docs.joinmastodon.org/methods/admin/trends/#tags} */ getTrendingTags: async () => { const response = await client.request('/api/v1/admin/trends/links'); return v.parse(filteredArray(adminTagSchema), response.json); }, }, /** Block certain email addresses by their hash. */ canonicalEmailBlocks: { /** * List all canonical email blocks * @see {@link https://docs.joinmastodon.org/methods/admin/canonical_email_blocks/#get} */ getCanonicalEmailBlocks: (params?: AdminGetCanonicalEmailBlocks) => client.paginatedGet( '/api/v1/admin/canonical_email_blocks', { params }, adminCanonicalEmailBlockSchema, ), /** * Show a single canonical email block * @see {@link https://docs.joinmastodon.org/methods/admin/canonical_email_blocks/#get-one} */ getCanonicalEmailBlock: async (canonicalEmailBlockId: string) => { const response = await client.request( `/api/v1/admin/canonical_email_blocks/${canonicalEmailBlockId}`, ); return v.parse(adminCanonicalEmailBlockSchema, response.json); }, /** * Test * Canoniocalize and hash an email address. * @see {@link https://docs.joinmastodon.org/methods/admin/canonical_email_blocks/#test} */ testCanonicalEmailBlock: async (email: string) => { const response = await client.request('/api/v1/admin/canonical_email_blocks/test', { method: 'POST', body: { email }, }); return v.parse(filteredArray(adminCanonicalEmailBlockSchema), response.json); }, /** * Block a canonical email * @see {@link https://docs.joinmastodon.org/methods/admin/canonical_email_blocks/#create} */ createCanonicalEmailBlock: async (email: string, canonical_email_hash?: string) => { const response = await client.request('/api/v1/admin/canonical_email_blocks', { method: 'POST', body: { email, canonical_email_hash }, }); return v.parse(filteredArray(adminCanonicalEmailBlockSchema), response.json); }, /** * Delete a canonical email block * @see {@link https://docs.joinmastodon.org/methods/admin/canonical_email_blocks/#delete} */ deleteCanonicalEmailBlock: async (canonicalEmailBlockId: string) => { const response = await client.request( `/api/v1/admin/canonical_email_blocks/${canonicalEmailBlockId}`, { method: 'DELETE' }, ); return response.json; }, }, /** Obtain qualitative metrics about the server. */ dimensions: { /** * Get dimensional data * Obtain information about popularity of certain accounts, servers, languages, etc. * @see {@link https://docs.joinmastodon.org/methods/admin/dimensions/#get} */ getDimensions: async (keys: AdminDimensionKey[], params?: AdminGetDimensionsParams) => { const response = await client.request('/api/v1/admin/dimensions', { method: 'POST', params: { ...params, keys }, }); return v.parse(filteredArray(adminDimensionSchema), response.json); }, }, /** Allow certain domains to federate. */ domainAllows: { /** * List all allowed domains * Show information about all allowed domains. * @see {@link https://docs.joinmastodon.org/methods/admin/domain_allows/#get} */ getDomainAllows: (params?: AdminGetDomainAllowsParams) => client.paginatedGet('/api/v1/admin/domain_allows', { params }, adminDomainAllowSchema), /** * Get a single allowed domain * Show information about a single allowed domain. * @see {@link https://docs.joinmastodon.org/methods/admin/domain_allows/#get-one} */ getDomainAllow: async (domainAllowId: string) => { const response = await client.request(`/api/v1/admin/domain_allows/${domainAllowId}`); return v.parse(adminDomainAllowSchema, response.json); }, /** * Allow a domain to federate * Add a domain to the list of domains allowed to federate, to be used when the instance is in allow-list federation mode. * @see {@link https://docs.joinmastodon.org/methods/admin/domain_allows/#create} */ createDomainAllow: async (domain: string) => { const response = await client.request('/api/v1/admin/domain_allows', { method: 'POST', body: { domain }, }); return v.parse(adminDomainAllowSchema, response.json); }, /** * Delete an allowed domain * Delete a domain from the allowed domains list. * @see {@link https://docs.joinmastodon.org/methods/admin/domain_allows/#delete} */ deleteDomainAllow: async (domainAllowId: string) => { const response = await client.request( `/api/v1/admin/domain_allows/${domainAllowId}`, { method: 'DELETE', }, ); return response.json; }, }, /** Disallow certain email domains from signing up. */ emailDomainBlocks: { /** * List all blocked email domains * Show information about all email domains blocked from signing up. * @see {@link https://docs.joinmastodon.org/methods/admin/email_domain_blocks/#get} */ getEmailDomainBlocks: (params?: AdminGetEmailDomainBlocksParams) => client.paginatedGet( '/api/v1/admin/email_domain_blocks', { params }, adminEmailDomainBlockSchema, ), /** * Get a single blocked email domain * Show information about a single email domain that is blocked from signups. * @see {@link https://docs.joinmastodon.org/methods/admin/email_domain_blocks/#get-one} */ getEmailDomainBlock: async (emailDomainBlockId: string) => { const response = await client.request( `/api/v1/admin/email_domain_blocks/${emailDomainBlockId}`, ); return v.parse(adminEmailDomainBlockSchema, response.json); }, /** * Block an email domain from signups * Add a domain to the list of email domains blocked from signups. * @see {@link https://docs.joinmastodon.org/methods/admin/email_domain_blocks/#create} */ createEmailDomainBlock: async (domain: string) => { const response = await client.request('/api/v1/admin/email_domain_blocks', { method: 'POST', body: { domain }, }); return v.parse(adminEmailDomainBlockSchema, response.json); }, /** * Delete an email domain block * Lift a block against an email domain. * @see {@link https://docs.joinmastodon.org/methods/admin/email_domain_blocks/#delete} */ deleteEmailDomainBlock: async (emailDomainBlockId: string) => { const response = await client.request( `/api/v1/admin/email_domain_blocks/${emailDomainBlockId}`, { method: 'DELETE' }, ); return response.json; }, }, /** Disallow certain IP address ranges from signing up. */ ipBlocks: { /** * List all IP blocks * Show information about all blocked IP ranges. * @see {@link https://docs.joinmastodon.org/methods/admin/ip_blocks/#get} */ getIpBlocks: (params?: AdminGetIpBlocksParams) => client.paginatedGet('/api/v1/admin/ip_blocks', { params }, adminIpBlockSchema), /** * Get a single IP block * Show information about a single IP block. * @see {@link https://docs.joinmastodon.org/methods/admin/ip_blocks/#get-one} */ getIpBlock: async (ipBlockId: string) => { const response = await client.request(`/api/v1/admin/ip_blocks/${ipBlockId}`); return v.parse(adminIpBlockSchema, response.json); }, /** * Block an IP address range from signing up * Add an IP address range to the list of IP blocks. * @see {@link https://docs.joinmastodon.org/methods/admin/ip_blocks/#create} */ createIpBlock: async (params: AdminCreateIpBlockParams) => { const response = await client.request('/api/v1/admin/ip_blocks', { method: 'POST', body: params, }); return v.parse(adminIpBlockSchema, response.json); }, /** * Update a domain block * Change parameters for an existing IP block. * @see {@link https://docs.joinmastodon.org/methods/admin/ip_blocks/#update} */ updateIpBlock: async (ipBlockId: string, params: AdminCreateIpBlockParams) => { const response = await client.request(`/api/v1/admin/ip_blocks/${ipBlockId}`, { method: 'POST', body: params, }); return v.parse(adminIpBlockSchema, response.json); }, /** * Delete an IP block * Lift a block against an IP range. * @see {@link https://docs.joinmastodon.org/methods/admin/ip_blocks/#delete} */ deleteIpBlock: async (ipBlockId: string) => { const response = await client.request(`/api/v1/admin/ip_blocks/${ipBlockId}`, { method: 'DELETE', }); return response.json; }, }, /** Obtain quantitative metrics about the server. */ measures: { /** * Get measurable data * Obtain quantitative metrics about the server. * @see {@link https://docs.joinmastodon.org/methods/admin/measures/#get} */ getMeasures: async ( keys: AdminMeasureKey[], start_at: string, end_at: string, params?: AdminGetMeasuresParams, ) => { const response = await client.request('/api/v1/admin/measures', { method: 'POST', params: { ...params, keys, start_at, end_at }, }); return v.parse(filteredArray(adminMeasureSchema), response.json); }, }, /** Show retention data over time. */ retention: { /** * Calculate retention data * * Generate a retention data report for a given time period and bucket. * @see {@link https://docs.joinmastodon.org/methods/admin/retention/#create} */ getRetention: async (start_at: string, end_at: string, frequency: 'day' | 'month') => { const response = await client.request('/api/v1/admin/retention', { method: 'POST', params: { start_at, end_at, frequency }, }); return v.parse(filteredArray(adminCohortSchema), response.json); }, }, announcements: { /** * List announcements * * Requires features{@link Features.pleromaAdminAnnouncements}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#get-apiv1pleromaadminannouncements} */ getAnnouncements: async ( params?: AdminGetAnnouncementsParams, ): Promise> => { const response = await client.request('/api/v1/pleroma/admin/announcements', { params }); const items = v.parse(filteredArray(adminAnnouncementSchema), response.json); return { previous: null, next: items.length ? () => category.announcements.getAnnouncements({ ...params, offset: (params?.offset || 0) + items.length, }) : null, items, partial: false, }; }, /** * Display one announcement * * Requires features{@link Features.pleromaAdminAnnouncements}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#get-apiv1pleromaadminannouncementsid} */ getAnnouncement: async (announcementId: string) => { const response = await client.request( `/api/v1/pleroma/admin/announcements/${announcementId}`, ); return v.parse(adminAnnouncementSchema, response.json); }, /** * Create an announcement * * Requires features{@link Features.pleromaAdminAnnouncements}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#post-apiv1pleromaadminannouncements} */ createAnnouncement: async (params: AdminCreateAnnouncementParams) => { const response = await client.request('/api/v1/pleroma/admin/announcements', { method: 'POST', body: params, }); return v.parse(adminAnnouncementSchema, response.json); }, /** * Change an announcement * * Requires features{@link Features.pleromaAdminAnnouncements}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#patch-apiv1pleromaadminannouncementsid} */ updateAnnouncement: async (announcementId: string, params: AdminUpdateAnnouncementParams) => { const response = await client.request( `/api/v1/pleroma/admin/announcements/${announcementId}`, { method: 'PATCH', body: params }, ); return v.parse(adminAnnouncementSchema, response.json); }, /** * Delete an announcement * * Requires features{@link Features.pleromaAdminAnnouncements}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#delete-apiv1pleromaadminannouncementsid} */ deleteAnnouncement: async (announcementId: string) => { const response = await client.request( `/api/v1/pleroma/admin/announcements/${announcementId}`, { method: 'DELETE' }, ); return response.json; }, }, domains: { /** * List of domains * * Requires features{@link Features.domains}. */ getDomains: async () => { const response = await client.request('/api/v1/pleroma/admin/domains'); return v.parse(filteredArray(adminDomainSchema), response.json); }, /** * Create a domain * * Requires features{@link Features.domains}. */ createDomain: async (params: AdminCreateDomainParams) => { const response = await client.request('/api/v1/pleroma/admin/domains', { method: 'POST', body: params, }); return v.parse(adminDomainSchema, response.json); }, /** * Change domain publicity * * Requires features{@link Features.domains}. */ updateDomain: async (domainId: string, isPublic: boolean) => { const response = await client.request(`/api/v1/pleroma/admin/domains/${domainId}`, { method: 'PATCH', body: { public: isPublic }, }); return v.parse(adminDomainSchema, response.json); }, /** * Delete a domain * * Requires features{@link Features.domains}. */ deleteDomain: async (domainId: string) => { const response = await client.request( `/api/v1/pleroma/admin/domains/${domainId}`, { method: 'DELETE', }, ); return response.json; }, }, moderationLog: { /** * Get moderation log * * Requires features{@link Features.pleromaAdminModerationLog}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#get-apiv1pleromaadminmoderation_log} */ getModerationLog: async ({ limit, ...params }: AdminGetModerationLogParams = {}): Promise< PaginatedResponse > => { const response = await client.request('/api/v1/pleroma/admin/moderation_log', { params: { page_size: limit, ...params }, }); const items = v.parse(filteredArray(adminModerationLogEntrySchema), response.json.items); return { previous: params.page && params.page > 1 ? () => category.moderationLog.getModerationLog({ ...params, page: params.page! - 1 }) : null, next: response.json.total > (params.page || 1) * (limit || 50) ? () => category.moderationLog.getModerationLog({ ...params, page: (params.page || 1) + 1, }) : null, items, partial: response.status === 206, }; }, }, relays: { /** * List Relays * * Requires features{@link Features.pleromaAdminRelays}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#get-apiv1pleromaadminrelay} */ getRelays: async () => { const response = await client.request('/api/v1/pleroma/admin/relay'); return v.parse(filteredArray(adminRelaySchema), response.json); }, /** * Follow a Relay * * Requires features{@link Features.pleromaAdminRelays}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#post-apiv1pleromaadminrelay} */ followRelay: async (relayUrl: string) => { const response = await client.request('/api/v1/pleroma/admin/relay', { method: 'POST', body: { relay_url: relayUrl }, }); return v.parse(adminRelaySchema, response.json); }, /** * Unfollow a Relay * * Requires features{@link Features.pleromaAdminRelays}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#delete-apiv1pleromaadminrelay} */ unfollowRelay: async (relayUrl: string, force = false) => { const response = await client.request('/api/v1/pleroma/admin/relay', { method: 'DELETE', body: { relay_url: relayUrl, force }, }); return v.parse(adminRelaySchema, response.json); }, }, rules: { /** * List rules * * Requires features{@link Features.adminRules}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#get-apiv1pleromaadminrules} */ getRules: async () => { const response = await client.request( client.features.version.software === GOTOSOCIAL ? '/api/v1/admin/instance/rules' : '/api/v1/pleroma/admin/rules', ); return v.parse(filteredArray(adminRuleSchema), response.json); }, /** * Create a rule * * Requires features{@link Features.adminRules}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#post-apiv1pleromaadminrules} */ createRule: async (params: AdminCreateRuleParams) => { const response = await client.request( client.features.version.software === GOTOSOCIAL ? '/api/v1/admin/instance/rules' : '/api/v1/pleroma/admin/rules', { method: 'POST', body: params }, ); return v.parse(adminRuleSchema, response.json); }, /** * Update a rule * * Requires features{@link Features.adminRules}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#patch-apiv1pleromaadminrulesid} */ updateRule: async (ruleId: string, params: AdminUpdateRuleParams) => { const response = await client.request( `/api/v1/${client.features.version.software === GOTOSOCIAL ? 'admin/instance' : 'pleroma/admin'}/rules/${ruleId}`, { method: 'PATCH', body: params }, ); return v.parse(adminRuleSchema, response.json); }, /** * Delete a rule * * Requires features{@link Features.adminRules}. * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#delete-apiv1pleromaadminrulesid} */ deleteRule: async (ruleId: string) => { const response = await client.request( `/api/v1/${client.features.version.software === GOTOSOCIAL ? 'admin/instance' : 'pleroma/admin'}/rules/${ruleId}`, { method: 'DELETE' }, ); return response.json; }, }, config: { getPleromaConfig: async () => { const response = await client.request('/api/v1/pleroma/admin/config'); return v.parse(pleromaConfigSchema, response.json); }, updatePleromaConfig: async (params: PleromaConfig['configs']) => { const response = await client.request('/api/v1/pleroma/admin/config', { method: 'POST', body: { configs: params }, }); return v.parse(pleromaConfigSchema, response.json); }, }, customEmojis: { /** * View local and remote emojis available to/known by this instance. * * Requires features{@link Features.adminCustomEmojis}. * @see {@link https://docs.gotosocial.org/en/latest/api/swagger/} */ getCustomEmojis: (params: AdminGetCustomEmojisParams) => client.paginatedGet('/api/v1/admin/custom_emojis', { params }, adminCustomEmojiSchema), /** * Get the admin view of a single emoji. * * Requires features{@link Features.adminCustomEmojis}. * @see {@link https://docs.gotosocial.org/en/latest/api/swagger/} */ getCustomEmoji: async (emojiId: string) => { const response = await client.request(`/api/v1/admin/custom_emojis/${emojiId}`); return v.parse(adminCustomEmojiSchema, response.json); }, /** * Get the admin view of a single emoji. * * Requires features{@link Features.adminCustomEmojis}. * @see {@link https://docs.gotosocial.org/en/latest/api/swagger/} */ createCustomEmoji: async (params: AdminCreateCustomEmojiParams) => { const response = await client.request('/api/v1/admin/custom_emojis', { method: 'POST', body: params, contentType: '', }); return v.parse(adminCustomEmojiSchema, response.json); }, updateCustomEmoji: async (emojiId: string, params: AdminUpdateCustomEmojiParams) => { const response = await client.request(`/api/v1/admin/custom_emojis/${emojiId}`, { method: 'PATCH', body: params, contentType: '', }); return v.parse(adminCustomEmojiSchema, response.json); }, /** * Delete a **local** emoji with the given ID from the instance. * * Requires features{@link Features.adminCustomEmojis}. * @see {@link https://docs.gotosocial.org/en/latest/api/swagger/} */ deleteCustomEmoji: async (emojiId: string) => { const response = await client.request(`/api/v1/admin/custom_emojis/${emojiId}`, { method: 'DELETE', }); return v.parse(adminCustomEmojiSchema, response.json); }, }, }; return category; }; export { admin };