feat(api): 🏷️ Port Role and CustomEmoji OpenAPI schemas
Some checks failed
Mirror to Codeberg / Mirror (push) Failing after 1s

This commit is contained in:
Jesse Wierzbinski 2025-02-11 18:22:39 +01:00
parent 7c622730dc
commit 264e2fe8ac
No known key found for this signature in database
17 changed files with 319 additions and 177 deletions

View file

@ -3,8 +3,8 @@ import type { Account as ApiAccount } from "@versia/client/types";
import ISO6391 from "iso-639-1";
import { config } from "~/packages/config-manager";
import { zBoolean } from "~/packages/config-manager/config.type";
import { Emoji } from "../database/emoji.ts";
import { Role } from "../database/role.ts";
import { CustomEmoji } from "./emoji.ts";
import { Role } from "./versia.ts";
export const Field = z.object({
name: z
@ -117,7 +117,7 @@ export const Account = z.object({
.string()
.uuid()
.openapi({
description: "The account id.",
description: "The account ID in the database.",
example: "9e84842b-4db6-4a9b-969d-46ab408278da",
externalDocs: {
url: "https://docs.joinmastodon.org/entities/Account/#id",
@ -260,7 +260,7 @@ export const Account = z.object({
url: "https://docs.joinmastodon.org/entities/Account/#fields",
},
}),
emojis: z.array(Emoji.schema).openapi({
emojis: z.array(CustomEmoji).openapi({
description:
"Custom emoji entities to be used when rendering the profile.",
externalDocs: {
@ -384,6 +384,7 @@ export const Account = z.object({
url: "https://docs.joinmastodon.org/entities/Account/#following_count",
},
}),
/* Versia Server API extension */
uri: z.string().url().openapi({
description:
"The location of the user's Versia profile page, as opposed to the local representation.",
@ -396,7 +397,10 @@ export const Account = z.object({
name: z.string(),
})
.optional(),
roles: z.array(Role.schema),
/* Versia Server API extension */
roles: z.array(Role).openapi({
description: "Roles assigned to the account.",
}),
mute_expires_at: z.string().datetime().nullable().openapi({
description: "When a timed mute will expire, if applicable.",
example: "2025-03-01T14:00:00.000Z",

View file

@ -0,0 +1,25 @@
import { z } from "@hono/zod-openapi";
import { Status } from "./status.ts";
export const Context = z
.object({
ancestors: z.array(Status).openapi({
description: "Parents in the thread.",
externalDocs: {
url: "https://docs.joinmastodon.org/entities/Context/#ancestors",
},
}),
descendants: z.array(Status).openapi({
description: "Children in the thread.",
externalDocs: {
url: "https://docs.joinmastodon.org/entities/Context/#descendants",
},
}),
})
.openapi({
description:
"Represents the tree around a given status. Used for reconstructing threads of statuses.",
externalDocs: {
url: "https://docs.joinmastodon.org/entities/Context/#context",
},
});

82
classes/schemas/emoji.ts Normal file
View file

@ -0,0 +1,82 @@
import { z } from "@hono/zod-openapi";
import { zBoolean } from "~/packages/config-manager/config.type";
import { Id } from "./common.ts";
export const CustomEmoji = z
.object({
/* Versia Server API extension */
id: Id.openapi({
description: "ID of the custom emoji in the database.",
example: "af9ccd29-c689-477f-aa27-d7d95fd8fb05",
}),
shortcode: z.string().openapi({
description: "The name of the custom emoji.",
example: "blobaww",
externalDocs: {
url: "https://docs.joinmastodon.org/entities/CustomEmoji/#shortcode",
},
}),
url: z
.string()
.url()
.openapi({
description: "A link to the custom emoji.",
example:
"https://cdn.versia.social/emojis/images/000/011/739/original/blobaww.png",
externalDocs: {
url: "https://docs.joinmastodon.org/entities/CustomEmoji/#url",
},
}),
static_url: z
.string()
.url()
.openapi({
description: "A link to a static copy of the custom emoji.",
example:
"https://cdn.versia.social/emojis/images/000/011/739/static/blobaww.png",
externalDocs: {
url: "https://docs.joinmastodon.org/entities/CustomEmoji/#static_url",
},
}),
visible_in_picker: z.boolean().openapi({
description:
"Whether this Emoji should be visible in the picker or unlisted.",
example: true,
externalDocs: {
url: "https://docs.joinmastodon.org/entities/CustomEmoji/#visible_in_picker",
},
}),
category: z
.string()
.nullable()
.openapi({
description: "Used for sorting custom emoji in the picker.",
example: "Blobs",
externalDocs: {
url: "https://docs.joinmastodon.org/entities/CustomEmoji/#category",
},
}),
/* Versia Server API extension */
global: zBoolean.openapi({
description: "Whether this emoji is visible to all users.",
example: false,
}),
/* Versia Server API extension */
description: z
.string()
.nullable()
.openapi({
description:
"Emoji description for users using screen readers.",
example: "A cute blob.",
externalDocs: {
url: "https://docs.joinmastodon.org/entities/CustomEmoji/#description",
},
}),
})
.openapi({
description: "Represents a custom emoji.",
externalDocs: {
url: "https://docs.joinmastodon.org/entities/CustomEmoji",
},
});

View file

@ -1,12 +1,14 @@
import { z } from "@hono/zod-openapi";
import type { Status as ApiNote } from "@versia/client/types";
import { Emoji, Media } from "@versia/kit/db";
import { Media } from "@versia/kit/db";
import ISO6391 from "iso-639-1";
import { zBoolean } from "~/packages/config-manager/config.type.ts";
import { Account } from "./account.ts";
import { PreviewCard } from "./card.ts";
import { Id } from "./common.ts";
import { CustomEmoji } from "./emoji.ts";
import { FilterResult } from "./filters.ts";
import { NoteReaction } from "./versia.ts";
export const Mention = z
.object({
@ -168,7 +170,7 @@ export const Poll = z.object({
url: "https://docs.joinmastodon.org/entities/Poll/#options",
},
}),
emojis: z.array(Emoji.schema).openapi({
emojis: z.array(CustomEmoji).openapi({
description: "Custom emoji to be used for rendering poll options.",
externalDocs: {
url: "https://docs.joinmastodon.org/entities/Poll/#emojis",
@ -284,7 +286,7 @@ export const Status = z.object({
url: "https://docs.joinmastodon.org/entities/Status/#edited_at",
},
}),
emojis: z.array(Emoji.schema).openapi({
emojis: z.array(CustomEmoji).openapi({
description: "Custom emoji to be used when rendering status content.",
externalDocs: {
url: "https://docs.joinmastodon.org/entities/Status/#emojis",
@ -455,17 +457,7 @@ export const Status = z.object({
url: "https://docs.joinmastodon.org/entities/Status/#pinned",
},
}),
emoji_reactions: z.array(
z.object({
count: z.number().int().nonnegative(),
me: zBoolean,
name: z.string(),
url: z.string().url().optional(),
static_url: z.string().url().optional(),
accounts: z.array(Account).optional(),
account_ids: z.array(z.string().uuid()).optional(),
}),
),
reactions: z.array(NoteReaction).openapi({}),
quote: z
.lazy((): z.ZodType<ApiNote> => Status as z.ZodType<ApiNote>)
.nullable(),

77
classes/schemas/versia.ts Normal file
View file

@ -0,0 +1,77 @@
import { z } from "@hono/zod-openapi";
import { RolePermission } from "@versia/client/types";
import { Id } from "./common.ts";
import { config } from "~/packages/config-manager/index.ts";
/* Versia Server API extension */
export const Role = z
.object({
id: Id.openapi({}).openapi({
description: "The role ID in the database.",
example: "b4a7e0f0-8f6a-479b-910b-9265c070d5bd",
}),
name: z.string().min(1).max(128).trim().openapi({
description: "The name of the role.",
example: "Moderator",
}),
permissions: z
.array(z.nativeEnum(RolePermission))
.transform(
// Deduplicate permissions
(permissions) => Array.from(new Set(permissions)),
)
.default([])
.openapi({
description: "The permissions granted to the role.",
example: [
RolePermission.ManageEmojis,
RolePermission.ManageAccounts,
],
}),
priority: z.number().int().default(0).openapi({
description:
"Role priority. Higher priority roles allow overriding lower priority roles.",
example: 100,
}),
description: z.string().min(0).max(1024).trim().optional().openapi({
description: "Short role description.",
example: "Allows managing emojis and accounts.",
}),
visible: z.boolean().default(true).openapi({
description: "Whether the role should be shown in the UI.",
}),
icon: z.string().url().optional().openapi({
description: "URL to the role icon.",
example: "https://example.com/role-icon.png",
}),
})
.openapi({
description:
"Information about a role in the system, as well as its permissions.",
});
/* Versia Server API extension */
export const NoteReaction = z
.object({
name: z
.string()
.min(1)
.max(config.validation.max_emoji_shortcode_size)
.trim()
.openapi({
description: "Custom Emoji shortcode or Unicode emoji.",
example: "blobfox_coffee",
}),
count: z.number().int().nonnegative().openapi({
description: "Number of users who reacted with this emoji.",
example: 5,
}),
me: z.boolean().optional().openapi({
description:
"Whether the current authenticated user reacted with this emoji.",
example: true,
}),
})
.openapi({
description: "Information about a reaction to a note.",
});