From 40c0c7512df80d2a4627fa24cd9f273c7a0366f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 2 Nov 2024 11:20:21 +0100 Subject: [PATCH] pl-api: Add missing files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- .../entities/grouped-notifications-results.ts | 143 ++++++++++++++++++ .../lib/params/grouped-notifications.ts | 18 +++ 2 files changed, 161 insertions(+) create mode 100644 packages/pl-api/lib/entities/grouped-notifications-results.ts create mode 100644 packages/pl-api/lib/params/grouped-notifications.ts diff --git a/packages/pl-api/lib/entities/grouped-notifications-results.ts b/packages/pl-api/lib/entities/grouped-notifications-results.ts new file mode 100644 index 000000000..646276c47 --- /dev/null +++ b/packages/pl-api/lib/entities/grouped-notifications-results.ts @@ -0,0 +1,143 @@ +import pick from 'lodash.pick'; +import * as v from 'valibot'; + +import { accountSchema } from './account'; +import { accountWarningSchema } from './account-warning'; +import { chatMessageSchema } from './chat-message'; +import { relationshipSeveranceEventSchema } from './relationship-severance-event'; +import { reportSchema } from './report'; +import { statusSchema } from './status'; +import { datetimeSchema, filteredArray } from './utils'; + +const partialAccountWithAvatarSchema = v.object({ + id: v.string(), + acct: v.string(), + url: v.pipe(v.string(), v.url()), + avatar: v.pipe(v.string(), v.url()), + avatar_static: v.pipe(v.string(), v.url()), + locked: v.boolean(), + bot: v.boolean(), +}); + +const baseNotificationGroupSchema = v.object({ + group_key: v.string(), + notifications_count: v.pipe(v.number(), v.integer()), + most_recent_notification_id: v.string(), + page_min_id: v.fallback(v.optional(v.string()), undefined), + page_max_id: v.fallback(v.optional(v.string()), undefined), + latest_page_notification_at: v.fallback(v.optional(datetimeSchema), undefined), + sample_account_ids: v.array(v.string()), + status_id: v.fallback(v.optional(v.string()), undefined), + + is_muted: v.fallback(v.optional(v.boolean()), undefined), + is_seen: v.fallback(v.optional(v.boolean()), undefined), +}); + +const accountNotificationGroupSchema = v.object({ + ...baseNotificationGroupSchema.entries, + type: v.picklist(['follow', 'follow_request', 'admin.sign_up', 'bite']), +}); + +const statusNotificationGroupSchema = v.object({ + ...baseNotificationGroupSchema.entries, + type: v.picklist(['status', 'mention', 'reblog', 'favourite', 'poll', 'update', 'event_reminder']), + status_id: v.string(), +}); + +const reportNotificationGroupSchema = v.object({ + ...baseNotificationGroupSchema.entries, + type: v.literal('admin.report'), + report: reportSchema, +}); + +const severedRelationshipNotificationGroupSchema = v.object({ + ...baseNotificationGroupSchema.entries, + type: v.literal('severed_relationships'), + relationship_severance_event: relationshipSeveranceEventSchema, +}); + +const moderationWarningNotificationGroupSchema = v.object({ + ...baseNotificationGroupSchema.entries, + type: v.literal('moderation_warning'), + moderation_warning: accountWarningSchema, +}); + +const moveNotificationGroupSchema = v.object({ + ...baseNotificationGroupSchema.entries, + type: v.literal('move'), + target_id: v.string(), +}); + +const emojiReactionNotificationGroupSchema = v.object({ + ...baseNotificationGroupSchema.entries, + type: v.literal('emoji_reaction'), + emoji: v.string(), + emoji_url: v.fallback(v.nullable(v.string()), null), + status_id: v.string(), +}); + +const chatMentionNotificationGroupSchema = v.object({ + ...baseNotificationGroupSchema.entries, + type: v.literal('chat_mention'), + chat_message: chatMessageSchema, +}); + +const eventParticipationRequestNotificationGroupSchema = v.object({ + ...baseNotificationGroupSchema.entries, + type: v.picklist(['participation_accepted', 'participation_request']), + status_id: v.string(), + participation_message: v.fallback(v.nullable(v.string()), null), +}); + +/** + * @category Schemas + * @see {@link https://docs.joinmastodon.org/entities/Notification/} + * */ +const notificationGroupSchema: v.BaseSchema> = v.pipe( + v.any(), + v.transform((notification: any) => ({ + group_key: `ungrouped-${notification.id}`, + ...pick(notification.pleroma || {}, ['is_muted', 'is_seen']), + ...notification, + type: notification.type === 'pleroma:report' + ? 'admin.report' + : notification.type?.replace(/^pleroma:/, ''), + })), + v.variant('type', [ + accountNotificationGroupSchema, + statusNotificationGroupSchema, + reportNotificationGroupSchema, + severedRelationshipNotificationGroupSchema, + moderationWarningNotificationGroupSchema, + moveNotificationGroupSchema, + emojiReactionNotificationGroupSchema, + chatMentionNotificationGroupSchema, + eventParticipationRequestNotificationGroupSchema, + ])) as any; + +type NotificationGroup = v.InferOutput< + | typeof accountNotificationGroupSchema + | typeof statusNotificationGroupSchema + | typeof reportNotificationGroupSchema + | typeof severedRelationshipNotificationGroupSchema + | typeof moderationWarningNotificationGroupSchema + | typeof moveNotificationGroupSchema + | typeof emojiReactionNotificationGroupSchema + | typeof chatMentionNotificationGroupSchema + | typeof eventParticipationRequestNotificationGroupSchema + >; + +/** + * @category Schemas + * @see {@link https://docs.joinmastodon.org/methods/grouped_notifications/#GroupedNotificationsResults} + */ +const groupedNotificationsResultsSchema = v.object({ + accounts: filteredArray(accountSchema), + partial_accounts: v.fallback(v.optional(v.array(partialAccountWithAvatarSchema)), undefined), + statuses: filteredArray(statusSchema), + notification_groups: filteredArray(notificationGroupSchema), +}); + +type GroupedNotificationsResults = v.InferOutput; + +export { notificationGroupSchema, groupedNotificationsResultsSchema, type NotificationGroup, type GroupedNotificationsResults }; diff --git a/packages/pl-api/lib/params/grouped-notifications.ts b/packages/pl-api/lib/params/grouped-notifications.ts new file mode 100644 index 000000000..2c90b8a3d --- /dev/null +++ b/packages/pl-api/lib/params/grouped-notifications.ts @@ -0,0 +1,18 @@ +import type { PaginationParams } from './common'; + +interface GetGroupedNotificationsParams extends PaginationParams { + /** Types to include in the result. */ + types?: Array; + /** Types to exclude from the results. */ + exclude_types?: Array; + /** Return only notifications received from the specified account. */ + acccount_id?: string; + /** One of `full` (default) or `partial_avatars`. When set to `partial_avatars`, some accounts will not be rendered in full in the returned `accounts` list but will be instead returned in stripped-down form in the `partial_accounts` list. The most recent account in a notification group is always rendered in full in the `accounts` attribute. */ + expand_accounts?: 'full' | 'partial_avatars'; + /** Restrict which notification types can be grouped. Use this if there are notification types for which your client does not support grouping. If omitted, the server will group notifications of all types it supports (currently, `favourite`, `follow` and `reblog`). If you do not want any notification grouping, use GET `/api/v1/notifications` instead. Notifications that would be grouped if not for this parameter will instead be returned as individual single-notification groups with a unique `group_key` that can be assumed to be of the form `ungrouped-{notification_id}`. Please note that neither the streaming API nor the individual notification APIs are aware of this parameter and will always include a “proper” `group_key` that can be different from what is returned here, meaning that you may have to ignore `group_key` for such notifications that you do not want grouped and use `ungrouped-{notification_id}` instead for consistency. */ + grouped_types?: Array; + /** Whether to include notifications filtered by the user’s NotificationPolicy. Defaults to false. */ + include_filtered?: boolean; +} + +export type { GetGroupedNotificationsParams };