refactor(api): ♻️ Refactor more routes into OpenAPI-compatible formats

This commit is contained in:
Jesse Wierzbinski 2024-08-27 18:55:02 +02:00
parent 02cb8bcd4f
commit bcbc9e6bf1
No known key found for this signature in database
17 changed files with 896 additions and 400 deletions

View file

@ -12,6 +12,7 @@ import {
eq,
inArray,
} from "drizzle-orm";
import { z } from "zod";
import { db } from "~/drizzle/db";
import { Attachments } from "~/drizzle/schema";
import { MediaBackendType } from "~/packages/config-manager/config.type";
@ -21,6 +22,34 @@ import { BaseInterface } from "./base";
export type AttachmentType = InferSelectModel<typeof Attachments>;
export class Attachment extends BaseInterface<typeof Attachments> {
static schema: z.ZodType<ApiAttachment> = z.object({
id: z.string().uuid(),
type: z.enum(["unknown", "image", "gifv", "video", "audio"]),
url: z.string().url(),
remote_url: z.string().url().nullable(),
preview_url: z.string().url().nullable(),
text_url: z.string().url().nullable(),
meta: z
.object({
width: z.number().optional(),
height: z.number().optional(),
fps: z.number().optional(),
size: z.string().optional(),
duration: z.number().optional(),
length: z.string().optional(),
aspect: z.number().optional(),
original: z.object({
width: z.number().optional(),
height: z.number().optional(),
size: z.string().optional(),
aspect: z.number().optional(),
}),
})
.nullable(),
description: z.string().nullable(),
blurhash: z.string().nullable(),
});
async reload(): Promise<void> {
const reloaded = await Attachment.fromId(this.data.id);

View file

@ -27,6 +27,7 @@ import {
} from "drizzle-orm";
import { htmlToText } from "html-to-text";
import { createRegExp, exactly, global } from "magic-regexp";
import { z } from "zod";
import {
type Application,
applicationToApi,
@ -56,6 +57,96 @@ import { User } from "./user";
* Gives helpers to fetch notes from database in a nice format
*/
export class Note extends BaseInterface<typeof Notes, StatusWithRelations> {
static schema: z.ZodType<ApiStatus> = z.object({
id: z.string().uuid(),
uri: z.string().url(),
url: z.string().url(),
account: z.lazy(() => User.schema),
in_reply_to_id: z.string().uuid().nullable(),
in_reply_to_account_id: z.string().uuid().nullable(),
reblog: z.lazy(() => Note.schema).nullable(),
content: z.string(),
plain_content: z.string().nullable(),
created_at: z.string(),
edited_at: z.string().nullable(),
emojis: z.array(Emoji.schema),
replies_count: z.number().int().nonnegative(),
reblogs_count: z.number().int().nonnegative(),
favourites_count: z.number().int().nonnegative(),
reblogged: z.boolean().nullable(),
favourited: z.boolean().nullable(),
muted: z.boolean().nullable(),
sensitive: z.boolean(),
spoiler_text: z.string(),
visibility: z.enum(["public", "unlisted", "private", "direct"]),
media_attachments: z.array(Attachment.schema),
mentions: z.array(
z.object({
id: z.string().uuid(),
username: z.string(),
acct: z.string(),
url: z.string().url(),
}),
),
tags: z.array(z.object({ name: z.string(), url: z.string().url() })),
card: z
.object({
url: z.string().url(),
title: z.string(),
description: z.string(),
type: z.enum(["link", "photo", "video", "rich"]),
image: z.string().url().nullable(),
author_name: z.string().nullable(),
author_url: z.string().url().nullable(),
provider_name: z.string().nullable(),
provider_url: z.string().url().nullable(),
html: z.string().nullable(),
width: z.number().int().nonnegative().nullable(),
height: z.number().int().nonnegative().nullable(),
embed_url: z.string().url().nullable(),
blurhash: z.string().nullable(),
})
.nullable(),
poll: z
.object({
id: z.string().uuid(),
expires_at: z.string(),
expired: z.boolean(),
multiple: z.boolean(),
votes_count: z.number().int().nonnegative(),
voted: z.boolean(),
options: z.array(
z.object({
title: z.string(),
votes_count: z.number().int().nonnegative().nullable(),
}),
),
})
.nullable(),
application: z
.object({
name: z.string(),
website: z.string().url().nullable().optional(),
vapid_key: z.string().nullable().optional(),
})
.nullable(),
language: z.string().nullable(),
pinned: z.boolean().nullable(),
emoji_reactions: z.array(
z.object({
count: z.number().int().nonnegative(),
me: z.boolean(),
name: z.string(),
url: z.string().url().optional(),
static_url: z.string().url().optional(),
accounts: z.array(z.lazy(() => User.schema)).optional(),
account_ids: z.array(z.string().uuid()).optional(),
}),
),
quote: z.lazy(() => Note.schema).nullable(),
bookmarked: z.boolean(),
});
save(): Promise<StatusWithRelations> {
return this.update(this.data);
}

View file

@ -65,7 +65,7 @@ import { Role } from "./role";
* Gives helpers to fetch users from database in a nice format
*/
export class User extends BaseInterface<typeof Users, UserWithRelations> {
static schema = z.object({
static schema: z.ZodType<ApiAccount> = z.object({
id: z.string(),
username: z.string(),
acct: z.string(),
@ -92,12 +92,12 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
z.object({
name: z.string(),
value: z.string(),
verified: z.boolean().nullable().optional(),
verified: z.boolean().optional(),
verified_at: z.string().nullable().optional(),
}),
),
// FIXME: Use a proper type
moved: z.any().nullable(),
moved: z.lazy(() => User.schema).nullable(),
bot: z.boolean().nullable(),
source: z
.object({
@ -105,6 +105,12 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
sensitive: z.boolean().nullable(),
language: z.string().nullable(),
note: z.string(),
fields: z.array(
z.object({
name: z.string(),
value: z.string(),
}),
),
})
.optional(),
role: z