From 55ebc8c6eecf66a32d4b29b07693d54dc80a7a47 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 4 May 2023 10:24:34 -0500 Subject: [PATCH] Add notificationSchema --- app/soapbox/schemas/chat-message.ts | 10 +++ app/soapbox/schemas/emoji-reaction.ts | 3 +- app/soapbox/schemas/notification.ts | 104 ++++++++++++++++++++++++++ app/soapbox/schemas/utils.ts | 5 +- 4 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 app/soapbox/schemas/chat-message.ts create mode 100644 app/soapbox/schemas/notification.ts diff --git a/app/soapbox/schemas/chat-message.ts b/app/soapbox/schemas/chat-message.ts new file mode 100644 index 000000000..a64ffec0b --- /dev/null +++ b/app/soapbox/schemas/chat-message.ts @@ -0,0 +1,10 @@ +import { z } from 'zod'; + +import { normalizeChatMessage } from 'soapbox/normalizers'; +import { toSchema } from 'soapbox/utils/normalizers'; + +const chatMessageSchema = toSchema(normalizeChatMessage); + +type ChatMessage = z.infer; + +export { chatMessageSchema, type ChatMessage }; \ No newline at end of file diff --git a/app/soapbox/schemas/emoji-reaction.ts b/app/soapbox/schemas/emoji-reaction.ts index 55c1762a0..28271fe29 100644 --- a/app/soapbox/schemas/emoji-reaction.ts +++ b/app/soapbox/schemas/emoji-reaction.ts @@ -1,7 +1,6 @@ import { z } from 'zod'; -/** Validates the string as an emoji. */ -const emojiSchema = z.string().refine((v) => /\p{Extended_Pictographic}/u.test(v)); +import { emojiSchema } from './utils'; /** Pleroma emoji reaction. */ const emojiReactionSchema = z.object({ diff --git a/app/soapbox/schemas/notification.ts b/app/soapbox/schemas/notification.ts new file mode 100644 index 000000000..3c77de6bf --- /dev/null +++ b/app/soapbox/schemas/notification.ts @@ -0,0 +1,104 @@ +import { z } from 'zod'; + +import { accountSchema } from './account'; +import { chatMessageSchema } from './chat-message'; +import { statusSchema } from './status'; +import { emojiSchema } from './utils'; + +const baseNotificationSchema = z.object({ + account: accountSchema, + created_at: z.string().datetime().catch(new Date().toUTCString()), + id: z.string(), + type: z.string(), + total_count: z.number().optional().catch(undefined), // TruthSocial +}); + +const mentionNotificationSchema = baseNotificationSchema.extend({ + type: z.literal('mention'), + status: statusSchema, +}); + +const statusNotificationSchema = baseNotificationSchema.extend({ + type: z.literal('status'), + status: statusSchema, +}); + +const reblogNotificationSchema = baseNotificationSchema.extend({ + type: z.literal('reblog'), + status: statusSchema, +}); + +const followNotificationSchema = baseNotificationSchema.extend({ + type: z.literal('follow'), +}); + +const followRequestNotificationSchema = baseNotificationSchema.extend({ + type: z.literal('follow_request'), +}); + +const favouriteNotificationSchema = baseNotificationSchema.extend({ + type: z.literal('favourite'), + status: statusSchema, +}); + +const pollNotificationSchema = baseNotificationSchema.extend({ + type: z.literal('poll'), + status: statusSchema, +}); + +const updateNotificationSchema = baseNotificationSchema.extend({ + type: z.literal('update'), + status: statusSchema, +}); + +const moveNotificationSchema = baseNotificationSchema.extend({ + type: z.literal('move'), + target: accountSchema, +}); + +const chatMessageNotificationSchema = baseNotificationSchema.extend({ + type: z.literal('chat_message'), + chat_message: chatMessageSchema, +}); + +const emojiReactionNotificationSchema = baseNotificationSchema.extend({ + type: z.literal('pleroma:emoji_reaction'), + emoji: emojiSchema, + emoji_url: z.string().url().optional().catch(undefined), +}); + +const eventReminderNotificationSchema = baseNotificationSchema.extend({ + type: z.literal('pleroma:event_reminder'), + status: statusSchema, +}); + +const participationRequestNotificationSchema = baseNotificationSchema.extend({ + type: z.literal('pleroma:participation_request'), + status: statusSchema, +}); + +const participationAcceptedNotificationSchema = baseNotificationSchema.extend({ + type: z.literal('pleroma:participation_accepted'), + status: statusSchema, +}); + +const notificationSchema = z.discriminatedUnion('type', [ + mentionNotificationSchema, + statusNotificationSchema, + reblogNotificationSchema, + followNotificationSchema, + followRequestNotificationSchema, + favouriteNotificationSchema, + pollNotificationSchema, + updateNotificationSchema, + moveNotificationSchema, + chatMessageNotificationSchema, + emojiReactionNotificationSchema, + eventReminderNotificationSchema, + participationRequestNotificationSchema, + participationAcceptedNotificationSchema, +]); + +type Notification = z.infer; + +export { notificationSchema, type Notification }; \ No newline at end of file diff --git a/app/soapbox/schemas/utils.ts b/app/soapbox/schemas/utils.ts index 5a62fa0c6..1e53e11aa 100644 --- a/app/soapbox/schemas/utils.ts +++ b/app/soapbox/schemas/utils.ts @@ -13,6 +13,9 @@ function filteredArray(schema: T) { )); } +/** Validates the string as an emoji. */ +const emojiSchema = z.string().refine((v) => /\p{Extended_Pictographic}/u.test(v)); + /** Map a list of CustomEmoji to their shortcodes. */ function makeCustomEmojiMap(customEmojis: CustomEmoji[]) { return customEmojis.reduce>((result, emoji) => { @@ -21,4 +24,4 @@ function makeCustomEmojiMap(customEmojis: CustomEmoji[]) { }, {}); } -export { filteredArray, makeCustomEmojiMap }; \ No newline at end of file +export { filteredArray, makeCustomEmojiMap, emojiSchema }; \ No newline at end of file