diff options
| author | tamaina <tamaina@hotmail.co.jp> | 2022-03-04 15:56:43 +0900 |
|---|---|---|
| committer | tamaina <tamaina@hotmail.co.jp> | 2022-03-04 15:56:43 +0900 |
| commit | a4de5aa94b9b318b1a286d36406e11e0e7f27590 (patch) | |
| tree | 6c0cd908b7e8f68fc300b9cb102f69b8ec2f5adc /packages/backend/src/server/api/endpoints/notes | |
| parent | Merge branch 'develop' into pizzax-indexeddb (diff) | |
| parent | fix federation chart pubsub (diff) | |
| download | misskey-a4de5aa94b9b318b1a286d36406e11e0e7f27590.tar.gz misskey-a4de5aa94b9b318b1a286d36406e11e0e7f27590.tar.bz2 misskey-a4de5aa94b9b318b1a286d36406e11e0e7f27590.zip | |
Merge branch 'develop' into pizzax-indexeddb
Diffstat (limited to 'packages/backend/src/server/api/endpoints/notes')
31 files changed, 696 insertions, 926 deletions
diff --git a/packages/backend/src/server/api/endpoints/notes/children.ts b/packages/backend/src/server/api/endpoints/notes/children.ts index 088ef65e96..86dde30d64 100644 --- a/packages/backend/src/server/api/endpoints/notes/children.ts +++ b/packages/backend/src/server/api/endpoints/notes/children.ts @@ -1,38 +1,17 @@ -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 define from '../../define.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; import { Brackets } from 'typeorm'; -import { Notes } from '@/models/index'; -import { generateBlockedUserQuery } from '../../common/generate-block-query'; -import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query'; +import { Notes } from '@/models/index.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; +import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query.js'; export const meta = { tags: ['notes'], requireCredential: false, - 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', optional: false, nullable: false, @@ -44,8 +23,19 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, 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 }) @@ -59,17 +49,23 @@ export default define(meta, async (ps, user) => { })); })) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); generateVisibilityQuery(query, user); if (user) generateMutedUserQuery(query, user); if (user) generateBlockedUserQuery(query, user); if (user) generateMutedInstanceQuery(query, user); - const notes = await query.take(ps.limit!).getMany(); + const notes = await query.take(ps.limit).getMany(); return await Notes.packMany(notes, user); }); diff --git a/packages/backend/src/server/api/endpoints/notes/clips.ts b/packages/backend/src/server/api/endpoints/notes/clips.ts index b89c6db4a8..9a863b7148 100644 --- a/packages/backend/src/server/api/endpoints/notes/clips.ts +++ b/packages/backend/src/server/api/endpoints/notes/clips.ts @@ -1,9 +1,7 @@ -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 define from '../../define.js'; +import { ClipNotes, Clips } from '@/models/index.js'; +import { getNote } from '../../common/getters.js'; +import { ApiError } from '../../error.js'; import { In } from 'typeorm'; export const meta = { @@ -11,12 +9,6 @@ export const meta = { requireCredential: false, - params: { - noteId: { - validator: $.type(ID), - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -36,8 +28,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, 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; diff --git a/packages/backend/src/server/api/endpoints/notes/conversation.ts b/packages/backend/src/server/api/endpoints/notes/conversation.ts index 4bd89c32e7..2552c0f99d 100644 --- a/packages/backend/src/server/api/endpoints/notes/conversation.ts +++ b/packages/backend/src/server/api/endpoints/notes/conversation.ts @@ -1,32 +1,14 @@ -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'; +import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { getNote } from '../../common/getters.js'; +import { Note } from '@/models/entities/note.js'; +import { Notes } from '@/models/index.js'; export const meta = { tags: ['notes'], requireCredential: false, - 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', optional: false, nullable: false, @@ -46,8 +28,18 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + offset: { type: 'integer', default: 0 }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, 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; @@ -65,7 +57,7 @@ export default define(meta, async (ps, user) => { conversation.push(p); } - if (conversation.length == ps.limit!) { + if (conversation.length == ps.limit) { return; } diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts index 4efa76b248..e4a9b28891 100644 --- a/packages/backend/src/server/api/endpoints/notes/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/create.ts @@ -1,26 +1,14 @@ -import $ from 'cafy'; import 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); +import create from '@/services/note/create.js'; +import define from '../../define.js'; +import { ApiError } from '../../error.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 { noteVisibilities } from '../../../../types.js'; +import { Channel } from '@/models/entities/channel.js'; +import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; export const meta = { tags: ['notes'], @@ -34,84 +22,6 @@ export const meta = { 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), - }, - - 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, 16), - }, - - mediaIds: { - validator: $.optional.arr($.type(ID)).unique().range(1, 16), - 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', optional: false, nullable: false, @@ -175,8 +85,49 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + visibility: { type: 'string', enum: ['public', 'home', 'followers', 'specified'], default: "public" }, + visibleUserIds: { type: 'array', uniqueItems: true, items: { + type: 'string', format: 'misskey:id', + } }, + text: { type: 'string', nullable: true, maxLength: MAX_NOTE_TEXT_LENGTH, default: null }, + cw: { type: 'string', nullable: true, maxLength: 100 }, + localOnly: { type: 'boolean', default: false }, + noExtractMentions: { type: 'boolean', default: false }, + noExtractHashtags: { type: 'boolean', default: false }, + noExtractEmojis: { type: 'boolean', default: false }, + fileIds: { type: 'array', uniqueItems: true, minItems: 1, maxItems: 16, items: { + type: 'string', format: 'misskey:id', + } }, + mediaIds: { type: 'array', uniqueItems: true, minItems: 1, maxItems: 16, items: { + type: 'string', format: 'misskey:id', + } }, + replyId: { type: 'string', format: 'misskey:id', nullable: true }, + renoteId: { type: 'string', format: 'misskey:id', nullable: true }, + channelId: { type: 'string', format: 'misskey:id', nullable: true }, + poll: { + type: 'object', nullable: true, + properties: { + choices: { + type: 'array', uniqueItems: true, minItems: 2, maxItems: 10, + items: { + type: 'string', minLength: 1, maxLength: 50, + }, + }, + multiple: { type: 'boolean', default: false }, + expiresAt: { type: 'integer', nullable: true }, + expiredAfter: { type: 'integer', nullable: true, minimum: 1 }, + }, + required: ['choices'], + }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { let visibleUsers: User[] = []; if (ps.visibleUserIds) { visibleUsers = (await Promise.all(ps.visibleUserIds.map(id => Users.findOne(id)))) diff --git a/packages/backend/src/server/api/endpoints/notes/delete.ts b/packages/backend/src/server/api/endpoints/notes/delete.ts index 9e080d9e99..22ff2275ca 100644 --- a/packages/backend/src/server/api/endpoints/notes/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/delete.ts @@ -1,11 +1,9 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import deleteNote from '@/services/note/delete'; -import define from '../../define'; +import deleteNote from '@/services/note/delete.js'; +import define from '../../define.js'; import ms from 'ms'; -import { getNote } from '../../common/getters'; -import { ApiError } from '../../error'; -import { Users } from '@/models/index'; +import { getNote } from '../../common/getters.js'; +import { ApiError } from '../../error.js'; +import { Users } from '@/models/index.js'; export const meta = { tags: ['notes'], @@ -20,12 +18,6 @@ export const meta = { minInterval: ms('1sec'), }, - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -41,8 +33,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, 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; diff --git a/packages/backend/src/server/api/endpoints/notes/favorites/create.ts b/packages/backend/src/server/api/endpoints/notes/favorites/create.ts index 78da6a3b00..bcc2c44c02 100644 --- a/packages/backend/src/server/api/endpoints/notes/favorites/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/favorites/create.ts @@ -1,10 +1,8 @@ -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'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { getNote } from '../../../common/getters.js'; +import { NoteFavorites } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; export const meta = { tags: ['notes', 'favorites'], @@ -13,12 +11,6 @@ export const meta = { kind: 'write:favorites', - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -34,8 +26,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, 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); diff --git a/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts b/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts index 3f3d50f0d5..d41fab22d3 100644 --- a/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts @@ -1,9 +1,7 @@ -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 define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { getNote } from '../../../common/getters.js'; +import { NoteFavorites } from '@/models/index.js'; export const meta = { tags: ['notes', 'favorites'], @@ -12,12 +10,6 @@ export const meta = { kind: 'write:favorites', - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -33,8 +25,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, 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); diff --git a/packages/backend/src/server/api/endpoints/notes/featured.ts b/packages/backend/src/server/api/endpoints/notes/featured.ts index 5a47fb9e08..6308d23696 100644 --- a/packages/backend/src/server/api/endpoints/notes/featured.ts +++ b/packages/backend/src/server/api/endpoints/notes/featured.ts @@ -1,26 +1,13 @@ -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'; +import define from '../../define.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { Notes } from '@/models/index.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['notes'], requireCredential: false, - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - offset: { - validator: $.optional.num.min(0), - default: 0, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -32,8 +19,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + offset: { type: 'integer', default: 0 }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const max = 30; const day = 1000 * 60 * 60 * 24 * 3; // 3日前まで @@ -44,10 +40,16 @@ export default define(meta, async (ps, user) => { .andWhere(`note.createdAt > :date`, { date: new Date(Date.now() - day) }) .andWhere(`note.visibility = 'public'`) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); if (user) generateMutedUserQuery(query, user); if (user) generateBlockedUserQuery(query, user); diff --git a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts index cac8b7d8a9..26aaa0919c 100644 --- a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts @@ -1,47 +1,18 @@ -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 { generateMutedInstanceQuery } from '../../common/generate-muted-instance-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'; +import define from '../../define.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { ApiError } from '../../error.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { Notes } from '@/models/index.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query.js'; +import { activeUsersChart } from '@/services/chart/index.js'; +import { generateRepliesQuery } from '../../common/generate-replies-query.js'; +import { generateMutedNoteQuery } from '../../common/generate-muted-note-query.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; 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', optional: false, nullable: false, @@ -61,8 +32,21 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + withFiles: { type: 'boolean' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + sinceDate: { type: 'integer' }, + untilDate: { type: 'integer' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const m = await fetchMeta(); if (m.disableGlobalTimeline) { if (user == null || (!user.isAdmin && !user.isModerator)) { @@ -76,10 +60,16 @@ export default define(meta, async (ps, user) => { .andWhere('note.visibility = \'public\'') .andWhere('note.channelId IS NULL') .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); generateRepliesQuery(query, user); if (user) generateMutedUserQuery(query, user); @@ -92,11 +82,11 @@ export default define(meta, async (ps, user) => { } //#endregion - const timeline = await query.take(ps.limit!).getMany(); + const timeline = await query.take(ps.limit).getMany(); process.nextTick(() => { if (user) { - activeUsersChart.update(user); + activeUsersChart.read(user); } }); diff --git a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts index 9683df4611..9bcb64b656 100644 --- a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -1,67 +1,23 @@ -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 define from '../../define.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { ApiError } from '../../error.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { Followings, Notes } from '@/models/index.js'; import { Brackets } from 'typeorm'; -import { generateVisibilityQuery } from '../../common/generate-visibility-query'; -import { generateMutedUserQuery } from '../../common/generate-muted-user-query'; -import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-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'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query.js'; +import { activeUsersChart } from '@/services/chart/index.js'; +import { generateRepliesQuery } from '../../common/generate-replies-query.js'; +import { generateMutedNoteQuery } from '../../common/generate-muted-note-query.js'; +import { generateChannelQuery } from '../../common/generate-channel-query.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['notes'], requireCredential: true, - 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', optional: false, nullable: false, @@ -81,8 +37,24 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + sinceDate: { type: 'integer' }, + untilDate: { type: 'integer' }, + includeMyRenotes: { type: 'boolean', default: true }, + includeRenotedMyNotes: { type: 'boolean', default: true }, + includeLocalRenotes: { type: 'boolean', default: true }, + withFiles: { type: 'boolean' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const m = await fetchMeta(); if (m.disableLocalTimeline && !user.isAdmin && !user.isModerator) { throw new ApiError(meta.errors.stlDisabled); @@ -100,10 +72,16 @@ export default define(meta, async (ps, user) => { .orWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)'); })) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') .setParameters(followingQuery.getParameters()); generateChannelQuery(query, user); @@ -149,11 +127,11 @@ export default define(meta, async (ps, user) => { } //#endregion - const timeline = await query.take(ps.limit!).getMany(); + const timeline = await query.take(ps.limit).getMany(); process.nextTick(() => { if (user) { - activeUsersChart.update(user); + activeUsersChart.read(user); } }); diff --git a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts index 7776644124..12fc88b1fd 100644 --- a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts @@ -1,58 +1,20 @@ -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 define from '../../define.js'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { ApiError } from '../../error.js'; +import { Notes } from '@/models/index.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { activeUsersChart } from '@/services/chart/index.js'; 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'; +import { generateRepliesQuery } from '../../common/generate-replies-query.js'; +import { generateMutedNoteQuery } from '../../common/generate-muted-note-query.js'; +import { generateChannelQuery } from '../../common/generate-channel-query.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; 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', optional: false, nullable: false, @@ -72,8 +34,25 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + withFiles: { type: 'boolean' }, + fileType: { type: 'array', items: { + type: 'string', + } }, + excludeNsfw: { type: 'boolean', default: false }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + sinceDate: { type: 'integer' }, + untilDate: { type: 'integer' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const m = await fetchMeta(); if (m.disableLocalTimeline) { if (user == null || (!user.isAdmin && !user.isModerator)) { @@ -86,10 +65,16 @@ export default define(meta, async (ps, user) => { ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) .andWhere('(note.visibility = \'public\') AND (note.userHost IS NULL)') .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); generateChannelQuery(query, user); generateRepliesQuery(query, user); @@ -118,11 +103,11 @@ export default define(meta, async (ps, user) => { } //#endregion - const timeline = await query.take(ps.limit!).getMany(); + const timeline = await query.take(ps.limit).getMany(); process.nextTick(() => { if (user) { - activeUsersChart.update(user); + activeUsersChart.read(user); } }); diff --git a/packages/backend/src/server/api/endpoints/notes/mentions.ts b/packages/backend/src/server/api/endpoints/notes/mentions.ts index 81b3844365..eafbba322d 100644 --- a/packages/backend/src/server/api/endpoints/notes/mentions.ts +++ b/packages/backend/src/server/api/endpoints/notes/mentions.ts @@ -1,44 +1,18 @@ -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 define from '../../define.js'; +import read from '@/services/note/read.js'; +import { Notes, Followings } from '@/models/index.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; import { Brackets } from 'typeorm'; -import { generateBlockedUserQuery } from '../../common/generate-block-query'; -import { generateMutedNoteThreadQuery } from '../../common/generate-muted-note-thread-query'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; +import { generateMutedNoteThreadQuery } from '../../common/generate-muted-note-thread-query.js'; export const meta = { tags: ['notes'], requireCredential: true, - 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', optional: false, nullable: false, @@ -50,8 +24,20 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + following: { type: 'boolean', default: false }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + visibility: { type: 'string' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const followingQuery = Followings.createQueryBuilder('following') .select('following.followeeId') .where('following.followerId = :followerId', { followerId: user.id }); @@ -62,10 +48,16 @@ export default define(meta, async (ps, user) => { .orWhere(`'{"${user.id}"}' <@ note.visibleUserIds`); })) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); generateVisibilityQuery(query, user); generateMutedUserQuery(query, user); @@ -81,7 +73,7 @@ export default define(meta, async (ps, user) => { query.setParameters(followingQuery.getParameters()); } - const mentions = await query.take(ps.limit!).getMany(); + const mentions = await query.take(ps.limit).getMany(); read(user.id, mentions); diff --git a/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts b/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts index 79b558e65e..bdd1aeecd4 100644 --- a/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts +++ b/packages/backend/src/server/api/endpoints/notes/polls/recommendation.ts @@ -1,6 +1,5 @@ -import $ from 'cafy'; -import define from '../../../define'; -import { Polls, Mutings, Notes, PollVotes } from '@/models/index'; +import define from '../../../define.js'; +import { Polls, Mutings, Notes, PollVotes } from '@/models/index.js'; import { Brackets, In } from 'typeorm'; export const meta = { @@ -8,18 +7,6 @@ export const meta = { requireCredential: true, - params: { - limit: { - validator: $.optional.num.range(1, 100), - default: 10, - }, - - offset: { - validator: $.optional.num.min(0), - default: 0, - }, - }, - res: { type: 'array', optional: false, nullable: false, @@ -31,8 +18,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + offset: { type: 'integer', default: 0 }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const query = Polls.createQueryBuilder('poll') .where('poll.userHost IS NULL') .andWhere(`poll.userId != :meId`, { meId: user.id }) @@ -64,7 +60,7 @@ export default define(meta, async (ps, user) => { query.setParameters(mutingQuery.getParameters()); //#endregion - const polls = await query.take(ps.limit!).skip(ps.offset).getMany(); + const polls = await query.take(ps.limit).skip(ps.offset).getMany(); if (polls.length === 0) return []; diff --git a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts index 77387cacb2..ef52d03664 100644 --- a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts +++ b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts @@ -1,18 +1,16 @@ -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 { publishNoteStream } from '@/services/stream.js'; +import { createNotification } from '@/services/create-notification.js'; +import define from '../../../define.js'; +import { ApiError } from '../../../error.js'; +import { getNote } from '../../../common/getters.js'; +import { deliver } from '@/queue/index.js'; +import { renderActivity } from '@/remote/activitypub/renderer/index.js'; +import renderVote from '@/remote/activitypub/renderer/vote.js'; +import { deliverQuestionUpdate } from '@/services/note/polls/update.js'; +import { PollVotes, NoteWatchings, Users, Polls, Blockings } from '@/models/index.js'; import { Not } from 'typeorm'; -import { IRemoteUser } from '@/models/entities/user'; -import { genId } from '@/misc/gen-id'; +import { IRemoteUser } from '@/models/entities/user.js'; +import { genId } from '@/misc/gen-id.js'; export const meta = { tags: ['notes'], @@ -21,16 +19,6 @@ export const meta = { kind: 'write:votes', - params: { - noteId: { - validator: $.type(ID), - }, - - choice: { - validator: $.num, - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -70,8 +58,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + choice: { type: 'integer' }, + }, + required: ['noteId', 'choice'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const createdAt = new Date(); // Get votee diff --git a/packages/backend/src/server/api/endpoints/notes/reactions.ts b/packages/backend/src/server/api/endpoints/notes/reactions.ts index 5205a78171..43e5d1ef6f 100644 --- a/packages/backend/src/server/api/endpoints/notes/reactions.ts +++ b/packages/backend/src/server/api/endpoints/notes/reactions.ts @@ -1,45 +1,15 @@ -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 define from '../../define.js'; +import { getNote } from '../../common/getters.js'; +import { ApiError } from '../../error.js'; +import { NoteReactions } from '@/models/index.js'; import { DeepPartial } from 'typeorm'; -import { NoteReaction } from '@/models/entities/note-reaction'; +import { NoteReaction } from '@/models/entities/note-reaction.js'; export const meta = { tags: ['notes', 'reactions'], requireCredential: false, - 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', optional: false, nullable: false, @@ -59,8 +29,21 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + type: { type: 'string', nullable: true }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + offset: { type: 'integer', default: 0 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, 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; @@ -80,11 +63,12 @@ export default define(meta, async (ps, user) => { const reactions = await NoteReactions.find({ where: query, - take: ps.limit!, + take: ps.limit, skip: ps.offset, order: { id: -1, }, + relations: ['user', 'user.avatar', 'user.banner', 'note'], }); return await Promise.all(reactions.map(reaction => NoteReactions.pack(reaction, user))); diff --git a/packages/backend/src/server/api/endpoints/notes/reactions/create.ts b/packages/backend/src/server/api/endpoints/notes/reactions/create.ts index 1b42781ceb..07e52a9266 100644 --- a/packages/backend/src/server/api/endpoints/notes/reactions/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/reactions/create.ts @@ -1,9 +1,7 @@ -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'; +import createReaction from '@/services/note/reaction/create.js'; +import define from '../../../define.js'; +import { getNote } from '../../../common/getters.js'; +import { ApiError } from '../../../error.js'; export const meta = { tags: ['reactions', 'notes'], @@ -12,16 +10,6 @@ export const meta = { kind: 'write:reactions', - params: { - noteId: { - validator: $.type(ID), - }, - - reaction: { - validator: $.str, - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -43,8 +31,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + reaction: { type: 'string' }, + }, + required: ['noteId', 'reaction'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, 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; diff --git a/packages/backend/src/server/api/endpoints/notes/reactions/delete.ts b/packages/backend/src/server/api/endpoints/notes/reactions/delete.ts index 1d686b5971..639ecae264 100644 --- a/packages/backend/src/server/api/endpoints/notes/reactions/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/reactions/delete.ts @@ -1,10 +1,8 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../../define'; +import define from '../../../define.js'; import ms from 'ms'; -import deleteReaction from '@/services/note/reaction/delete'; -import { getNote } from '../../../common/getters'; -import { ApiError } from '../../../error'; +import deleteReaction from '@/services/note/reaction/delete.js'; +import { getNote } from '../../../common/getters.js'; +import { ApiError } from '../../../error.js'; export const meta = { tags: ['reactions', 'notes'], @@ -19,12 +17,6 @@ export const meta = { minInterval: ms('3sec'), }, - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -40,8 +32,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, 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; diff --git a/packages/backend/src/server/api/endpoints/notes/renotes.ts b/packages/backend/src/server/api/endpoints/notes/renotes.ts index f71d23146a..87c855a5e8 100644 --- a/packages/backend/src/server/api/endpoints/notes/renotes.ts +++ b/packages/backend/src/server/api/endpoints/notes/renotes.ts @@ -1,38 +1,17 @@ -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'; +import define from '../../define.js'; +import { getNote } from '../../common/getters.js'; +import { ApiError } from '../../error.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { Notes } from '@/models/index.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['notes'], requireCredential: false, - 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', optional: false, nullable: false, @@ -52,8 +31,19 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, 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; @@ -62,16 +52,22 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.renoteId = :renoteId`, { renoteId: note.id }) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); generateVisibilityQuery(query, user); if (user) generateMutedUserQuery(query, user); if (user) generateBlockedUserQuery(query, user); - const renotes = await query.take(ps.limit!).getMany(); + const renotes = await query.take(ps.limit).getMany(); return await Notes.packMany(renotes, user); }); diff --git a/packages/backend/src/server/api/endpoints/notes/replies.ts b/packages/backend/src/server/api/endpoints/notes/replies.ts index 62c56534e1..3053eabe33 100644 --- a/packages/backend/src/server/api/endpoints/notes/replies.ts +++ b/packages/backend/src/server/api/endpoints/notes/replies.ts @@ -1,36 +1,15 @@ -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'; +import define from '../../define.js'; +import { Notes } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['notes'], requireCredential: false, - 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', optional: false, nullable: false, @@ -42,21 +21,38 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, 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('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); generateVisibilityQuery(query, user); if (user) generateMutedUserQuery(query, user); if (user) generateBlockedUserQuery(query, user); - const timeline = await query.take(ps.limit!).getMany(); + const timeline = await query.take(ps.limit).getMany(); return await Notes.packMany(timeline, user); }); diff --git a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts index 87eaffe2f1..c6503eb057 100644 --- a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts +++ b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts @@ -1,60 +1,16 @@ -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 define from '../../define.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { Notes } from '@/models/index.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; 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'; +import { safeForSql } from '@/misc/safe-for-sql.js'; +import { normalizeForSearch } from '@/misc/normalize-for-search.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; 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', optional: false, nullable: false, @@ -66,14 +22,40 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + tag: { type: 'string' }, + query: { type: 'array', items: { + type: 'array', items: { + type: 'string', + }, + } }, + reply: { type: 'boolean', nullable: true, default: null }, + renote: { type: 'boolean', nullable: true, default: null }, + withFiles: { type: 'boolean' }, + poll: { type: 'boolean', nullable: true, default: null }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); generateVisibilityQuery(query, me); if (me) generateMutedUserQuery(query, me); @@ -129,7 +111,7 @@ export default define(meta, async (ps, me) => { } // Search notes - const notes = await query.take(ps.limit!).getMany(); + const notes = await query.take(ps.limit).getMany(); return await Notes.packMany(notes, me); }); diff --git a/packages/backend/src/server/api/endpoints/notes/search.ts b/packages/backend/src/server/api/endpoints/notes/search.ts index e75212b14b..e77892b150 100644 --- a/packages/backend/src/server/api/endpoints/notes/search.ts +++ b/packages/backend/src/server/api/endpoints/notes/search.ts @@ -1,54 +1,18 @@ -import $ from 'cafy'; -import es from '../../../../db/elasticsearch'; -import define from '../../define'; -import { Notes } from '@/models/index'; +import es from '../../../../db/elasticsearch.js'; +import define from '../../define.js'; +import { Notes } from '@/models/index.js'; 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'; +import config from '@/config/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['notes'], requireCredential: false, - 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', optional: false, nullable: false, @@ -63,8 +27,23 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + query: { type: 'string' }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + offset: { type: 'integer', default: 0 }, + host: { type: 'string', nullable: true }, + userId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, + channelId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, + }, + required: ['query'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, me) => { +export default define(meta, paramDef, async (ps, me) => { if (es == null) { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId); @@ -77,16 +56,22 @@ export default define(meta, async (ps, me) => { query .andWhere('note.text ILIKE :q', { q: `%${ps.query}%` }) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') - .leftJoinAndSelect('renote.user', 'renoteUser'); + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') + .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner'); generateVisibilityQuery(query, me); if (me) generateMutedUserQuery(query, me); if (me) generateBlockedUserQuery(query, me); - const notes = await query.take(ps.limit!).getMany(); + const notes = await query.take(ps.limit).getMany(); return await Notes.packMany(notes, me); } else { @@ -115,7 +100,7 @@ export default define(meta, async (ps, me) => { const result = await es.search({ index: config.elasticsearch.index || 'misskey_note', body: { - size: ps.limit!, + size: ps.limit, from: ps.offset, query: { bool: { diff --git a/packages/backend/src/server/api/endpoints/notes/show.ts b/packages/backend/src/server/api/endpoints/notes/show.ts index feb94be1a1..d6692923c3 100644 --- a/packages/backend/src/server/api/endpoints/notes/show.ts +++ b/packages/backend/src/server/api/endpoints/notes/show.ts @@ -1,21 +1,13 @@ -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'; +import define from '../../define.js'; +import { getNote } from '../../common/getters.js'; +import { ApiError } from '../../error.js'; +import { Notes } from '@/models/index.js'; export const meta = { tags: ['notes'], requireCredential: false, - params: { - noteId: { - validator: $.type(ID), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -31,8 +23,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, 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; diff --git a/packages/backend/src/server/api/endpoints/notes/state.ts b/packages/backend/src/server/api/endpoints/notes/state.ts index c3e9090bbf..6fdb8e88fb 100644 --- a/packages/backend/src/server/api/endpoints/notes/state.ts +++ b/packages/backend/src/server/api/endpoints/notes/state.ts @@ -1,19 +1,11 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { NoteFavorites, Notes, NoteThreadMutings, NoteWatchings } from '@/models/index'; +import define from '../../define.js'; +import { NoteFavorites, Notes, NoteThreadMutings, NoteWatchings } from '@/models/index.js'; export const meta = { tags: ['notes'], requireCredential: true, - params: { - noteId: { - validator: $.type(ID), - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -34,8 +26,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const note = await Notes.findOneOrFail(ps.noteId); const [favorite, watching, threadMuting] = await Promise.all([ diff --git a/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts b/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts index a8b50d90f6..e48a2cf576 100644 --- a/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts @@ -1,11 +1,9 @@ -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'; +import define from '../../../define.js'; +import { getNote } from '../../../common/getters.js'; +import { ApiError } from '../../../error.js'; +import { Notes, NoteThreadMutings } from '@/models/index.js'; +import { genId } from '@/misc/gen-id.js'; +import readNote from '@/services/note/read.js'; export const meta = { tags: ['notes'], @@ -14,12 +12,6 @@ export const meta = { kind: 'write:account', - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -29,8 +21,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, 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; diff --git a/packages/backend/src/server/api/endpoints/notes/thread-muting/delete.ts b/packages/backend/src/server/api/endpoints/notes/thread-muting/delete.ts index f76b526ce1..4fb3137a5e 100644 --- a/packages/backend/src/server/api/endpoints/notes/thread-muting/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/thread-muting/delete.ts @@ -1,9 +1,7 @@ -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'; +import define from '../../../define.js'; +import { getNote } from '../../../common/getters.js'; +import { ApiError } from '../../../error.js'; +import { NoteThreadMutings } from '@/models/index.js'; export const meta = { tags: ['notes'], @@ -12,12 +10,6 @@ export const meta = { kind: 'write:account', - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -27,8 +19,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, 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; diff --git a/packages/backend/src/server/api/endpoints/notes/timeline.ts b/packages/backend/src/server/api/endpoints/notes/timeline.ts index 8be2861aec..fde66b241b 100644 --- a/packages/backend/src/server/api/endpoints/notes/timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/timeline.ts @@ -1,65 +1,21 @@ -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 { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query'; -import { activeUsersChart } from '@/services/chart/index'; +import define from '../../define.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { Notes, Followings } from '@/models/index.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { generateMutedUserQuery } from '../../common/generate-muted-user-query.js'; +import { generateMutedInstanceQuery } from '../../common/generate-muted-instance-query.js'; +import { activeUsersChart } from '@/services/chart/index.js'; 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'; +import { generateRepliesQuery } from '../../common/generate-replies-query.js'; +import { generateMutedNoteQuery } from '../../common/generate-muted-note-query.js'; +import { generateChannelQuery } from '../../common/generate-channel-query.js'; +import { generateBlockedUserQuery } from '../../common/generate-block-query.js'; export const meta = { tags: ['notes'], requireCredential: true, - 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', optional: false, nullable: false, @@ -71,8 +27,24 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + sinceDate: { type: 'integer' }, + untilDate: { type: 'integer' }, + includeMyRenotes: { type: 'boolean', default: true }, + includeRenotedMyNotes: { type: 'boolean', default: true }, + includeLocalRenotes: { type: 'boolean', default: true }, + withFiles: { type: 'boolean' }, + }, + required: [], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const hasFollowing = (await Followings.count({ where: { followerId: user.id, @@ -92,10 +64,16 @@ export default define(meta, async (ps, user) => { if (hasFollowing) qb.orWhere(`note.userId IN (${ followingQuery.getQuery() })`); })) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') .setParameters(followingQuery.getParameters()); generateChannelQuery(query, user); @@ -141,11 +119,11 @@ export default define(meta, async (ps, user) => { } //#endregion - const timeline = await query.take(ps.limit!).getMany(); + const timeline = await query.take(ps.limit).getMany(); process.nextTick(() => { if (user) { - activeUsersChart.update(user); + activeUsersChart.read(user); } }); diff --git a/packages/backend/src/server/api/endpoints/notes/translate.ts b/packages/backend/src/server/api/endpoints/notes/translate.ts index ed069cb75a..068df6940b 100644 --- a/packages/backend/src/server/api/endpoints/notes/translate.ts +++ b/packages/backend/src/server/api/endpoints/notes/translate.ts @@ -1,29 +1,18 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import define from '../../define'; -import { getNote } from '../../common/getters'; -import { ApiError } from '../../error'; +import define from '../../define.js'; +import { getNote } from '../../common/getters.js'; +import { ApiError } from '../../error.js'; 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'; +import config from '@/config/index.js'; +import { getAgentByUrl } from '@/misc/fetch.js'; +import { URLSearchParams } from 'node:url'; +import { fetchMeta } from '@/misc/fetch-meta.js'; +import { Notes } from '@/models/index.js'; export const meta = { tags: ['notes'], requireCredential: false, - params: { - noteId: { - validator: $.type(ID), - }, - targetLang: { - validator: $.str, - }, - }, - res: { type: 'object', optional: false, nullable: false, @@ -38,8 +27,17 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + targetLang: { type: 'string' }, + }, + required: ['noteId', 'targetLang'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, 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; diff --git a/packages/backend/src/server/api/endpoints/notes/unrenote.ts b/packages/backend/src/server/api/endpoints/notes/unrenote.ts index 8db543d328..a9aadba338 100644 --- a/packages/backend/src/server/api/endpoints/notes/unrenote.ts +++ b/packages/backend/src/server/api/endpoints/notes/unrenote.ts @@ -1,11 +1,9 @@ -import $ from 'cafy'; -import { ID } from '@/misc/cafy-id'; -import deleteNote from '@/services/note/delete'; -import define from '../../define'; +import deleteNote from '@/services/note/delete.js'; +import define from '../../define.js'; import ms from 'ms'; -import { getNote } from '../../common/getters'; -import { ApiError } from '../../error'; -import { Notes, Users } from '@/models/index'; +import { getNote } from '../../common/getters.js'; +import { ApiError } from '../../error.js'; +import { Notes, Users } from '@/models/index.js'; export const meta = { tags: ['notes'], @@ -20,12 +18,6 @@ export const meta = { minInterval: ms('1sec'), }, - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -35,8 +27,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, 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; diff --git a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts index 89de73fb9d..0829d0e4c1 100644 --- a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts @@ -1,11 +1,9 @@ -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 define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { UserLists, UserListJoinings, Notes } from '@/models/index.js'; +import { makePaginationQuery } from '../../common/make-pagination-query.js'; +import { generateVisibilityQuery } from '../../common/generate-visibility-query.js'; +import { activeUsersChart } from '@/services/chart/index.js'; import { Brackets } from 'typeorm'; export const meta = { @@ -13,52 +11,6 @@ export const meta = { requireCredential: true, - 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', optional: false, nullable: false, @@ -78,8 +30,25 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + listId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + sinceDate: { type: 'integer' }, + untilDate: { type: 'integer' }, + includeMyRenotes: { type: 'boolean', default: true }, + includeRenotedMyNotes: { type: 'boolean', default: true }, + includeLocalRenotes: { type: 'boolean', default: true }, + withFiles: { type: 'boolean' }, + }, + required: ['listId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, async (ps, user) => { const list = await UserLists.findOne({ id: ps.listId, userId: user.id, @@ -97,10 +66,16 @@ export default define(meta, async (ps, user) => { const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) .andWhere(`note.userId IN (${ listQuery.getQuery() })`) .innerJoinAndSelect('note.user', 'user') + .leftJoinAndSelect('user.avatar', 'avatar') + .leftJoinAndSelect('user.banner', 'banner') .leftJoinAndSelect('note.reply', 'reply') .leftJoinAndSelect('note.renote', 'renote') .leftJoinAndSelect('reply.user', 'replyUser') + .leftJoinAndSelect('replyUser.avatar', 'replyUserAvatar') + .leftJoinAndSelect('replyUser.banner', 'replyUserBanner') .leftJoinAndSelect('renote.user', 'renoteUser') + .leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar') + .leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner') .setParameters(listQuery.getParameters()); generateVisibilityQuery(query, user); @@ -140,9 +115,9 @@ export default define(meta, async (ps, user) => { } //#endregion - const timeline = await query.take(ps.limit!).getMany(); + const timeline = await query.take(ps.limit).getMany(); - activeUsersChart.update(user); + activeUsersChart.read(user); return await Notes.packMany(timeline, user); }); diff --git a/packages/backend/src/server/api/endpoints/notes/watching/create.ts b/packages/backend/src/server/api/endpoints/notes/watching/create.ts index 6433c6bc2a..8fdf84624e 100644 --- a/packages/backend/src/server/api/endpoints/notes/watching/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/watching/create.ts @@ -1,9 +1,7 @@ -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'; +import define from '../../../define.js'; +import watch from '@/services/note/watch.js'; +import { getNote } from '../../../common/getters.js'; +import { ApiError } from '../../../error.js'; export const meta = { tags: ['notes'], @@ -12,12 +10,6 @@ export const meta = { kind: 'write:account', - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -27,8 +19,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, 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; diff --git a/packages/backend/src/server/api/endpoints/notes/watching/delete.ts b/packages/backend/src/server/api/endpoints/notes/watching/delete.ts index 3e9faa2b23..d58f09797c 100644 --- a/packages/backend/src/server/api/endpoints/notes/watching/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/watching/delete.ts @@ -1,9 +1,7 @@ -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'; +import define from '../../../define.js'; +import unwatch from '@/services/note/unwatch.js'; +import { getNote } from '../../../common/getters.js'; +import { ApiError } from '../../../error.js'; export const meta = { tags: ['notes'], @@ -12,12 +10,6 @@ export const meta = { kind: 'write:account', - params: { - noteId: { - validator: $.type(ID), - }, - }, - errors: { noSuchNote: { message: 'No such note.', @@ -27,8 +19,16 @@ export const meta = { }, } as const; +export const paramDef = { + type: 'object', + properties: { + noteId: { type: 'string', format: 'misskey:id' }, + }, + required: ['noteId'], +} as const; + // eslint-disable-next-line import/no-default-export -export default define(meta, async (ps, user) => { +export default define(meta, paramDef, 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; |