mirror of
https://iceshrimp.dev/limepotato/jormungandr-bite.git
synced 2024-11-21 17:37:29 -07:00
[backend] More Web API rewrite preparations
This commit is contained in:
parent
71d171a953
commit
b9c86d0d4c
8 changed files with 62 additions and 42 deletions
|
@ -9,6 +9,6 @@ export class NoteController {
|
|||
@CurrentUser() me: ILocalUser | null,
|
||||
@Params('id') id: string,
|
||||
) {
|
||||
NoteHandler.getNote(me, id);
|
||||
NoteHandler.getNoteOrFail(me, id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import { Controller, Get, CurrentUser, Params, } from "@iceshrimp/koa-openapi";
|
|||
import type { ILocalUser } from "@/models/entities/user.js";
|
||||
import { NoteHandler } from "@/server/api/web/handlers/note.js";
|
||||
import { NoteResponse } from "@/server/api/web/entities/note.js";
|
||||
import { notFound } from "@hapi/boom";
|
||||
|
||||
@Controller('/note')
|
||||
export class NoteController {
|
||||
|
@ -10,6 +11,7 @@ export class NoteController {
|
|||
@CurrentUser() me: ILocalUser | null,
|
||||
@Params('id') id: string,
|
||||
): Promise<NoteResponse> {
|
||||
return NoteHandler.getNote(me, id);
|
||||
return NoteHandler.getNoteOrFail(id, notFound("No such note"))
|
||||
.then(note => NoteHandler.encodeOrFail(note, me));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Controller, CurrentUser, Get, Params, Query } from "@iceshrimp/koa-openapi";
|
||||
import { UserDetailedResponse, UserResponse } from "@/server/api/web/entities/user.js";
|
||||
import { UserResponse } from "@/server/api/web/entities/user.js";
|
||||
import { TimelineResponse } from "@/server/api/web/entities/note.js";
|
||||
import type { ILocalUser } from "@/models/entities/user.js";
|
||||
import { UserHandler } from "@/server/api/web/handlers/user.js";
|
||||
|
@ -11,10 +11,8 @@ export class UserController {
|
|||
@CurrentUser() me: ILocalUser | null,
|
||||
@Params('id') id: string,
|
||||
@Query('detail') detail: boolean
|
||||
): Promise<UserResponse | UserDetailedResponse> {
|
||||
return detail
|
||||
? UserHandler.getUser(me, id)
|
||||
: UserHandler.getUserDetailed(me, id);
|
||||
): Promise<UserResponse> {
|
||||
return UserHandler.getUser(me, id);
|
||||
}
|
||||
|
||||
@Get('/:id/notes')
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
|
||||
export namespace WebEntities {}
|
|
@ -1,13 +1,15 @@
|
|||
import { Note } from "@/models/entities/note.js";
|
||||
import { UserResponse } from "@/server/api/web/entities/user.js";
|
||||
|
||||
namespace WebEntities {
|
||||
export type NoteResponse = {
|
||||
id: Note["id"];
|
||||
export type NoteResponse = {
|
||||
id: Note["id"];
|
||||
text: string | null;
|
||||
user: UserResponse;
|
||||
reply: NoteResponse | undefined | null; // Undefined if no record, null if not visible
|
||||
renote: NoteResponse | undefined | null; // Undefined if no record, null if not visible
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
export type TimelineResponse = {
|
||||
notes: NoteResponse[],
|
||||
|
||||
};
|
||||
}
|
||||
export type TimelineResponse = {
|
||||
notes: NoteResponse[];
|
||||
pagination: {}; //TODO
|
||||
};
|
||||
|
|
|
@ -4,8 +4,3 @@ export type UserResponse = {
|
|||
avatarUrl?: string;
|
||||
bannerUrl?: string;
|
||||
}
|
||||
|
||||
export type UserDetailedResponse = UserResponse & {
|
||||
followers: number;
|
||||
following: number;
|
||||
}
|
||||
|
|
|
@ -1,17 +1,41 @@
|
|||
import { ILocalUser } from "@/models/entities/user.js";
|
||||
import { NoteResponse } from "@/server/api/web/entities/note.js";
|
||||
import { Notes } from "@/models/index.js";
|
||||
import { notFound } from "@hapi/boom";
|
||||
import { Boom, notFound, internal } from "@hapi/boom";
|
||||
import { Note } from "@/models/entities/note.js";
|
||||
import { UserHandler } from "@/server/api/web/handlers/user.js";
|
||||
import isQuote from "@/misc/is-quote.js";
|
||||
|
||||
export class NoteHandler {
|
||||
static async getNote(me: ILocalUser | null, id: string): Promise<NoteResponse> {
|
||||
const note = await Notes.findOneBy({ id });
|
||||
if (!note) throw notFound('No such user');
|
||||
|
||||
static async getNoteOrFail(id: string, error: Boom = internal('No such note')): Promise<Note> {
|
||||
const note = await this.getNote(id);
|
||||
if (!note) throw error;
|
||||
return note;
|
||||
}
|
||||
|
||||
static async encode(me: ILocalUser | null, id: string): Promise<NoteResponse | null> {
|
||||
static async getNote(id: string): Promise<Note | null> {
|
||||
return Notes.findOneBy({ id });
|
||||
}
|
||||
|
||||
static async encode(note: Note, me: ILocalUser | null, recurse: number = 2): Promise<NoteResponse | null> {
|
||||
if (!await Notes.isVisibleForMe(note, me?.id ?? null)) return null;
|
||||
|
||||
return {
|
||||
id: note.id,
|
||||
text: note.text,
|
||||
user: note.user ? await UserHandler.encode(note.user, me) : await UserHandler.getUser(me, note.userId),
|
||||
renote: note.renoteId && recurse > 0 ? await this.encode(note.renote ?? await this.getNoteOrFail(note.renoteId), me, isQuote(note) ? --recurse : 0) : undefined,
|
||||
reply: note.replyId && recurse > 0 ? await this.encode(note.renote ?? await this.getNoteOrFail(note.replyId), me, 0) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
static async encodeOrFail(note: Note, me: ILocalUser | null, error: Boom = internal("Cannot encode note not visible for user")): Promise<NoteResponse> {
|
||||
const result = await this.encode(note, me);
|
||||
if (!result) throw error;
|
||||
return result;
|
||||
}
|
||||
|
||||
static async encodeMany(notes: Note[], me: ILocalUser | null): Promise<NoteResponse[]> {
|
||||
return Promise.all(notes.map(n => this.encodeOrFail(n, me)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import { TimelineResponse } from "@/server/api/web/entities/note.js";
|
||||
import { UserDetailedResponse, UserResponse } from "@/server/api/web/entities/user.js";
|
||||
import { UserResponse } from "@/server/api/web/entities/user.js";
|
||||
import { Notes, UserProfiles, Users } from "@/models/index.js";
|
||||
import { makePaginationQuery } from "@/server/api/common/make-pagination-query.js";
|
||||
import { generateVisibilityQuery } from "@/server/api/common/generate-visibility-query.js";
|
||||
import { generateMutedUserQuery } from "@/server/api/common/generate-muted-user-query.js";
|
||||
import { generateBlockedUserQuery } from "@/server/api/common/generate-block-query.js";
|
||||
import { ILocalUser } from "@/models/entities/user.js";
|
||||
import { ILocalUser, User } from "@/models/entities/user.js";
|
||||
import { notFound } from "@hapi/boom";
|
||||
import { NoteHandler } from "@/server/api/web/handlers/note.js";
|
||||
|
||||
export class UserHandler {
|
||||
public static async getUserNotes(me: ILocalUser | null, id: string, limit: number, replies: boolean): Promise<TimelineResponse> {
|
||||
|
@ -31,12 +32,21 @@ export class UserHandler {
|
|||
query.andWhere("note.replyId IS NULL");
|
||||
}
|
||||
|
||||
return query.take(Math.min(limit, 100)).getMany();
|
||||
const result = query.take(Math.min(limit, 100)).getMany();
|
||||
return {
|
||||
notes: await NoteHandler.encodeMany(await result, me),
|
||||
pagination: {},
|
||||
}
|
||||
}
|
||||
|
||||
public static async getUser(me: ILocalUser | null, id: string): Promise<UserResponse> {
|
||||
const user = await Users.findOneBy({ id });
|
||||
if (!user) throw notFound('No such user');
|
||||
|
||||
return this.encode(user, me);
|
||||
}
|
||||
|
||||
public static async encode(user: User, me: ILocalUser | null): Promise<UserResponse> {
|
||||
return {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
|
@ -44,13 +54,4 @@ export class UserHandler {
|
|||
bannerUrl: user.bannerUrl ?? undefined,
|
||||
};
|
||||
}
|
||||
|
||||
public static async getUserDetailed(me: ILocalUser | null, id: string): Promise<UserDetailedResponse> {
|
||||
const profile = await UserProfiles.findOneBy({ userId: id });
|
||||
return {
|
||||
followers: 0,
|
||||
following: 0,
|
||||
...await this.getUser(me, id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue