summaryrefslogtreecommitdiff
path: root/src/server/api/endpoints/notes
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/api/endpoints/notes')
-rw-r--r--src/server/api/endpoints/notes/children.ts72
-rw-r--r--src/server/api/endpoints/notes/clips.ts55
-rw-r--r--src/server/api/endpoints/notes/conversation.ts81
-rw-r--r--src/server/api/endpoints/notes/create.ts299
-rw-r--r--src/server/api/endpoints/notes/delete.ts56
-rw-r--r--src/server/api/endpoints/notes/favorites/create.ts61
-rw-r--r--src/server/api/endpoints/notes/favorites/delete.ts55
-rw-r--r--src/server/api/endpoints/notes/featured.ts64
-rw-r--r--src/server/api/endpoints/notes/global-timeline.ts101
-rw-r--r--src/server/api/endpoints/notes/hybrid-timeline.ts158
-rw-r--r--src/server/api/endpoints/notes/local-timeline.ts129
-rw-r--r--src/server/api/endpoints/notes/mentions.ts88
-rw-r--r--src/server/api/endpoints/notes/polls/recommendation.ts77
-rw-r--r--src/server/api/endpoints/notes/polls/vote.ts170
-rw-r--r--src/server/api/endpoints/notes/reactions.ts90
-rw-r--r--src/server/api/endpoints/notes/reactions/create.ts57
-rw-r--r--src/server/api/endpoints/notes/reactions/delete.ts52
-rw-r--r--src/server/api/endpoints/notes/renotes.ts76
-rw-r--r--src/server/api/endpoints/notes/replies.ts61
-rw-r--r--src/server/api/endpoints/notes/search-by-tag.ts134
-rw-r--r--src/server/api/endpoints/notes/search.ts152
-rw-r--r--src/server/api/endpoints/notes/show.ts43
-rw-r--r--src/server/api/endpoints/notes/state.ts69
-rw-r--r--src/server/api/endpoints/notes/thread-muting/create.ts54
-rw-r--r--src/server/api/endpoints/notes/thread-muting/delete.ts40
-rw-r--r--src/server/api/endpoints/notes/timeline.ts150
-rw-r--r--src/server/api/endpoints/notes/translate.ts89
-rw-r--r--src/server/api/endpoints/notes/unrenote.ts52
-rw-r--r--src/server/api/endpoints/notes/user-list-timeline.ts147
-rw-r--r--src/server/api/endpoints/notes/watching/create.ts37
-rw-r--r--src/server/api/endpoints/notes/watching/delete.ts37
31 files changed, 0 insertions, 2806 deletions
diff --git a/src/server/api/endpoints/notes/children.ts b/src/server/api/endpoints/notes/children.ts
deleted file mode 100644
index 68881fda9e..0000000000
--- a/src/server/api/endpoints/notes/children.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../define';
-import { makePaginationQuery } from '../../common/make-pagination-query';
-import { generateVisibilityQuery } from '../../common/generate-visibility-query';
-import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
-import { Brackets } from 'typeorm';
-import { Notes } from '@/models/index';
-import { generateBlockedUserQuery } from '../../common/generate-block-query';
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: false as const,
-
- params: {
- noteId: {
- validator: $.type(ID),
- },
-
- limit: {
- validator: $.optional.num.range(1, 100),
- default: 10
- },
-
- sinceId: {
- validator: $.optional.type(ID),
- },
-
- untilId: {
- validator: $.optional.type(ID),
- },
- },
-
- res: {
- type: 'array' as const,
- optional: false as const, nullable: false as const,
- items: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- ref: 'Note',
- }
- },
-};
-
-export default define(meta, async (ps, user) => {
- const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId)
- .andWhere(new Brackets(qb => { qb
- .where(`note.replyId = :noteId`, { noteId: ps.noteId })
- .orWhere(new Brackets(qb => { qb
- .where(`note.renoteId = :noteId`, { noteId: ps.noteId })
- .andWhere(new Brackets(qb => { qb
- .where(`note.text IS NOT NULL`)
- .orWhere(`note.fileIds != '{}'`)
- .orWhere(`note.hasPoll = TRUE`);
- }));
- }));
- }))
- .innerJoinAndSelect('note.user', 'user')
- .leftJoinAndSelect('note.reply', 'reply')
- .leftJoinAndSelect('note.renote', 'renote')
- .leftJoinAndSelect('reply.user', 'replyUser')
- .leftJoinAndSelect('renote.user', 'renoteUser');
-
- generateVisibilityQuery(query, user);
- if (user) generateMutedUserQuery(query, user);
- if (user) generateBlockedUserQuery(query, user);
-
- const notes = await query.take(ps.limit!).getMany();
-
- return await Notes.packMany(notes, user);
-});
diff --git a/src/server/api/endpoints/notes/clips.ts b/src/server/api/endpoints/notes/clips.ts
deleted file mode 100644
index 6b303d87ec..0000000000
--- a/src/server/api/endpoints/notes/clips.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../define';
-import { ClipNotes, Clips } from '@/models/index';
-import { getNote } from '../../common/getters';
-import { ApiError } from '../../error';
-import { In } from 'typeorm';
-
-export const meta = {
- tags: ['clips', 'notes'],
-
- requireCredential: false as const,
-
- params: {
- noteId: {
- validator: $.type(ID),
- },
- },
-
- res: {
- type: 'array' as const,
- optional: false as const, nullable: false as const,
- items: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- ref: 'Note',
- }
- },
-
- errors: {
- noSuchNote: {
- message: 'No such note.',
- code: 'NO_SUCH_NOTE',
- id: '47db1a1c-b0af-458d-8fb4-986e4efafe1e'
- }
- }
-};
-
-export default define(meta, async (ps, me) => {
- const note = await getNote(ps.noteId).catch(e => {
- if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
- throw e;
- });
-
- const clipNotes = await ClipNotes.find({
- noteId: note.id,
- });
-
- const clips = await Clips.find({
- id: In(clipNotes.map(x => x.clipId)),
- isPublic: true
- });
-
- return await Promise.all(clips.map(x => Clips.pack(x)));
-});
diff --git a/src/server/api/endpoints/notes/conversation.ts b/src/server/api/endpoints/notes/conversation.ts
deleted file mode 100644
index 0fe323ea00..0000000000
--- a/src/server/api/endpoints/notes/conversation.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../define';
-import { ApiError } from '../../error';
-import { getNote } from '../../common/getters';
-import { Note } from '@/models/entities/note';
-import { Notes } from '@/models/index';
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: false as const,
-
- params: {
- noteId: {
- validator: $.type(ID),
- },
-
- limit: {
- validator: $.optional.num.range(1, 100),
- default: 10
- },
-
- offset: {
- validator: $.optional.num.min(0),
- default: 0
- },
- },
-
- res: {
- type: 'array' as const,
- optional: false as const, nullable: false as const,
- items: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- ref: 'Note',
- }
- },
-
- errors: {
- noSuchNote: {
- message: 'No such note.',
- code: 'NO_SUCH_NOTE',
- id: 'e1035875-9551-45ec-afa8-1ded1fcb53c8'
- }
- }
-};
-
-export default define(meta, async (ps, user) => {
- const note = await getNote(ps.noteId).catch(e => {
- if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
- throw e;
- });
-
- const conversation: Note[] = [];
- let i = 0;
-
- async function get(id: any) {
- i++;
- const p = await Notes.findOne(id);
- if (p == null) return;
-
- if (i > ps.offset!) {
- conversation.push(p);
- }
-
- if (conversation.length == ps.limit!) {
- return;
- }
-
- if (p.replyId) {
- await get(p.replyId);
- }
- }
-
- if (note.replyId) {
- await get(note.replyId);
- }
-
- return await Notes.packMany(conversation, user);
-});
diff --git a/src/server/api/endpoints/notes/create.ts b/src/server/api/endpoints/notes/create.ts
deleted file mode 100644
index 751673f955..0000000000
--- a/src/server/api/endpoints/notes/create.ts
+++ /dev/null
@@ -1,299 +0,0 @@
-import $ from 'cafy';
-import * as ms from 'ms';
-import { length } from 'stringz';
-import create from '@/services/note/create';
-import define from '../../define';
-import { fetchMeta } from '@/misc/fetch-meta';
-import { ApiError } from '../../error';
-import { ID } from '@/misc/cafy-id';
-import { User } from '@/models/entities/user';
-import { Users, DriveFiles, Notes, Channels, Blockings } from '@/models/index';
-import { DriveFile } from '@/models/entities/drive-file';
-import { Note } from '@/models/entities/note';
-import { DB_MAX_NOTE_TEXT_LENGTH } from '@/misc/hard-limits';
-import { noteVisibilities } from '../../../../types';
-import { Channel } from '@/models/entities/channel';
-
-let maxNoteTextLength = 500;
-
-setInterval(() => {
- fetchMeta().then(m => {
- maxNoteTextLength = m.maxNoteTextLength;
- });
-}, 3000);
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: true as const,
-
- limit: {
- duration: ms('1hour'),
- max: 300
- },
-
- kind: 'write:notes',
-
- params: {
- visibility: {
- validator: $.optional.str.or(noteVisibilities as unknown as string[]),
- default: 'public',
- },
-
- visibleUserIds: {
- validator: $.optional.arr($.type(ID)).unique().min(0),
- },
-
- text: {
- validator: $.optional.nullable.str.pipe(text =>
- text.trim() != ''
- && length(text.trim()) <= maxNoteTextLength
- && Array.from(text.trim()).length <= DB_MAX_NOTE_TEXT_LENGTH // DB limit
- ),
- default: null,
- },
-
- cw: {
- validator: $.optional.nullable.str.pipe(Notes.validateCw),
- },
-
- viaMobile: {
- validator: $.optional.bool,
- default: false,
- },
-
- localOnly: {
- validator: $.optional.bool,
- default: false,
- },
-
- noExtractMentions: {
- validator: $.optional.bool,
- default: false,
- },
-
- noExtractHashtags: {
- validator: $.optional.bool,
- default: false,
- },
-
- noExtractEmojis: {
- validator: $.optional.bool,
- default: false,
- },
-
- fileIds: {
- validator: $.optional.arr($.type(ID)).unique().range(1, 4),
- },
-
- mediaIds: {
- validator: $.optional.arr($.type(ID)).unique().range(1, 4),
- deprecated: true,
- },
-
- replyId: {
- validator: $.optional.nullable.type(ID),
- },
-
- renoteId: {
- validator: $.optional.nullable.type(ID),
- },
-
- channelId: {
- validator: $.optional.nullable.type(ID),
- },
-
- poll: {
- validator: $.optional.nullable.obj({
- choices: $.arr($.str)
- .unique()
- .range(2, 10)
- .each(c => c.length > 0 && c.length < 50),
- multiple: $.optional.bool,
- expiresAt: $.optional.nullable.num.int(),
- expiredAfter: $.optional.nullable.num.int().min(1)
- }).strict(),
- ref: 'poll'
- }
- },
-
- res: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- properties: {
- createdNote: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- ref: 'Note',
- }
- }
- },
-
- errors: {
- noSuchRenoteTarget: {
- message: 'No such renote target.',
- code: 'NO_SUCH_RENOTE_TARGET',
- id: 'b5c90186-4ab0-49c8-9bba-a1f76c282ba4'
- },
-
- cannotReRenote: {
- message: 'You can not Renote a pure Renote.',
- code: 'CANNOT_RENOTE_TO_A_PURE_RENOTE',
- id: 'fd4cc33e-2a37-48dd-99cc-9b806eb2031a'
- },
-
- noSuchReplyTarget: {
- message: 'No such reply target.',
- code: 'NO_SUCH_REPLY_TARGET',
- id: '749ee0f6-d3da-459a-bf02-282e2da4292c'
- },
-
- cannotReplyToPureRenote: {
- message: 'You can not reply to a pure Renote.',
- code: 'CANNOT_REPLY_TO_A_PURE_RENOTE',
- id: '3ac74a84-8fd5-4bb0-870f-01804f82ce15'
- },
-
- contentRequired: {
- message: 'Content required. You need to set text, fileIds, renoteId or poll.',
- code: 'CONTENT_REQUIRED',
- id: '6f57e42b-c348-439b-bc45-993995cc515a'
- },
-
- cannotCreateAlreadyExpiredPoll: {
- message: 'Poll is already expired.',
- code: 'CANNOT_CREATE_ALREADY_EXPIRED_POLL',
- id: '04da457d-b083-4055-9082-955525eda5a5'
- },
-
- noSuchChannel: {
- message: 'No such channel.',
- code: 'NO_SUCH_CHANNEL',
- id: 'b1653923-5453-4edc-b786-7c4f39bb0bbb'
- },
-
- youHaveBeenBlocked: {
- message: 'You have been blocked by this user.',
- code: 'YOU_HAVE_BEEN_BLOCKED',
- id: 'b390d7e1-8a5e-46ed-b625-06271cafd3d3'
- },
- }
-};
-
-export default define(meta, async (ps, user) => {
- let visibleUsers: User[] = [];
- if (ps.visibleUserIds) {
- visibleUsers = (await Promise.all(ps.visibleUserIds.map(id => Users.findOne(id))))
- .filter(x => x != null) as User[];
- }
-
- let files: DriveFile[] = [];
- const fileIds = ps.fileIds != null ? ps.fileIds : ps.mediaIds != null ? ps.mediaIds : null;
- if (fileIds != null) {
- files = (await Promise.all(fileIds.map(fileId =>
- DriveFiles.findOne({
- id: fileId,
- userId: user.id
- })
- ))).filter(file => file != null) as DriveFile[];
- }
-
- let renote: Note | undefined;
- if (ps.renoteId != null) {
- // Fetch renote to note
- renote = await Notes.findOne(ps.renoteId);
-
- if (renote == null) {
- throw new ApiError(meta.errors.noSuchRenoteTarget);
- } else if (renote.renoteId && !renote.text && !renote.fileIds) {
- throw new ApiError(meta.errors.cannotReRenote);
- }
-
- // Check blocking
- if (renote.userId !== user.id) {
- const block = await Blockings.findOne({
- blockerId: renote.userId,
- blockeeId: user.id,
- });
- if (block) {
- throw new ApiError(meta.errors.youHaveBeenBlocked);
- }
- }
- }
-
- let reply: Note | undefined;
- if (ps.replyId != null) {
- // Fetch reply
- reply = await Notes.findOne(ps.replyId);
-
- if (reply == null) {
- throw new ApiError(meta.errors.noSuchReplyTarget);
- }
-
- // 返信対象が引用でないRenoteだったらエラー
- if (reply.renoteId && !reply.text && !reply.fileIds) {
- throw new ApiError(meta.errors.cannotReplyToPureRenote);
- }
-
- // Check blocking
- if (reply.userId !== user.id) {
- const block = await Blockings.findOne({
- blockerId: reply.userId,
- blockeeId: user.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);
- } else if (typeof ps.poll.expiredAfter === 'number') {
- ps.poll.expiresAt = Date.now() + ps.poll.expiredAfter;
- }
- }
-
- // テキストが無いかつ添付ファイルが無いかつRenoteも無いかつ投票も無かったらエラー
- if (!(ps.text || files.length || renote || ps.poll)) {
- throw new ApiError(meta.errors.contentRequired);
- }
-
- let channel: Channel | undefined;
- if (ps.channelId != null) {
- channel = await Channels.findOne(ps.channelId);
-
- if (channel == null) {
- throw new ApiError(meta.errors.noSuchChannel);
- }
- }
-
- // 投稿を作成
- 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,
- viaMobile: ps.viaMobile,
- 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)
- };
-});
diff --git a/src/server/api/endpoints/notes/delete.ts b/src/server/api/endpoints/notes/delete.ts
deleted file mode 100644
index 7163a2b9d2..0000000000
--- a/src/server/api/endpoints/notes/delete.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import deleteNote from '@/services/note/delete';
-import define from '../../define';
-import * as ms from 'ms';
-import { getNote } from '../../common/getters';
-import { ApiError } from '../../error';
-import { Users } from '@/models/index';
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: true as const,
-
- kind: 'write:notes',
-
- limit: {
- duration: ms('1hour'),
- max: 300,
- minInterval: ms('1sec')
- },
-
- params: {
- noteId: {
- validator: $.type(ID),
- }
- },
-
- errors: {
- noSuchNote: {
- message: 'No such note.',
- code: 'NO_SUCH_NOTE',
- id: '490be23f-8c1f-4796-819f-94cb4f9d1630'
- },
-
- accessDenied: {
- message: 'Access denied.',
- code: 'ACCESS_DENIED',
- id: 'fe8d7103-0ea8-4ec3-814d-f8b401dc69e9'
- }
- }
-};
-
-export default define(meta, async (ps, user) => {
- const note = await getNote(ps.noteId).catch(e => {
- if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
- throw e;
- });
-
- if (!user.isAdmin && !user.isModerator && (note.userId !== user.id)) {
- throw new ApiError(meta.errors.accessDenied);
- }
-
- // この操作を行うのが投稿者とは限らない(例えばモデレーター)ため
- await deleteNote(await Users.findOneOrFail(note.userId), note);
-});
diff --git a/src/server/api/endpoints/notes/favorites/create.ts b/src/server/api/endpoints/notes/favorites/create.ts
deleted file mode 100644
index 1bb25edd7f..0000000000
--- a/src/server/api/endpoints/notes/favorites/create.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../../define';
-import { ApiError } from '../../../error';
-import { getNote } from '../../../common/getters';
-import { NoteFavorites } from '@/models/index';
-import { genId } from '@/misc/gen-id';
-
-export const meta = {
- tags: ['notes', 'favorites'],
-
- requireCredential: true as const,
-
- kind: 'write:favorites',
-
- params: {
- noteId: {
- validator: $.type(ID),
- }
- },
-
- errors: {
- noSuchNote: {
- message: 'No such note.',
- code: 'NO_SUCH_NOTE',
- id: '6dd26674-e060-4816-909a-45ba3f4da458'
- },
-
- alreadyFavorited: {
- message: 'The note has already been marked as a favorite.',
- code: 'ALREADY_FAVORITED',
- id: 'a402c12b-34dd-41d2-97d8-4d2ffd96a1a6'
- },
- }
-};
-
-export default define(meta, async (ps, user) => {
- // Get favoritee
- const note = await getNote(ps.noteId).catch(e => {
- if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
- throw e;
- });
-
- // if already favorited
- const exist = await NoteFavorites.findOne({
- noteId: note.id,
- userId: user.id
- });
-
- if (exist != null) {
- throw new ApiError(meta.errors.alreadyFavorited);
- }
-
- // Create favorite
- await NoteFavorites.insert({
- id: genId(),
- createdAt: new Date(),
- noteId: note.id,
- userId: user.id
- });
-});
diff --git a/src/server/api/endpoints/notes/favorites/delete.ts b/src/server/api/endpoints/notes/favorites/delete.ts
deleted file mode 100644
index 75eb9a359a..0000000000
--- a/src/server/api/endpoints/notes/favorites/delete.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../../define';
-import { ApiError } from '../../../error';
-import { getNote } from '../../../common/getters';
-import { NoteFavorites } from '@/models/index';
-
-export const meta = {
- tags: ['notes', 'favorites'],
-
- requireCredential: true as const,
-
- kind: 'write:favorites',
-
- params: {
- noteId: {
- validator: $.type(ID),
- }
- },
-
- errors: {
- noSuchNote: {
- message: 'No such note.',
- code: 'NO_SUCH_NOTE',
- id: '80848a2c-398f-4343-baa9-df1d57696c56'
- },
-
- notFavorited: {
- message: 'You have not marked that note a favorite.',
- code: 'NOT_FAVORITED',
- id: 'b625fc69-635e-45e9-86f4-dbefbef35af5'
- },
- }
-};
-
-export default define(meta, async (ps, user) => {
- // Get favoritee
- const note = await getNote(ps.noteId).catch(e => {
- if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
- throw e;
- });
-
- // if already favorited
- const exist = await NoteFavorites.findOne({
- noteId: note.id,
- userId: user.id
- });
-
- if (exist == null) {
- throw new ApiError(meta.errors.notFavorited);
- }
-
- // Delete favorite
- await NoteFavorites.delete(exist.id);
-});
diff --git a/src/server/api/endpoints/notes/featured.ts b/src/server/api/endpoints/notes/featured.ts
deleted file mode 100644
index 8d33c0e73d..0000000000
--- a/src/server/api/endpoints/notes/featured.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-import $ from 'cafy';
-import define from '../../define';
-import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
-import { Notes } from '@/models/index';
-import { generateBlockedUserQuery } from '../../common/generate-block-query';
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: false as const,
-
- params: {
- limit: {
- validator: $.optional.num.range(1, 100),
- default: 10,
- },
-
- offset: {
- validator: $.optional.num.min(0),
- default: 0
- },
- },
-
- res: {
- type: 'array' as const,
- optional: false as const, nullable: false as const,
- items: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- ref: 'Note',
- }
- },
-};
-
-export default define(meta, async (ps, user) => {
- const max = 30;
- const day = 1000 * 60 * 60 * 24 * 3; // 3日前まで
-
- const query = Notes.createQueryBuilder('note')
- .addSelect('note.score')
- .where('note.userHost IS NULL')
- .andWhere(`note.score > 0`)
- .andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) })
- .andWhere(`note.visibility = 'public'`)
- .innerJoinAndSelect('note.user', 'user')
- .leftJoinAndSelect('note.reply', 'reply')
- .leftJoinAndSelect('note.renote', 'renote')
- .leftJoinAndSelect('reply.user', 'replyUser')
- .leftJoinAndSelect('renote.user', 'renoteUser');
-
- if (user) generateMutedUserQuery(query, user);
- if (user) generateBlockedUserQuery(query, user);
-
- let notes = await query
- .orderBy('note.score', 'DESC')
- .take(max)
- .getMany();
-
- notes.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
-
- notes = notes.slice(ps.offset, ps.offset + ps.limit);
-
- return await Notes.packMany(notes, user);
-});
diff --git a/src/server/api/endpoints/notes/global-timeline.ts b/src/server/api/endpoints/notes/global-timeline.ts
deleted file mode 100644
index 5902c0415c..0000000000
--- a/src/server/api/endpoints/notes/global-timeline.ts
+++ /dev/null
@@ -1,101 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../define';
-import { fetchMeta } from '@/misc/fetch-meta';
-import { ApiError } from '../../error';
-import { makePaginationQuery } from '../../common/make-pagination-query';
-import { Notes } from '@/models/index';
-import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
-import { activeUsersChart } from '@/services/chart/index';
-import { generateRepliesQuery } from '../../common/generate-replies-query';
-import { generateMutedNoteQuery } from '../../common/generate-muted-note-query';
-import { generateBlockedUserQuery } from '../../common/generate-block-query';
-
-export const meta = {
- tags: ['notes'],
-
- params: {
- withFiles: {
- validator: $.optional.bool,
- },
-
- limit: {
- validator: $.optional.num.range(1, 100),
- default: 10
- },
-
- sinceId: {
- validator: $.optional.type(ID),
- },
-
- untilId: {
- validator: $.optional.type(ID),
- },
-
- sinceDate: {
- validator: $.optional.num
- },
-
- untilDate: {
- validator: $.optional.num
- },
- },
-
- res: {
- type: 'array' as const,
- optional: false as const, nullable: false as const,
- items: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- ref: 'Note',
- }
- },
-
- errors: {
- gtlDisabled: {
- message: 'Global timeline has been disabled.',
- code: 'GTL_DISABLED',
- id: '0332fc13-6ab2-4427-ae80-a9fadffd1a6b'
- },
- }
-};
-
-export default define(meta, async (ps, user) => {
- const m = await fetchMeta();
- if (m.disableGlobalTimeline) {
- if (user == null || (!user.isAdmin && !user.isModerator)) {
- throw new ApiError(meta.errors.gtlDisabled);
- }
- }
-
- //#region Construct query
- const query = makePaginationQuery(Notes.createQueryBuilder('note'),
- ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
- .andWhere('note.visibility = \'public\'')
- .andWhere('note.channelId IS NULL')
- .innerJoinAndSelect('note.user', 'user')
- .leftJoinAndSelect('note.reply', 'reply')
- .leftJoinAndSelect('note.renote', 'renote')
- .leftJoinAndSelect('reply.user', 'replyUser')
- .leftJoinAndSelect('renote.user', 'renoteUser');
-
- generateRepliesQuery(query, user);
- if (user) generateMutedUserQuery(query, user);
- if (user) generateMutedNoteQuery(query, user);
- if (user) generateBlockedUserQuery(query, user);
-
- if (ps.withFiles) {
- query.andWhere('note.fileIds != \'{}\'');
- }
- //#endregion
-
- const timeline = await query.take(ps.limit!).getMany();
-
- process.nextTick(() => {
- if (user) {
- activeUsersChart.update(user);
- }
- });
-
- return await Notes.packMany(timeline, user);
-});
diff --git a/src/server/api/endpoints/notes/hybrid-timeline.ts b/src/server/api/endpoints/notes/hybrid-timeline.ts
deleted file mode 100644
index 47f08f208b..0000000000
--- a/src/server/api/endpoints/notes/hybrid-timeline.ts
+++ /dev/null
@@ -1,158 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../define';
-import { fetchMeta } from '@/misc/fetch-meta';
-import { ApiError } from '../../error';
-import { makePaginationQuery } from '../../common/make-pagination-query';
-import { Followings, Notes } from '@/models/index';
-import { Brackets } from 'typeorm';
-import { generateVisibilityQuery } from '../../common/generate-visibility-query';
-import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
-import { activeUsersChart } from '@/services/chart/index';
-import { generateRepliesQuery } from '../../common/generate-replies-query';
-import { generateMutedNoteQuery } from '../../common/generate-muted-note-query';
-import { generateChannelQuery } from '../../common/generate-channel-query';
-import { generateBlockedUserQuery } from '../../common/generate-block-query';
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: true as const,
-
- params: {
- limit: {
- validator: $.optional.num.range(1, 100),
- default: 10,
- },
-
- sinceId: {
- validator: $.optional.type(ID),
- },
-
- untilId: {
- validator: $.optional.type(ID),
- },
-
- sinceDate: {
- validator: $.optional.num,
- },
-
- untilDate: {
- validator: $.optional.num,
- },
-
- includeMyRenotes: {
- validator: $.optional.bool,
- default: true,
- },
-
- includeRenotedMyNotes: {
- validator: $.optional.bool,
- default: true,
- },
-
- includeLocalRenotes: {
- validator: $.optional.bool,
- default: true,
- },
-
- withFiles: {
- validator: $.optional.bool,
- },
- },
-
- res: {
- type: 'array' as const,
- optional: false as const, nullable: false as const,
- items: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- ref: 'Note',
- }
- },
-
- errors: {
- stlDisabled: {
- message: 'Hybrid timeline has been disabled.',
- code: 'STL_DISABLED',
- id: '620763f4-f621-4533-ab33-0577a1a3c342'
- },
- }
-};
-
-export default define(meta, async (ps, user) => {
- const m = await fetchMeta();
- if (m.disableLocalTimeline && !user.isAdmin && !user.isModerator) {
- throw new ApiError(meta.errors.stlDisabled);
- }
-
- //#region Construct query
- const followingQuery = Followings.createQueryBuilder('following')
- .select('following.followeeId')
- .where('following.followerId = :followerId', { followerId: user.id });
-
- const query = makePaginationQuery(Notes.createQueryBuilder('note'),
- ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
- .andWhere(new Brackets(qb => {
- qb.where(`((note.userId IN (${ followingQuery.getQuery() })) OR (note.userId = :meId))`, { meId: user.id })
- .orWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)');
- }))
- .innerJoinAndSelect('note.user', 'user')
- .leftJoinAndSelect('note.reply', 'reply')
- .leftJoinAndSelect('note.renote', 'renote')
- .leftJoinAndSelect('reply.user', 'replyUser')
- .leftJoinAndSelect('renote.user', 'renoteUser')
- .setParameters(followingQuery.getParameters());
-
- generateChannelQuery(query, user);
- generateRepliesQuery(query, user);
- generateVisibilityQuery(query, user);
- generateMutedUserQuery(query, user);
- generateMutedNoteQuery(query, user);
- generateBlockedUserQuery(query, user);
-
- if (ps.includeMyRenotes === false) {
- query.andWhere(new Brackets(qb => {
- qb.orWhere('note.userId != :meId', { meId: user.id });
- qb.orWhere('note.renoteId IS NULL');
- qb.orWhere('note.text IS NOT NULL');
- qb.orWhere('note.fileIds != \'{}\'');
- qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)');
- }));
- }
-
- if (ps.includeRenotedMyNotes === false) {
- query.andWhere(new Brackets(qb => {
- qb.orWhere('note.renoteUserId != :meId', { meId: user.id });
- qb.orWhere('note.renoteId IS NULL');
- qb.orWhere('note.text IS NOT NULL');
- qb.orWhere('note.fileIds != \'{}\'');
- qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)');
- }));
- }
-
- if (ps.includeLocalRenotes === false) {
- query.andWhere(new Brackets(qb => {
- qb.orWhere('note.renoteUserHost IS NOT NULL');
- qb.orWhere('note.renoteId IS NULL');
- qb.orWhere('note.text IS NOT NULL');
- qb.orWhere('note.fileIds != \'{}\'');
- qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)');
- }));
- }
-
- if (ps.withFiles) {
- query.andWhere('note.fileIds != \'{}\'');
- }
- //#endregion
-
- const timeline = await query.take(ps.limit!).getMany();
-
- process.nextTick(() => {
- if (user) {
- activeUsersChart.update(user);
- }
- });
-
- return await Notes.packMany(timeline, user);
-});
diff --git a/src/server/api/endpoints/notes/local-timeline.ts b/src/server/api/endpoints/notes/local-timeline.ts
deleted file mode 100644
index f670d478bf..0000000000
--- a/src/server/api/endpoints/notes/local-timeline.ts
+++ /dev/null
@@ -1,129 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../define';
-import { fetchMeta } from '@/misc/fetch-meta';
-import { ApiError } from '../../error';
-import { Notes } from '@/models/index';
-import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
-import { makePaginationQuery } from '../../common/make-pagination-query';
-import { generateVisibilityQuery } from '../../common/generate-visibility-query';
-import { activeUsersChart } from '@/services/chart/index';
-import { Brackets } from 'typeorm';
-import { generateRepliesQuery } from '../../common/generate-replies-query';
-import { generateMutedNoteQuery } from '../../common/generate-muted-note-query';
-import { generateChannelQuery } from '../../common/generate-channel-query';
-import { generateBlockedUserQuery } from '../../common/generate-block-query';
-
-export const meta = {
- tags: ['notes'],
-
- params: {
- withFiles: {
- validator: $.optional.bool,
- },
-
- fileType: {
- validator: $.optional.arr($.str),
- },
-
- excludeNsfw: {
- validator: $.optional.bool,
- default: false,
- },
-
- limit: {
- validator: $.optional.num.range(1, 100),
- default: 10
- },
-
- sinceId: {
- validator: $.optional.type(ID),
- },
-
- untilId: {
- validator: $.optional.type(ID),
- },
-
- sinceDate: {
- validator: $.optional.num,
- },
-
- untilDate: {
- validator: $.optional.num,
- },
- },
-
- res: {
- type: 'array' as const,
- optional: false as const, nullable: false as const,
- items: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- ref: 'Note',
- }
- },
-
- errors: {
- ltlDisabled: {
- message: 'Local timeline has been disabled.',
- code: 'LTL_DISABLED',
- id: '45a6eb02-7695-4393-b023-dd3be9aaaefd'
- },
- }
-};
-
-export default define(meta, async (ps, user) => {
- const m = await fetchMeta();
- if (m.disableLocalTimeline) {
- if (user == null || (!user.isAdmin && !user.isModerator)) {
- throw new ApiError(meta.errors.ltlDisabled);
- }
- }
-
- //#region Construct query
- const query = makePaginationQuery(Notes.createQueryBuilder('note'),
- ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
- .andWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)')
- .innerJoinAndSelect('note.user', 'user')
- .leftJoinAndSelect('note.reply', 'reply')
- .leftJoinAndSelect('note.renote', 'renote')
- .leftJoinAndSelect('reply.user', 'replyUser')
- .leftJoinAndSelect('renote.user', 'renoteUser');
-
- generateChannelQuery(query, user);
- generateRepliesQuery(query, user);
- generateVisibilityQuery(query, user);
- if (user) generateMutedUserQuery(query, user);
- if (user) generateMutedNoteQuery(query, user);
- if (user) generateBlockedUserQuery(query, user);
-
- if (ps.withFiles) {
- query.andWhere('note.fileIds != \'{}\'');
- }
-
- if (ps.fileType != null) {
- query.andWhere('note.fileIds != \'{}\'');
- query.andWhere(new Brackets(qb => {
- for (const type of ps.fileType!) {
- const i = ps.fileType!.indexOf(type);
- qb.orWhere(`:type${i} = ANY(note.attachedFileTypes)`, { [`type${i}`]: type });
- }
- }));
-
- if (ps.excludeNsfw) {
- query.andWhere('note.cw IS NULL');
- query.andWhere('0 = (SELECT COUNT(*) FROM drive_file df WHERE df.id = ANY(note."fileIds") AND df."isSensitive" = TRUE)');
- }
- }
- //#endregion
-
- const timeline = await query.take(ps.limit!).getMany();
-
- process.nextTick(() => {
- if (user) {
- activeUsersChart.update(user);
- }
- });
-
- return await Notes.packMany(timeline, user);
-});
diff --git a/src/server/api/endpoints/notes/mentions.ts b/src/server/api/endpoints/notes/mentions.ts
deleted file mode 100644
index ffaebd6c95..0000000000
--- a/src/server/api/endpoints/notes/mentions.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../define';
-import read from '@/services/note/read';
-import { Notes, Followings } from '@/models/index';
-import { generateVisibilityQuery } from '../../common/generate-visibility-query';
-import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
-import { makePaginationQuery } from '../../common/make-pagination-query';
-import { Brackets } from 'typeorm';
-import { generateBlockedUserQuery } from '../../common/generate-block-query';
-import { generateMutedNoteThreadQuery } from '../../common/generate-muted-note-thread-query';
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: true as const,
-
- params: {
- following: {
- validator: $.optional.bool,
- default: false
- },
-
- limit: {
- validator: $.optional.num.range(1, 100),
- default: 10
- },
-
- sinceId: {
- validator: $.optional.type(ID),
- },
-
- untilId: {
- validator: $.optional.type(ID),
- },
-
- visibility: {
- validator: $.optional.str,
- },
- },
-
- res: {
- type: 'array' as const,
- optional: false as const, nullable: false as const,
- items: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- ref: 'Note',
- }
- },
-};
-
-export default define(meta, async (ps, user) => {
- const followingQuery = Followings.createQueryBuilder('following')
- .select('following.followeeId')
- .where('following.followerId = :followerId', { followerId: user.id });
-
- const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId)
- .andWhere(new Brackets(qb => { qb
- .where(`'{"${user.id}"}' <@ note.mentions`)
- .orWhere(`'{"${user.id}"}' <@ note.visibleUserIds`);
- }))
- .innerJoinAndSelect('note.user', 'user')
- .leftJoinAndSelect('note.reply', 'reply')
- .leftJoinAndSelect('note.renote', 'renote')
- .leftJoinAndSelect('reply.user', 'replyUser')
- .leftJoinAndSelect('renote.user', 'renoteUser');
-
- generateVisibilityQuery(query, user);
- generateMutedUserQuery(query, user);
- generateMutedNoteThreadQuery(query, user);
- generateBlockedUserQuery(query, user);
-
- if (ps.visibility) {
- query.andWhere('note.visibility = :visibility', { visibility: ps.visibility });
- }
-
- if (ps.following) {
- query.andWhere(`((note.userId IN (${ followingQuery.getQuery() })) OR (note.userId = :meId))`, { meId: user.id });
- query.setParameters(followingQuery.getParameters());
- }
-
- const mentions = await query.take(ps.limit!).getMany();
-
- read(user.id, mentions);
-
- return await Notes.packMany(mentions, user);
-});
diff --git a/src/server/api/endpoints/notes/polls/recommendation.ts b/src/server/api/endpoints/notes/polls/recommendation.ts
deleted file mode 100644
index 0763f0c8fd..0000000000
--- a/src/server/api/endpoints/notes/polls/recommendation.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-import $ from 'cafy';
-import define from '../../../define';
-import { Polls, Mutings, Notes, PollVotes } from '@/models/index';
-import { Brackets, In } from 'typeorm';
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: true as const,
-
- params: {
- limit: {
- validator: $.optional.num.range(1, 100),
- default: 10
- },
-
- offset: {
- validator: $.optional.num.min(0),
- default: 0
- }
- },
-
- res: {
- type: 'array' as const,
- optional: false as const, nullable: false as const,
- items: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- ref: 'Note'
- }
- }
-};
-
-export default define(meta, async (ps, user) => {
- const query = Polls.createQueryBuilder('poll')
- .where('poll.userHost IS NULL')
- .andWhere(`poll.userId != :meId`, { meId: user.id })
- .andWhere(`poll.noteVisibility = 'public'`)
- .andWhere(new Brackets(qb => { qb
- .where('poll.expiresAt IS NULL')
- .orWhere('poll.expiresAt > :now', { now: new Date() });
- }));
-
- //#region exclude arleady voted polls
- const votedQuery = PollVotes.createQueryBuilder('vote')
- .select('vote.noteId')
- .where('vote.userId = :meId', { meId: user.id });
-
- query
- .andWhere(`poll.noteId NOT IN (${ votedQuery.getQuery() })`);
-
- query.setParameters(votedQuery.getParameters());
- //#endregion
-
- //#region mute
- const mutingQuery = Mutings.createQueryBuilder('muting')
- .select('muting.muteeId')
- .where('muting.muterId = :muterId', { muterId: user.id });
-
- query
- .andWhere(`poll.userId NOT IN (${ mutingQuery.getQuery() })`);
-
- query.setParameters(mutingQuery.getParameters());
- //#endregion
-
- const polls = await query.take(ps.limit!).skip(ps.offset).getMany();
-
- if (polls.length === 0) return [];
-
- const notes = await Notes.find({
- id: In(polls.map(poll => poll.noteId))
- });
-
- return await Notes.packMany(notes, user, {
- detail: true
- });
-});
diff --git a/src/server/api/endpoints/notes/polls/vote.ts b/src/server/api/endpoints/notes/polls/vote.ts
deleted file mode 100644
index f670501385..0000000000
--- a/src/server/api/endpoints/notes/polls/vote.ts
+++ /dev/null
@@ -1,170 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import { publishNoteStream } from '@/services/stream';
-import { createNotification } from '@/services/create-notification';
-import define from '../../../define';
-import { ApiError } from '../../../error';
-import { getNote } from '../../../common/getters';
-import { deliver } from '@/queue/index';
-import { renderActivity } from '@/remote/activitypub/renderer/index';
-import renderVote from '@/remote/activitypub/renderer/vote';
-import { deliverQuestionUpdate } from '@/services/note/polls/update';
-import { PollVotes, NoteWatchings, Users, Polls, Blockings } from '@/models/index';
-import { Not } from 'typeorm';
-import { IRemoteUser } from '@/models/entities/user';
-import { genId } from '@/misc/gen-id';
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: true as const,
-
- kind: 'write:votes',
-
- params: {
- noteId: {
- validator: $.type(ID),
- },
-
- choice: {
- validator: $.num
- },
- },
-
- errors: {
- noSuchNote: {
- message: 'No such note.',
- code: 'NO_SUCH_NOTE',
- id: 'ecafbd2e-c283-4d6d-aecb-1a0a33b75396'
- },
-
- noPoll: {
- message: 'The note does not attach a poll.',
- code: 'NO_POLL',
- id: '5f979967-52d9-4314-a911-1c673727f92f'
- },
-
- invalidChoice: {
- message: 'Choice ID is invalid.',
- code: 'INVALID_CHOICE',
- id: 'e0cc9a04-f2e8-41e4-a5f1-4127293260cc'
- },
-
- alreadyVoted: {
- message: 'You have already voted.',
- code: 'ALREADY_VOTED',
- id: '0963fc77-efac-419b-9424-b391608dc6d8'
- },
-
- alreadyExpired: {
- message: 'The poll is already expired.',
- code: 'ALREADY_EXPIRED',
- id: '1022a357-b085-4054-9083-8f8de358337e'
- },
-
- youHaveBeenBlocked: {
- message: 'You cannot vote this poll because you have been blocked by this user.',
- code: 'YOU_HAVE_BEEN_BLOCKED',
- id: '85a5377e-b1e9-4617-b0b9-5bea73331e49'
- },
- }
-};
-
-export default define(meta, async (ps, user) => {
- const createdAt = new Date();
-
- // Get votee
- const note = await getNote(ps.noteId).catch(e => {
- if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
- throw e;
- });
-
- if (!note.hasPoll) {
- throw new ApiError(meta.errors.noPoll);
- }
-
- // Check blocking
- if (note.userId !== user.id) {
- const block = await Blockings.findOne({
- blockerId: note.userId,
- blockeeId: user.id,
- });
- if (block) {
- throw new ApiError(meta.errors.youHaveBeenBlocked);
- }
- }
-
- const poll = await Polls.findOneOrFail({ noteId: note.id });
-
- if (poll.expiresAt && poll.expiresAt < createdAt) {
- throw new ApiError(meta.errors.alreadyExpired);
- }
-
- if (poll.choices[ps.choice] == null) {
- throw new ApiError(meta.errors.invalidChoice);
- }
-
- // if already voted
- const exist = await PollVotes.find({
- noteId: note.id,
- userId: user.id
- });
-
- if (exist.length) {
- if (poll.multiple) {
- if (exist.some(x => x.choice == ps.choice))
- throw new ApiError(meta.errors.alreadyVoted);
- } else {
- throw new ApiError(meta.errors.alreadyVoted);
- }
- }
-
- // Create vote
- const vote = await PollVotes.insert({
- id: genId(),
- createdAt,
- noteId: note.id,
- userId: user.id,
- choice: ps.choice
- }).then(x => PollVotes.findOneOrFail(x.identifiers[0]));
-
- // Increment votes count
- const index = ps.choice + 1; // In SQL, array index is 1 based
- await Polls.query(`UPDATE poll SET votes[${index}] = votes[${index}] + 1 WHERE "noteId" = '${poll.noteId}'`);
-
- publishNoteStream(note.id, 'pollVoted', {
- choice: ps.choice,
- userId: user.id
- });
-
- // Notify
- createNotification(note.userId, 'pollVote', {
- notifierId: user.id,
- noteId: note.id,
- choice: ps.choice
- });
-
- // Fetch watchers
- NoteWatchings.find({
- noteId: note.id,
- userId: Not(user.id),
- }).then(watchers => {
- for (const watcher of watchers) {
- createNotification(watcher.userId, 'pollVote', {
- notifierId: user.id,
- noteId: note.id,
- choice: ps.choice
- });
- }
- });
-
- // リモート投票の場合リプライ送信
- if (note.userHost != null) {
- const pollOwner = await Users.findOneOrFail(note.userId) as IRemoteUser;
-
- deliver(user, renderActivity(await renderVote(user, vote, note, poll, pollOwner)), pollOwner.inbox);
- }
-
- // リモートフォロワーにUpdate配信
- deliverQuestionUpdate(note.id);
-});
diff --git a/src/server/api/endpoints/notes/reactions.ts b/src/server/api/endpoints/notes/reactions.ts
deleted file mode 100644
index 09dd6b600b..0000000000
--- a/src/server/api/endpoints/notes/reactions.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../define';
-import { getNote } from '../../common/getters';
-import { ApiError } from '../../error';
-import { NoteReactions } from '@/models/index';
-import { DeepPartial } from 'typeorm';
-import { NoteReaction } from '@/models/entities/note-reaction';
-
-export const meta = {
- tags: ['notes', 'reactions'],
-
- requireCredential: false as const,
-
- params: {
- noteId: {
- validator: $.type(ID),
- },
-
- type: {
- validator: $.optional.nullable.str,
- },
-
- limit: {
- validator: $.optional.num.range(1, 100),
- default: 10
- },
-
- offset: {
- validator: $.optional.num,
- default: 0
- },
-
- sinceId: {
- validator: $.optional.type(ID),
- },
-
- untilId: {
- validator: $.optional.type(ID),
- },
- },
-
- res: {
- type: 'array' as const,
- optional: false as const, nullable: false as const,
- items: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- ref: 'NoteReaction',
- }
- },
-
- errors: {
- noSuchNote: {
- message: 'No such note.',
- code: 'NO_SUCH_NOTE',
- id: '263fff3d-d0e1-4af4-bea7-8408059b451a'
- }
- }
-};
-
-export default define(meta, async (ps, user) => {
- const note = await getNote(ps.noteId).catch(e => {
- if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
- throw e;
- });
-
- const query = {
- noteId: note.id
- } as DeepPartial<NoteReaction>;
-
- if (ps.type) {
- // ローカルリアクションはホスト名が . とされているが
- // DB 上ではそうではないので、必要に応じて変換
- const suffix = '@.:';
- const type = ps.type.endsWith(suffix) ? ps.type.slice(0, ps.type.length - suffix.length) + ':' : ps.type;
- query.reaction = type;
- }
-
- const reactions = await NoteReactions.find({
- where: query,
- take: ps.limit!,
- skip: ps.offset,
- order: {
- id: -1
- }
- });
-
- return await Promise.all(reactions.map(reaction => NoteReactions.pack(reaction, user)));
-});
diff --git a/src/server/api/endpoints/notes/reactions/create.ts b/src/server/api/endpoints/notes/reactions/create.ts
deleted file mode 100644
index 24a73a8d4f..0000000000
--- a/src/server/api/endpoints/notes/reactions/create.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import createReaction from '@/services/note/reaction/create';
-import define from '../../../define';
-import { getNote } from '../../../common/getters';
-import { ApiError } from '../../../error';
-
-export const meta = {
- tags: ['reactions', 'notes'],
-
- requireCredential: true as const,
-
- kind: 'write:reactions',
-
- params: {
- noteId: {
- validator: $.type(ID),
- },
-
- reaction: {
- validator: $.str,
- }
- },
-
- errors: {
- noSuchNote: {
- message: 'No such note.',
- code: 'NO_SUCH_NOTE',
- id: '033d0620-5bfe-4027-965d-980b0c85a3ea'
- },
-
- alreadyReacted: {
- message: 'You are already reacting to that note.',
- code: 'ALREADY_REACTED',
- id: '71efcf98-86d6-4e2b-b2ad-9d032369366b'
- },
-
- youHaveBeenBlocked: {
- message: 'You cannot react this note because you have been blocked by this user.',
- code: 'YOU_HAVE_BEEN_BLOCKED',
- id: '20ef5475-9f38-4e4c-bd33-de6d979498ec'
- },
- }
-};
-
-export default define(meta, async (ps, user) => {
- const note = await getNote(ps.noteId).catch(e => {
- if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
- throw e;
- });
- await createReaction(user, note, ps.reaction).catch(e => {
- if (e.id === '51c42bb4-931a-456b-bff7-e5a8a70dd298') throw new ApiError(meta.errors.alreadyReacted);
- if (e.id === 'e70412a4-7197-4726-8e74-f3e0deb92aa7') throw new ApiError(meta.errors.youHaveBeenBlocked);
- throw e;
- });
- return;
-});
diff --git a/src/server/api/endpoints/notes/reactions/delete.ts b/src/server/api/endpoints/notes/reactions/delete.ts
deleted file mode 100644
index 69550f96de..0000000000
--- a/src/server/api/endpoints/notes/reactions/delete.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../../define';
-import * as ms from 'ms';
-import deleteReaction from '@/services/note/reaction/delete';
-import { getNote } from '../../../common/getters';
-import { ApiError } from '../../../error';
-
-export const meta = {
- tags: ['reactions', 'notes'],
-
- requireCredential: true as const,
-
- kind: 'write:reactions',
-
- limit: {
- duration: ms('1hour'),
- max: 60,
- minInterval: ms('3sec')
- },
-
- params: {
- noteId: {
- validator: $.type(ID),
- },
- },
-
- errors: {
- noSuchNote: {
- message: 'No such note.',
- code: 'NO_SUCH_NOTE',
- id: '764d9fce-f9f2-4a0e-92b1-6ceac9a7ad37'
- },
-
- notReacted: {
- message: 'You are not reacting to that note.',
- code: 'NOT_REACTED',
- id: '92f4426d-4196-4125-aa5b-02943e2ec8fc'
- },
- }
-};
-
-export default define(meta, async (ps, user) => {
- const note = await getNote(ps.noteId).catch(e => {
- if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
- throw e;
- });
- await deleteReaction(user, note).catch(e => {
- if (e.id === '60527ec9-b4cb-4a88-a6bd-32d3ad26817d') throw new ApiError(meta.errors.notReacted);
- throw e;
- });
-});
diff --git a/src/server/api/endpoints/notes/renotes.ts b/src/server/api/endpoints/notes/renotes.ts
deleted file mode 100644
index 26bfc1657d..0000000000
--- a/src/server/api/endpoints/notes/renotes.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../define';
-import { getNote } from '../../common/getters';
-import { ApiError } from '../../error';
-import { generateVisibilityQuery } from '../../common/generate-visibility-query';
-import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
-import { makePaginationQuery } from '../../common/make-pagination-query';
-import { Notes } from '@/models/index';
-import { generateBlockedUserQuery } from '../../common/generate-block-query';
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: false as const,
-
- params: {
- noteId: {
- validator: $.type(ID),
- },
-
- limit: {
- validator: $.optional.num.range(1, 100),
- default: 10
- },
-
- sinceId: {
- validator: $.optional.type(ID),
- },
-
- untilId: {
- validator: $.optional.type(ID),
- }
- },
-
- res: {
- type: 'array' as const,
- optional: false as const, nullable: false as const,
- items: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- ref: 'Note',
- }
- },
-
- errors: {
- noSuchNote: {
- message: 'No such note.',
- code: 'NO_SUCH_NOTE',
- id: '12908022-2e21-46cd-ba6a-3edaf6093f46'
- }
- }
-};
-
-export default define(meta, async (ps, user) => {
- const note = await getNote(ps.noteId).catch(e => {
- if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
- throw e;
- });
-
- const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId)
- .andWhere(`note.renoteId = :renoteId`, { renoteId: note.id })
- .innerJoinAndSelect('note.user', 'user')
- .leftJoinAndSelect('note.reply', 'reply')
- .leftJoinAndSelect('note.renote', 'renote')
- .leftJoinAndSelect('reply.user', 'replyUser')
- .leftJoinAndSelect('renote.user', 'renoteUser');
-
- generateVisibilityQuery(query, user);
- if (user) generateMutedUserQuery(query, user);
- if (user) generateBlockedUserQuery(query, user);
-
- const renotes = await query.take(ps.limit!).getMany();
-
- return await Notes.packMany(renotes, user);
-});
diff --git a/src/server/api/endpoints/notes/replies.ts b/src/server/api/endpoints/notes/replies.ts
deleted file mode 100644
index 0bb62413ae..0000000000
--- a/src/server/api/endpoints/notes/replies.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../define';
-import { Notes } from '@/models/index';
-import { makePaginationQuery } from '../../common/make-pagination-query';
-import { generateVisibilityQuery } from '../../common/generate-visibility-query';
-import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
-import { generateBlockedUserQuery } from '../../common/generate-block-query';
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: false as const,
-
- params: {
- noteId: {
- validator: $.type(ID),
- },
-
- sinceId: {
- validator: $.optional.type(ID),
- },
-
- untilId: {
- validator: $.optional.type(ID),
- },
-
- limit: {
- validator: $.optional.num.range(1, 100),
- default: 10
- },
- },
-
- res: {
- type: 'array' as const,
- optional: false as const, nullable: false as const,
- items: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- ref: 'Note',
- }
- },
-};
-
-export default define(meta, async (ps, user) => {
- const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId)
- .andWhere('note.replyId = :replyId', { replyId: ps.noteId })
- .innerJoinAndSelect('note.user', 'user')
- .leftJoinAndSelect('note.reply', 'reply')
- .leftJoinAndSelect('note.renote', 'renote')
- .leftJoinAndSelect('reply.user', 'replyUser')
- .leftJoinAndSelect('renote.user', 'renoteUser');
-
- generateVisibilityQuery(query, user);
- if (user) generateMutedUserQuery(query, user);
- if (user) generateBlockedUserQuery(query, user);
-
- const timeline = await query.take(ps.limit!).getMany();
-
- return await Notes.packMany(timeline, user);
-});
diff --git a/src/server/api/endpoints/notes/search-by-tag.ts b/src/server/api/endpoints/notes/search-by-tag.ts
deleted file mode 100644
index 40e1499736..0000000000
--- a/src/server/api/endpoints/notes/search-by-tag.ts
+++ /dev/null
@@ -1,134 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../define';
-import { makePaginationQuery } from '../../common/make-pagination-query';
-import { Notes } from '@/models/index';
-import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
-import { generateVisibilityQuery } from '../../common/generate-visibility-query';
-import { Brackets } from 'typeorm';
-import { safeForSql } from '@/misc/safe-for-sql';
-import { normalizeForSearch } from '@/misc/normalize-for-search';
-import { generateBlockedUserQuery } from '../../common/generate-block-query';
-
-export const meta = {
- tags: ['notes', 'hashtags'],
-
- params: {
- tag: {
- validator: $.optional.str,
- },
-
- query: {
- validator: $.optional.arr($.arr($.str)),
- },
-
- reply: {
- validator: $.optional.nullable.bool,
- default: null,
- },
-
- renote: {
- validator: $.optional.nullable.bool,
- default: null,
- },
-
- withFiles: {
- validator: $.optional.bool,
- },
-
- poll: {
- validator: $.optional.nullable.bool,
- default: null,
- },
-
- sinceId: {
- validator: $.optional.type(ID),
- },
-
- untilId: {
- validator: $.optional.type(ID),
- },
-
- limit: {
- validator: $.optional.num.range(1, 100),
- default: 10
- },
- },
-
- res: {
- type: 'array' as const,
- optional: false as const, nullable: false as const,
- items: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- ref: 'Note',
- }
- },
-};
-
-export default define(meta, async (ps, me) => {
- const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId)
- .innerJoinAndSelect('note.user', 'user')
- .leftJoinAndSelect('note.reply', 'reply')
- .leftJoinAndSelect('note.renote', 'renote')
- .leftJoinAndSelect('reply.user', 'replyUser')
- .leftJoinAndSelect('renote.user', 'renoteUser');
-
- generateVisibilityQuery(query, me);
- if (me) generateMutedUserQuery(query, me);
- if (me) generateBlockedUserQuery(query, me);
-
- try {
- if (ps.tag) {
- if (!safeForSql(ps.tag)) throw 'Injection';
- query.andWhere(`'{"${normalizeForSearch(ps.tag)}"}' <@ note.tags`);
- } else {
- query.andWhere(new Brackets(qb => {
- for (const tags of ps.query!) {
- qb.orWhere(new Brackets(qb => {
- for (const tag of tags) {
- if (!safeForSql(tag)) throw 'Injection';
- qb.andWhere(`'{"${normalizeForSearch(tag)}"}' <@ note.tags`);
- }
- }));
- }
- }));
- }
- } catch (e) {
- if (e === 'Injection') return [];
- throw e;
- }
-
- if (ps.reply != null) {
- if (ps.reply) {
- query.andWhere('note.replyId IS NOT NULL');
- } else {
- query.andWhere('note.replyId IS NULL');
- }
- }
-
- if (ps.renote != null) {
- if (ps.renote) {
- query.andWhere('note.renoteId IS NOT NULL');
- } else {
- query.andWhere('note.renoteId IS NULL');
- }
- }
-
- if (ps.withFiles) {
- query.andWhere('note.fileIds != \'{}\'');
- }
-
- if (ps.poll != null) {
- if (ps.poll) {
- query.andWhere('note.hasPoll = TRUE');
- } else {
- query.andWhere('note.hasPoll = FALSE');
- }
- }
-
- // Search notes
- const notes = await query.take(ps.limit!).getMany();
-
- return await Notes.packMany(notes, me);
-});
diff --git a/src/server/api/endpoints/notes/search.ts b/src/server/api/endpoints/notes/search.ts
deleted file mode 100644
index eb832a6b31..0000000000
--- a/src/server/api/endpoints/notes/search.ts
+++ /dev/null
@@ -1,152 +0,0 @@
-import $ from 'cafy';
-import es from '../../../../db/elasticsearch';
-import define from '../../define';
-import { Notes } from '@/models/index';
-import { In } from 'typeorm';
-import { ID } from '@/misc/cafy-id';
-import config from '@/config/index';
-import { makePaginationQuery } from '../../common/make-pagination-query';
-import { generateVisibilityQuery } from '../../common/generate-visibility-query';
-import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
-import { generateBlockedUserQuery } from '../../common/generate-block-query';
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: false as const,
-
- params: {
- query: {
- validator: $.str
- },
-
- sinceId: {
- validator: $.optional.type(ID),
- },
-
- untilId: {
- validator: $.optional.type(ID),
- },
-
- limit: {
- validator: $.optional.num.range(1, 100),
- default: 10
- },
-
- host: {
- validator: $.optional.nullable.str,
- default: undefined
- },
-
- userId: {
- validator: $.optional.nullable.type(ID),
- default: null
- },
-
- channelId: {
- validator: $.optional.nullable.type(ID),
- default: null
- },
- },
-
- res: {
- type: 'array' as const,
- optional: false as const, nullable: false as const,
- items: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- ref: 'Note',
- }
- },
-
- errors: {
- }
-};
-
-export default define(meta, async (ps, me) => {
- if (es == null) {
- const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId);
-
- if (ps.userId) {
- query.andWhere('note.userId = :userId', { userId: ps.userId });
- } else if (ps.channelId) {
- query.andWhere('note.channelId = :channelId', { channelId: ps.channelId });
- }
-
- query
- .andWhere('note.text ILIKE :q', { q: `%${ps.query}%` })
- .innerJoinAndSelect('note.user', 'user')
- .leftJoinAndSelect('note.reply', 'reply')
- .leftJoinAndSelect('note.renote', 'renote')
- .leftJoinAndSelect('reply.user', 'replyUser')
- .leftJoinAndSelect('renote.user', 'renoteUser');
-
- generateVisibilityQuery(query, me);
- if (me) generateMutedUserQuery(query, me);
- if (me) generateBlockedUserQuery(query, me);
-
- const notes = await query.take(ps.limit!).getMany();
-
- return await Notes.packMany(notes, me);
- } else {
- const userQuery = ps.userId != null ? [{
- term: {
- userId: ps.userId
- }
- }] : [];
-
- const hostQuery = ps.userId == null ?
- ps.host === null ? [{
- bool: {
- must_not: {
- exists: {
- field: 'userHost'
- }
- }
- }
- }] : ps.host !== undefined ? [{
- term: {
- userHost: ps.host
- }
- }] : []
- : [];
-
- const result = await es.search({
- index: config.elasticsearch.index || 'misskey_note',
- body: {
- size: ps.limit!,
- from: ps.offset,
- query: {
- bool: {
- must: [{
- simple_query_string: {
- fields: ['text'],
- query: ps.query.toLowerCase(),
- default_operator: 'and'
- },
- }, ...hostQuery, ...userQuery]
- }
- },
- sort: [{
- _doc: 'desc'
- }]
- }
- });
-
- const hits = result.body.hits.hits.map((hit: any) => hit._id);
-
- if (hits.length === 0) return [];
-
- // Fetch found notes
- const notes = await Notes.find({
- where: {
- id: In(hits)
- },
- order: {
- id: -1
- }
- });
-
- return await Notes.packMany(notes, me);
- }
-});
diff --git a/src/server/api/endpoints/notes/show.ts b/src/server/api/endpoints/notes/show.ts
deleted file mode 100644
index fad63d6483..0000000000
--- a/src/server/api/endpoints/notes/show.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../define';
-import { getNote } from '../../common/getters';
-import { ApiError } from '../../error';
-import { Notes } from '@/models/index';
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: false as const,
-
- params: {
- noteId: {
- validator: $.type(ID),
- }
- },
-
- res: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- ref: 'Note',
- },
-
- errors: {
- noSuchNote: {
- message: 'No such note.',
- code: 'NO_SUCH_NOTE',
- id: '24fcbfc6-2e37-42b6-8388-c29b3861a08d'
- }
- }
-};
-
-export default define(meta, async (ps, user) => {
- const note = await getNote(ps.noteId).catch(e => {
- if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
- throw e;
- });
-
- return await Notes.pack(note, user, {
- detail: true
- });
-});
diff --git a/src/server/api/endpoints/notes/state.ts b/src/server/api/endpoints/notes/state.ts
deleted file mode 100644
index b3913a5e79..0000000000
--- a/src/server/api/endpoints/notes/state.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../define';
-import { NoteFavorites, Notes, NoteThreadMutings, NoteWatchings } from '@/models/index';
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: true as const,
-
- params: {
- noteId: {
- validator: $.type(ID),
- }
- },
-
- res: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- properties: {
- isFavorited: {
- type: 'boolean' as const,
- optional: false as const, nullable: false as const
- },
- isWatching: {
- type: 'boolean' as const,
- optional: false as const, nullable: false as const
- },
- isMutedThread: {
- type: 'boolean' as const,
- optional: false as const, nullable: false as const
- },
- }
- }
-};
-
-export default define(meta, async (ps, user) => {
- const note = await Notes.findOneOrFail(ps.noteId);
-
- const [favorite, watching, threadMuting] = await Promise.all([
- NoteFavorites.count({
- where: {
- userId: user.id,
- noteId: note.id,
- },
- take: 1
- }),
- NoteWatchings.count({
- where: {
- userId: user.id,
- noteId: note.id,
- },
- take: 1
- }),
- NoteThreadMutings.count({
- where: {
- userId: user.id,
- threadId: note.threadId || note.id,
- },
- take: 1
- }),
- ]);
-
- return {
- isFavorited: favorite !== 0,
- isWatching: watching !== 0,
- isMutedThread: threadMuting !== 0,
- };
-});
diff --git a/src/server/api/endpoints/notes/thread-muting/create.ts b/src/server/api/endpoints/notes/thread-muting/create.ts
deleted file mode 100644
index 2010d54331..0000000000
--- a/src/server/api/endpoints/notes/thread-muting/create.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../../define';
-import { getNote } from '../../../common/getters';
-import { ApiError } from '../../../error';
-import { Notes, NoteThreadMutings } from '@/models';
-import { genId } from '@/misc/gen-id';
-import readNote from '@/services/note/read';
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: true as const,
-
- kind: 'write:account',
-
- params: {
- noteId: {
- validator: $.type(ID),
- }
- },
-
- errors: {
- noSuchNote: {
- message: 'No such note.',
- code: 'NO_SUCH_NOTE',
- id: '5ff67ada-ed3b-2e71-8e87-a1a421e177d2'
- }
- }
-};
-
-export default define(meta, async (ps, user) => {
- const note = await getNote(ps.noteId).catch(e => {
- if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
- throw e;
- });
-
- const mutedNotes = await Notes.find({
- where: [{
- id: note.threadId || note.id,
- }, {
- threadId: note.threadId || note.id,
- }],
- });
-
- await readNote(user.id, mutedNotes);
-
- await NoteThreadMutings.insert({
- id: genId(),
- createdAt: new Date(),
- threadId: note.threadId || note.id,
- userId: user.id,
- });
-});
diff --git a/src/server/api/endpoints/notes/thread-muting/delete.ts b/src/server/api/endpoints/notes/thread-muting/delete.ts
deleted file mode 100644
index 05d5691870..0000000000
--- a/src/server/api/endpoints/notes/thread-muting/delete.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../../define';
-import { getNote } from '../../../common/getters';
-import { ApiError } from '../../../error';
-import { NoteThreadMutings } from '@/models';
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: true as const,
-
- kind: 'write:account',
-
- params: {
- noteId: {
- validator: $.type(ID),
- }
- },
-
- errors: {
- noSuchNote: {
- message: 'No such note.',
- code: 'NO_SUCH_NOTE',
- id: 'bddd57ac-ceb3-b29d-4334-86ea5fae481a'
- }
- }
-};
-
-export default define(meta, async (ps, user) => {
- const note = await getNote(ps.noteId).catch(e => {
- if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
- throw e;
- });
-
- await NoteThreadMutings.delete({
- threadId: note.threadId || note.id,
- userId: user.id,
- });
-});
diff --git a/src/server/api/endpoints/notes/timeline.ts b/src/server/api/endpoints/notes/timeline.ts
deleted file mode 100644
index 1bd0e57d34..0000000000
--- a/src/server/api/endpoints/notes/timeline.ts
+++ /dev/null
@@ -1,150 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../define';
-import { makePaginationQuery } from '../../common/make-pagination-query';
-import { Notes, Followings } from '@/models/index';
-import { generateVisibilityQuery } from '../../common/generate-visibility-query';
-import { generateMutedUserQuery } from '../../common/generate-muted-user-query';
-import { activeUsersChart } from '@/services/chart/index';
-import { Brackets } from 'typeorm';
-import { generateRepliesQuery } from '../../common/generate-replies-query';
-import { generateMutedNoteQuery } from '../../common/generate-muted-note-query';
-import { generateChannelQuery } from '../../common/generate-channel-query';
-import { generateBlockedUserQuery } from '../../common/generate-block-query';
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: true as const,
-
- params: {
- limit: {
- validator: $.optional.num.range(1, 100),
- default: 10,
- },
-
- sinceId: {
- validator: $.optional.type(ID),
- },
-
- untilId: {
- validator: $.optional.type(ID),
- },
-
- sinceDate: {
- validator: $.optional.num,
- },
-
- untilDate: {
- validator: $.optional.num,
- },
-
- includeMyRenotes: {
- validator: $.optional.bool,
- default: true,
- },
-
- includeRenotedMyNotes: {
- validator: $.optional.bool,
- default: true,
- },
-
- includeLocalRenotes: {
- validator: $.optional.bool,
- default: true,
- },
-
- withFiles: {
- validator: $.optional.bool,
- },
- },
-
- res: {
- type: 'array' as const,
- optional: false as const, nullable: false as const,
- items: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- ref: 'Note',
- }
- },
-};
-
-export default define(meta, async (ps, user) => {
- const hasFollowing = (await Followings.count({
- where: {
- followerId: user.id,
- },
- take: 1
- })) !== 0;
-
- //#region Construct query
- const followingQuery = Followings.createQueryBuilder('following')
- .select('following.followeeId')
- .where('following.followerId = :followerId', { followerId: user.id });
-
- const query = makePaginationQuery(Notes.createQueryBuilder('note'),
- ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
- .andWhere(new Brackets(qb => { qb
- .where('note.userId = :meId', { meId: user.id });
- if (hasFollowing) qb.orWhere(`note.userId IN (${ followingQuery.getQuery() })`);
- }))
- .innerJoinAndSelect('note.user', 'user')
- .leftJoinAndSelect('note.reply', 'reply')
- .leftJoinAndSelect('note.renote', 'renote')
- .leftJoinAndSelect('reply.user', 'replyUser')
- .leftJoinAndSelect('renote.user', 'renoteUser')
- .setParameters(followingQuery.getParameters());
-
- generateChannelQuery(query, user);
- generateRepliesQuery(query, user);
- generateVisibilityQuery(query, user);
- generateMutedUserQuery(query, user);
- generateMutedNoteQuery(query, user);
- generateBlockedUserQuery(query, user);
-
- if (ps.includeMyRenotes === false) {
- query.andWhere(new Brackets(qb => {
- qb.orWhere('note.userId != :meId', { meId: user.id });
- qb.orWhere('note.renoteId IS NULL');
- qb.orWhere('note.text IS NOT NULL');
- qb.orWhere('note.fileIds != \'{}\'');
- qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)');
- }));
- }
-
- if (ps.includeRenotedMyNotes === false) {
- query.andWhere(new Brackets(qb => {
- qb.orWhere('note.renoteUserId != :meId', { meId: user.id });
- qb.orWhere('note.renoteId IS NULL');
- qb.orWhere('note.text IS NOT NULL');
- qb.orWhere('note.fileIds != \'{}\'');
- qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)');
- }));
- }
-
- if (ps.includeLocalRenotes === false) {
- query.andWhere(new Brackets(qb => {
- qb.orWhere('note.renoteUserHost IS NOT NULL');
- qb.orWhere('note.renoteId IS NULL');
- qb.orWhere('note.text IS NOT NULL');
- qb.orWhere('note.fileIds != \'{}\'');
- qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)');
- }));
- }
-
- if (ps.withFiles) {
- query.andWhere('note.fileIds != \'{}\'');
- }
- //#endregion
-
- const timeline = await query.take(ps.limit!).getMany();
-
- process.nextTick(() => {
- if (user) {
- activeUsersChart.update(user);
- }
- });
-
- return await Notes.packMany(timeline, user);
-});
diff --git a/src/server/api/endpoints/notes/translate.ts b/src/server/api/endpoints/notes/translate.ts
deleted file mode 100644
index b56b1debdd..0000000000
--- a/src/server/api/endpoints/notes/translate.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../define';
-import { getNote } from '../../common/getters';
-import { ApiError } from '../../error';
-import fetch from 'node-fetch';
-import config from '@/config/index';
-import { getAgentByUrl } from '@/misc/fetch';
-import { URLSearchParams } from 'url';
-import { fetchMeta } from '@/misc/fetch-meta';
-import { Notes } from '@/models';
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: false as const,
-
- params: {
- noteId: {
- validator: $.type(ID),
- },
- targetLang: {
- validator: $.str,
- },
- },
-
- res: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- },
-
- errors: {
- noSuchNote: {
- message: 'No such note.',
- code: 'NO_SUCH_NOTE',
- id: 'bea9b03f-36e0-49c5-a4db-627a029f8971'
- }
- }
-};
-
-export default define(meta, async (ps, user) => {
- const note = await getNote(ps.noteId).catch(e => {
- if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
- throw e;
- });
-
- if (!(await Notes.isVisibleForMe(note, user ? user.id : null))) {
- return 204; // TODO: 良い感じのエラー返す
- }
-
- if (note.text == null) {
- return 204;
- }
-
- const instance = await fetchMeta();
-
- if (instance.deeplAuthKey == null) {
- return 204; // TODO: 良い感じのエラー返す
- }
-
- let targetLang = ps.targetLang;
- if (targetLang.includes('-')) targetLang = targetLang.split('-')[0];
-
- const params = new URLSearchParams();
- params.append('auth_key', instance.deeplAuthKey);
- params.append('text', note.text);
- params.append('target_lang', targetLang);
-
- const endpoint = instance.deeplIsPro ? 'https://api.deepl.com/v2/translate' : 'https://api-free.deepl.com/v2/translate';
-
- const res = await fetch(endpoint, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded',
- 'User-Agent': config.userAgent,
- Accept: 'application/json, */*'
- },
- body: params,
- timeout: 10000,
- agent: getAgentByUrl,
- });
-
- const json = await res.json();
-
- return {
- sourceLang: json.translations[0].detected_source_language,
- text: json.translations[0].text
- };
-});
diff --git a/src/server/api/endpoints/notes/unrenote.ts b/src/server/api/endpoints/notes/unrenote.ts
deleted file mode 100644
index dce43d9d9c..0000000000
--- a/src/server/api/endpoints/notes/unrenote.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import deleteNote from '@/services/note/delete';
-import define from '../../define';
-import * as ms from 'ms';
-import { getNote } from '../../common/getters';
-import { ApiError } from '../../error';
-import { Notes, Users } from '@/models/index';
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: true as const,
-
- kind: 'write:notes',
-
- limit: {
- duration: ms('1hour'),
- max: 300,
- minInterval: ms('1sec')
- },
-
- params: {
- noteId: {
- validator: $.type(ID),
- }
- },
-
- errors: {
- noSuchNote: {
- message: 'No such note.',
- code: 'NO_SUCH_NOTE',
- id: 'efd4a259-2442-496b-8dd7-b255aa1a160f'
- },
- }
-};
-
-export default define(meta, async (ps, user) => {
- const note = await getNote(ps.noteId).catch(e => {
- if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
- throw e;
- });
-
- const renotes = await Notes.find({
- userId: user.id,
- renoteId: note.id
- });
-
- for (const note of renotes) {
- deleteNote(await Users.findOneOrFail(user.id), note);
- }
-});
diff --git a/src/server/api/endpoints/notes/user-list-timeline.ts b/src/server/api/endpoints/notes/user-list-timeline.ts
deleted file mode 100644
index 32c370004c..0000000000
--- a/src/server/api/endpoints/notes/user-list-timeline.ts
+++ /dev/null
@@ -1,147 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../define';
-import { ApiError } from '../../error';
-import { UserLists, UserListJoinings, Notes } from '@/models/index';
-import { makePaginationQuery } from '../../common/make-pagination-query';
-import { generateVisibilityQuery } from '../../common/generate-visibility-query';
-import { activeUsersChart } from '@/services/chart/index';
-import { Brackets } from 'typeorm';
-
-export const meta = {
- tags: ['notes', 'lists'],
-
- requireCredential: true as const,
-
- params: {
- listId: {
- validator: $.type(ID),
- },
-
- limit: {
- validator: $.optional.num.range(1, 100),
- default: 10,
- },
-
- sinceId: {
- validator: $.optional.type(ID),
- },
-
- untilId: {
- validator: $.optional.type(ID),
- },
-
- sinceDate: {
- validator: $.optional.num,
- },
-
- untilDate: {
- validator: $.optional.num,
- },
-
- includeMyRenotes: {
- validator: $.optional.bool,
- default: true,
- },
-
- includeRenotedMyNotes: {
- validator: $.optional.bool,
- default: true,
- },
-
- includeLocalRenotes: {
- validator: $.optional.bool,
- default: true,
- },
-
- withFiles: {
- validator: $.optional.bool,
- },
- },
-
- res: {
- type: 'array' as const,
- optional: false as const, nullable: false as const,
- items: {
- type: 'object' as const,
- optional: false as const, nullable: false as const,
- ref: 'Note',
- }
- },
-
- errors: {
- noSuchList: {
- message: 'No such list.',
- code: 'NO_SUCH_LIST',
- id: '8fb1fbd5-e476-4c37-9fb0-43d55b63a2ff'
- }
- }
-};
-
-export default define(meta, async (ps, user) => {
- const list = await UserLists.findOne({
- id: ps.listId,
- userId: user.id
- });
-
- if (list == null) {
- throw new ApiError(meta.errors.noSuchList);
- }
-
- //#region Construct query
- const listQuery = UserListJoinings.createQueryBuilder('joining')
- .select('joining.userId')
- .where('joining.userListId = :userListId', { userListId: list.id });
-
- const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId)
- .andWhere(`note.userId IN (${ listQuery.getQuery() })`)
- .innerJoinAndSelect('note.user', 'user')
- .leftJoinAndSelect('note.reply', 'reply')
- .leftJoinAndSelect('note.renote', 'renote')
- .leftJoinAndSelect('reply.user', 'replyUser')
- .leftJoinAndSelect('renote.user', 'renoteUser')
- .setParameters(listQuery.getParameters());
-
- generateVisibilityQuery(query, user);
-
- if (ps.includeMyRenotes === false) {
- query.andWhere(new Brackets(qb => {
- qb.orWhere('note.userId != :meId', { meId: user.id });
- qb.orWhere('note.renoteId IS NULL');
- qb.orWhere('note.text IS NOT NULL');
- qb.orWhere('note.fileIds != \'{}\'');
- qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)');
- }));
- }
-
- if (ps.includeRenotedMyNotes === false) {
- query.andWhere(new Brackets(qb => {
- qb.orWhere('note.renoteUserId != :meId', { meId: user.id });
- qb.orWhere('note.renoteId IS NULL');
- qb.orWhere('note.text IS NOT NULL');
- qb.orWhere('note.fileIds != \'{}\'');
- qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)');
- }));
- }
-
- if (ps.includeLocalRenotes === false) {
- query.andWhere(new Brackets(qb => {
- qb.orWhere('note.renoteUserHost IS NOT NULL');
- qb.orWhere('note.renoteId IS NULL');
- qb.orWhere('note.text IS NOT NULL');
- qb.orWhere('note.fileIds != \'{}\'');
- qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)');
- }));
- }
-
- if (ps.withFiles) {
- query.andWhere('note.fileIds != \'{}\'');
- }
- //#endregion
-
- const timeline = await query.take(ps.limit!).getMany();
-
- activeUsersChart.update(user);
-
- return await Notes.packMany(timeline, user);
-});
diff --git a/src/server/api/endpoints/notes/watching/create.ts b/src/server/api/endpoints/notes/watching/create.ts
deleted file mode 100644
index 4d182d3715..0000000000
--- a/src/server/api/endpoints/notes/watching/create.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../../define';
-import watch from '@/services/note/watch';
-import { getNote } from '../../../common/getters';
-import { ApiError } from '../../../error';
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: true as const,
-
- kind: 'write:account',
-
- params: {
- noteId: {
- validator: $.type(ID),
- }
- },
-
- errors: {
- noSuchNote: {
- message: 'No such note.',
- code: 'NO_SUCH_NOTE',
- id: 'ea0e37a6-90a3-4f58-ba6b-c328ca206fc7'
- }
- }
-};
-
-export default define(meta, async (ps, user) => {
- const note = await getNote(ps.noteId).catch(e => {
- if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
- throw e;
- });
-
- await watch(user.id, note);
-});
diff --git a/src/server/api/endpoints/notes/watching/delete.ts b/src/server/api/endpoints/notes/watching/delete.ts
deleted file mode 100644
index dd58c52b57..0000000000
--- a/src/server/api/endpoints/notes/watching/delete.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import $ from 'cafy';
-import { ID } from '@/misc/cafy-id';
-import define from '../../../define';
-import unwatch from '@/services/note/unwatch';
-import { getNote } from '../../../common/getters';
-import { ApiError } from '../../../error';
-
-export const meta = {
- tags: ['notes'],
-
- requireCredential: true as const,
-
- kind: 'write:account',
-
- params: {
- noteId: {
- validator: $.type(ID),
- }
- },
-
- errors: {
- noSuchNote: {
- message: 'No such note.',
- code: 'NO_SUCH_NOTE',
- id: '09b3695c-f72c-4731-a428-7cff825fc82e'
- }
- }
-};
-
-export default define(meta, async (ps, user) => {
- const note = await getNote(ps.noteId).catch(e => {
- if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
- throw e;
- });
-
- await unwatch(user.id, note);
-});