diff --git a/packages/pl-api/lib/client.ts b/packages/pl-api/lib/client.ts index 5231fd217..3e5989778 100644 --- a/packages/pl-api/lib/client.ts +++ b/packages/pl-api/lib/client.ts @@ -3,15 +3,20 @@ import z from 'zod'; import { accountSchema, adminAccountSchema, + adminAnnouncementSchema, adminCanonicalEmailBlockSchema, adminCohortSchema, adminDimensionSchema, adminDomainAllowSchema, adminDomainBlockSchema, + adminDomainSchema, adminEmailDomainBlockSchema, adminIpBlockSchema, adminMeasureSchema, + adminModerationLogEntrySchema, + adminRelaySchema, adminReportSchema, + adminRuleSchema, adminTagSchema, announcementSchema, applicationSchema, @@ -46,6 +51,7 @@ import { notificationRequestSchema, notificationSchema, oauthTokenSchema, + pleromaConfigSchema, pollSchema, relationshipSchema, reportSchema, @@ -71,11 +77,13 @@ import { buildFullPath } from './utils/url'; import type { Account, AdminAccount, + AdminAnnouncement, AdminCanonicalEmailBlock, AdminDomainAllow, AdminDomainBlock, AdminEmailDomainBlock, AdminIpBlock, + AdminModerationLogEntry, AdminReport, Chat, ChatMessage, @@ -83,6 +91,7 @@ import type { GroupRole, Instance, Notification, + PleromaConfig, ScheduledStatus, Status, StreamingEvent, @@ -90,10 +99,14 @@ import type { } from './entities'; import type { AdminAccountAction, + AdminCreateAnnouncementParams, AdminCreateDomainBlockParams, + AdminCreateDomainParams, AdminCreateIpBlockParams, + AdminCreateRuleParams, AdminDimensionKey, AdminGetAccountsParams, + AdminGetAnnouncementsParams, AdminGetCanonicalEmailBlocks, AdminGetDimensionsParams, AdminGetDomainAllowsParams, @@ -102,12 +115,15 @@ import type { AdminGetGroupsParams, AdminGetIpBlocksParams, AdminGetMeasuresParams, + AdminGetModerationLogParams, AdminGetReportsParams, AdminGetStatusesParams, AdminMeasureKey, AdminPerformAccountActionParams, + AdminUpdateAnnouncementParams, AdminUpdateDomainBlockParams, AdminUpdateReportParams, + AdminUpdateRuleParams, AdminUpdateStatusParams, BubbleTimelineParams, CreateAccountParams, @@ -1775,6 +1791,17 @@ class PlApiClient { return translationSchema.parse(response.json); }, + /** + * Translate multiple statuses into given language. + * + * Requires features{@link Features['lazyTranslations']}. + */ + translateStatuses: async (statusIds: Array, lang: string) => { + const response = await this.request('/api/v1/pl/statuses/translate', { method: 'POST', body: { ids: statusIds, lang } }); + + return filteredArray(translationSchema).parse(response.json); + }, + /** * See who boosted a status * View who boosted a given status. @@ -2708,7 +2735,7 @@ class PlApiClient { getFrontendConfigurations: async () => { const response = await this.request('/api/pleroma/frontend_configurations'); - return z.record(z.record(z.any())).catch({}).parse(response); + return z.record(z.record(z.any())).catch({}).parse(response.json); }, }; @@ -2965,7 +2992,7 @@ class PlApiClient { } else { const { account } = await this.admin.accounts.getAccount(accountId)!; - response = await this.request('/api/v1/pleroma/admin/users/activate', { body: { nicknames: [account!.username] } }); + response = await this.request('/api/v1/pleroma/admin/users/activate', { body: { nicknames: [account!.acct] } }); response.json = response.json?.users?.[0]; } @@ -2991,11 +3018,11 @@ class PlApiClient { await this.request('/api/v1/pleroma/admin/users/permission_group/moderator', { method: 'DELETE', - body: { nicknames: [account!.username] }, + body: { nicknames: [account!.acct] }, }); const response = await this.request('/api/v1/pleroma/admin/users/permission_group/admin', { method: 'POST', - body: { nicknames: [account!.username] }, + body: { nicknames: [account!.acct] }, }); return response.json as {}; @@ -3008,9 +3035,9 @@ class PlApiClient { const { account } = await this.admin.accounts.getAccount(accountId)!; await this.request('/api/v1/pleroma/admin/users/permission_group/admin', { - method: 'DELETE', body: { nicknames: [account!.username] } }); + method: 'DELETE', body: { nicknames: [account!.acct] } }); const response = await this.request('/api/v1/pleroma/admin/users/permission_group/moderator', { - method: 'POST', body: { nicknames: [account!.username] } }); + method: 'POST', body: { nicknames: [account!.acct] } }); return response.json as {}; }, @@ -3023,11 +3050,79 @@ class PlApiClient { await this.request('/api/v1/pleroma/admin/users/permission_group/moderator', { method: 'DELETE', - body: { nicknames: [account!.username] }, + body: { nicknames: [account!.acct] }, }); const response = await this.request('/api/v1/pleroma/admin/users/permission_group/admin', { method: 'DELETE', - body: { nicknames: [account!.username] }, + body: { nicknames: [account!.acct] }, + }); + + return response.json as {}; + }, + + /** + * 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 this.admin.accounts.getAccount(accountId)!; + + const response = await this.request('/api/v1/pleroma/admin/users/suggest', { + method: 'PATCH', + body: { nicknames: [account!.acct] }, + }); + + return response.json as {}; + }, + + /** + * 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 this.admin.accounts.getAccount(accountId)!; + + const response = await this.request('/api/v1/pleroma/admin/users/unsuggest', { + method: 'PATCH', + body: { nicknames: [account!.acct] }, + }); + + return response.json as {}; + }, + + /** + * 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 this.admin.accounts.getAccount(accountId)!; + + const response = await this.request('/api/v1/pleroma/admin/users/tag', { + method: 'PUT', + body: { nicknames: [account!.acct], tags }, + }); + + return response.json as {}; + }, + + /** + * 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 this.admin.accounts.getAccount(accountId)!; + + const response = await this.request('/api/v1/pleroma/admin/users/tag', { + method: 'DELETE', + body: { nicknames: [account!.acct], tags }, }); return response.json as {}; @@ -3517,6 +3612,7 @@ class PlApiClient { 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} */ @@ -3526,6 +3622,244 @@ class PlApiClient { return adminCohortSchema.parse(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 this.request('/api/v1/pleroma/admin/announcements', { params }); + + const items = filteredArray(adminAnnouncementSchema).parse(response.json); + + return { + previous: null, + next: items.length ? () => this.admin.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 this.request(`/api/v1/pleroma/admin/announcements/${announcementId}`); + + return adminAnnouncementSchema.parse(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 this.request('/api/v1/pleroma/admin/announcements', { method: 'POST', body: params }); + + return adminAnnouncementSchema.parse(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 this.request(`/api/v1/pleroma/admin/announcements/${announcementId}`, { method: 'PATCH', body: params }); + + return adminAnnouncementSchema.parse(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 this.request(`/api/v1/pleroma/admin/announcements/${announcementId}`, { method: 'DELETE' }); + + return response.json as {}; + }, + }, + + domains: { + /** + * List of domains + * + * Requires features{@link Features['domains']}. + */ + getDomains: async () => { + const response = await this.request('/api/v1/pleroma/admin/domains'); + + return filteredArray(adminDomainSchema).parse(response.json); + }, + + /** + * Create a domain + * + * Requires features{@link Features['domains']}. + */ + createDomain: async (params: AdminCreateDomainParams) => { + const response = await this.request('/api/v1/pleroma/admin/domains', { method: 'POST', body: params }); + + return adminDomainSchema.parse(response.json); + }, + + /** + * Change domain publicity + * + * Requires features{@link Features['domains']}. + */ + updateDomain: async (domainId: string, isPublic: boolean) => { + const response = await this.request(`/api/v1/pleroma/admin/domains/${domainId}`, { method: 'PATCH', body: { public: isPublic } }); + + return adminDomainSchema.parse(response.json); + }, + + /** + * Delete a domain + * + * Requires features{@link Features['domains']}. + */ + deleteDomain: async (domainId: string) => { + const response = await this.request(`/api/v1/pleroma/admin/domains/${domainId}`, { method: 'DELETE' }); + + return response.json as {}; + }, + }, + + 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> => { + const response = await this.request('/api/v1/pleroma/admin/moderation_log', { params: { page_size: limit, ...params } }); + + const items = filteredArray(adminModerationLogEntrySchema).parse(response.json.items); + + return { + previous: (params.page && params.page > 1) ? () => this.admin.moderationLog.getModerationLog({ ...params, page: params.page! - 1 }) : null, + next: response.json.total > (params.page || 1) * (limit || 50) ? () => this.admin.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 this.request('/api/v1/pleroma/admin/relay'); + + return filteredArray(adminRelaySchema).parse(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 this.request('/api/v1/pleroma/admin/relay', { method: 'POST', body: { relay_url: relayUrl } }); + + return adminRelaySchema.parse(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 this.request('/api/v1/pleroma/admin/relay', { method: 'DELETE', body: { relay_url: relayUrl, force } }); + + return adminRelaySchema.parse(response.json); + }, + }, + + rules: { + /** + * List rules + * + * Requires features{@link Features['pleromaAdminRules']}. + * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#get-apiv1pleromaadminrules} + */ + getRules: async () => { + const response = await this.request('/api/v1/pleroma/admin/rules'); + + return filteredArray(adminRuleSchema).parse(response.json); + }, + + /** + * Create a rule + * + * Requires features{@link Features['pleromaAdminRules']}. + * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#post-apiv1pleromaadminrules} + */ + createRule: async (params: AdminCreateRuleParams) => { + const response = await this.request('/api/v1/pleroma/admin/rules', { method: 'POST', body: params }); + + return adminRuleSchema.parse(response.json); + }, + + /** + * Update a rule + * + * Requires features{@link Features['pleromaAdminRules']}. + * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#patch-apiv1pleromaadminrulesid} + */ + updateRule: async (ruleId: string, params: AdminUpdateRuleParams) => { + const response = await this.request(`/api/v1/pleroma/admin/rules/${ruleId}`, { method: 'PATCH', body: params }); + + return adminRuleSchema.parse(response.json); + }, + + /** + * Delete a rule + * + * Requires features{@link Features['pleromaAdminRules']}. + * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#delete-apiv1pleromaadminrulesid} + */ + deleteRule: async (ruleId: string) => { + const response = await this.request(`/api/v1/pleroma/admin/rules/${ruleId}`, { method: 'DELETE' }); + + return response.json as {}; + }, + }, + + config: { + getPleromaConfig: async () => { + const response = await this.request('/api/v1/pleroma/admin/config'); + + return pleromaConfigSchema.parse(response.json); + }, + + updatePleromaConfig: async (params: PleromaConfig['configs']) => { + const response = await this.request('/api/v1/pleroma/admin/config', { method: 'POST', body: { configs: params } }); + + return pleromaConfigSchema.parse(response.json); + }, + }, }; public readonly oembed = { diff --git a/packages/pl-api/lib/entities/admin/pleroma-config.ts b/packages/pl-api/lib/entities/admin/pleroma-config.ts new file mode 100644 index 000000000..8bb49e5f0 --- /dev/null +++ b/packages/pl-api/lib/entities/admin/pleroma-config.ts @@ -0,0 +1,14 @@ +import { z } from 'zod'; + +const pleromaConfigSchema = z.object({ + configs: z.array(z.object({ + value: z.any(), + group: z.string(), + key: z.string(), + })), + need_reboot: z.boolean(), +}); + +type PleromaConfig = z.infer + +export { pleromaConfigSchema, type PleromaConfig }; diff --git a/packages/pl-api/lib/entities/index.ts b/packages/pl-api/lib/entities/index.ts index 7c993597e..e65ec4ce7 100644 --- a/packages/pl-api/lib/entities/index.ts +++ b/packages/pl-api/lib/entities/index.ts @@ -13,6 +13,7 @@ export * from './admin/ip'; export * from './admin/ip-block'; export * from './admin/measure'; export * from './admin/moderation-log-entry'; +export * from './admin/pleroma-config'; export * from './admin/relay'; export * from './admin/report'; export * from './admin/rule'; diff --git a/packages/pl-api/lib/entities/translation.ts b/packages/pl-api/lib/entities/translation.ts index 8e69b13f6..4bb64e793 100644 --- a/packages/pl-api/lib/entities/translation.ts +++ b/packages/pl-api/lib/entities/translation.ts @@ -30,6 +30,7 @@ const translationSchema = z.preprocess((translation: any) => { return translation; }, z.object({ + id: z.string().nullable().catch(null), content: z.string().catch(''), spoiler_text: z.string().catch(''), poll: translationPollSchema.optional().catch(undefined), diff --git a/packages/pl-api/lib/features.ts b/packages/pl-api/lib/features.ts index 3178dfb08..fbe4c95aa 100644 --- a/packages/pl-api/lib/features.ts +++ b/packages/pl-api/lib/features.ts @@ -188,29 +188,6 @@ const getFeatures = (instance?: Instance) => { v.software === GOTOSOCIAL, ]), - /** - * Ability to manage announcements by admins. - * @see GET /api/v1/pleroma/admin/announcements - * @see GET /api/v1/pleroma/admin/announcements/:id - * @see POST /api/v1/pleroma/admin/announcements - * @see PATCH /api/v1/pleroma/admin/announcements/:id - * @see DELETE /api/v1/pleroma/admin/announcements/:id - * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#get-apiv1pleromaadminannouncements} - */ - adminAnnouncements: v.software === PLEROMA, - - /** - * Ability to manage instance rules by admins. - * @see GET /api/v1/pleroma/admin/rules - * @see POST /api/v1/pleroma/admin/rules - * @see PATCH /api/v1/pleroma/admin/rules/:id - * @see DELETE /api/v1/pleroma/admin/rules/:id - */ - adminRules: any([ - v.software === PLEROMA && v.build === REBASED && gte(v.version, '2.5.0'), - v.software === PLEROMA && gte(v.version, '2.7.0'), - ]), - /** * Ability to address a status to a list of users. * @see POST /api/v1/statuses @@ -830,7 +807,34 @@ const getFeatures = (instance?: Instance) => { v.software === GOTOSOCIAL, ]), - pleromaAdminAccoumts: v.software === PLEROMA, + pleromaAdminAccounts: v.software === PLEROMA, + + /** + * Ability to manage announcements by admins. + * @see GET /api/v1/pleroma/admin/announcements + * @see GET /api/v1/pleroma/admin/announcements/:id + * @see POST /api/v1/pleroma/admin/announcements + * @see PATCH /api/v1/pleroma/admin/announcements/:id + * @see DELETE /api/v1/pleroma/admin/announcements/:id + * @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#get-apiv1pleromaadminannouncements} + */ + pleromaAdminAnnouncements: v.software === PLEROMA, + + pleromaAdminModerationLog: v.software === PLEROMA, + + pleromaAdminRelays: v.software === PLEROMA, + + /** + * Ability to manage instance rules by admins. + * @see GET /api/v1/pleroma/admin/rules + * @see POST /api/v1/pleroma/admin/rules + * @see PATCH /api/v1/pleroma/admin/rules/:id + * @see DELETE /api/v1/pleroma/admin/rules/:id + */ + pleromaAdminRules: any([ + v.software === PLEROMA && v.build === REBASED && gte(v.version, '2.5.0'), + v.software === PLEROMA && gte(v.version, '2.7.0'), + ]), pleromaAdminStatuses: v.software === PLEROMA, diff --git a/packages/pl-api/lib/params/admin.ts b/packages/pl-api/lib/params/admin.ts index 326eddd72..6e256e6f3 100644 --- a/packages/pl-api/lib/params/admin.ts +++ b/packages/pl-api/lib/params/admin.ts @@ -172,6 +172,52 @@ interface AdminGetMeasuresParams { }; } +interface AdminGetAnnouncementsParams { + offset?: number; + limit?: number; +} + +interface AdminCreateAnnouncementParams { + /** announcement content */ + content: string; + /** datetime, optional, default to null, the time when the announcement will become active (displayed to users); if it is null, the announcement will be active immediately */ + starts_at?: string; + /** datetime, optional, default to null, the time when the announcement will become inactive (no longer displayed to users); if it is null, the announcement will be active until an admin deletes it */ + ends_at?: string; + /** boolean, optional, default to false, tells the client whether to only display dates for `starts_at` and `ends_at` */ + all_day?: boolean; +} + +type AdminUpdateAnnouncementParams = Partial; + +interface AdminCreateDomainParams { + /** domain name */ + domain: string; + /** defaults to false, whether it is possible to register an account under the domain by everyone */ + public?: boolean; +} + +interface AdminGetModerationLogParams extends Pick { + /** page number */ + page?: number; + /** datetime (ISO 8601) filter logs by creation date, start from start_date. Accepts datetime in ISO 8601 format (YYYY-MM-DDThh:mm:ss), e.g. 2005-08-09T18:31:42 */ + start_date?: string; + /** datetime (ISO 8601) filter logs by creation date, end by from end_date. Accepts datetime in ISO 8601 format (YYYY-MM-DDThh:mm:ss), e.g. 2005-08-09T18:31:42 */ + end_date?: string; + /** filter logs by actor's id */ + user_id?: string; + /** search logs by the log message */ + search?: string; +} + +interface AdminCreateRuleParams { + text: string; + hint?: string; + priority?: number; +} + +type AdminUpdateRuleParams = Partial; + interface AdminGetGroupsParams { } @@ -196,5 +242,12 @@ export type { AdminUpdateIpBlockParams, AdminMeasureKey, AdminGetMeasuresParams, + AdminGetAnnouncementsParams, + AdminCreateAnnouncementParams, + AdminUpdateAnnouncementParams, + AdminCreateDomainParams, + AdminGetModerationLogParams, + AdminCreateRuleParams, + AdminUpdateRuleParams, AdminGetGroupsParams, }; diff --git a/packages/pl-api/package.json b/packages/pl-api/package.json index 377e774bd..120c3eeda 100644 --- a/packages/pl-api/package.json +++ b/packages/pl-api/package.json @@ -1,6 +1,6 @@ { "name": "pl-api", - "version": "0.0.22", + "version": "0.0.23", "type": "module", "homepage": "https://github.com/mkljczk/pl-fe/tree/fork/packages/pl-api", "repository": { diff --git a/packages/pl-fe/package.json b/packages/pl-fe/package.json index c29bdfc48..3b14792c5 100644 --- a/packages/pl-fe/package.json +++ b/packages/pl-fe/package.json @@ -133,7 +133,7 @@ "multiselect-react-dropdown": "^2.0.25", "object-to-formdata": "^4.5.1", "path-browserify": "^1.0.1", - "pl-api": "^0.0.22", + "pl-api": "^0.0.23", "postcss": "^8.4.29", "process": "^0.11.10", "punycode": "^2.1.1", diff --git a/packages/pl-fe/src/actions/admin.ts b/packages/pl-fe/src/actions/admin.ts index 48e8bd746..6173bba3e 100644 --- a/packages/pl-fe/src/actions/admin.ts +++ b/packages/pl-fe/src/actions/admin.ts @@ -1,12 +1,11 @@ import { fetchRelationships } from 'pl-fe/actions/accounts'; import { importFetchedAccount, importFetchedAccounts, importFetchedStatuses } from 'pl-fe/actions/importer'; -import { accountIdsToAccts } from 'pl-fe/selectors'; import { filterBadges, getTagDiff } from 'pl-fe/utils/badges'; import { getClient } from '../api'; -import type { Account, AdminGetAccountsParams, AdminGetReportsParams } from 'pl-api'; +import type { Account, AdminGetAccountsParams, AdminGetReportsParams, PleromaConfig } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; const ADMIN_CONFIG_FETCH_REQUEST = 'ADMIN_CONFIG_FETCH_REQUEST' as const; @@ -49,13 +48,13 @@ const ADMIN_STATUS_TOGGLE_SENSITIVITY_REQUEST = 'ADMIN_STATUS_TOGGLE_SENSITIVITY const ADMIN_STATUS_TOGGLE_SENSITIVITY_SUCCESS = 'ADMIN_STATUS_TOGGLE_SENSITIVITY_SUCCESS' as const; const ADMIN_STATUS_TOGGLE_SENSITIVITY_FAIL = 'ADMIN_STATUS_TOGGLE_SENSITIVITY_FAIL' as const; -const ADMIN_USERS_TAG_REQUEST = 'ADMIN_USERS_TAG_REQUEST' as const; -const ADMIN_USERS_TAG_SUCCESS = 'ADMIN_USERS_TAG_SUCCESS' as const; -const ADMIN_USERS_TAG_FAIL = 'ADMIN_USERS_TAG_FAIL' as const; +const ADMIN_USER_TAG_REQUEST = 'ADMIN_USERS_TAG_REQUEST' as const; +const ADMIN_USER_TAG_SUCCESS = 'ADMIN_USERS_TAG_SUCCESS' as const; +const ADMIN_USER_TAG_FAIL = 'ADMIN_USERS_TAG_FAIL' as const; -const ADMIN_USERS_UNTAG_REQUEST = 'ADMIN_USERS_UNTAG_REQUEST' as const; -const ADMIN_USERS_UNTAG_SUCCESS = 'ADMIN_USERS_UNTAG_SUCCESS' as const; -const ADMIN_USERS_UNTAG_FAIL = 'ADMIN_USERS_UNTAG_FAIL' as const; +const ADMIN_USER_UNTAG_REQUEST = 'ADMIN_USERS_UNTAG_REQUEST' as const; +const ADMIN_USER_UNTAG_SUCCESS = 'ADMIN_USERS_UNTAG_SUCCESS' as const; +const ADMIN_USER_UNTAG_FAIL = 'ADMIN_USERS_UNTAG_FAIL' as const; const ADMIN_USER_INDEX_EXPAND_FAIL = 'ADMIN_USER_INDEX_EXPAND_FAIL' as const; const ADMIN_USER_INDEX_EXPAND_REQUEST = 'ADMIN_USER_INDEX_EXPAND_REQUEST' as const; @@ -70,19 +69,19 @@ const ADMIN_USER_INDEX_QUERY_SET = 'ADMIN_USER_INDEX_QUERY_SET' as const; const fetchConfig = () => (dispatch: AppDispatch, getState: () => RootState) => { dispatch({ type: ADMIN_CONFIG_FETCH_REQUEST }); - return getClient(getState).request('/api/v1/pleroma/admin/config') - .then(({ json: data }) => { + return getClient(getState).admin.config.getPleromaConfig() + .then((data) => { dispatch({ type: ADMIN_CONFIG_FETCH_SUCCESS, configs: data.configs, needsReboot: data.need_reboot }); }).catch(error => { dispatch({ type: ADMIN_CONFIG_FETCH_FAIL, error }); }); }; -const updateConfig = (configs: Record[]) => +const updateConfig = (configs: PleromaConfig['configs']) => (dispatch: AppDispatch, getState: () => RootState) => { dispatch({ type: ADMIN_CONFIG_UPDATE_REQUEST, configs }); - return getClient(getState).request('/api/v1/pleroma/admin/config', { method: 'POST', body: { configs } }) - .then(({ json: data }) => { + return getClient(getState).admin.config.updatePleromaConfig(configs) + .then((data) => { dispatch({ type: ADMIN_CONFIG_UPDATE_SUCCESS, configs: data.configs, needsReboot: data.need_reboot }); }).catch(error => { dispatch({ type: ADMIN_CONFIG_UPDATE_FAIL, error, configs }); @@ -208,34 +207,24 @@ const toggleStatusSensitivity = (statusId: string, sensitive: boolean) => }); }; -const tagUsers = (accountIds: string[], tags: string[]) => +const tagUser = (accountId: string, tags: string[]) => (dispatch: AppDispatch, getState: () => RootState) => { - const nicknames = accountIdsToAccts(getState(), accountIds); - dispatch({ type: ADMIN_USERS_TAG_REQUEST, accountIds, tags }); - return getClient(getState).request('/api/v1/pleroma/admin/users/tag', { - method: 'PUT', - body: { nicknames, tags }, - }).then(() => { - dispatch({ type: ADMIN_USERS_TAG_SUCCESS, accountIds, tags }); + dispatch({ type: ADMIN_USER_TAG_REQUEST, accountId, tags }); + return getClient(getState).admin.accounts.tagUser(accountId, tags).then(() => { + dispatch({ type: ADMIN_USER_TAG_SUCCESS, accountId, tags }); }).catch(error => { - dispatch({ type: ADMIN_USERS_TAG_FAIL, error, accountIds, tags }); + dispatch({ type: ADMIN_USER_TAG_FAIL, error, accountId, tags }); }); }; -const untagUsers = (accountIds: string[], tags: string[]) => +const untagUser = (accountId: string, tags: string[]) => (dispatch: AppDispatch, getState: () => RootState) => { - const nicknames = accountIdsToAccts(getState(), accountIds); - - dispatch({ type: ADMIN_USERS_UNTAG_REQUEST, accountIds, tags }); - return getClient(getState).request('/api/v1/pleroma/admin/users/tag', { - method: 'DELETE', - body: { nicknames, tags }, - }) - .then(() => { - dispatch({ type: ADMIN_USERS_UNTAG_SUCCESS, accountIds, tags }); - }).catch(error => { - dispatch({ type: ADMIN_USERS_UNTAG_FAIL, error, accountIds, tags }); - }); + dispatch({ type: ADMIN_USER_UNTAG_REQUEST, accountId, tags }); + return getClient(getState).admin.accounts.untagUser(accountId, tags).then(() => { + dispatch({ type: ADMIN_USER_UNTAG_SUCCESS, accountId, tags }); + }).catch(error => { + dispatch({ type: ADMIN_USER_UNTAG_FAIL, error, accountId, tags }); + }); }; /** Synchronizes user tags to the backend. */ @@ -243,8 +232,8 @@ const setTags = (accountId: string, oldTags: string[], newTags: string[]) => async(dispatch: AppDispatch) => { const diff = getTagDiff(oldTags, newTags); - if (diff.added.length) await dispatch(tagUsers([accountId], diff.added)); - if (diff.removed.length) await dispatch(untagUsers([accountId], diff.removed)); + if (diff.added.length) await dispatch(tagUser(accountId, diff.added)); + if (diff.removed.length) await dispatch(untagUser(accountId, diff.removed)); }; /** Synchronizes badges to the backend. */ @@ -322,18 +311,6 @@ const expandUserIndex = () => }); }; -const getSubscribersCsv = () => - (dispatch: any, getState: () => RootState) => - getClient(getState).request('/api/v1/pleroma/admin/email_list/subscribers.csv', { contentType: '' }); - -const getUnsubscribersCsv = () => - (dispatch: any, getState: () => RootState) => - getClient(getState).request('/api/v1/pleroma/admin/email_list/unsubscribers.csv', { contentType: '' }); - -const getCombinedCsv = () => - (dispatch: any, getState: () => RootState) => - getClient(getState).request('/api/v1/pleroma/admin/email_list/combined.csv', { contentType: '' }); - export { ADMIN_CONFIG_FETCH_REQUEST, ADMIN_CONFIG_FETCH_SUCCESS, @@ -365,12 +342,12 @@ export { ADMIN_STATUS_TOGGLE_SENSITIVITY_REQUEST, ADMIN_STATUS_TOGGLE_SENSITIVITY_SUCCESS, ADMIN_STATUS_TOGGLE_SENSITIVITY_FAIL, - ADMIN_USERS_TAG_REQUEST, - ADMIN_USERS_TAG_SUCCESS, - ADMIN_USERS_TAG_FAIL, - ADMIN_USERS_UNTAG_REQUEST, - ADMIN_USERS_UNTAG_SUCCESS, - ADMIN_USERS_UNTAG_FAIL, + ADMIN_USER_TAG_REQUEST, + ADMIN_USER_TAG_SUCCESS, + ADMIN_USER_TAG_FAIL, + ADMIN_USER_UNTAG_REQUEST, + ADMIN_USER_UNTAG_SUCCESS, + ADMIN_USER_UNTAG_FAIL, ADMIN_USER_INDEX_EXPAND_FAIL, ADMIN_USER_INDEX_EXPAND_REQUEST, ADMIN_USER_INDEX_EXPAND_SUCCESS, @@ -389,8 +366,8 @@ export { approveUser, deleteStatus, toggleStatusSensitivity, - tagUsers, - untagUsers, + tagUser, + untagUser, setTags, setBadges, promoteToAdmin, @@ -400,7 +377,4 @@ export { setUserIndexQuery, fetchUserIndex, expandUserIndex, - getSubscribersCsv, - getUnsubscribersCsv, - getCombinedCsv, }; diff --git a/packages/pl-fe/src/actions/mrf.ts b/packages/pl-fe/src/actions/mrf.ts index daad6bf10..ac7b990d9 100644 --- a/packages/pl-fe/src/actions/mrf.ts +++ b/packages/pl-fe/src/actions/mrf.ts @@ -29,7 +29,7 @@ const updateMrf = (host: string, restrictions: Record) => const simplePolicy = ConfigDB.toSimplePolicy(configs); const merged = simplePolicyMerge(simplePolicy, host, restrictions); const config = ConfigDB.fromSimplePolicy(merged); - return dispatch(updateConfig(config.toJS() as Array>)); + return dispatch(updateConfig(config)); }); export { updateMrf }; diff --git a/packages/pl-fe/src/actions/statuses.ts b/packages/pl-fe/src/actions/statuses.ts index 0e8f03ab9..fa258531d 100644 --- a/packages/pl-fe/src/actions/statuses.ts +++ b/packages/pl-fe/src/actions/statuses.ts @@ -12,7 +12,6 @@ import { deleteFromTimelines } from './timelines'; import type { CreateStatusParams, Status as BaseStatus } from 'pl-api'; import type { Status } from 'pl-fe/normalizers'; import type { AppDispatch, RootState } from 'pl-fe/store'; -import type { APIEntity } from 'pl-fe/types/entities'; import type { IntlShape } from 'react-intl'; const STATUS_CREATE_REQUEST = 'STATUS_CREATE_REQUEST' as const; @@ -285,7 +284,7 @@ const toggleStatusSpoilerExpanded = (status: Pick) => let TRANSLATIONS_QUEUE: Set = new Set(); let TRANSLATIONS_TIMEOUT: NodeJS.Timeout | null = null; -const translateStatus = (statusId: string, targetLanguage?: string, lazy?: boolean) => +const translateStatus = (statusId: string, targetLanguage: string, lazy?: boolean) => (dispatch: AppDispatch, getState: () => RootState) => { const client = getClient(getState); const features = client.features; @@ -297,10 +296,8 @@ const translateStatus = (statusId: string, targetLanguage?: string, lazy?: boole TRANSLATIONS_QUEUE = new Set(); if (TRANSLATIONS_TIMEOUT) clearTimeout(TRANSLATIONS_TIMEOUT); - return client.request('/api/v1/pl/statuses/translate', { - method: 'POST', body: { ids: copy, lang: targetLanguage }, - }).then((response) => { - response.json.forEach((translation: APIEntity) => { + return client.statuses.translateStatuses(copy, targetLanguage).then((response) => { + response.forEach((translation) => { dispatch({ type: STATUS_TRANSLATE_SUCCESS, statusId: translation.id, @@ -308,7 +305,7 @@ const translateStatus = (statusId: string, targetLanguage?: string, lazy?: boole }); copy - .filter((statusId) => !response.json.some(({ id }: APIEntity) => id === statusId)) + .filter((statusId) => !response.some(({ id }) => id === statusId)) .forEach((statusId) => dispatch({ type: STATUS_TRANSLATE_FAIL, statusId, diff --git a/packages/pl-fe/src/api/hooks/admin/useAnnouncements.ts b/packages/pl-fe/src/api/hooks/admin/useAnnouncements.ts index 8cd36336b..43eaf9124 100644 --- a/packages/pl-fe/src/api/hooks/admin/useAnnouncements.ts +++ b/packages/pl-fe/src/api/hooks/admin/useAnnouncements.ts @@ -1,31 +1,25 @@ import { useMutation, useQuery } from '@tanstack/react-query'; +import { + adminAnnouncementSchema, + type AdminAnnouncement as BaseAdminAnnouncement, + type AdminCreateAnnouncementParams, + type AdminUpdateAnnouncementParams, +} from 'pl-api'; import { useClient } from 'pl-fe/hooks'; +import { normalizeAnnouncement, AdminAnnouncement } from 'pl-fe/normalizers'; import { queryClient } from 'pl-fe/queries/client'; -import { adminAnnouncementSchema, type AdminAnnouncement } from 'pl-fe/schemas'; import { useAnnouncements as useUserAnnouncements } from '../announcements'; -interface CreateAnnouncementParams { - content: string; - starts_at?: string | null; - ends_at?: string | null; - all_day?: boolean; -} - -interface UpdateAnnouncementParams extends CreateAnnouncementParams { - id: string; -} - const useAnnouncements = () => { const client = useClient(); const userAnnouncements = useUserAnnouncements(); const getAnnouncements = async () => { - const { json: data } = await client.request('/api/v1/pleroma/admin/announcements'); + const data = await client.admin.announcements.getAnnouncements(); - const normalizedData = data.map((announcement) => adminAnnouncementSchema.parse(announcement)); - return normalizedData; + return data.items.map(normalizeAnnouncement); }; const result = useQuery>({ @@ -38,11 +32,9 @@ const useAnnouncements = () => { mutate: createAnnouncement, isPending: isCreating, } = useMutation({ - mutationFn: (params: CreateAnnouncementParams) => client.request('/api/v1/pleroma/admin/announcements', { - method: 'POST', body: params, - }), + mutationFn: (params: AdminCreateAnnouncementParams) => client.admin.announcements.createAnnouncement(params), retry: false, - onSuccess: ({ json: data }) => + onSuccess: (data) => queryClient.setQueryData(['admin', 'announcements'], (prevResult: ReadonlyArray) => [...prevResult, adminAnnouncementSchema.parse(data)], ), @@ -53,11 +45,10 @@ const useAnnouncements = () => { mutate: updateAnnouncement, isPending: isUpdating, } = useMutation({ - mutationFn: ({ id, ...params }: UpdateAnnouncementParams) => client.request(`/api/v1/pleroma/admin/announcements/${id}`, { - method: 'PATCH', body: params, - }), + mutationFn: ({ id, ...params }: AdminUpdateAnnouncementParams & { id: string }) => + client.admin.announcements.updateAnnouncement(id, params), retry: false, - onSuccess: ({ json: data }) => + onSuccess: (data) => queryClient.setQueryData(['admin', 'announcements'], (prevResult: ReadonlyArray) => prevResult.map((announcement) => announcement.id === data.id ? adminAnnouncementSchema.parse(data) : announcement), ), @@ -68,7 +59,7 @@ const useAnnouncements = () => { mutate: deleteAnnouncement, isPending: isDeleting, } = useMutation({ - mutationFn: (id: string) => client.request(`/api/v1/pleroma/admin/announcements/${id}`, { method: 'DELETE' }), + mutationFn: (id: string) => client.admin.announcements.deleteAnnouncement(id), retry: false, onSuccess: (_, id) => queryClient.setQueryData(['admin', 'announcements'], (prevResult: ReadonlyArray) => diff --git a/packages/pl-fe/src/api/hooks/admin/useDomains.ts b/packages/pl-fe/src/api/hooks/admin/useDomains.ts index f1e24377c..1bacd06f4 100644 --- a/packages/pl-fe/src/api/hooks/admin/useDomains.ts +++ b/packages/pl-fe/src/api/hooks/admin/useDomains.ts @@ -2,7 +2,8 @@ import { useMutation, useQuery } from '@tanstack/react-query'; import { useClient } from 'pl-fe/hooks'; import { queryClient } from 'pl-fe/queries/client'; -import { domainSchema, type Domain } from 'pl-fe/schemas'; + +import type { AdminDomain } from 'pl-api'; interface CreateDomainParams { domain: string; @@ -17,14 +18,9 @@ interface UpdateDomainParams { const useDomains = () => { const client = useClient(); - const getDomains = async () => { - const { json: data } = await client.request('/api/v1/pleroma/admin/domains'); + const getDomains = () => client.admin.domains.getDomains(); - const normalizedData = data.map((domain) => domainSchema.parse(domain)); - return normalizedData; - }; - - const result = useQuery>({ + const result = useQuery>({ queryKey: ['admin', 'domains'], queryFn: getDomains, placeholderData: [], @@ -34,13 +30,11 @@ const useDomains = () => { mutate: createDomain, isPending: isCreating, } = useMutation({ - mutationFn: (params: CreateDomainParams) => client.request('/api/v1/pleroma/admin/domains', { - method: 'POST', body: params, - }), + mutationFn: (params: CreateDomainParams) => client.admin.domains.createDomain(params), retry: false, - onSuccess: ({ data }) => - queryClient.setQueryData(['admin', 'domains'], (prevResult: ReadonlyArray) => - [...prevResult, domainSchema.parse(data)], + onSuccess: (data) => + queryClient.setQueryData(['admin', 'domains'], (prevResult: ReadonlyArray) => + [...prevResult, data], ), }); @@ -48,13 +42,11 @@ const useDomains = () => { mutate: updateDomain, isPending: isUpdating, } = useMutation({ - mutationFn: ({ id, ...params }: UpdateDomainParams) => client.request(`/api/v1/pleroma/admin/domains/${id}`, { - method: 'PATCH', body: params, - }), + mutationFn: ({ id, ...params }: UpdateDomainParams) => client.admin.domains.updateDomain(id, params.public), retry: false, - onSuccess: ({ json: data }) => - queryClient.setQueryData(['admin', 'domains'], (prevResult: ReadonlyArray) => - prevResult.map((domain) => domain.id === data.id ? domainSchema.parse(data) : domain), + onSuccess: (data) => + queryClient.setQueryData(['admin', 'domains'], (prevResult: ReadonlyArray) => + prevResult.map((domain) => domain.id === data.id ? data : domain), ), }); @@ -62,10 +54,10 @@ const useDomains = () => { mutate: deleteDomain, isPending: isDeleting, } = useMutation({ - mutationFn: (id: string) => client.request(`/api/v1/pleroma/admin/domains/${id}`, { method: 'DELETE' }), + mutationFn: (id: string) => client.admin.domains.deleteDomain(id), retry: false, onSuccess: (_, id) => - queryClient.setQueryData(['admin', 'domains'], (prevResult: ReadonlyArray) => + queryClient.setQueryData(['admin', 'domains'], (prevResult: ReadonlyArray) => prevResult.filter(({ id: domainId }) => domainId !== id), ), }); diff --git a/packages/pl-fe/src/api/hooks/admin/useModerationLog.ts b/packages/pl-fe/src/api/hooks/admin/useModerationLog.ts index e43696c26..9b395216e 100644 --- a/packages/pl-fe/src/api/hooks/admin/useModerationLog.ts +++ b/packages/pl-fe/src/api/hooks/admin/useModerationLog.ts @@ -1,37 +1,25 @@ import { useInfiniteQuery } from '@tanstack/react-query'; +import { PaginatedResponse } from 'pl-api'; import { useClient } from 'pl-fe/hooks'; -import { moderationLogEntrySchema, type ModerationLogEntry } from 'pl-fe/schemas'; +import { flattenPages } from 'pl-fe/utils/queries'; -interface ModerationLogResult { - items: ModerationLogEntry[]; - total: number; -} - -const flattenPages = (pages?: ModerationLogResult[]): ModerationLogEntry[] => (pages || []).map(({ items }) => items).flat(); +import type { AdminModerationLogEntry } from 'pl-api'; const useModerationLog = () => { const client = useClient(); - const getModerationLog = async (page: number): Promise => { - const { json: data } = await client.request('/api/v1/pleroma/admin/moderation_log', { params: { page } }); - - const normalizedData = data.items.map((domain) => moderationLogEntrySchema.parse(domain)); - - return { - items: normalizedData, - total: data.total, - }; - }; + const getModerationLog = (pageParam?: Pick, 'next'>): Promise> => + (pageParam?.next || client.admin.moderationLog.getModerationLog)(); const queryInfo = useInfiniteQuery({ queryKey: ['admin', 'moderation_log'], queryFn: ({ pageParam }) => getModerationLog(pageParam), - initialPageParam: 1, - getNextPageParam: (page, allPages) => flattenPages(allPages)!.length >= page.total ? undefined : allPages.length + 1, + initialPageParam: { next: null as (() => Promise>) | null }, + getNextPageParam: (config) => config.next ? config : undefined, }); - const data = flattenPages(queryInfo.data?.pages); + const data = flattenPages(queryInfo.data) || []; return { ...queryInfo, diff --git a/packages/pl-fe/src/api/hooks/admin/useRelays.ts b/packages/pl-fe/src/api/hooks/admin/useRelays.ts index 25967da17..08d57ac33 100644 --- a/packages/pl-fe/src/api/hooks/admin/useRelays.ts +++ b/packages/pl-fe/src/api/hooks/admin/useRelays.ts @@ -2,19 +2,15 @@ import { useMutation, useQuery } from '@tanstack/react-query'; import { useClient } from 'pl-fe/hooks'; import { queryClient } from 'pl-fe/queries/client'; -import { relaySchema, type Relay } from 'pl-fe/schemas'; + +import type { AdminRelay } from 'pl-api'; const useRelays = () => { const client = useClient(); - const getRelays = async () => { - const { json: data } = await client.request<{ relays: Relay[] }>('/api/v1/pleroma/admin/relay'); + const getRelays = () => client.admin.relays.getRelays(); - const normalizedData = data.relays?.map((relay) => relaySchema.parse(relay)); - return normalizedData; - }; - - const result = useQuery>({ + const result = useQuery>({ queryKey: ['admin', 'relays'], queryFn: getRelays, placeholderData: [], @@ -24,14 +20,11 @@ const useRelays = () => { mutate: followRelay, isPending: isPendingFollow, } = useMutation({ - mutationFn: (relayUrl: string) => client.request('/api/v1/pleroma/admin/relays', { - method: 'POST', - body: JSON.stringify({ relay_url: relayUrl }), - }), + mutationFn: (relayUrl: string) => client.admin.relays.followRelay(relayUrl), retry: false, - onSuccess: ({ json: data }) => - queryClient.setQueryData(['admin', 'relays'], (prevResult: ReadonlyArray) => - [...prevResult, relaySchema.parse(data)], + onSuccess: (data) => + queryClient.setQueryData(['admin', 'relays'], (prevResult: ReadonlyArray) => + [...prevResult, data], ), }); @@ -39,13 +32,10 @@ const useRelays = () => { mutate: unfollowRelay, isPending: isPendingUnfollow, } = useMutation({ - mutationFn: (relayUrl: string) => client.request('/api/v1/pleroma/admin/relays', { - method: 'DELETE', - body: JSON.stringify({ relay_url: relayUrl }), - }), + mutationFn: (relayUrl: string) => client.admin.relays.unfollowRelay(relayUrl), retry: false, onSuccess: (_, relayUrl) => - queryClient.setQueryData(['admin', 'relays'], (prevResult: ReadonlyArray) => + queryClient.setQueryData(['admin', 'relays'], (prevResult: ReadonlyArray) => prevResult.filter(({ actor }) => actor !== relayUrl), ), }); diff --git a/packages/pl-fe/src/api/hooks/admin/useRules.ts b/packages/pl-fe/src/api/hooks/admin/useRules.ts index 72829046a..f7b2202df 100644 --- a/packages/pl-fe/src/api/hooks/admin/useRules.ts +++ b/packages/pl-fe/src/api/hooks/admin/useRules.ts @@ -2,7 +2,8 @@ import { useMutation, useQuery } from '@tanstack/react-query'; import { useClient } from 'pl-fe/hooks'; import { queryClient } from 'pl-fe/queries/client'; -import { adminRuleSchema, type AdminRule } from 'pl-fe/schemas'; + +import type { AdminRule } from 'pl-api'; interface CreateRuleParams { priority?: number; @@ -20,12 +21,7 @@ interface UpdateRuleParams { const useRules = () => { const client = useClient(); - const getRules = async () => { - const { json: data } = await client.request('/api/v1/pleroma/admin/rules'); - - const normalizedData = data.map((rule) => adminRuleSchema.parse(rule)); - return normalizedData; - }; + const getRules = () => client.admin.rules.getRules(); const result = useQuery>({ queryKey: ['admin', 'rules'], @@ -37,13 +33,11 @@ const useRules = () => { mutate: createRule, isPending: isCreating, } = useMutation({ - mutationFn: (params: CreateRuleParams) => client.request('/api/v1/pleroma/admin/rules', { - method: 'POST', body: params, - }), + mutationFn: (params: CreateRuleParams) => client.admin.rules.createRule(params), retry: false, - onSuccess: ({ json: data }) => + onSuccess: (data) => queryClient.setQueryData(['admin', 'rules'], (prevResult: ReadonlyArray) => - [...prevResult, adminRuleSchema.parse(data)], + [...prevResult, data], ), }); @@ -51,13 +45,11 @@ const useRules = () => { mutate: updateRule, isPending: isUpdating, } = useMutation({ - mutationFn: ({ id, ...params }: UpdateRuleParams) => client.request(`/api/v1/pleroma/admin/rules/${id}`, { - method: 'PATCH', body: params, - }), + mutationFn: ({ id, ...params }: UpdateRuleParams) => client.admin.rules.updateRule(id, params), retry: false, - onSuccess: ({ json: data }) => + onSuccess: (data) => queryClient.setQueryData(['admin', 'rules'], (prevResult: ReadonlyArray) => - prevResult.map((rule) => rule.id === data.id ? adminRuleSchema.parse(data) : rule), + prevResult.map((rule) => rule.id === data.id ? data : rule), ), }); @@ -65,7 +57,7 @@ const useRules = () => { mutate: deleteRule, isPending: isDeleting, } = useMutation({ - mutationFn: (id: string) => client.request(`/api/v1/pleroma/admin/rules/${id}`, { method: 'DELETE' }), + mutationFn: (id: string) => client.admin.rules.deleteRule(id), retry: false, onSuccess: (_, id) => queryClient.setQueryData(['admin', 'rules'], (prevResult: ReadonlyArray) => diff --git a/packages/pl-fe/src/api/hooks/admin/useSuggest.ts b/packages/pl-fe/src/api/hooks/admin/useSuggest.ts index 465626478..fd9ab98bb 100644 --- a/packages/pl-fe/src/api/hooks/admin/useSuggest.ts +++ b/packages/pl-fe/src/api/hooks/admin/useSuggest.ts @@ -1,53 +1,45 @@ import { useTransaction } from 'pl-fe/entity-store/hooks'; import { EntityCallbacks } from 'pl-fe/entity-store/hooks/types'; -import { useClient, useGetState } from 'pl-fe/hooks'; -import { accountIdsToAccts } from 'pl-fe/selectors'; +import { useClient } from 'pl-fe/hooks'; import type { Account } from 'pl-fe/normalizers'; const useSuggest = () => { const client = useClient(); - const getState = useGetState(); const { transaction } = useTransaction(); - const suggestEffect = (accountIds: string[], suggested: boolean) => { + const suggestEffect = (accountId: string, suggested: boolean) => { const updater = (account: Account): Account => { account.is_suggested = suggested; return account; }; transaction({ - Accounts: accountIds.reduce Account>>( - (result, id) => ({ ...result, [id]: updater }), - {}), + Accounts: { + [accountId]: updater, + }, }); }; - const suggest = async (accountIds: string[], callbacks?: EntityCallbacks) => { - const accts = accountIdsToAccts(getState(), accountIds); - suggestEffect(accountIds, true); + const suggest = async (accountId: string, callbacks?: EntityCallbacks) => { + suggestEffect(accountId, true); try { - await client.request('/api/v1/pleroma/admin/users/suggest', { - method: 'PATCH', body: { nicknames: accts }, - }); + await client.admin.accounts.suggestUser(accountId); callbacks?.onSuccess?.(); } catch (e) { callbacks?.onError?.(e); - suggestEffect(accountIds, false); + suggestEffect(accountId, false); } }; - const unsuggest = async (accountIds: string[], callbacks?: EntityCallbacks) => { - const accts = accountIdsToAccts(getState(), accountIds); - suggestEffect(accountIds, false); + const unsuggest = async (accountId: string, callbacks?: EntityCallbacks) => { + suggestEffect(accountId, false); try { - await client.request('/api/v1/pleroma/admin/users/unsuggest', { - method: 'PATCH', body: { nicknames: accts }, - }); + await client.admin.accounts.unsuggestUser(accountId); callbacks?.onSuccess?.(); } catch (e) { callbacks?.onError?.(e); - suggestEffect(accountIds, true); + suggestEffect(accountId, true); } }; diff --git a/packages/pl-fe/src/api/hooks/admin/useVerify.ts b/packages/pl-fe/src/api/hooks/admin/useVerify.ts index 22cd3ed02..aab39f662 100644 --- a/packages/pl-fe/src/api/hooks/admin/useVerify.ts +++ b/packages/pl-fe/src/api/hooks/admin/useVerify.ts @@ -1,16 +1,14 @@ import { useTransaction } from 'pl-fe/entity-store/hooks'; import { EntityCallbacks } from 'pl-fe/entity-store/hooks/types'; -import { useClient, useGetState } from 'pl-fe/hooks'; -import { accountIdsToAccts } from 'pl-fe/selectors'; +import { useClient } from 'pl-fe/hooks'; import type { Account } from 'pl-fe/normalizers'; const useVerify = () => { const client = useClient(); - const getState = useGetState(); const { transaction } = useTransaction(); - const verifyEffect = (accountIds: string[], verified: boolean) => { + const verifyEffect = (accountId: string, verified: boolean) => { const updater = (account: Account): Account => { if (account.__meta.pleroma) { const tags = account.__meta.pleroma.tags.filter((tag: string) => tag !== 'verified'); @@ -24,39 +22,29 @@ const useVerify = () => { }; transaction({ - Accounts: accountIds.reduce Account>>( - (result, id) => ({ ...result, [id]: updater }), - {}), + Accounts: ({ [accountId]: updater }), }); }; - const verify = async (accountIds: string[], callbacks?: EntityCallbacks) => { - const accts = accountIdsToAccts(getState(), accountIds); - verifyEffect(accountIds, true); + const verify = async (accountId: string, callbacks?: EntityCallbacks) => { + verifyEffect(accountId, true); try { - await client.request('/api/v1/pleroma/admin/users/tag', { - method: 'PUT', - body: { nicknames: accts, tags: ['verified'] }, - }); + await client.admin.accounts.tagUser(accountId, ['verified']); callbacks?.onSuccess?.(); } catch (e) { callbacks?.onError?.(e); - verifyEffect(accountIds, false); + verifyEffect(accountId, false); } }; - const unverify = async (accountIds: string[], callbacks?: EntityCallbacks) => { - const accts = accountIdsToAccts(getState(), accountIds); - verifyEffect(accountIds, false); + const unverify = async (accountId: string, callbacks?: EntityCallbacks) => { + verifyEffect(accountId, false); try { - await client.request('/api/v1/pleroma/admin/users/tag', { - method: 'DELETE', - body: { nicknames: accts, tags: ['verified'] }, - }); + await client.admin.accounts.untagUser(accountId, ['verified']); callbacks?.onSuccess?.(); } catch (e) { callbacks?.onError?.(e); - verifyEffect(accountIds, true); + verifyEffect(accountId, true); } }; diff --git a/packages/pl-fe/src/api/hooks/groups/useGroups.test.ts b/packages/pl-fe/src/api/hooks/groups/useGroups.test.ts index 0f0c8a7ec..e0200b92d 100644 --- a/packages/pl-fe/src/api/hooks/groups/useGroups.test.ts +++ b/packages/pl-fe/src/api/hooks/groups/useGroups.test.ts @@ -1,7 +1,8 @@ +import { instanceSchema } from 'pl-api'; + import { __stub } from 'pl-fe/api'; import { buildGroup } from 'pl-fe/jest/factory'; import { renderHook, waitFor } from 'pl-fe/jest/test-helpers'; -import { instanceSchema } from 'pl-fe/schemas'; import { useGroups } from './useGroups'; diff --git a/packages/pl-fe/src/components/polls/poll-footer.test.tsx b/packages/pl-fe/src/components/polls/poll-footer.test.tsx index 808f09c69..12821e200 100644 --- a/packages/pl-fe/src/components/polls/poll-footer.test.tsx +++ b/packages/pl-fe/src/components/polls/poll-footer.test.tsx @@ -1,11 +1,11 @@ import userEvent from '@testing-library/user-event'; +import { type Poll } from 'pl-api'; import React from 'react'; import { IntlProvider } from 'react-intl'; import { Provider } from 'react-redux'; import { __stub } from 'pl-fe/api'; import { mockStore, render, screen, rootState } from 'pl-fe/jest/test-helpers'; -import { type Poll } from 'pl-fe/schemas'; import PollFooter from './poll-footer'; diff --git a/packages/pl-fe/src/components/sidebar-menu.tsx b/packages/pl-fe/src/components/sidebar-menu.tsx index 0d70c5322..9f19a6381 100644 --- a/packages/pl-fe/src/components/sidebar-menu.tsx +++ b/packages/pl-fe/src/components/sidebar-menu.tsx @@ -19,7 +19,6 @@ import { isStandalone } from 'pl-fe/utils/state'; import type { List as ImmutableList } from 'immutable'; import type { Account as AccountEntity } from 'pl-fe/normalizers'; - const messages = defineMessages({ profile: { id: 'account.profile', defaultMessage: 'Profile' }, preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, diff --git a/packages/pl-fe/src/entity-store/entities.ts b/packages/pl-fe/src/entity-store/entities.ts index a22f23679..6706540e1 100644 --- a/packages/pl-fe/src/entity-store/entities.ts +++ b/packages/pl-fe/src/entity-store/entities.ts @@ -1,6 +1,5 @@ -import type { BookmarkFolder, GroupMember, GroupRelationship, Relationship, TrendsLink } from 'pl-api'; +import type { AdminDomain, AdminRelay, AdminRule, BookmarkFolder, GroupMember, GroupRelationship, Relationship, TrendsLink } from 'pl-api'; import type { Account, Group, Status } from 'pl-fe/normalizers'; -import type * as Schemas from 'pl-fe/schemas'; enum Entities { ACCOUNTS = 'Accounts', @@ -20,13 +19,13 @@ enum Entities { interface EntityTypes { [Entities.ACCOUNTS]: Account; [Entities.BOOKMARK_FOLDERS]: BookmarkFolder; - [Entities.DOMAINS]: Schemas.Domain; + [Entities.DOMAINS]: AdminDomain; [Entities.GROUPS]: Group; [Entities.GROUP_MEMBERSHIPS]: GroupMember; [Entities.GROUP_RELATIONSHIPS]: GroupRelationship; [Entities.RELATIONSHIPS]: Relationship; - [Entities.RELAYS]: Schemas.Relay; - [Entities.RULES]: Schemas.AdminRule; + [Entities.RELAYS]: AdminRelay; + [Entities.RULES]: AdminRule; [Entities.STATUSES]: Status; [Entities.TRENDS_LINKS]: TrendsLink; } diff --git a/packages/pl-fe/src/features/admin/announcements.tsx b/packages/pl-fe/src/features/admin/announcements.tsx index ea1b1e557..bb898a057 100644 --- a/packages/pl-fe/src/features/admin/announcements.tsx +++ b/packages/pl-fe/src/features/admin/announcements.tsx @@ -6,7 +6,7 @@ import { useAnnouncements } from 'pl-fe/api/hooks/admin/useAnnouncements'; import ScrollableList from 'pl-fe/components/scrollable-list'; import { Button, Column, HStack, Stack, Text } from 'pl-fe/components/ui'; import { useAppDispatch } from 'pl-fe/hooks'; -import { AdminAnnouncement } from 'pl-fe/schemas'; +import { AdminAnnouncement } from 'pl-fe/normalizers'; import toast from 'pl-fe/toast'; const messages = defineMessages({ diff --git a/packages/pl-fe/src/features/admin/domains.tsx b/packages/pl-fe/src/features/admin/domains.tsx index fad245866..9bf25dabe 100644 --- a/packages/pl-fe/src/features/admin/domains.tsx +++ b/packages/pl-fe/src/features/admin/domains.tsx @@ -11,7 +11,7 @@ import toast from 'pl-fe/toast'; import Indicator from '../developers/components/indicator'; -import type { Domain as DomainEntity } from 'pl-fe/schemas'; +import type { AdminDomain as DomainEntity } from 'pl-api'; const messages = defineMessages({ heading: { id: 'column.admin.domains', defaultMessage: 'Domains' }, diff --git a/packages/pl-fe/src/features/admin/moderation-log.tsx b/packages/pl-fe/src/features/admin/moderation-log.tsx index 12676318e..8318e6bf0 100644 --- a/packages/pl-fe/src/features/admin/moderation-log.tsx +++ b/packages/pl-fe/src/features/admin/moderation-log.tsx @@ -5,7 +5,7 @@ import { useModerationLog } from 'pl-fe/api/hooks/admin'; import ScrollableList from 'pl-fe/components/scrollable-list'; import { Column, Stack, Text } from 'pl-fe/components/ui'; -import type { ModerationLogEntry } from 'pl-fe/schemas'; +import type { AdminModerationLogEntry } from 'pl-api'; const messages = defineMessages({ heading: { id: 'column.admin.moderation_log', defaultMessage: 'Moderation log' }, @@ -48,7 +48,7 @@ const ModerationLog = () => { }; interface ILogItem { - log: ModerationLogEntry; + log: AdminModerationLogEntry; } const LogItem: React.FC = ({ log }) => ( diff --git a/packages/pl-fe/src/features/admin/relays.tsx b/packages/pl-fe/src/features/admin/relays.tsx index f330cb47f..0a9707d20 100644 --- a/packages/pl-fe/src/features/admin/relays.tsx +++ b/packages/pl-fe/src/features/admin/relays.tsx @@ -7,7 +7,7 @@ import { Button, Column, Form, HStack, Input, Stack, Text } from 'pl-fe/componen import { useTextField } from 'pl-fe/hooks/forms'; import toast from 'pl-fe/toast'; -import type { Relay as RelayEntity } from 'pl-fe/schemas'; +import type { AdminRelay as RelayEntity } from 'pl-api'; const messages = defineMessages({ heading: { id: 'column.admin.relays', defaultMessage: 'Instance relays' }, diff --git a/packages/pl-fe/src/features/admin/rules.tsx b/packages/pl-fe/src/features/admin/rules.tsx index cb0a0f128..efc518225 100644 --- a/packages/pl-fe/src/features/admin/rules.tsx +++ b/packages/pl-fe/src/features/admin/rules.tsx @@ -6,9 +6,10 @@ import { useRules } from 'pl-fe/api/hooks/admin'; import ScrollableList from 'pl-fe/components/scrollable-list'; import { Button, Column, HStack, Stack, Text } from 'pl-fe/components/ui'; import { useAppDispatch } from 'pl-fe/hooks'; -import { AdminRule } from 'pl-fe/schemas'; import toast from 'pl-fe/toast'; +import type { AdminRule } from 'pl-api'; + const messages = defineMessages({ heading: { id: 'column.admin.rules', defaultMessage: 'Instance rules' }, deleteConfirm: { id: 'confirmations.admin.delete_rule.confirm', defaultMessage: 'Delete' }, diff --git a/packages/pl-fe/src/features/admin/tabs/dashboard.tsx b/packages/pl-fe/src/features/admin/tabs/dashboard.tsx index 5b4f13294..2be54faad 100644 --- a/packages/pl-fe/src/features/admin/tabs/dashboard.tsx +++ b/packages/pl-fe/src/features/admin/tabs/dashboard.tsx @@ -1,43 +1,19 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; -import { getSubscribersCsv, getUnsubscribersCsv, getCombinedCsv } from 'pl-fe/actions/admin'; import List, { ListItem } from 'pl-fe/components/list'; -import { CardTitle, Icon, IconButton, Stack } from 'pl-fe/components/ui'; -import { useAppDispatch, useOwnAccount, useFeatures, useInstance } from 'pl-fe/hooks'; +import { CardTitle, Icon, Stack } from 'pl-fe/components/ui'; +import { useOwnAccount, useFeatures, useInstance } from 'pl-fe/hooks'; import sourceCode from 'pl-fe/utils/code'; -import { download } from 'pl-fe/utils/download'; import { DashCounter, DashCounters } from '../components/dashcounter'; import RegistrationModePicker from '../components/registration-mode-picker'; const Dashboard: React.FC = () => { - const dispatch = useAppDispatch(); const instance = useInstance(); const features = useFeatures(); const { account } = useOwnAccount(); - const handleSubscribersClick: React.MouseEventHandler = e => { - dispatch(getSubscribersCsv()).then(({ data }) => { - download(data, 'subscribers.csv'); - }).catch(() => {}); - e.preventDefault(); - }; - - const handleUnsubscribersClick: React.MouseEventHandler = e => { - dispatch(getUnsubscribersCsv()).then(({ data }) => { - download(data, 'unsubscribers.csv'); - }).catch(() => {}); - e.preventDefault(); - }; - - const handleCombinedClick: React.MouseEventHandler = e => { - dispatch(getCombinedCsv()).then(({ data }) => { - download(data, 'combined.csv'); - }).catch(() => {}); - e.preventDefault(); - }; - const v = features.version; const { @@ -92,14 +68,14 @@ const Dashboard: React.FC = () => { label={} /> - {features.adminAnnouncements && ( + {features.pleromaAdminAnnouncements && ( } /> )} - {features.adminRules && ( + {features.pleromaAdminRules && ( } @@ -148,40 +124,6 @@ const Dashboard: React.FC = () => { {v.software + (v.build ? `+${v.build}` : '')} {v.version} - - {(features.emailList && account.is_admin) && ( - <> - } - /> - - - - - - - - - - - - - - - - )} ); }; diff --git a/packages/pl-fe/src/features/auth-login/components/login-form.test.tsx b/packages/pl-fe/src/features/auth-login/components/login-form.test.tsx index e4871b452..bc985d929 100644 --- a/packages/pl-fe/src/features/auth-login/components/login-form.test.tsx +++ b/packages/pl-fe/src/features/auth-login/components/login-form.test.tsx @@ -1,7 +1,7 @@ +import { instanceSchema } from 'pl-api'; import React from 'react'; import { fireEvent, render, screen } from 'pl-fe/jest/test-helpers'; -import { instanceSchema } from 'pl-fe/schemas'; import LoginForm from './login-form'; diff --git a/packages/pl-fe/src/features/auth-login/components/login-page.test.tsx b/packages/pl-fe/src/features/auth-login/components/login-page.test.tsx index 8effa04be..67762b8e7 100644 --- a/packages/pl-fe/src/features/auth-login/components/login-page.test.tsx +++ b/packages/pl-fe/src/features/auth-login/components/login-page.test.tsx @@ -1,7 +1,7 @@ +import { instanceSchema } from 'pl-api'; import React from 'react'; import { render, screen } from 'pl-fe/jest/test-helpers'; -import { instanceSchema } from 'pl-fe/schemas'; import LoginPage from './login-page'; diff --git a/packages/pl-fe/src/features/ui/components/modals/account-moderation-modal/account-moderation-modal.tsx b/packages/pl-fe/src/features/ui/components/modals/account-moderation-modal/account-moderation-modal.tsx index 872a801ec..8b7f535f3 100644 --- a/packages/pl-fe/src/features/ui/components/modals/account-moderation-modal/account-moderation-modal.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/account-moderation-modal/account-moderation-modal.tsx @@ -67,7 +67,7 @@ const AccountModerationModal: React.FC toast.success(intl.formatMessage(message, { acct: account.acct })), }); }; @@ -78,7 +78,7 @@ const AccountModerationModal: React.FC toast.success(intl.formatMessage(message, { acct: account.acct })), }); }; diff --git a/packages/pl-fe/src/features/ui/components/modals/edit-announcement-modal.tsx b/packages/pl-fe/src/features/ui/components/modals/edit-announcement-modal.tsx index f7c95dad6..5babfda04 100644 --- a/packages/pl-fe/src/features/ui/components/modals/edit-announcement-modal.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/edit-announcement-modal.tsx @@ -9,7 +9,7 @@ import { useAppDispatch } from 'pl-fe/hooks'; import toast from 'pl-fe/toast'; import type { BaseModalProps } from '../modal-root'; -import type { AdminAnnouncement } from 'pl-fe/schemas'; +import type { AdminAnnouncement } from 'pl-api'; const messages = defineMessages({ save: { id: 'admin.edit_announcement.save', defaultMessage: 'Save' }, @@ -29,7 +29,7 @@ const EditAnnouncementModal: React.FC { const form = { content, - starts_at: startTime?.toISOString() || null, - ends_at: endTime?.toISOString() || null, + starts_at: startTime?.toISOString() || undefined, + ends_at: endTime?.toISOString() || undefined, all_day: allDay, }; diff --git a/packages/pl-fe/src/features/ui/components/modals/edit-domain-modal.tsx b/packages/pl-fe/src/features/ui/components/modals/edit-domain-modal.tsx index 35bf1a0e5..e6d1bf2f9 100644 --- a/packages/pl-fe/src/features/ui/components/modals/edit-domain-modal.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/edit-domain-modal.tsx @@ -8,7 +8,7 @@ import { useAppDispatch } from 'pl-fe/hooks'; import toast from 'pl-fe/toast'; import type { BaseModalProps } from '../modal-root'; -import type { Domain } from 'pl-fe/schemas'; +import type { AdminDomain } from 'pl-api'; const messages = defineMessages({ save: { id: 'admin.edit_domain.save', defaultMessage: 'Save' }, @@ -27,7 +27,7 @@ const EditDomainModal: React.FC = ({ onCl const { data: domains, createDomain, isCreating, updateDomain, isUpdating } = useDomains(); - const [domain] = useState(domainId ? domains!.find(({ id }) => domainId === id)! : null); + const [domain] = useState(domainId ? domains!.find(({ id }) => domainId === id)! : null); const [domainName, setDomainName] = useState(domain?.domain || ''); const [isPublic, setPublic] = useState(domain?.public || false); diff --git a/packages/pl-fe/src/features/ui/components/modals/edit-rule-modal.tsx b/packages/pl-fe/src/features/ui/components/modals/edit-rule-modal.tsx index 30c1111dd..d70ee18be 100644 --- a/packages/pl-fe/src/features/ui/components/modals/edit-rule-modal.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/edit-rule-modal.tsx @@ -7,7 +7,7 @@ import { useTextField } from 'pl-fe/hooks/forms'; import toast from 'pl-fe/toast'; import type { BaseModalProps } from '../modal-root'; -import type { AdminRule } from 'pl-fe/schemas'; +import type { AdminRule } from 'pl-api'; const messages = defineMessages({ save: { id: 'admin.edit_rule.save', defaultMessage: 'Save' }, diff --git a/packages/pl-fe/src/features/ui/index.tsx b/packages/pl-fe/src/features/ui/index.tsx index 72ee39798..4799d25f4 100644 --- a/packages/pl-fe/src/features/ui/index.tsx +++ b/packages/pl-fe/src/features/ui/index.tsx @@ -301,9 +301,9 @@ const SwitchingColumnsArea: React.FC = ({ children }) => - {features.adminAnnouncements && } + {features.pleromaAdminAnnouncements && } {features.domains && } - {features.adminRules && } + {features.pleromaAdminRules && } diff --git a/packages/pl-fe/src/locales/en.json b/packages/pl-fe/src/locales/en.json index 3299d0475..42a67a2f7 100644 --- a/packages/pl-fe/src/locales/en.json +++ b/packages/pl-fe/src/locales/en.json @@ -107,7 +107,6 @@ "admin.dashcounters.retention_label": "user retention", "admin.dashcounters.status_count_label": "posts", "admin.dashcounters.user_count_label": "total users", - "admin.dashwidgets.email_list_header": "Email list", "admin.dashwidgets.software_header": "Software", "admin.domains.action": "Create domain", "admin.domains.delete": "Delete", diff --git a/packages/pl-fe/src/locales/pl.json b/packages/pl-fe/src/locales/pl.json index e9ec7513a..02775117d 100644 --- a/packages/pl-fe/src/locales/pl.json +++ b/packages/pl-fe/src/locales/pl.json @@ -107,7 +107,6 @@ "admin.dashcounters.retention_label": "utrzymywanie użytkowników", "admin.dashcounters.status_count_label": "wpisy", "admin.dashcounters.user_count_label": "użytkownicy łącznie", - "admin.dashwidgets.email_list_header": "Lista adresów e-mail", "admin.dashwidgets.software_header": "Oprogramowanie", "admin.domains.action": "Utwórz domenę", "admin.domains.delete": "Usuń", diff --git a/packages/pl-fe/src/normalizers/announcement.ts b/packages/pl-fe/src/normalizers/announcement.ts index de33beed0..ffb1ad4c8 100644 --- a/packages/pl-fe/src/normalizers/announcement.ts +++ b/packages/pl-fe/src/normalizers/announcement.ts @@ -1,9 +1,9 @@ import emojify from 'pl-fe/features/emoji'; import { makeCustomEmojiMap } from 'pl-fe/schemas/utils'; -import type { Announcement as BaseAnnouncement } from 'pl-api'; +import type { AdminAnnouncement as BaseAdminAnnouncement, Announcement as BaseAnnouncement } from 'pl-api'; -const normalizeAnnouncement = (announcement: BaseAnnouncement) => { +const normalizeAnnouncement = (announcement: T) => { const emojiMap = makeCustomEmojiMap(announcement.emojis); const contentHtml = emojify(announcement.content, emojiMap); @@ -15,5 +15,6 @@ const normalizeAnnouncement = (announcement: BaseAnnouncement) => { }; type Announcement = ReturnType; +type AdminAnnouncement = ReturnType>; -export { normalizeAnnouncement, type Announcement }; +export { normalizeAnnouncement, type AdminAnnouncement, type Announcement }; diff --git a/packages/pl-fe/src/normalizers/index.ts b/packages/pl-fe/src/normalizers/index.ts index f59902632..00c473a46 100644 --- a/packages/pl-fe/src/normalizers/index.ts +++ b/packages/pl-fe/src/normalizers/index.ts @@ -1,6 +1,6 @@ export { normalizeAccount, type Account } from './account'; export { normalizeAdminReport, type AdminReport } from './admin-report'; -export { normalizeAnnouncement, type Announcement } from './announcement'; +export { normalizeAnnouncement, type AdminAnnouncement, type Announcement } from './announcement'; export { normalizeChatMessage, type ChatMessage } from './chat-message'; export { normalizeGroup, type Group } from './group'; export { normalizeGroupMember, type GroupMember } from './group-member'; diff --git a/packages/pl-fe/src/schemas/admin-announcement.ts b/packages/pl-fe/src/schemas/admin-announcement.ts deleted file mode 100644 index 9c4a11cc9..000000000 --- a/packages/pl-fe/src/schemas/admin-announcement.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { announcementSchema } from 'pl-api'; -import { z } from 'zod'; - -import emojify from 'pl-fe/features/emoji'; - -import { makeCustomEmojiMap } from './utils'; - -import type { Resolve } from 'pl-fe/utils/types'; - -const transformAnnouncement = (announcement: Resolve>) => { - const emojiMap = makeCustomEmojiMap(announcement.emojis); - - const contentHtml = emojify(announcement.content, emojiMap); - - return { - ...announcement, - contentHtml, - }; -}; - -const adminAnnouncementSchema = announcementSchema.extend({ - pleroma: z.object({ - raw_content: z.string().catch(''), - }), -}).transform(transformAnnouncement); - -type AdminAnnouncement = Resolve>; - -export { adminAnnouncementSchema, type AdminAnnouncement }; diff --git a/packages/pl-fe/src/schemas/domain.ts b/packages/pl-fe/src/schemas/domain.ts deleted file mode 100644 index ca15c36e2..000000000 --- a/packages/pl-fe/src/schemas/domain.ts +++ /dev/null @@ -1,13 +0,0 @@ -import z from 'zod'; - -const domainSchema = z.object({ - domain: z.string().catch(''), - id: z.coerce.string(), - public: z.boolean().catch(false), - resolves: z.boolean().catch(false), - last_checked_at: z.string().datetime().catch(''), -}); - -type Domain = z.infer - -export { domainSchema, type Domain }; diff --git a/packages/pl-fe/src/schemas/index.ts b/packages/pl-fe/src/schemas/index.ts deleted file mode 100644 index a15d63506..000000000 --- a/packages/pl-fe/src/schemas/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { adminAnnouncementSchema, type AdminAnnouncement } from './admin-announcement'; -export { domainSchema, type Domain } from './domain'; -export { moderationLogEntrySchema, type ModerationLogEntry } from './moderation-log-entry'; -export { relaySchema, type Relay } from './relay'; -export { adminRuleSchema, type AdminRule } from './rule'; diff --git a/packages/pl-fe/src/schemas/moderation-log-entry.ts b/packages/pl-fe/src/schemas/moderation-log-entry.ts deleted file mode 100644 index d3e553381..000000000 --- a/packages/pl-fe/src/schemas/moderation-log-entry.ts +++ /dev/null @@ -1,12 +0,0 @@ -import z from 'zod'; - -const moderationLogEntrySchema = z.object({ - id: z.coerce.string(), - data: z.record(z.string(), z.any()).catch({}), - time: z.number().catch(0), - message: z.string().catch(''), -}); - -type ModerationLogEntry = z.infer - -export { moderationLogEntrySchema, type ModerationLogEntry }; diff --git a/packages/pl-fe/src/schemas/relay.ts b/packages/pl-fe/src/schemas/relay.ts deleted file mode 100644 index f0daa4133..000000000 --- a/packages/pl-fe/src/schemas/relay.ts +++ /dev/null @@ -1,11 +0,0 @@ -import z from 'zod'; - -const relaySchema = z.preprocess((data: any) => ({ id: data.actor, ...data }), z.object({ - actor: z.string().catch(''), - id: z.string(), - followed_back: z.boolean().catch(false), -})); - -type Relay = z.infer - -export { relaySchema, type Relay }; diff --git a/packages/pl-fe/src/schemas/rule.ts b/packages/pl-fe/src/schemas/rule.ts deleted file mode 100644 index d015fbd95..000000000 --- a/packages/pl-fe/src/schemas/rule.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { z } from 'zod'; - -const adminRuleSchema = z.object({ - id: z.string(), - text: z.string().catch(''), - hint: z.string().catch(''), - priority: z.number().nullable().catch(null), -}); - -type AdminRule = z.infer; - -export { adminRuleSchema, type AdminRule }; diff --git a/packages/pl-fe/src/schemas/utils.ts b/packages/pl-fe/src/schemas/utils.ts index 752fb3fda..8af87e166 100644 --- a/packages/pl-fe/src/schemas/utils.ts +++ b/packages/pl-fe/src/schemas/utils.ts @@ -2,12 +2,6 @@ import z from 'zod'; import type { CustomEmoji } from 'pl-api'; -/** Ensure HTML content is a string, and drop empty `

` tags. */ -const contentSchema = z.string().catch('').transform((value) => value === '

' ? '' : value); - -/** Validate to Mastodon's date format, or use the current date. */ -const dateSchema = z.string().datetime().catch(new Date().toUTCString()); - /** Validates individual items in an array, dropping any that aren't valid. */ const filteredArray = (schema: T) => z.any().array().catch([]) @@ -18,30 +12,14 @@ const filteredArray = (schema: T) => }).filter((item): item is z.infer => Boolean(item)) )); -/** Validates the string as an emoji. */ -const emojiSchema = z.string().refine((v) => /\p{Extended_Pictographic}|[\u{1F1E6}-\u{1F1FF}]{2}/u.test(v)); - /** Map a list of CustomEmoji to their shortcodes. */ const makeCustomEmojiMap = (customEmojis: CustomEmoji[]) => customEmojis.reduce>((result, emoji) => { result[`:${emoji.shortcode}:`] = emoji; return result; }, {}); - -const jsonSchema = z.string().transform((value, ctx) => { - try { - return JSON.parse(value) as unknown; - } catch (_e) { - ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Invalid JSON' }); - return z.NEVER; - } -}); - -/** MIME schema, eg `image/png`. */ -const mimeSchema = z.string().regex(/^\w+\/[-+.\w]+$/); - /** zod schema to force the value into an object, if it isn't already. */ const coerceObject = (shape: T) => z.object({}).passthrough().catch({}).pipe(z.object(shape)); -export { filteredArray, makeCustomEmojiMap, emojiSchema, contentSchema, dateSchema, jsonSchema, mimeSchema, coerceObject }; +export { filteredArray, makeCustomEmojiMap, coerceObject }; diff --git a/packages/pl-fe/src/selectors/index.ts b/packages/pl-fe/src/selectors/index.ts index fef6692c4..490e43f47 100644 --- a/packages/pl-fe/src/selectors/index.ts +++ b/packages/pl-fe/src/selectors/index.ts @@ -35,8 +35,6 @@ const selectOwnAccount = (state: RootState) => { } }; -const accountIdsToAccts = (state: RootState, accountIds: string[]) => accountIds.map((accountId) => selectAccount(state, accountId)!.acct); - const getAccountBase = (state: RootState, accountId: string) => state.entities[Entities.ACCOUNTS]?.store[accountId] as Account | undefined; const getAccountRelationship = (state: RootState, accountId: string) => state.relationships.get(accountId); const getAccountMeta = (state: RootState, accountId: string) => state.accounts_meta[accountId]; @@ -354,7 +352,6 @@ export { selectAccount, selectAccounts, selectOwnAccount, - accountIdsToAccts, makeGetAccount, getFilters, regexFromFilters, diff --git a/packages/pl-fe/src/utils/config-db.ts b/packages/pl-fe/src/utils/config-db.ts index 57d096c91..e434dc441 100644 --- a/packages/pl-fe/src/utils/config-db.ts +++ b/packages/pl-fe/src/utils/config-db.ts @@ -2,7 +2,6 @@ import { Map as ImmutableMap, List as ImmutableList, Set as ImmutableSet, - fromJS, } from 'immutable'; import trimStart from 'lodash/trimStart'; @@ -37,18 +36,18 @@ const toSimplePolicy = (configs: ImmutableList): MRFSimple => { } }; -const fromSimplePolicy = (simplePolicy: Policy): ImmutableList => { - const mapper = ([key, hosts]: [key: string, hosts: ImmutableList]) => fromJS({ tuple: [`:${key}`, hosts] }); +const fromSimplePolicy = (simplePolicy: Policy)=> { + const mapper = ([key, hosts]: [key: string, hosts: ImmutableList]) => ({ tuple: [`:${key}`, hosts.toJS()] }); const value = Object.entries(simplePolicy).map(mapper); - return ImmutableList([ - ImmutableMap({ + return [ + { group: ':pleroma', key: ':mrf_simple', - value: ImmutableList(value), - }), - ]); + value: value, + }, + ]; }; const ConfigDB = { diff --git a/packages/pl-fe/src/utils/emoji-reacts.test.ts b/packages/pl-fe/src/utils/emoji-reacts.test.ts index c81a8d7f0..75cad80db 100644 --- a/packages/pl-fe/src/utils/emoji-reacts.test.ts +++ b/packages/pl-fe/src/utils/emoji-reacts.test.ts @@ -1,7 +1,7 @@ import { List as ImmutableList, fromJS } from 'immutable'; +import { emojiReactionSchema } from 'pl-api'; import { normalizeStatus } from 'pl-fe/normalizers'; -import { emojiReactionSchema } from 'pl-fe/schemas'; import { sortEmoji, diff --git a/packages/pl-fe/yarn.lock b/packages/pl-fe/yarn.lock index ff37f15fd..a193f26d2 100644 --- a/packages/pl-fe/yarn.lock +++ b/packages/pl-fe/yarn.lock @@ -8385,10 +8385,10 @@ pkg-types@^1.0.3: mlly "^1.2.0" pathe "^1.1.0" -pl-api@^0.0.22: - version "0.0.22" - resolved "https://registry.yarnpkg.com/pl-api/-/pl-api-0.0.22.tgz#1c8eedc70198a292bf86182a2ec677386f7ade6d" - integrity sha512-yDjoXuzvfsukuYdvxhExfWfE1CRzLzKypgRv6YK8L5C8KzkFjEhjYQFLref1dBGGta0kCUIZNDi+rk0l9j3x4g== +pl-api@^0.0.23: + version "0.0.23" + resolved "https://registry.yarnpkg.com/pl-api/-/pl-api-0.0.23.tgz#ecee4e08f86d14701106da7cc6f2d1a16c903795" + integrity sha512-bOlfHNNlW5Lw+H8+3RZriAFXsMygRQjU+g12dTwB/pvLhWgPgTSMn42oy723EJhlcf4576wdC9tSGfrTboY/Og== dependencies: blurhash "^2.0.5" http-link-header "^1.1.3"