From 6a2fc0f0cf36c6f40fcbe797af708f0bf99e1d25 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih Date: Mon, 9 Oct 2023 18:45:26 +0900 Subject: [PATCH 1/8] =?UTF-8?q?(add)=20=E3=83=95=E3=82=A1=E3=82=A4?= =?UTF-8?q?=E3=83=AB=E3=83=93=E3=83=A5=E3=83=BC=E3=82=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/index.d.ts | 8 + locales/ja-JP.yml | 8 + .../backend/src/server/api/EndpointsModule.ts | 4 + packages/backend/src/server/api/endpoints.ts | 2 + .../api/endpoints/notes/search-by-file-id.ts | 88 ++++++ .../frontend/src/components/MkDrive.file.vue | 5 +- .../frontend/src/pages/drive.file.info.vue | 279 ++++++++++++++++++ .../frontend/src/pages/drive.file.notes.vue | 32 ++ packages/frontend/src/pages/drive.file.vue | 52 ++++ packages/frontend/src/router.ts | 4 + .../src/scripts/get-drive-file-menu.ts | 7 +- packages/misskey-js/etc/misskey-js.api.md | 6 +- packages/misskey-js/src/api.types.ts | 1 + 13 files changed, 493 insertions(+), 3 deletions(-) create mode 100644 packages/backend/src/server/api/endpoints/notes/search-by-file-id.ts create mode 100644 packages/frontend/src/pages/drive.file.info.vue create mode 100644 packages/frontend/src/pages/drive.file.notes.vue create mode 100644 packages/frontend/src/pages/drive.file.vue diff --git a/locales/index.d.ts b/locales/index.d.ts index 8a429e3b661d..75017293728f 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -2294,6 +2294,14 @@ export interface Locale { "deleteAd": string; "updateAd": string; }; + "_fileViewer": { + "title": string; + "type": string; + "size": string; + "url": string; + "uploadedAt": string; + "attachedNotes": string; + }; } declare const locales: { [lang: string]: Locale; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 52e06e720d74..cb2aae7e9f96 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2206,3 +2206,11 @@ _moderationLogTypes: createAd: "広告を作成" deleteAd: "広告を削除" updateAd: "広告を更新" + +_fileViewer: + title: "ファイルの詳細" + type: "ファイルタイプ" + size: "ファイルサイズ" + url: "URL" + uploadedAt: "追加日" + attachedNotes: "添付されたノート" diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts index f834561456e1..cf97887b452b 100644 --- a/packages/backend/src/server/api/EndpointsModule.ts +++ b/packages/backend/src/server/api/EndpointsModule.ts @@ -271,6 +271,7 @@ import * as ep___notes_reactions_create from './endpoints/notes/reactions/create import * as ep___notes_reactions_delete from './endpoints/notes/reactions/delete.js'; import * as ep___notes_renotes from './endpoints/notes/renotes.js'; import * as ep___notes_replies from './endpoints/notes/replies.js'; +import * as ep___notes_searchByFileId from './endpoints/notes/search-by-file-id.js'; import * as ep___notes_searchByTag from './endpoints/notes/search-by-tag.js'; import * as ep___notes_search from './endpoints/notes/search.js'; import * as ep___notes_show from './endpoints/notes/show.js'; @@ -621,6 +622,7 @@ const $notes_reactions_create: Provider = { provide: 'ep:notes/reactions/create' const $notes_reactions_delete: Provider = { provide: 'ep:notes/reactions/delete', useClass: ep___notes_reactions_delete.default }; const $notes_renotes: Provider = { provide: 'ep:notes/renotes', useClass: ep___notes_renotes.default }; const $notes_replies: Provider = { provide: 'ep:notes/replies', useClass: ep___notes_replies.default }; +const $notes_searchByFileId: Provider = { provide: 'ep:notes/search-by-file-id', useClass: ep___notes_searchByFileId.default }; const $notes_searchByTag: Provider = { provide: 'ep:notes/search-by-tag', useClass: ep___notes_searchByTag.default }; const $notes_search: Provider = { provide: 'ep:notes/search', useClass: ep___notes_search.default }; const $notes_show: Provider = { provide: 'ep:notes/show', useClass: ep___notes_show.default }; @@ -975,6 +977,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $notes_reactions_delete, $notes_renotes, $notes_replies, + $notes_searchByFileId, $notes_searchByTag, $notes_search, $notes_show, @@ -1323,6 +1326,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $notes_reactions_delete, $notes_renotes, $notes_replies, + $notes_searchByFileId, $notes_searchByTag, $notes_search, $notes_show, diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index d12a035afac2..085c678dfb3d 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -271,6 +271,7 @@ import * as ep___notes_reactions_create from './endpoints/notes/reactions/create import * as ep___notes_reactions_delete from './endpoints/notes/reactions/delete.js'; import * as ep___notes_renotes from './endpoints/notes/renotes.js'; import * as ep___notes_replies from './endpoints/notes/replies.js'; +import * as ep___notes_searchByFileId from './endpoints/notes/search-by-file-id.js'; import * as ep___notes_searchByTag from './endpoints/notes/search-by-tag.js'; import * as ep___notes_search from './endpoints/notes/search.js'; import * as ep___notes_show from './endpoints/notes/show.js'; @@ -619,6 +620,7 @@ const eps = [ ['notes/reactions/delete', ep___notes_reactions_delete], ['notes/renotes', ep___notes_renotes], ['notes/replies', ep___notes_replies], + ['notes/search-by-file-id', ep___notes_searchByFileId], ['notes/search-by-tag', ep___notes_searchByTag], ['notes/search', ep___notes_search], ['notes/show', ep___notes_show], diff --git a/packages/backend/src/server/api/endpoints/notes/search-by-file-id.ts b/packages/backend/src/server/api/endpoints/notes/search-by-file-id.ts new file mode 100644 index 000000000000..8fc4b66407e0 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/notes/search-by-file-id.ts @@ -0,0 +1,88 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Brackets } from 'typeorm'; +import { Inject, Injectable } from '@nestjs/common'; +import type { NotesRepository } from '@/models/_.js'; +import { safeForSql } from '@/misc/safe-for-sql.js'; +import { normalizeForSearch } from '@/misc/normalize-for-search.js'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { QueryService } from '@/core/QueryService.js'; +import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; +import { DI } from '@/di-symbols.js'; + +export const meta = { + tags: ['notes', 'drive'], + + res: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + ref: 'Note', + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + reply: { 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 }, + + fileId: { type: 'string', format: 'misskey:id' }, + }, + required: ['fileId'], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + @Inject(DI.notesRepository) + private notesRepository: NotesRepository, + + private noteEntityService: NoteEntityService, + private queryService: QueryService, + ) { + super(meta, paramDef, async (ps, me) => { + const query = this.queryService.makePaginationQuery(this.notesRepository.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'); + + this.queryService.generateVisibilityQuery(query, me); + if (me) this.queryService.generateMutedUserQuery(query, me); + if (me) this.queryService.generateBlockedUserQuery(query, me); + + try { + if (ps.fileId) { + if (!safeForSql(normalizeForSearch(ps.fileId))) throw new Error('Injection'); + query.andWhere(`'{"${normalizeForSearch(ps.fileId)}"}' <@ note.fileIds`); + } + } 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'); + } + } + + // Search notes + const notes = await query.limit(ps.limit).getMany(); + + return await this.noteEntityService.packMany(notes, me); + }); + } +} diff --git a/packages/frontend/src/components/MkDrive.file.vue b/packages/frontend/src/components/MkDrive.file.vue index e3f96724d9dc..96704996f9c3 100644 --- a/packages/frontend/src/components/MkDrive.file.vue +++ b/packages/frontend/src/components/MkDrive.file.vue @@ -45,8 +45,11 @@ import bytes from '@/filters/bytes.js'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; import { $i } from '@/account.js'; +import { useRouter } from '@/router.js'; import { getDriveFileMenu } from '@/scripts/get-drive-file-menu.js'; +const router = useRouter(); + const props = withDefaults(defineProps<{ file: Misskey.entities.DriveFile; folder: Misskey.entities.DriveFolder | null; @@ -71,7 +74,7 @@ function onClick(ev: MouseEvent) { if (props.selectMode) { emit('chosen', props.file); } else { - os.popupMenu(getDriveFileMenu(props.file, props.folder), (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined); + router.push(`/my/drive/file/${props.file.id}`); } } diff --git a/packages/frontend/src/pages/drive.file.info.vue b/packages/frontend/src/pages/drive.file.info.vue new file mode 100644 index 000000000000..daefec140b5d --- /dev/null +++ b/packages/frontend/src/pages/drive.file.info.vue @@ -0,0 +1,279 @@ + + + + + + + diff --git a/packages/frontend/src/pages/drive.file.notes.vue b/packages/frontend/src/pages/drive.file.notes.vue new file mode 100644 index 000000000000..a3d68fbed46c --- /dev/null +++ b/packages/frontend/src/pages/drive.file.notes.vue @@ -0,0 +1,32 @@ + + + + + diff --git a/packages/frontend/src/pages/drive.file.vue b/packages/frontend/src/pages/drive.file.vue new file mode 100644 index 000000000000..2c1e5d20a77e --- /dev/null +++ b/packages/frontend/src/pages/drive.file.vue @@ -0,0 +1,52 @@ + + + + + diff --git a/packages/frontend/src/router.ts b/packages/frontend/src/router.ts index 294f66aaafa6..6c33d0d8ee91 100644 --- a/packages/frontend/src/router.ts +++ b/packages/frontend/src/router.ts @@ -467,6 +467,10 @@ export const routes = [{ path: '/my/drive', component: page(() => import('./pages/drive.vue')), loginRequired: true, +}, { + path: '/my/drive/file/:fileId', + component: page(() => import('./pages/drive.file.vue')), + loginRequired: true, }, { path: '/my/follow-requests', component: page(() => import('./pages/follow-requests.vue')), diff --git a/packages/frontend/src/scripts/get-drive-file-menu.ts b/packages/frontend/src/scripts/get-drive-file-menu.ts index 096410824994..8b2144a22f65 100644 --- a/packages/frontend/src/scripts/get-drive-file-menu.ts +++ b/packages/frontend/src/scripts/get-drive-file-menu.ts @@ -27,7 +27,7 @@ function rename(file: Misskey.entities.DriveFile) { function describe(file: Misskey.entities.DriveFile) { os.popup(defineAsyncComponent(() => import('@/components/MkFileCaptionEditWindow.vue')), { - default: file.comment != null ? file.comment : '', + default: file.comment ?? '', file: file, }, { done: caption => { @@ -112,6 +112,11 @@ export function getDriveFileMenu(file: Misskey.entities.DriveFile, folder?: Miss text: i18n.ts.download, icon: 'ti ti-download', download: file.name, + }, null, { + type: 'link', + to: `/my/drive/file/${file.id}`, + text: i18n.ts._fileViewer.title, + icon: 'ti ti-file', }, null, { text: i18n.ts.delete, icon: 'ti ti-trash', diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 1a0bbeac78ea..e95619afcfb6 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -1851,6 +1851,10 @@ export type Endpoints = { }; res: Note[]; }; + 'notes/search-by-file-id': { + req: TODO; + res: TODO; + }; 'notes/search-by-tag': { req: TODO; res: TODO; @@ -2982,7 +2986,7 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u // // src/api.types.ts:16:32 - (ae-forgotten-export) The symbol "TODO" needs to be exported by the entry point index.d.ts // src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts -// src/api.types.ts:630:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts +// src/api.types.ts:631:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts // src/entities.ts:107:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts // src/entities.ts:600:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts diff --git a/packages/misskey-js/src/api.types.ts b/packages/misskey-js/src/api.types.ts index a7a2ea1b36ee..303e20563500 100644 --- a/packages/misskey-js/src/api.types.ts +++ b/packages/misskey-js/src/api.types.ts @@ -521,6 +521,7 @@ export type Endpoints = { 'notes/reactions/delete': { req: { noteId: Note['id']; }; res: null; }; 'notes/renotes': { req: { limit?: number; sinceId?: Note['id']; untilId?: Note['id']; noteId: Note['id']; }; res: Note[]; }; 'notes/replies': { req: { limit?: number; sinceId?: Note['id']; untilId?: Note['id']; noteId: Note['id']; }; res: Note[]; }; + 'notes/search-by-file-id': { req: TODO; res: TODO; }; 'notes/search-by-tag': { req: TODO; res: TODO; }; 'notes/search': { req: TODO; res: TODO; }; 'notes/show': { req: { noteId: Note['id']; }; res: Note; }; From 2fd8831cfd39c2f60028cca37bff34bc520d7088 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih Date: Mon, 9 Oct 2023 18:47:35 +0900 Subject: [PATCH 2/8] Update Changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e655bef8b766..c30fb872f412 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,9 @@ - Feat: タイムラインがリアルタイム更新中に広告を挿入できるようになりました - デフォルトは無効 - 頻度はコントロールパネルから設定できます。運営中のサーバーのTLの流速を見て、最適な値を指定してください。 +- Feat: 「ファイルの詳細」ページを追加 + - ドライブのファイルの拡大プレビューができるように + - ファイルが添付されたノートの一覧が表示できるように - Enhance: ソフトワードミュートとハードワードミュートは統合されました - Enhance: モデレーションログ機能の強化 - Enhance: ローカリゼーションの更新 From 072d5fae7a111e01b4295935c2c4309c317a42de Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih Date: Mon, 9 Oct 2023 19:30:42 +0900 Subject: [PATCH 3/8] =?UTF-8?q?=E6=97=A2=E5=AD=98=E3=81=AEAPI=E3=82=92?= =?UTF-8?q?=E5=88=A9=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/src/server/api/EndpointsModule.ts | 4 - packages/backend/src/server/api/endpoints.ts | 2 - .../endpoints/drive/files/attached-notes.ts | 12 ++- .../api/endpoints/notes/search-by-file-id.ts | 88 ------------------- .../frontend/src/pages/drive.file.notes.vue | 4 +- packages/misskey-js/src/api.types.ts | 1 - 6 files changed, 10 insertions(+), 101 deletions(-) delete mode 100644 packages/backend/src/server/api/endpoints/notes/search-by-file-id.ts diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts index cf97887b452b..f834561456e1 100644 --- a/packages/backend/src/server/api/EndpointsModule.ts +++ b/packages/backend/src/server/api/EndpointsModule.ts @@ -271,7 +271,6 @@ import * as ep___notes_reactions_create from './endpoints/notes/reactions/create import * as ep___notes_reactions_delete from './endpoints/notes/reactions/delete.js'; import * as ep___notes_renotes from './endpoints/notes/renotes.js'; import * as ep___notes_replies from './endpoints/notes/replies.js'; -import * as ep___notes_searchByFileId from './endpoints/notes/search-by-file-id.js'; import * as ep___notes_searchByTag from './endpoints/notes/search-by-tag.js'; import * as ep___notes_search from './endpoints/notes/search.js'; import * as ep___notes_show from './endpoints/notes/show.js'; @@ -622,7 +621,6 @@ const $notes_reactions_create: Provider = { provide: 'ep:notes/reactions/create' const $notes_reactions_delete: Provider = { provide: 'ep:notes/reactions/delete', useClass: ep___notes_reactions_delete.default }; const $notes_renotes: Provider = { provide: 'ep:notes/renotes', useClass: ep___notes_renotes.default }; const $notes_replies: Provider = { provide: 'ep:notes/replies', useClass: ep___notes_replies.default }; -const $notes_searchByFileId: Provider = { provide: 'ep:notes/search-by-file-id', useClass: ep___notes_searchByFileId.default }; const $notes_searchByTag: Provider = { provide: 'ep:notes/search-by-tag', useClass: ep___notes_searchByTag.default }; const $notes_search: Provider = { provide: 'ep:notes/search', useClass: ep___notes_search.default }; const $notes_show: Provider = { provide: 'ep:notes/show', useClass: ep___notes_show.default }; @@ -977,7 +975,6 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $notes_reactions_delete, $notes_renotes, $notes_replies, - $notes_searchByFileId, $notes_searchByTag, $notes_search, $notes_show, @@ -1326,7 +1323,6 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $notes_reactions_delete, $notes_renotes, $notes_replies, - $notes_searchByFileId, $notes_searchByTag, $notes_search, $notes_show, diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index 085c678dfb3d..d12a035afac2 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -271,7 +271,6 @@ import * as ep___notes_reactions_create from './endpoints/notes/reactions/create import * as ep___notes_reactions_delete from './endpoints/notes/reactions/delete.js'; import * as ep___notes_renotes from './endpoints/notes/renotes.js'; import * as ep___notes_replies from './endpoints/notes/replies.js'; -import * as ep___notes_searchByFileId from './endpoints/notes/search-by-file-id.js'; import * as ep___notes_searchByTag from './endpoints/notes/search-by-tag.js'; import * as ep___notes_search from './endpoints/notes/search.js'; import * as ep___notes_show from './endpoints/notes/show.js'; @@ -620,7 +619,6 @@ const eps = [ ['notes/reactions/delete', ep___notes_reactions_delete], ['notes/renotes', ep___notes_renotes], ['notes/replies', ep___notes_replies], - ['notes/search-by-file-id', ep___notes_searchByFileId], ['notes/search-by-tag', ep___notes_searchByTag], ['notes/search', ep___notes_search], ['notes/show', ep___notes_show], diff --git a/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts b/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts index 779231a856f1..14a13b09c926 100644 --- a/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts +++ b/packages/backend/src/server/api/endpoints/drive/files/attached-notes.ts @@ -6,6 +6,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; import type { NotesRepository, DriveFilesRepository } from '@/models/_.js'; +import { QueryService } from '@/core/QueryService.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { DI } from '@/di-symbols.js'; import { ApiError } from '../../../error.js'; @@ -41,6 +42,9 @@ export const meta = { export const paramDef = { type: 'object', properties: { + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, fileId: { type: 'string', format: 'misskey:id' }, }, required: ['fileId'], @@ -56,6 +60,7 @@ export default class extends Endpoint { // eslint- private notesRepository: NotesRepository, private noteEntityService: NoteEntityService, + private queryService: QueryService, ) { super(meta, paramDef, async (ps, me) => { // Fetch file @@ -68,9 +73,10 @@ export default class extends Endpoint { // eslint- throw new ApiError(meta.errors.noSuchFile); } - const notes = await this.notesRepository.createQueryBuilder('note') - .where(':file = ANY(note.fileIds)', { file: file.id }) - .getMany(); + const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId); + query.andWhere(':file = ANY(note.fileIds)', { file: file.id }); + + const notes = await query.limit(ps.limit).getMany(); return await this.noteEntityService.packMany(notes, me, { detail: true, diff --git a/packages/backend/src/server/api/endpoints/notes/search-by-file-id.ts b/packages/backend/src/server/api/endpoints/notes/search-by-file-id.ts deleted file mode 100644 index 8fc4b66407e0..000000000000 --- a/packages/backend/src/server/api/endpoints/notes/search-by-file-id.ts +++ /dev/null @@ -1,88 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and other misskey contributors - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import { Brackets } from 'typeorm'; -import { Inject, Injectable } from '@nestjs/common'; -import type { NotesRepository } from '@/models/_.js'; -import { safeForSql } from '@/misc/safe-for-sql.js'; -import { normalizeForSearch } from '@/misc/normalize-for-search.js'; -import { Endpoint } from '@/server/api/endpoint-base.js'; -import { QueryService } from '@/core/QueryService.js'; -import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; -import { DI } from '@/di-symbols.js'; - -export const meta = { - tags: ['notes', 'drive'], - - res: { - type: 'array', - optional: false, nullable: false, - items: { - type: 'object', - optional: false, nullable: false, - ref: 'Note', - }, - }, -} as const; - -export const paramDef = { - type: 'object', - properties: { - reply: { 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 }, - - fileId: { type: 'string', format: 'misskey:id' }, - }, - required: ['fileId'], -} as const; - -@Injectable() -export default class extends Endpoint { // eslint-disable-line import/no-default-export - constructor( - @Inject(DI.notesRepository) - private notesRepository: NotesRepository, - - private noteEntityService: NoteEntityService, - private queryService: QueryService, - ) { - super(meta, paramDef, async (ps, me) => { - const query = this.queryService.makePaginationQuery(this.notesRepository.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'); - - this.queryService.generateVisibilityQuery(query, me); - if (me) this.queryService.generateMutedUserQuery(query, me); - if (me) this.queryService.generateBlockedUserQuery(query, me); - - try { - if (ps.fileId) { - if (!safeForSql(normalizeForSearch(ps.fileId))) throw new Error('Injection'); - query.andWhere(`'{"${normalizeForSearch(ps.fileId)}"}' <@ note.fileIds`); - } - } 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'); - } - } - - // Search notes - const notes = await query.limit(ps.limit).getMany(); - - return await this.noteEntityService.packMany(notes, me); - }); - } -} diff --git a/packages/frontend/src/pages/drive.file.notes.vue b/packages/frontend/src/pages/drive.file.notes.vue index a3d68fbed46c..c42a6c578fdc 100644 --- a/packages/frontend/src/pages/drive.file.notes.vue +++ b/packages/frontend/src/pages/drive.file.notes.vue @@ -13,8 +13,6 @@ SPDX-License-Identifier: AGPL-3.0-only import { ref, computed } from 'vue'; import { Paging } from '@/components/MkPagination.vue'; import MkNotes from '@/components/MkNotes.vue'; -import { i18n } from '@/i18n.js'; -import { definePageMetadata } from '@/scripts/page-metadata.js'; const props = defineProps<{ fileId: string; @@ -23,7 +21,7 @@ const props = defineProps<{ const realFileId = computed(() => props.fileId); const pagination = ref({ - endpoint: 'notes/search-by-file-id', + endpoint: 'drive/files/attached-notes', limit: 10, params: { fileId: realFileId.value, diff --git a/packages/misskey-js/src/api.types.ts b/packages/misskey-js/src/api.types.ts index 303e20563500..a7a2ea1b36ee 100644 --- a/packages/misskey-js/src/api.types.ts +++ b/packages/misskey-js/src/api.types.ts @@ -521,7 +521,6 @@ export type Endpoints = { 'notes/reactions/delete': { req: { noteId: Note['id']; }; res: null; }; 'notes/renotes': { req: { limit?: number; sinceId?: Note['id']; untilId?: Note['id']; noteId: Note['id']; }; res: Note[]; }; 'notes/replies': { req: { limit?: number; sinceId?: Note['id']; untilId?: Note['id']; noteId: Note['id']; }; res: Note[]; }; - 'notes/search-by-file-id': { req: TODO; res: TODO; }; 'notes/search-by-tag': { req: TODO; res: TODO; }; 'notes/search': { req: TODO; res: TODO; }; 'notes/show': { req: { noteId: Note['id']; }; res: Note; }; From 46f70740c7a52f4712b7369e5659364fb623b801 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih Date: Mon, 9 Oct 2023 19:33:12 +0900 Subject: [PATCH 4/8] run api extratctor --- packages/misskey-js/etc/misskey-js.api.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index e95619afcfb6..1a0bbeac78ea 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -1851,10 +1851,6 @@ export type Endpoints = { }; res: Note[]; }; - 'notes/search-by-file-id': { - req: TODO; - res: TODO; - }; 'notes/search-by-tag': { req: TODO; res: TODO; @@ -2986,7 +2982,7 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u // // src/api.types.ts:16:32 - (ae-forgotten-export) The symbol "TODO" needs to be exported by the entry point index.d.ts // src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts -// src/api.types.ts:631:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts +// src/api.types.ts:630:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts // src/entities.ts:107:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts // src/entities.ts:600:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts From 125e437dc3bed01e1988b62ad62e3b9a5b1df06c Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih Date: Mon, 9 Oct 2023 19:34:57 +0900 Subject: [PATCH 5/8] Change i18n --- locales/ja-JP.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index cb2aae7e9f96..9e83f6b565be 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2213,4 +2213,4 @@ _fileViewer: size: "ファイルサイズ" url: "URL" uploadedAt: "追加日" - attachedNotes: "添付されたノート" + attachedNotes: "添付されているノート" From 23d217054b14e237f2c6a65bdaa05421894b59b4 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih Date: Mon, 9 Oct 2023 20:01:11 +0900 Subject: [PATCH 6/8] =?UTF-8?q?(add)=20=E3=83=9A=E3=83=BC=E3=82=B8?= =?UTF-8?q?=E3=81=AB=E9=96=A2=E3=81=99=E3=82=8B=E8=AA=AC=E6=98=8E=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/index.d.ts | 1 + locales/ja-JP.yml | 1 + packages/frontend/src/pages/drive.file.info.vue | 4 +++- packages/frontend/src/pages/drive.file.notes.vue | 3 +++ 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/locales/index.d.ts b/locales/index.d.ts index 75017293728f..5227caa083c7 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -2301,6 +2301,7 @@ export interface Locale { "url": string; "uploadedAt": string; "attachedNotes": string; + "thisPageCanBeSeenFromTheAuthor": string; }; } declare const locales: { diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 9e83f6b565be..bf179ca73321 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2214,3 +2214,4 @@ _fileViewer: url: "URL" uploadedAt: "追加日" attachedNotes: "添付されているノート" + thisPageCanBeSeenFromTheAuthor: "このページは、このファイルをアップロードしたユーザーしか閲覧できません。" diff --git a/packages/frontend/src/pages/drive.file.info.vue b/packages/frontend/src/pages/drive.file.info.vue index daefec140b5d..6a72283d6377 100644 --- a/packages/frontend/src/pages/drive.file.info.vue +++ b/packages/frontend/src/pages/drive.file.info.vue @@ -4,7 +4,8 @@ SPDX-License-Identifier: AGPL-3.0-only -->