summaryrefslogtreecommitdiff
path: root/packages/backend/src/server/api/endpoints/notes/create.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/backend/src/server/api/endpoints/notes/create.ts')
-rw-r--r--packages/backend/src/server/api/endpoints/notes/create.ts234
1 files changed, 130 insertions, 104 deletions
diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts
index a133294169..30b7a889fc 100644
--- a/packages/backend/src/server/api/endpoints/notes/create.ts
+++ b/packages/backend/src/server/api/endpoints/notes/create.ts
@@ -1,15 +1,18 @@
import ms from 'ms';
import { In } from 'typeorm';
-import create from '@/services/note/create.js';
-import { User } from '@/models/entities/user.js';
-import { Users, DriveFiles, Notes, Channels, Blockings } from '@/models/index.js';
-import { DriveFile } from '@/models/entities/drive-file.js';
-import { Note } from '@/models/entities/note.js';
-import { Channel } from '@/models/entities/channel.js';
+import { Inject, Injectable } from '@nestjs/common';
+import type { User } from '@/models/entities/User.js';
+import { UsersRepository, NotesRepository, BlockingsRepository, DriveFilesRepository, ChannelsRepository } from '@/models/index.js';
+import type { DriveFile } from '@/models/entities/DriveFile.js';
+import type { Note } from '@/models/entities/Note.js';
+import type { Channel } from '@/models/entities/Channel.js';
import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
+import { Endpoint } from '@/server/api/endpoint-base.js';
+import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
+import { NoteCreateService } from '@/core/NoteCreateService.js';
+import { DI } from '@/di-symbols.js';
import { noteVisibilities } from '../../../../types.js';
import { ApiError } from '../../error.js';
-import define from '../../define.js';
export const meta = {
tags: ['notes'],
@@ -161,115 +164,138 @@ export const paramDef = {
} as const;
// eslint-disable-next-line import/no-default-export
-export default define(meta, paramDef, async (ps, user) => {
- let visibleUsers: User[] = [];
- if (ps.visibleUserIds) {
- visibleUsers = await Users.findBy({
- id: In(ps.visibleUserIds),
- });
- }
+@Injectable()
+export default class extends Endpoint<typeof meta, typeof paramDef> {
+ constructor(
+ @Inject(DI.usersRepository)
+ private usersRepository: UsersRepository,
- let files: DriveFile[] = [];
- const fileIds = ps.fileIds != null ? ps.fileIds : ps.mediaIds != null ? ps.mediaIds : null;
- if (fileIds != null) {
- files = await DriveFiles.createQueryBuilder('file')
- .where('file.userId = :userId AND file.id IN (:...fileIds)', {
- userId: user.id,
- fileIds,
- })
- .orderBy('array_position(ARRAY[:...fileIds], "id"::text)')
- .setParameters({ fileIds })
- .getMany();
- }
+ @Inject(DI.notesRepository)
+ private notesRepository: NotesRepository,
- let renote: Note | null = null;
- if (ps.renoteId != null) {
- // Fetch renote to note
- renote = await Notes.findOneBy({ id: ps.renoteId });
+ @Inject(DI.blockingsRepository)
+ private blockingsRepository: BlockingsRepository,
- if (renote == null) {
- throw new ApiError(meta.errors.noSuchRenoteTarget);
- } else if (renote.renoteId && !renote.text && !renote.fileIds && !renote.hasPoll) {
- throw new ApiError(meta.errors.cannotReRenote);
- }
+ @Inject(DI.driveFilesRepository)
+ private driveFilesRepository: DriveFilesRepository,
- // Check blocking
- if (renote.userId !== user.id) {
- const block = await Blockings.findOneBy({
- blockerId: renote.userId,
- blockeeId: user.id,
- });
- if (block) {
- throw new ApiError(meta.errors.youHaveBeenBlocked);
+ @Inject(DI.channelsRepository)
+ private channelsRepository: ChannelsRepository,
+
+ private noteEntityService: NoteEntityService,
+ private noteCreateService: NoteCreateService,
+ ) {
+ super(meta, paramDef, async (ps, me) => {
+ let visibleUsers: User[] = [];
+ if (ps.visibleUserIds) {
+ visibleUsers = await this.usersRepository.findBy({
+ id: In(ps.visibleUserIds),
+ });
}
- }
- }
- let reply: Note | null = null;
- if (ps.replyId != null) {
- // Fetch reply
- reply = await Notes.findOneBy({ id: ps.replyId });
+ let files: DriveFile[] = [];
+ const fileIds = ps.fileIds != null ? ps.fileIds : ps.mediaIds != null ? ps.mediaIds : null;
+ if (fileIds != null) {
+ files = await this.driveFilesRepository.createQueryBuilder('file')
+ .where('file.userId = :userId AND file.id IN (:...fileIds)', {
+ userId: me.id,
+ fileIds,
+ })
+ .orderBy('array_position(ARRAY[:...fileIds], "id"::text)')
+ .setParameters({ fileIds })
+ .getMany();
+ }
- if (reply == null) {
- throw new ApiError(meta.errors.noSuchReplyTarget);
- } else if (reply.renoteId && !reply.text && !reply.fileIds && !reply.hasPoll) {
- throw new ApiError(meta.errors.cannotReplyToPureRenote);
- }
+ let renote: Note | null = null;
+ if (ps.renoteId != null) {
+ // Fetch renote to note
+ renote = await this.notesRepository.findOneBy({ id: ps.renoteId });
- // Check blocking
- if (reply.userId !== user.id) {
- const block = await Blockings.findOneBy({
- blockerId: reply.userId,
- blockeeId: user.id,
- });
- if (block) {
- throw new ApiError(meta.errors.youHaveBeenBlocked);
+ if (renote == null) {
+ throw new ApiError(meta.errors.noSuchRenoteTarget);
+ } else if (renote.renoteId && !renote.text && !renote.fileIds && !renote.hasPoll) {
+ throw new ApiError(meta.errors.cannotReRenote);
+ }
+
+ // Check blocking
+ if (renote.userId !== me.id) {
+ const block = await this.blockingsRepository.findOneBy({
+ blockerId: renote.userId,
+ blockeeId: me.id,
+ });
+ if (block) {
+ throw new ApiError(meta.errors.youHaveBeenBlocked);
+ }
+ }
}
- }
- }
- if (ps.poll) {
- if (typeof ps.poll.expiresAt === 'number') {
- if (ps.poll.expiresAt < Date.now()) {
- throw new ApiError(meta.errors.cannotCreateAlreadyExpiredPoll);
+ let reply: Note | null = null;
+ if (ps.replyId != null) {
+ // Fetch reply
+ reply = await this.notesRepository.findOneBy({ id: ps.replyId });
+
+ if (reply == null) {
+ throw new ApiError(meta.errors.noSuchReplyTarget);
+ } else if (reply.renoteId && !reply.text && !reply.fileIds && !reply.hasPoll) {
+ throw new ApiError(meta.errors.cannotReplyToPureRenote);
+ }
+
+ // Check blocking
+ if (reply.userId !== me.id) {
+ const block = await this.blockingsRepository.findOneBy({
+ blockerId: reply.userId,
+ blockeeId: me.id,
+ });
+ if (block) {
+ throw new ApiError(meta.errors.youHaveBeenBlocked);
+ }
+ }
}
- } else if (typeof ps.poll.expiredAfter === 'number') {
- ps.poll.expiresAt = Date.now() + ps.poll.expiredAfter;
- }
- }
- let channel: Channel | null = null;
- if (ps.channelId != null) {
- channel = await Channels.findOneBy({ id: ps.channelId });
+ if (ps.poll) {
+ if (typeof ps.poll.expiresAt === 'number') {
+ if (ps.poll.expiresAt < Date.now()) {
+ throw new ApiError(meta.errors.cannotCreateAlreadyExpiredPoll);
+ }
+ } else if (typeof ps.poll.expiredAfter === 'number') {
+ ps.poll.expiresAt = Date.now() + ps.poll.expiredAfter;
+ }
+ }
- if (channel == null) {
- throw new ApiError(meta.errors.noSuchChannel);
- }
- }
+ let channel: Channel | null = null;
+ if (ps.channelId != null) {
+ channel = await this.channelsRepository.findOneBy({ id: ps.channelId });
- // 投稿を作成
- const note = await create(user, {
- createdAt: new Date(),
- files: files,
- poll: ps.poll ? {
- choices: ps.poll.choices,
- multiple: ps.poll.multiple || false,
- expiresAt: ps.poll.expiresAt ? new Date(ps.poll.expiresAt) : null,
- } : undefined,
- text: ps.text || undefined,
- reply,
- renote,
- cw: ps.cw,
- localOnly: ps.localOnly,
- visibility: ps.visibility,
- visibleUsers,
- channel,
- apMentions: ps.noExtractMentions ? [] : undefined,
- apHashtags: ps.noExtractHashtags ? [] : undefined,
- apEmojis: ps.noExtractEmojis ? [] : undefined,
- });
+ if (channel == null) {
+ throw new ApiError(meta.errors.noSuchChannel);
+ }
+ }
+
+ // 投稿を作成
+ const note = await this.noteCreateService.create(me, {
+ createdAt: new Date(),
+ files: files,
+ poll: ps.poll ? {
+ choices: ps.poll.choices,
+ multiple: ps.poll.multiple || false,
+ expiresAt: ps.poll.expiresAt ? new Date(ps.poll.expiresAt) : null,
+ } : undefined,
+ text: ps.text ?? undefined,
+ reply,
+ renote,
+ cw: ps.cw,
+ localOnly: ps.localOnly,
+ visibility: ps.visibility,
+ visibleUsers,
+ channel,
+ apMentions: ps.noExtractMentions ? [] : undefined,
+ apHashtags: ps.noExtractHashtags ? [] : undefined,
+ apEmojis: ps.noExtractEmojis ? [] : undefined,
+ });
- return {
- createdNote: await Notes.pack(note, user),
- };
-});
+ return {
+ createdNote: await this.noteEntityService.pack(note, me),
+ };
+ });
+ }
+}