From e024e9212565731a92f21071bc3551284aee3a4c Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 4 May 2023 12:13:39 -0500 Subject: [PATCH] Add a real statusSchema --- app/soapbox/schemas/mention.ts | 18 +++++++++++ app/soapbox/schemas/status.ts | 57 ++++++++++++++++++++++++++++++++-- app/soapbox/schemas/utils.ts | 5 ++- 3 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 app/soapbox/schemas/mention.ts diff --git a/app/soapbox/schemas/mention.ts b/app/soapbox/schemas/mention.ts new file mode 100644 index 0000000000..9bbdbff5b1 --- /dev/null +++ b/app/soapbox/schemas/mention.ts @@ -0,0 +1,18 @@ +import { z } from 'zod'; + +const mentionSchema = z.object({ + acct: z.string(), + id: z.string(), + url: z.string().url().catch(''), + username: z.string().catch(''), +}).transform((mention) => { + if (!mention.username) { + mention.username = mention.acct.split('@')[0]; + } + + return mention; +}); + +type Mention = z.infer; + +export { mentionSchema, type Mention }; \ No newline at end of file diff --git a/app/soapbox/schemas/status.ts b/app/soapbox/schemas/status.ts index 66d6f05ebe..00fa6d4839 100644 --- a/app/soapbox/schemas/status.ts +++ b/app/soapbox/schemas/status.ts @@ -1,9 +1,60 @@ import { z } from 'zod'; -import { normalizeStatus } from 'soapbox/normalizers'; -import { toSchema } from 'soapbox/utils/normalizers'; +import { accountSchema } from './account'; +import { attachmentSchema } from './attachment'; +import { cardSchema } from './card'; +import { customEmojiSchema } from './custom-emoji'; +import { groupSchema } from './group'; +import { mentionSchema } from './mention'; +import { pollSchema } from './poll'; +import { tagSchema } from './tag'; +import { contentSchema, dateSchema, filteredArray } from './utils'; -const statusSchema = toSchema(normalizeStatus); +const baseStatusSchema = z.object({ + account: accountSchema, + application: z.object({ + name: z.string(), + website: z.string().url().nullable().catch(null), + }).nullable().catch(null), + bookmarked: z.coerce.boolean(), + card: cardSchema.nullable().catch(null), + content: contentSchema, + created_at: dateSchema, + disliked: z.coerce.boolean(), + dislikes_count: z.number().catch(0), + edited_at: z.string().datetime().nullable().catch(null), + emojis: filteredArray(customEmojiSchema), + favourited: z.coerce.boolean(), + favourites_count: z.number().catch(0), + group: groupSchema.nullable().catch(null), + in_reply_to_account_id: z.string().nullable().catch(null), + in_reply_to_id: z.string().nullable().catch(null), + id: z.string(), + language: z.string().nullable().catch(null), + media_attachments: filteredArray(attachmentSchema), + mentions: filteredArray(mentionSchema), + muted: z.coerce.boolean(), + pinned: z.coerce.boolean(), + pleroma: z.object({}).optional().catch(undefined), + poll: pollSchema.nullable().catch(null), + quote: z.literal(null).catch(null), + quotes_count: z.number().catch(0), + reblog: z.literal(null).catch(null), + reblogged: z.coerce.boolean(), + reblogs_count: z.number().catch(0), + replies_count: z.number().catch(0), + sensitive: z.coerce.boolean(), + spoiler_text: contentSchema, + tags: filteredArray(tagSchema), + uri: z.string().url().catch(''), + url: z.string().url().catch(''), + visibility: z.string().catch('public'), +}); + +const statusSchema = baseStatusSchema.extend({ + quote: baseStatusSchema.nullable().catch(null), + reblog: baseStatusSchema.nullable().catch(null), +}); type Status = z.infer; diff --git a/app/soapbox/schemas/utils.ts b/app/soapbox/schemas/utils.ts index b641858000..c85b2b2b16 100644 --- a/app/soapbox/schemas/utils.ts +++ b/app/soapbox/schemas/utils.ts @@ -5,6 +5,9 @@ import type { CustomEmoji } from './custom-emoji'; /** 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. */ function filteredArray(schema: T) { return z.any().array().catch([]) @@ -27,4 +30,4 @@ function makeCustomEmojiMap(customEmojis: CustomEmoji[]) { }, {}); } -export { filteredArray, makeCustomEmojiMap, emojiSchema, contentSchema }; \ No newline at end of file +export { filteredArray, makeCustomEmojiMap, emojiSchema, contentSchema, dateSchema }; \ No newline at end of file