mirror of
https://github.com/versia-pub/server.git
synced 2026-03-13 05:49:16 +01:00
refactor(api): ♻️ Convery more routes to use OpenAPI
This commit is contained in:
parent
1ab1c68d36
commit
b0b750c05d
6 changed files with 289 additions and 131 deletions
|
|
@ -1,10 +1,11 @@
|
|||
import { apiRoute, applyConfig, auth, handleZodError } from "@/api";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { apiRoute, applyConfig, auth } from "@/api";
|
||||
import { createRoute } from "@hono/zod-openapi";
|
||||
import ISO6391 from "iso-639-1";
|
||||
import { z } from "zod";
|
||||
import { RolePermissions } from "~/drizzle/schema";
|
||||
import { Relationship } from "~/packages/database-interface/relationship";
|
||||
import { User } from "~/packages/database-interface/user";
|
||||
import { ErrorSchema } from "~/types/api";
|
||||
|
||||
export const meta = applyConfig({
|
||||
allowedMethods: ["POST"],
|
||||
|
|
@ -41,42 +42,79 @@ export const schemas = {
|
|||
.default({ reblogs: true, notify: false, languages: [] }),
|
||||
};
|
||||
|
||||
export default apiRoute((app) =>
|
||||
app.on(
|
||||
meta.allowedMethods,
|
||||
meta.route,
|
||||
zValidator("param", schemas.param, handleZodError),
|
||||
zValidator("json", schemas.json, handleZodError),
|
||||
auth(meta.auth, meta.permissions),
|
||||
async (context) => {
|
||||
const { id } = context.req.valid("param");
|
||||
const { user } = context.get("auth");
|
||||
const { reblogs, notify, languages } = context.req.valid("json");
|
||||
|
||||
if (!user) {
|
||||
return context.json({ error: "Unauthorized" }, 401);
|
||||
}
|
||||
|
||||
const otherUser = await User.fromId(id);
|
||||
|
||||
if (!otherUser) {
|
||||
return context.json({ error: "User not found" }, 404);
|
||||
}
|
||||
|
||||
let relationship = await Relationship.fromOwnerAndSubject(
|
||||
user,
|
||||
otherUser,
|
||||
);
|
||||
|
||||
if (!relationship.data.following) {
|
||||
relationship = await user.followRequest(otherUser, {
|
||||
reblogs,
|
||||
notify,
|
||||
languages,
|
||||
});
|
||||
}
|
||||
|
||||
return context.json(relationship.toApi());
|
||||
const route = createRoute({
|
||||
method: "post",
|
||||
path: "/api/v1/accounts/{id}/follow",
|
||||
summary: "Follow user",
|
||||
description: "Follow a user",
|
||||
middleware: [auth(meta.auth, meta.permissions)],
|
||||
responses: {
|
||||
200: {
|
||||
description: "User followed",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: Relationship.schema,
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
401: {
|
||||
description: "Unauthorized",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: ErrorSchema,
|
||||
},
|
||||
},
|
||||
},
|
||||
404: {
|
||||
description: "User not found",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: ErrorSchema,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
request: {
|
||||
params: schemas.param,
|
||||
body: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: schemas.json,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default apiRoute((app) =>
|
||||
app.openapi(route, async (context) => {
|
||||
const { id } = context.req.valid("param");
|
||||
const { user } = context.get("auth");
|
||||
const { reblogs, notify, languages } = context.req.valid("json");
|
||||
|
||||
if (!user) {
|
||||
return context.json({ error: "Unauthorized" }, 401);
|
||||
}
|
||||
|
||||
const otherUser = await User.fromId(id);
|
||||
|
||||
if (!otherUser) {
|
||||
return context.json({ error: "User not found" }, 404);
|
||||
}
|
||||
|
||||
let relationship = await Relationship.fromOwnerAndSubject(
|
||||
user,
|
||||
otherUser,
|
||||
);
|
||||
|
||||
if (!relationship.data.following) {
|
||||
relationship = await user.followRequest(otherUser, {
|
||||
reblogs,
|
||||
notify,
|
||||
languages,
|
||||
});
|
||||
}
|
||||
|
||||
return context.json(relationship.toApi(), 200);
|
||||
}),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,16 +1,11 @@
|
|||
import {
|
||||
apiRoute,
|
||||
applyConfig,
|
||||
auth,
|
||||
handleZodError,
|
||||
idValidator,
|
||||
} from "@/api";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { apiRoute, applyConfig, auth, idValidator } from "@/api";
|
||||
import { createRoute } from "@hono/zod-openapi";
|
||||
import { and, gt, gte, lt, sql } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { RolePermissions, Users } from "~/drizzle/schema";
|
||||
import { Timeline } from "~/packages/database-interface/timeline";
|
||||
import { User } from "~/packages/database-interface/user";
|
||||
import { ErrorSchema } from "~/types/api";
|
||||
|
||||
export const meta = applyConfig({
|
||||
allowedMethods: ["GET"],
|
||||
|
|
@ -43,44 +38,72 @@ export const schemas = {
|
|||
}),
|
||||
};
|
||||
|
||||
export default apiRoute((app) =>
|
||||
app.on(
|
||||
meta.allowedMethods,
|
||||
meta.route,
|
||||
zValidator("query", schemas.query, handleZodError),
|
||||
zValidator("param", schemas.param, handleZodError),
|
||||
auth(meta.auth, meta.permissions),
|
||||
async (context) => {
|
||||
const { id } = context.req.valid("param");
|
||||
const { max_id, since_id, min_id, limit } =
|
||||
context.req.valid("query");
|
||||
|
||||
const otherUser = await User.fromId(id);
|
||||
|
||||
// TODO: Add follower/following privacy settings
|
||||
|
||||
if (!otherUser) {
|
||||
return context.json({ error: "User not found" }, 404);
|
||||
}
|
||||
|
||||
const { objects, link } = await Timeline.getUserTimeline(
|
||||
and(
|
||||
max_id ? lt(Users.id, max_id) : undefined,
|
||||
since_id ? gte(Users.id, since_id) : undefined,
|
||||
min_id ? gt(Users.id, min_id) : undefined,
|
||||
sql`EXISTS (SELECT 1 FROM "Relationships" WHERE "Relationships"."subjectId" = ${otherUser.id} AND "Relationships"."ownerId" = ${Users.id} AND "Relationships"."following" = true)`,
|
||||
),
|
||||
limit,
|
||||
context.req.url,
|
||||
);
|
||||
|
||||
return context.json(
|
||||
await Promise.all(objects.map((object) => object.toApi())),
|
||||
200,
|
||||
{
|
||||
Link: link,
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
path: "/api/v1/accounts/{id}/followers",
|
||||
summary: "Get account followers",
|
||||
description:
|
||||
"Gets an paginated list of accounts that follow the specified account",
|
||||
middleware: [auth(meta.auth, meta.permissions)],
|
||||
request: {
|
||||
params: schemas.param,
|
||||
query: schemas.query,
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: "A list of accounts that follow the specified account",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.array(User.schema),
|
||||
},
|
||||
);
|
||||
},
|
||||
headers: {
|
||||
Link: {
|
||||
description: "Links to the next and previous pages",
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
404: {
|
||||
description: "The specified account was not found",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: ErrorSchema,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default apiRoute((app) =>
|
||||
app.openapi(route, async (context) => {
|
||||
const { id } = context.req.valid("param");
|
||||
const { max_id, since_id, min_id, limit } = context.req.valid("query");
|
||||
|
||||
const otherUser = await User.fromId(id);
|
||||
|
||||
// TODO: Add follower/following privacy settings
|
||||
|
||||
if (!otherUser) {
|
||||
return context.json({ error: "User not found" }, 404);
|
||||
}
|
||||
|
||||
const { objects, link } = await Timeline.getUserTimeline(
|
||||
and(
|
||||
max_id ? lt(Users.id, max_id) : undefined,
|
||||
since_id ? gte(Users.id, since_id) : undefined,
|
||||
min_id ? gt(Users.id, min_id) : undefined,
|
||||
sql`EXISTS (SELECT 1 FROM "Relationships" WHERE "Relationships"."subjectId" = ${otherUser.id} AND "Relationships"."ownerId" = ${Users.id} AND "Relationships"."following" = true)`,
|
||||
),
|
||||
limit,
|
||||
context.req.url,
|
||||
);
|
||||
|
||||
return context.json(
|
||||
await Promise.all(objects.map((object) => object.toApi())),
|
||||
200,
|
||||
{
|
||||
Link: link,
|
||||
},
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,16 +1,11 @@
|
|||
import {
|
||||
apiRoute,
|
||||
applyConfig,
|
||||
auth,
|
||||
handleZodError,
|
||||
idValidator,
|
||||
} from "@/api";
|
||||
import { zValidator } from "@hono/zod-validator";
|
||||
import { apiRoute, applyConfig, auth, idValidator } from "@/api";
|
||||
import { createRoute } from "@hono/zod-openapi";
|
||||
import { and, gt, gte, lt, sql } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { RolePermissions, Users } from "~/drizzle/schema";
|
||||
import { Timeline } from "~/packages/database-interface/timeline";
|
||||
import { User } from "~/packages/database-interface/user";
|
||||
import { ErrorSchema } from "~/types/api";
|
||||
|
||||
export const meta = applyConfig({
|
||||
allowedMethods: ["GET"],
|
||||
|
|
@ -43,43 +38,73 @@ export const schemas = {
|
|||
}),
|
||||
};
|
||||
|
||||
export default apiRoute((app) =>
|
||||
app.on(
|
||||
meta.allowedMethods,
|
||||
meta.route,
|
||||
zValidator("query", schemas.query, handleZodError),
|
||||
zValidator("param", schemas.param, handleZodError),
|
||||
auth(meta.auth, meta.permissions),
|
||||
async (context) => {
|
||||
const { id } = context.req.valid("param");
|
||||
const { max_id, since_id, min_id } = context.req.valid("query");
|
||||
|
||||
const otherUser = await User.fromId(id);
|
||||
|
||||
if (!otherUser) {
|
||||
return context.json({ error: "User not found" }, 404);
|
||||
}
|
||||
|
||||
// TODO: Add follower/following privacy settings
|
||||
|
||||
const { objects, link } = await Timeline.getUserTimeline(
|
||||
and(
|
||||
max_id ? lt(Users.id, max_id) : undefined,
|
||||
since_id ? gte(Users.id, since_id) : undefined,
|
||||
min_id ? gt(Users.id, min_id) : undefined,
|
||||
sql`EXISTS (SELECT 1 FROM "Relationships" WHERE "Relationships"."subjectId" = ${Users.id} AND "Relationships"."ownerId" = ${otherUser.id} AND "Relationships"."following" = true)`,
|
||||
),
|
||||
context.req.valid("query").limit,
|
||||
context.req.url,
|
||||
);
|
||||
|
||||
return context.json(
|
||||
await Promise.all(objects.map((object) => object.toApi())),
|
||||
200,
|
||||
{
|
||||
Link: link,
|
||||
const route = createRoute({
|
||||
method: "get",
|
||||
path: "/api/v1/accounts/{id}/following",
|
||||
summary: "Get account following",
|
||||
description:
|
||||
"Gets an paginated list of accounts that the specified account follows",
|
||||
middleware: [auth(meta.auth, meta.permissions)],
|
||||
request: {
|
||||
params: schemas.param,
|
||||
query: schemas.query,
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description:
|
||||
"A list of accounts that the specified account follows",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.array(User.schema),
|
||||
},
|
||||
);
|
||||
},
|
||||
headers: {
|
||||
Link: {
|
||||
description: "Link to the next page of results",
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
404: {
|
||||
description: "User not found",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: ErrorSchema,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default apiRoute((app) =>
|
||||
app.openapi(route, async (context) => {
|
||||
const { id } = context.req.valid("param");
|
||||
const { max_id, since_id, min_id } = context.req.valid("query");
|
||||
|
||||
const otherUser = await User.fromId(id);
|
||||
|
||||
if (!otherUser) {
|
||||
return context.json({ error: "User not found" }, 404);
|
||||
}
|
||||
|
||||
// TODO: Add follower/following privacy settings
|
||||
|
||||
const { objects, link } = await Timeline.getUserTimeline(
|
||||
and(
|
||||
max_id ? lt(Users.id, max_id) : undefined,
|
||||
since_id ? gte(Users.id, since_id) : undefined,
|
||||
min_id ? gt(Users.id, min_id) : undefined,
|
||||
sql`EXISTS (SELECT 1 FROM "Relationships" WHERE "Relationships"."subjectId" = ${Users.id} AND "Relationships"."ownerId" = ${otherUser.id} AND "Relationships"."following" = true)`,
|
||||
),
|
||||
context.req.valid("query").limit,
|
||||
context.req.url,
|
||||
);
|
||||
|
||||
return context.json(
|
||||
await Promise.all(objects.map((object) => object.toApi())),
|
||||
200,
|
||||
{
|
||||
Link: link,
|
||||
},
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue