Groups zod See merge request soapbox-pub/soapbox!2338environments/review-develop-3zknud/deployments/2819
commit
a40222c2de
@ -0,0 +1,17 @@
|
|||||||
|
import z from 'zod';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a custom emoji.
|
||||||
|
* https://docs.joinmastodon.org/entities/CustomEmoji/
|
||||||
|
*/
|
||||||
|
const customEmojiSchema = z.object({
|
||||||
|
category: z.string().catch(''),
|
||||||
|
shortcode: z.string(),
|
||||||
|
static_url: z.string().catch(''),
|
||||||
|
url: z.string(),
|
||||||
|
visible_in_picker: z.boolean().catch(true),
|
||||||
|
});
|
||||||
|
|
||||||
|
type CustomEmoji = z.infer<typeof customEmojiSchema>;
|
||||||
|
|
||||||
|
export { customEmojiSchema, CustomEmoji };
|
@ -0,0 +1,12 @@
|
|||||||
|
import z from 'zod';
|
||||||
|
|
||||||
|
const groupRelationshipSchema = z.object({
|
||||||
|
id: z.string(),
|
||||||
|
member: z.boolean().catch(false),
|
||||||
|
requested: z.boolean().catch(false),
|
||||||
|
role: z.string().nullish().catch(null),
|
||||||
|
});
|
||||||
|
|
||||||
|
type GroupRelationship = z.infer<typeof groupRelationshipSchema>;
|
||||||
|
|
||||||
|
export { groupRelationshipSchema, GroupRelationship };
|
@ -0,0 +1,49 @@
|
|||||||
|
import escapeTextContentForBrowser from 'escape-html';
|
||||||
|
import z from 'zod';
|
||||||
|
|
||||||
|
import emojify from 'soapbox/features/emoji';
|
||||||
|
import { unescapeHTML } from 'soapbox/utils/html';
|
||||||
|
|
||||||
|
import { customEmojiSchema } from './custom-emoji';
|
||||||
|
import { groupRelationshipSchema } from './group-relationship';
|
||||||
|
import { filteredArray, makeCustomEmojiMap } from './utils';
|
||||||
|
|
||||||
|
const avatarMissing = require('assets/images/avatar-missing.png');
|
||||||
|
const headerMissing = require('assets/images/header-missing.png');
|
||||||
|
|
||||||
|
const groupSchema = z.object({
|
||||||
|
avatar: z.string().catch(avatarMissing),
|
||||||
|
avatar_static: z.string().catch(''),
|
||||||
|
created_at: z.string().datetime().catch(new Date().toUTCString()),
|
||||||
|
display_name: z.string().catch(''),
|
||||||
|
domain: z.string().catch(''),
|
||||||
|
emojis: filteredArray(customEmojiSchema).catch([]),
|
||||||
|
group_visibility: z.string().catch(''), // TruthSocial
|
||||||
|
header: z.string().catch(headerMissing),
|
||||||
|
header_static: z.string().catch(''),
|
||||||
|
id: z.string().catch(''),
|
||||||
|
locked: z.boolean().catch(false),
|
||||||
|
membership_required: z.boolean().catch(false),
|
||||||
|
members_count: z.number().catch(0),
|
||||||
|
note: z.string().transform(note => note === '<p></p>' ? '' : note).catch(''),
|
||||||
|
relationship: groupRelationshipSchema.nullable().catch(null), // Dummy field to be overwritten later
|
||||||
|
statuses_visibility: z.string().catch('public'),
|
||||||
|
uri: z.string().catch(''),
|
||||||
|
url: z.string().catch(''),
|
||||||
|
}).transform(group => {
|
||||||
|
group.avatar_static = group.avatar_static || group.avatar;
|
||||||
|
group.header_static = group.header_static || group.header;
|
||||||
|
group.locked = group.locked || group.group_visibility === 'members_only'; // TruthSocial
|
||||||
|
|
||||||
|
const customEmojiMap = makeCustomEmojiMap(group.emojis);
|
||||||
|
return {
|
||||||
|
...group,
|
||||||
|
display_name_html: emojify(escapeTextContentForBrowser(group.display_name), customEmojiMap),
|
||||||
|
note_emojified: emojify(group.note, customEmojiMap),
|
||||||
|
note_plain: unescapeHTML(group.note),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
type Group = z.infer<typeof groupSchema>;
|
||||||
|
|
||||||
|
export { groupSchema, Group };
|
@ -0,0 +1,3 @@
|
|||||||
|
export { customEmojiSchema, CustomEmoji } from './custom-emoji';
|
||||||
|
export { groupSchema, Group } from './group';
|
||||||
|
export { groupRelationshipSchema, GroupRelationship } from './group-relationship';
|
@ -0,0 +1,21 @@
|
|||||||
|
import z from 'zod';
|
||||||
|
|
||||||
|
import type { CustomEmoji } from './custom-emoji';
|
||||||
|
|
||||||
|
/** Validates individual items in an array, dropping any that aren't valid. */
|
||||||
|
function filteredArray<T extends z.ZodTypeAny>(schema: T) {
|
||||||
|
return z.any().array().transform((arr) => (
|
||||||
|
arr.map((item) => schema.safeParse(item).success ? item as z.infer<T> : undefined)
|
||||||
|
.filter((item): item is z.infer<T> => Boolean(item))
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Map a list of CustomEmoji to their shortcodes. */
|
||||||
|
function makeCustomEmojiMap(customEmojis: CustomEmoji[]) {
|
||||||
|
return customEmojis.reduce<Record<string, CustomEmoji>>((result, emoji) => {
|
||||||
|
result[`:${emoji.shortcode}:`] = emoji;
|
||||||
|
return result;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
export { filteredArray, makeCustomEmojiMap };
|
Loading…
Reference in new issue