From 3cd04c4b81190e4cfe6dc1def8335be02f8b4b37 Mon Sep 17 00:00:00 2001 From: MeiMei <30769358+mei23@users.noreply.github.com> Date: Sun, 23 May 2021 13:07:11 +0900 Subject: [PATCH 01/48] Fix agent type (#7532) --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 3d84305649..9e32e6e913 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1536,9 +1536,9 @@ acorn@^8.2.1: integrity sha512-Ibt84YwBDDA890eDiDCEqcbwvHlBvzzDkU2cGBBDDI1QWT12jTiXIOn2CIw5KK4i6N5Z2HUxwYjzriDyqaqqZg== agent-base@6: - version "6.0.0" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.0.tgz#5d0101f19bbfaed39980b22ae866de153b93f09a" - integrity sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw== + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== dependencies: debug "4" From 7063a6925fb4cfa47747193e88c059514730ff44 Mon Sep 17 00:00:00 2001 From: okayurisotto <47853651+okayurisotto@users.noreply.github.com> Date: Sun, 23 May 2021 18:55:21 +0900 Subject: [PATCH 02/48] =?UTF-8?q?fix:=20Safari=E3=81=A7=E3=82=82=E3=83=A2?= =?UTF-8?q?=E3=83=BC=E3=83=80=E3=83=AB=E3=81=AE=E3=81=BC=E3=81=8B=E3=81=97?= =?UTF-8?q?=E5=8A=B9=E6=9E=9C=E3=81=8C=E5=8A=B9=E3=81=8F=E3=82=88=E3=81=86?= =?UTF-8?q?=E3=81=AB=E3=81=97=E3=81=9F=20(#7530)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/misskey-dev/misskey/issues/7529 --- src/client/style.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/src/client/style.scss b/src/client/style.scss index 39bf6ef2d5..dc419bd872 100644 --- a/src/client/style.scss +++ b/src/client/style.scss @@ -146,6 +146,7 @@ hr { width: 100%; height: 100%; background: var(--modalBg); + -webkit-backdrop-filter: var(--modalBgFilter); backdrop-filter: var(--modalBgFilter); } From 47aaf044813662931fbaddd965272267fd94ed6a Mon Sep 17 00:00:00 2001 From: MeiMei <30769358+mei23@users.noreply.github.com> Date: Sun, 23 May 2021 18:57:12 +0900 Subject: [PATCH 03/48] Fix search-by-tag (#7531) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix search-by-tag * Revert "Fix search-by-tag" This reverts commit c971d1d5d82f2d8b58fdec76e42f4404339ab83a. * Fix typo * Remove unused var * インジェクションは[]を返すように --- .../api/endpoints/notes/search-by-tag.ts | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/server/api/endpoints/notes/search-by-tag.ts b/src/server/api/endpoints/notes/search-by-tag.ts index 61f62dd5a6..463c5fff5a 100644 --- a/src/server/api/endpoints/notes/search-by-tag.ts +++ b/src/server/api/endpoints/notes/search-by-tag.ts @@ -104,22 +104,25 @@ export default define(meta, async (ps, me) => { generateVisibilityQuery(query, me); if (me) generateMutedUserQuery(query, me); - if (ps.tag) { - if (!safeForSql(ps.tag)) return; - query.andWhere(`'{"${normalizeForSearch(ps.tag)}"}' <@ note.tags`); - } else { - let i = 0; - query.andWhere(new Brackets(qb => { - for (const tags of ps.query!) { - qb.orWhere(new Brackets(qb => { - for (const tag of tags) { - if (!safeForSql(tag)) return; - qb.andWhere(`'{"${normalizeForSearch(ps.tag)}"}' <@ note.tags`); - i++; - } - })); - } - })); + try { + if (ps.tag) { + if (!safeForSql(ps.tag)) throw 'Injection'; + query.andWhere(`'{"${normalizeForSearch(ps.tag)}"}' <@ note.tags`); + } else { + query.andWhere(new Brackets(qb => { + for (const tags of ps.query!) { + qb.orWhere(new Brackets(qb => { + for (const tag of tags) { + if (!safeForSql(tag)) throw 'Injection'; + qb.andWhere(`'{"${normalizeForSearch(tag)}"}' <@ note.tags`); + } + })); + } + })); + } + } catch (e) { + if (e === 'Injection') return []; + throw e; } if (ps.reply != null) { From f85399e355685344d45efa49d220cf1508d0bfd5 Mon Sep 17 00:00:00 2001 From: Sandy Nicko Mac Corzeta <4186454+sandycorzeta@users.noreply.github.com> Date: Sun, 23 May 2021 09:57:33 +0000 Subject: [PATCH 04/48] Add Indonesian to index language (#7528) Co-authored-by: Sandy Nicko Mac Corzeta --- locales/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/locales/index.js b/locales/index.js index 727e0e3848..35f9972ff7 100644 --- a/locales/index.js +++ b/locales/index.js @@ -21,6 +21,7 @@ const languages = [ 'en-US', 'es-ES', 'fr-FR', + 'id-ID', 'ja-JP', 'ja-KS', 'kab-KAB', From c06091f78ab507085da3a1a4898b325a43e3201e Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 23 May 2021 21:14:29 +0900 Subject: [PATCH 05/48] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 5cff3619fd..816765af67 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,11 @@ Please see the [Contribution Guide](./CONTRIBUTING.md). To receive updates of this repo, follow [@repo@misskey.io](https://misskey.io/@repo) on fediverse. +Related projects +---------------------------------------------------------------- +- [misskey.js](https://github.com/misskey-dev/misskey.js) - Misskey SDK for JavaScript +- [mfm.js](https://github.com/misskey-dev/mfm.js) - MFM parser + :heart: Backers ---------------------------------------------------------------- From 35f075b8871f240aa94c4a21c77b9759ffd2c1b9 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 23 May 2021 21:28:41 +0900 Subject: [PATCH 06/48] :art: --- assets/about/banner.svg | Bin 35817 -> 39137 bytes assets/banner.afdesign | Bin 65435 -> 73201 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/about/banner.svg b/assets/about/banner.svg index 31b6ca95e1158d8006458757dc39607ac922077e..75308c09500782cd00e8a312bbc86472d308557d 100644 GIT binary patch literal 39137 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 z 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 literal 35817 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 diff --git a/assets/banner.afdesign b/assets/banner.afdesign index def3e884d3c1145f398944c81f8bae5723f14a0b..08b5c1b4a0b4720db0f3a7cab153edfa1a103ad1 100644 GIT binary patch delta 18972 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 CS}B$Q delta 11135 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 From c92744c3d36e371ddc8c6f9bbf9d64812ae5ace9 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 24 May 2021 05:50:45 +0900 Subject: [PATCH 07/48] Create SECURITY.md --- SECURITY.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000..2c026a5f33 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,9 @@ +# Reporting Security Issues + +If you discover a security issue in Misskey, please report it by sending an +email to [syuilotan@yahoo.co.jp](mailto:syuilotan@yahoo.co.jp). + +This will allow us to assess the risk, and make a fix available before we add a +bug report to the GitHub repository. + +Thanks for helping make Misskey safe for everyone. From ae2267220bb743808bffaf9a33f3bc6eed75a5b1 Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 27 May 2021 17:15:08 +0900 Subject: [PATCH 08/48] wip #7533 --- package.json | 1 + src/client/components/drive.vue | 4 +- src/client/components/follow-button.vue | 2 +- src/client/components/notification.vue | 2 +- src/client/components/notifications.vue | 2 +- src/client/components/timeline.vue | 20 +- src/client/init.ts | 8 +- src/client/instance.ts | 16 +- src/client/os.ts | 24 +- src/client/pages/instance/metrics.vue | 4 +- src/client/pages/instance/queue.vue | 2 +- src/client/pages/messaging/index.vue | 2 +- src/client/pages/messaging/messaging-room.vue | 2 +- src/client/pages/reversi/game.vue | 2 +- src/client/pages/reversi/index.vue | 2 +- src/client/scripts/select-file.ts | 4 +- src/client/scripts/stream.ts | 312 ------------------ src/client/ui/_common_/common.vue | 2 +- src/client/ui/chat/timeline.vue | 20 +- src/client/widgets/job-queue.vue | 2 +- src/client/widgets/photos.vue | 2 +- src/client/widgets/server-metric/index.vue | 2 +- yarn.lock | 18 +- 23 files changed, 69 insertions(+), 386 deletions(-) delete mode 100644 src/client/scripts/stream.ts diff --git a/package.json b/package.json index 4f01c78817..610678989f 100644 --- a/package.json +++ b/package.json @@ -174,6 +174,7 @@ "markdown-it-anchor": "7.1.0", "matter-js": "0.17.1", "mfm-js": "0.16.4", + "misskey-js": "0.0.2", "mocha": "8.4.0", "moji": "0.5.1", "ms": "2.1.3", diff --git a/src/client/components/drive.vue b/src/client/components/drive.vue index 06f9cf7806..ca637e3f3d 100644 --- a/src/client/components/drive.vue +++ b/src/client/components/drive.vue @@ -139,7 +139,7 @@ export default defineComponent({ }); } - this.connection = os.stream.useSharedConnection('drive'); + this.connection = os.stream.useChannel('drive'); this.connection.on('fileCreated', this.onStreamDriveFileCreated); this.connection.on('fileUpdated', this.onStreamDriveFileUpdated); @@ -301,7 +301,7 @@ export default defineComponent({ } }).then(({ canceled, result: url }) => { if (canceled) return; - os.api('drive/files/upload_from_url', { + os.api('drive/files/upload-from-url', { url: url, folderId: this.folder ? this.folder.id : undefined }); diff --git a/src/client/components/follow-button.vue b/src/client/components/follow-button.vue index 7199183c66..49bf678491 100644 --- a/src/client/components/follow-button.vue +++ b/src/client/components/follow-button.vue @@ -71,7 +71,7 @@ export default defineComponent({ }, mounted() { - this.connection = os.stream.useSharedConnection('main'); + this.connection = os.stream.useChannel('main'); this.connection.on('follow', this.onFollowChange); this.connection.on('unfollow', this.onFollowChange); diff --git a/src/client/components/notification.vue b/src/client/components/notification.vue index 9badd7a708..c7063b0aa2 100644 --- a/src/client/components/notification.vue +++ b/src/client/components/notification.vue @@ -109,7 +109,7 @@ export default defineComponent({ this.readObserver.observe(this.$el); - this.connection = os.stream.useSharedConnection('main'); + this.connection = os.stream.useChannel('main'); this.connection.on('readAllNotifications', () => this.readObserver.unobserve(this.$el)); } }, diff --git a/src/client/components/notifications.vue b/src/client/components/notifications.vue index 161419f891..6caf8eb8e3 100644 --- a/src/client/components/notifications.vue +++ b/src/client/components/notifications.vue @@ -87,7 +87,7 @@ export default defineComponent({ }, mounted() { - this.connection = os.stream.useSharedConnection('main'); + this.connection = os.stream.useChannel('main'); this.connection.on('notification', this.onNotification); }, diff --git a/src/client/components/timeline.vue b/src/client/components/timeline.vue index 753eba2ba1..c21e1ec2a6 100644 --- a/src/client/components/timeline.vue +++ b/src/client/components/timeline.vue @@ -92,33 +92,33 @@ export default defineComponent({ this.query = { antennaId: this.antenna }; - this.connection = os.stream.connectToChannel('antenna', { + this.connection = os.stream.useChannel('antenna', { antennaId: this.antenna }); this.connection.on('note', prepend); } else if (this.src == 'home') { endpoint = 'notes/timeline'; - this.connection = os.stream.useSharedConnection('homeTimeline'); + this.connection = os.stream.useChannel('homeTimeline'); this.connection.on('note', prepend); - this.connection2 = os.stream.useSharedConnection('main'); + this.connection2 = os.stream.useChannel('main'); this.connection2.on('follow', onChangeFollowing); this.connection2.on('unfollow', onChangeFollowing); } else if (this.src == 'local') { endpoint = 'notes/local-timeline'; - this.connection = os.stream.useSharedConnection('localTimeline'); + this.connection = os.stream.useChannel('localTimeline'); this.connection.on('note', prepend); } else if (this.src == 'social') { endpoint = 'notes/hybrid-timeline'; - this.connection = os.stream.useSharedConnection('hybridTimeline'); + this.connection = os.stream.useChannel('hybridTimeline'); this.connection.on('note', prepend); } else if (this.src == 'global') { endpoint = 'notes/global-timeline'; - this.connection = os.stream.useSharedConnection('globalTimeline'); + this.connection = os.stream.useChannel('globalTimeline'); this.connection.on('note', prepend); } else if (this.src == 'mentions') { endpoint = 'notes/mentions'; - this.connection = os.stream.useSharedConnection('main'); + this.connection = os.stream.useChannel('main'); this.connection.on('mention', prepend); } else if (this.src == 'directs') { endpoint = 'notes/mentions'; @@ -130,14 +130,14 @@ export default defineComponent({ prepend(note); } }; - this.connection = os.stream.useSharedConnection('main'); + this.connection = os.stream.useChannel('main'); this.connection.on('mention', onNote); } else if (this.src == 'list') { endpoint = 'notes/user-list-timeline'; this.query = { listId: this.list }; - this.connection = os.stream.connectToChannel('userList', { + this.connection = os.stream.useChannel('userList', { listId: this.list }); this.connection.on('note', prepend); @@ -148,7 +148,7 @@ export default defineComponent({ this.query = { channelId: this.channel }; - this.connection = os.stream.connectToChannel('channel', { + this.connection = os.stream.useChannel('channel', { channelId: this.channel }); this.connection.on('note', prepend); diff --git a/src/client/init.ts b/src/client/init.ts index a4465d75c3..19b95fc50e 100644 --- a/src/client/init.ts +++ b/src/client/init.ts @@ -163,8 +163,6 @@ fetchInstance().then(() => { initializeSw(); }); -stream.init($i); - const app = createApp(await ( window.location.search === '?zen' ? import('@client/ui/zen.vue') : !$i ? import('@client/ui/visitor.vue') : @@ -296,7 +294,7 @@ if ($i) { } } - const main = stream.useSharedConnection('main', 'System'); + const main = stream.useChannel('main', 'System'); // 自分の情報が更新されたとき main.on('meUpdated', i => { @@ -358,10 +356,6 @@ if ($i) { sound.play('channel'); }); - main.on('readAllAnnouncements', () => { - updateAccount({ hasUnreadAnnouncement: false }); - }); - // トークンが再生成されたとき // このままではMisskeyが利用できないので強制的にサインアウトさせる main.on('myTokenRegenerated', () => { diff --git a/src/client/instance.ts b/src/client/instance.ts index 024ff1acbd..04d3353208 100644 --- a/src/client/instance.ts +++ b/src/client/instance.ts @@ -1,26 +1,14 @@ import { computed, reactive } from 'vue'; +import * as Misskey from 'misskey-js'; import { api } from './os'; // TODO: 他のタブと永続化されたstateを同期 -export type Instance = { - emojis: { - category: string; - }[]; - ads: { - id: string; - ratio: number; - place: string; - url: string; - imageUrl: string; - }[]; -}; - const data = localStorage.getItem('instance'); // TODO: instanceをリアクティブにするかは再考の余地あり -export const instance: Instance = reactive(data ? JSON.parse(data) : { +export const instance: Misskey.entities.InstanceMetadata = reactive(data ? JSON.parse(data) : { // TODO: set default values }); diff --git a/src/client/os.ts b/src/client/os.ts index b159cf509d..e6355b45b8 100644 --- a/src/client/os.ts +++ b/src/client/os.ts @@ -3,16 +3,16 @@ import { Component, defineAsyncComponent, markRaw, reactive, Ref, ref } from 'vue'; import { EventEmitter } from 'eventemitter3'; import insertTextAtCursor from 'insert-text-at-cursor'; +import * as Misskey from 'misskey-js'; import * as Sentry from '@sentry/browser'; -import Stream from '@client/scripts/stream'; -import { apiUrl, debug } from '@client/config'; +import { apiUrl, debug, url } from '@client/config'; import MkPostFormDialog from '@client/components/post-form-dialog.vue'; import MkWaitingDialog from '@client/components/waiting-dialog.vue'; import { resolve } from '@client/router'; import { $i } from '@client/account'; import { defaultStore } from '@client/store'; -export const stream = markRaw(new Stream()); +export const stream = markRaw(new Misskey.Stream(url, $i)); export const pendingApiRequestsCount = ref(0); let apiRequestsCount = 0; // for debug @@ -20,7 +20,11 @@ export const apiRequests = ref([]); // for debug export const windows = new Map(); -export function api(endpoint: string, data: Record = {}, token?: string | null | undefined) { +const apiClient = new Misskey.api.APIClient({ + origin: url, +}); + +export const api = ((endpoint: string, data: Record = {}, token?: string | null | undefined) => { pendingApiRequestsCount.value++; const onFinally = () => { @@ -90,17 +94,15 @@ export function api(endpoint: string, data: Record = {}, token?: st promise.then(onFinally, onFinally); return promise; -} +}) as typeof apiClient.request; -export function apiWithDialog( +export const apiWithDialog = (( endpoint: string, data: Record = {}, token?: string | null | undefined, - onSuccess?: (res: any) => void, - onFailure?: (e: Error) => void, -) { +) => { const promise = api(endpoint, data, token); - promiseDialog(promise, onSuccess, onFailure ? onFailure : (e) => { + promiseDialog(promise, null, (e) => { dialog({ type: 'error', text: e.message + '\n' + (e as any).id, @@ -108,7 +110,7 @@ export function apiWithDialog( }); return promise; -} +}) as typeof api; export function promiseDialog>( promise: T, diff --git a/src/client/pages/instance/metrics.vue b/src/client/pages/instance/metrics.vue index 18cfe5eee2..407cce9e7f 100644 --- a/src/client/pages/instance/metrics.vue +++ b/src/client/pages/instance/metrics.vue @@ -90,7 +90,7 @@ export default defineComponent({ stats: null, serverInfo: null, connection: null, - queueConnection: os.stream.useSharedConnection('queueStats'), + queueConnection: os.stream.useChannel('queueStats'), memUsage: 0, chartCpuMem: null, chartNet: null, @@ -121,7 +121,7 @@ export default defineComponent({ os.api('admin/server-info', {}).then(res => { this.serverInfo = res; - this.connection = os.stream.useSharedConnection('serverStats'); + this.connection = os.stream.useChannel('serverStats'); this.connection.on('stats', this.onStats); this.connection.on('statsLog', this.onStatsLog); this.connection.send('requestLog', { diff --git a/src/client/pages/instance/queue.vue b/src/client/pages/instance/queue.vue index 2dccf48d31..8f56fd74bf 100644 --- a/src/client/pages/instance/queue.vue +++ b/src/client/pages/instance/queue.vue @@ -35,7 +35,7 @@ export default defineComponent({ title: this.$ts.jobQueue, icon: 'fas fa-clipboard-list', }, - connection: os.stream.useSharedConnection('queueStats'), + connection: os.stream.useChannel('queueStats'), } }, diff --git a/src/client/pages/messaging/index.vue b/src/client/pages/messaging/index.vue index 9f3323f629..832cce5ab9 100644 --- a/src/client/pages/messaging/index.vue +++ b/src/client/pages/messaging/index.vue @@ -63,7 +63,7 @@ export default defineComponent({ }, mounted() { - this.connection = os.stream.useSharedConnection('messagingIndex'); + this.connection = os.stream.useChannel('messagingIndex'); this.connection.on('message', this.onMessage); this.connection.on('read', this.onRead); diff --git a/src/client/pages/messaging/messaging-room.vue b/src/client/pages/messaging/messaging-room.vue index 44bfd6c51d..f1d55ee288 100644 --- a/src/client/pages/messaging/messaging-room.vue +++ b/src/client/pages/messaging/messaging-room.vue @@ -141,7 +141,7 @@ const Component = defineComponent({ this.group = group; } - this.connection = os.stream.connectToChannel('messaging', { + this.connection = os.stream.useChannel('messaging', { otherparty: this.user ? this.user.id : undefined, group: this.group ? this.group.id : undefined, }); diff --git a/src/client/pages/reversi/game.vue b/src/client/pages/reversi/game.vue index 62c99d7755..dc4d11ca4a 100644 --- a/src/client/pages/reversi/game.vue +++ b/src/client/pages/reversi/game.vue @@ -61,7 +61,7 @@ export default defineComponent({ if (this.connection) { this.connection.dispose(); } - this.connection = os.stream.connectToChannel('gamesReversiGame', { + this.connection = os.stream.useChannel('gamesReversiGame', { gameId: this.game.id }); this.connection.on('started', this.onStarted); diff --git a/src/client/pages/reversi/index.vue b/src/client/pages/reversi/index.vue index 37126fca10..dd329084a8 100644 --- a/src/client/pages/reversi/index.vue +++ b/src/client/pages/reversi/index.vue @@ -92,7 +92,7 @@ export default defineComponent({ mounted() { if (this.$i) { - this.connection = os.stream.useSharedConnection('gamesReversi'); + this.connection = os.stream.useChannel('gamesReversi'); this.connection.on('invited', this.onInvited); diff --git a/src/client/scripts/select-file.ts b/src/client/scripts/select-file.ts index c193e7dc71..b8039fb670 100644 --- a/src/client/scripts/select-file.ts +++ b/src/client/scripts/select-file.ts @@ -47,7 +47,7 @@ export function selectFile(src: any, label: string | null, multiple = false) { const marker = Math.random().toString(); // TODO: UUIDとか使う - const connection = os.stream.useSharedConnection('main'); + const connection = os.stream.useChannel('main'); connection.on('urlUploadFinished', data => { if (data.marker === marker) { res(multiple ? [data.file] : data.file); @@ -55,7 +55,7 @@ export function selectFile(src: any, label: string | null, multiple = false) { } }); - os.api('drive/files/upload_from_url', { + os.api('drive/files/upload-from-url', { url: url, marker }); diff --git a/src/client/scripts/stream.ts b/src/client/scripts/stream.ts deleted file mode 100644 index 065059221d..0000000000 --- a/src/client/scripts/stream.ts +++ /dev/null @@ -1,312 +0,0 @@ -import autobind from 'autobind-decorator'; -import { EventEmitter } from 'eventemitter3'; -import ReconnectingWebsocket from 'reconnecting-websocket'; -import { markRaw } from 'vue'; -import { debug, wsUrl } from '@client/config'; -import { query as urlQuery } from '../../prelude/url'; - -/** - * Misskey stream connection - */ -export default class Stream extends EventEmitter { - private stream: ReconnectingWebsocket; - public state: 'initializing' | 'reconnecting' | 'connected' = 'initializing'; - private sharedConnectionPools: Pool[] = []; - private sharedConnections: SharedConnection[] = []; - private nonSharedConnections: NonSharedConnection[] = []; - - @autobind - public init(user): void { - const query = urlQuery({ - i: user?.token, - _t: Date.now(), - }); - - this.stream = new ReconnectingWebsocket(`${wsUrl}?${query}`, '', { minReconnectionDelay: 1 }); // https://github.com/pladaria/reconnecting-websocket/issues/91 - this.stream.addEventListener('open', this.onOpen); - this.stream.addEventListener('close', this.onClose); - this.stream.addEventListener('message', this.onMessage); - } - - @autobind - public useSharedConnection(channel: string, name?: string): SharedConnection { - let pool = this.sharedConnectionPools.find(p => p.channel === channel); - - if (pool == null) { - pool = new Pool(this, channel); - this.sharedConnectionPools.push(pool); - } - - const connection = markRaw(new SharedConnection(this, channel, pool, name)); - this.sharedConnections.push(connection); - return connection; - } - - @autobind - public removeSharedConnection(connection: SharedConnection) { - this.sharedConnections = this.sharedConnections.filter(c => c !== connection); - } - - @autobind - public removeSharedConnectionPool(pool: Pool) { - this.sharedConnectionPools = this.sharedConnectionPools.filter(p => p !== pool); - } - - @autobind - public connectToChannel(channel: string, params?: any): NonSharedConnection { - const connection = markRaw(new NonSharedConnection(this, channel, params)); - this.nonSharedConnections.push(connection); - return connection; - } - - @autobind - public disconnectToChannel(connection: NonSharedConnection) { - this.nonSharedConnections = this.nonSharedConnections.filter(c => c !== connection); - } - - /** - * Callback of when open connection - */ - @autobind - private onOpen() { - const isReconnect = this.state === 'reconnecting'; - - this.state = 'connected'; - this.emit('_connected_'); - - // チャンネル再接続 - if (isReconnect) { - for (const p of this.sharedConnectionPools) - p.connect(); - for (const c of this.nonSharedConnections) - c.connect(); - } - } - - /** - * Callback of when close connection - */ - @autobind - private onClose() { - if (this.state === 'connected') { - this.state = 'reconnecting'; - this.emit('_disconnected_'); - } - } - - /** - * Callback of when received a message from connection - */ - @autobind - private onMessage(message) { - const { type, body } = JSON.parse(message.data); - - if (type === 'channel') { - const id = body.id; - - let connections: Connection[]; - - connections = this.sharedConnections.filter(c => c.id === id); - - if (connections.length === 0) { - connections = [this.nonSharedConnections.find(c => c.id === id)]; - } - - for (const c of connections.filter(c => c != null)) { - c.emit(body.type, Object.freeze(body.body)); - if (debug) c.inCount++; - } - } else { - this.emit(type, Object.freeze(body)); - } - } - - /** - * Send a message to connection - */ - @autobind - public send(typeOrPayload, payload?) { - const data = payload === undefined ? typeOrPayload : { - type: typeOrPayload, - body: payload - }; - - this.stream.send(JSON.stringify(data)); - } - - /** - * Close this connection - */ - @autobind - public close() { - this.stream.removeEventListener('open', this.onOpen); - this.stream.removeEventListener('message', this.onMessage); - } -} - -let idCounter = 0; - -class Pool { - public channel: string; - public id: string; - protected stream: Stream; - public users = 0; - private disposeTimerId: any; - private isConnected = false; - - constructor(stream: Stream, channel: string) { - this.channel = channel; - this.stream = stream; - - this.id = (++idCounter).toString(); - - this.stream.on('_disconnected_', this.onStreamDisconnected); - } - - @autobind - private onStreamDisconnected() { - this.isConnected = false; - } - - @autobind - public inc() { - if (this.users === 0 && !this.isConnected) { - this.connect(); - } - - this.users++; - - // タイマー解除 - if (this.disposeTimerId) { - clearTimeout(this.disposeTimerId); - this.disposeTimerId = null; - } - } - - @autobind - public dec() { - this.users--; - - // そのコネクションの利用者が誰もいなくなったら - if (this.users === 0) { - // また直ぐに再利用される可能性があるので、一定時間待ち、 - // 新たな利用者が現れなければコネクションを切断する - this.disposeTimerId = setTimeout(() => { - this.disconnect(); - }, 3000); - } - } - - @autobind - public connect() { - if (this.isConnected) return; - this.isConnected = true; - this.stream.send('connect', { - channel: this.channel, - id: this.id - }); - } - - @autobind - private disconnect() { - this.stream.off('_disconnected_', this.onStreamDisconnected); - this.stream.send('disconnect', { id: this.id }); - this.stream.removeSharedConnectionPool(this); - } -} - -abstract class Connection extends EventEmitter { - public channel: string; - protected stream: Stream; - public abstract id: string; - - public name?: string; // for debug - public inCount: number = 0; // for debug - public outCount: number = 0; // for debug - - constructor(stream: Stream, channel: string, name?: string) { - super(); - - this.stream = stream; - this.channel = channel; - this.name = name; - } - - @autobind - public send(id: string, typeOrPayload, payload?) { - const type = payload === undefined ? typeOrPayload.type : typeOrPayload; - const body = payload === undefined ? typeOrPayload.body : payload; - - this.stream.send('ch', { - id: id, - type: type, - body: body - }); - - if (debug) this.outCount++; - } - - public abstract dispose(): void; -} - -class SharedConnection extends Connection { - private pool: Pool; - - public get id(): string { - return this.pool.id; - } - - constructor(stream: Stream, channel: string, pool: Pool, name?: string) { - super(stream, channel, name); - - this.pool = pool; - this.pool.inc(); - } - - @autobind - public send(typeOrPayload, payload?) { - super.send(this.pool.id, typeOrPayload, payload); - } - - @autobind - public dispose() { - this.pool.dec(); - this.removeAllListeners(); - this.stream.removeSharedConnection(this); - } -} - -class NonSharedConnection extends Connection { - public id: string; - protected params: any; - - constructor(stream: Stream, channel: string, params?: any) { - super(stream, channel); - - this.params = params; - this.id = (++idCounter).toString(); - - this.connect(); - } - - @autobind - public connect() { - this.stream.send('connect', { - channel: this.channel, - id: this.id, - params: this.params - }); - } - - @autobind - public send(typeOrPayload, payload?) { - super.send(this.id, typeOrPayload, payload); - } - - @autobind - public dispose() { - this.removeAllListeners(); - this.stream.send('disconnect', { id: this.id }); - this.stream.disconnectToChannel(this); - } -} diff --git a/src/client/ui/_common_/common.vue b/src/client/ui/_common_/common.vue index 785b1631db..1e825e0fe0 100644 --- a/src/client/ui/_common_/common.vue +++ b/src/client/ui/_common_/common.vue @@ -43,7 +43,7 @@ export default defineComponent({ }; if ($i) { - const connection = stream.useSharedConnection('main', 'UI'); + const connection = stream.useChannel('main', 'UI'); connection.on('notification', onNotification); } diff --git a/src/client/ui/chat/timeline.vue b/src/client/ui/chat/timeline.vue index 13032cce09..2245a9d8a5 100644 --- a/src/client/ui/chat/timeline.vue +++ b/src/client/ui/chat/timeline.vue @@ -121,33 +121,33 @@ export default defineComponent({ this.query = { antennaId: this.antenna }; - this.connection = os.stream.connectToChannel('antenna', { + this.connection = os.stream.useChannel('antenna', { antennaId: this.antenna }); this.connection.on('note', prepend); } else if (this.src == 'home') { endpoint = 'notes/timeline'; - this.connection = os.stream.useSharedConnection('homeTimeline'); + this.connection = os.stream.useChannel('homeTimeline'); this.connection.on('note', prepend); - this.connection2 = os.stream.useSharedConnection('main'); + this.connection2 = os.stream.useChannel('main'); this.connection2.on('follow', onChangeFollowing); this.connection2.on('unfollow', onChangeFollowing); } else if (this.src == 'local') { endpoint = 'notes/local-timeline'; - this.connection = os.stream.useSharedConnection('localTimeline'); + this.connection = os.stream.useChannel('localTimeline'); this.connection.on('note', prepend); } else if (this.src == 'social') { endpoint = 'notes/hybrid-timeline'; - this.connection = os.stream.useSharedConnection('hybridTimeline'); + this.connection = os.stream.useChannel('hybridTimeline'); this.connection.on('note', prepend); } else if (this.src == 'global') { endpoint = 'notes/global-timeline'; - this.connection = os.stream.useSharedConnection('globalTimeline'); + this.connection = os.stream.useChannel('globalTimeline'); this.connection.on('note', prepend); } else if (this.src == 'mentions') { endpoint = 'notes/mentions'; - this.connection = os.stream.useSharedConnection('main'); + this.connection = os.stream.useChannel('main'); this.connection.on('mention', prepend); } else if (this.src == 'directs') { endpoint = 'notes/mentions'; @@ -159,14 +159,14 @@ export default defineComponent({ prepend(note); } }; - this.connection = os.stream.useSharedConnection('main'); + this.connection = os.stream.useChannel('main'); this.connection.on('mention', onNote); } else if (this.src == 'list') { endpoint = 'notes/user-list-timeline'; this.query = { listId: this.list }; - this.connection = os.stream.connectToChannel('userList', { + this.connection = os.stream.useChannel('userList', { listId: this.list }); this.connection.on('note', prepend); @@ -178,7 +178,7 @@ export default defineComponent({ this.query = { channelId: this.channel }; - this.connection = os.stream.connectToChannel('channel', { + this.connection = os.stream.useChannel('channel', { channelId: this.channel }); this.connection.on('note', prepend); diff --git a/src/client/widgets/job-queue.vue b/src/client/widgets/job-queue.vue index 31a322e6e2..162ffe9c89 100644 --- a/src/client/widgets/job-queue.vue +++ b/src/client/widgets/job-queue.vue @@ -65,7 +65,7 @@ export default defineComponent({ extends: widget, data() { return { - connection: os.stream.useSharedConnection('queueStats'), + connection: os.stream.useChannel('queueStats'), inbox: { activeSincePrevTick: 0, active: 0, diff --git a/src/client/widgets/photos.vue b/src/client/widgets/photos.vue index 65843385b6..7f6fa82722 100644 --- a/src/client/widgets/photos.vue +++ b/src/client/widgets/photos.vue @@ -48,7 +48,7 @@ export default defineComponent({ }; }, mounted() { - this.connection = os.stream.useSharedConnection('main'); + this.connection = os.stream.useChannel('main'); this.connection.on('driveFileCreated', this.onDriveFileCreated); diff --git a/src/client/widgets/server-metric/index.vue b/src/client/widgets/server-metric/index.vue index 6331b5bdf1..2398e9920f 100644 --- a/src/client/widgets/server-metric/index.vue +++ b/src/client/widgets/server-metric/index.vue @@ -63,7 +63,7 @@ export default defineComponent({ os.api('server-info', {}).then(res => { this.meta = res; }); - this.connection = os.stream.useSharedConnection('serverStats'); + this.connection = os.stream.useChannel('serverStats'); }, unmounted() { this.connection.dispose(); diff --git a/yarn.lock b/yarn.lock index 9e32e6e913..9296aafc4e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1290,7 +1290,7 @@ "@vue/compiler-dom" "3.0.11" "@vue/shared" "3.0.11" -"@vue/reactivity@3.0.11": +"@vue/reactivity@3.0.11", "@vue/reactivity@^3.0.11": version "3.0.11" resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.0.11.tgz#07b588349fd05626b17f3500cbef7d4bdb4dbd0b" integrity sha512-SKM3YKxtXHBPMf7yufXeBhCZ4XZDKP9/iXeQSC8bBO3ivBuzAi4aZi0bNoeE2IF2iGfP/AHEt1OU4ARj4ao/Xw== @@ -1899,7 +1899,7 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -autobind-decorator@2.4.0: +autobind-decorator@2.4.0, autobind-decorator@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/autobind-decorator/-/autobind-decorator-2.4.0.tgz#ea9e1c98708cf3b5b356f7cf9f10f265ff18239c" integrity sha512-OGYhWUO72V6DafbF8PM8rm3EPbfuyMZcJhtm5/n26IDwO18pohE4eNazLoCGhPiXOCD0gEGmrbU3849QvM8bbw== @@ -4203,7 +4203,7 @@ event-target-shim@^5.0.0: resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== -eventemitter3@4.0.7: +eventemitter3@4.0.7, eventemitter3@^4.0.7: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== @@ -6977,6 +6977,16 @@ minizlib@^2.0.0, minizlib@^2.1.1: minipass "^3.0.0" yallist "^4.0.0" +misskey-js@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/misskey-js/-/misskey-js-0.0.2.tgz#233d62e5a326a00dd72f36d63436e6584c8076f2" + integrity sha512-gsq3E9lUepNapK4i/3mmqjobQV6gYlgO1O1rQt401ot3LCYlcaLhlUrwBOFtI+ALMGKgwRgkLlDQhcWgAfHHuQ== + dependencies: + "@vue/reactivity" "^3.0.11" + autobind-decorator "^2.4.0" + eventemitter3 "^4.0.7" + reconnecting-websocket "^4.4.0" + mixin-deep@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" @@ -9072,7 +9082,7 @@ rechoir@^0.7.0: dependencies: resolve "^1.9.0" -reconnecting-websocket@4.4.0: +reconnecting-websocket@4.4.0, reconnecting-websocket@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/reconnecting-websocket/-/reconnecting-websocket-4.4.0.tgz#3b0e5b96ef119e78a03135865b8bb0af1b948783" integrity sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng== From 466c083233d5f44cfcdfdfa02d8a6bb090382400 Mon Sep 17 00:00:00 2001 From: rinsuki <428rinsuki+git@gmail.com> Date: Thu, 27 May 2021 22:40:48 +0900 Subject: [PATCH 09/48] =?UTF-8?q?=E3=82=AB=E3=82=B9=E3=82=BF=E3=83=A0?= =?UTF-8?q?=E7=B5=B5=E6=96=87=E5=AD=97=E3=82=92proxy=E3=81=AB=E9=80=9A?= =?UTF-8?q?=E3=81=99=E3=82=88=E3=81=86=E3=81=AB=20(#7526)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/client/scripts/get-static-image-url.ts | 5 +++++ src/misc/populate-emojis.ts | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/client/scripts/get-static-image-url.ts b/src/client/scripts/get-static-image-url.ts index e2728d73f4..92c31914c7 100644 --- a/src/client/scripts/get-static-image-url.ts +++ b/src/client/scripts/get-static-image-url.ts @@ -3,6 +3,11 @@ import * as url from '../../prelude/url'; export function getStaticImageUrl(baseUrl: string): string { const u = new URL(baseUrl); + if (u.href.startsWith(`${instanceUrl}/proxy/`)) { + // もう既にproxyっぽそうだったらsearchParams付けるだけ + u.searchParams.set('static', '1'); + return u.href; + } const dummy = `${u.host}${u.pathname}`; // 拡張子がないとキャッシュしてくれないCDNがあるので return `${instanceUrl}/proxy/${dummy}?${url.query({ url: u.href, diff --git a/src/misc/populate-emojis.ts b/src/misc/populate-emojis.ts index 8052c71489..a3f67ccb98 100644 --- a/src/misc/populate-emojis.ts +++ b/src/misc/populate-emojis.ts @@ -5,6 +5,8 @@ import { Note } from '../models/entities/note'; import { Cache } from './cache'; import { isSelfHost, toPunyNullable } from './convert-host'; import { decodeReaction } from './reaction-lib'; +import config from '@/config'; +import { query } from '@/prelude/url'; const cache = new Cache(1000 * 60 * 60 * 12); @@ -59,9 +61,12 @@ export async function populateEmoji(emojiName: string, noteUserHost: string | nu if (emoji == null) return null; + const isLocal = emojiName.endsWith('@.'); + const url = isLocal ? emoji.url : `${config.url}/proxy/image.png?${query({url: emoji.url})}`; + return { name: emojiName, - url: emoji.url, + url, }; } From db3724cf33c402d66700f89b319b423887466757 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 28 May 2021 09:34:42 +0900 Subject: [PATCH 10/48] improve types --- src/server/api/define.ts | 7 +++++-- .../api/endpoints/gallery/posts/create.ts | 3 ++- .../api/endpoints/gallery/posts/update.ts | 3 ++- src/services/chart/core.ts | 21 +++++++++---------- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/server/api/define.ts b/src/server/api/define.ts index 432d5017e8..cba69cfdc4 100644 --- a/src/server/api/define.ts +++ b/src/server/api/define.ts @@ -5,6 +5,8 @@ import { ApiError } from './error'; import { SchemaType } from '@/misc/schema'; import { AccessToken } from '../../models/entities/access-token'; +type NonOptional = T extends undefined ? never : T; + type SimpleUserInfo = { id: ILocalUser['id']; host: ILocalUser['host']; @@ -17,11 +19,12 @@ type SimpleUserInfo = { isSilenced: ILocalUser['isSilenced']; }; -// TODO: defaultが設定されている場合はその型も考慮する type Params = { [P in keyof T['params']]: NonNullable[P]['transform'] extends Function ? ReturnType[P]['transform']> - : ReturnType[P]['validator']['get']>[0]; + : NonNullable[P]['default'] extends null | number | string + ? NonOptional[P]['validator']['get']>[0]> + : ReturnType[P]['validator']['get']>[0]; }; export type Response = Record | void; diff --git a/src/server/api/endpoints/gallery/posts/create.ts b/src/server/api/endpoints/gallery/posts/create.ts index d1ae68b126..ed24a45f88 100644 --- a/src/server/api/endpoints/gallery/posts/create.ts +++ b/src/server/api/endpoints/gallery/posts/create.ts @@ -6,6 +6,7 @@ import { DriveFiles, GalleryPosts } from '../../../../../models'; import { genId } from '../../../../../misc/gen-id'; import { GalleryPost } from '../../../../../models/entities/gallery-post'; import { ApiError } from '../../../error'; +import { DriveFile } from '@/models/entities/drive-file'; export const meta = { tags: ['gallery'], @@ -55,7 +56,7 @@ export default define(meta, async (ps, user) => { id: fileId, userId: user.id }) - ))).filter(file => file != null); + ))).filter((file): file is DriveFile => file != null); if (files.length === 0) { throw new Error(); diff --git a/src/server/api/endpoints/gallery/posts/update.ts b/src/server/api/endpoints/gallery/posts/update.ts index c8bb8d48c9..d9176ea407 100644 --- a/src/server/api/endpoints/gallery/posts/update.ts +++ b/src/server/api/endpoints/gallery/posts/update.ts @@ -5,6 +5,7 @@ import { ID } from '../../../../../misc/cafy-id'; import { DriveFiles, GalleryPosts } from '../../../../../models'; import { GalleryPost } from '../../../../../models/entities/gallery-post'; import { ApiError } from '../../../error'; +import { DriveFile } from '@/models/entities/drive-file'; export const meta = { tags: ['gallery'], @@ -58,7 +59,7 @@ export default define(meta, async (ps, user) => { id: fileId, userId: user.id }) - ))).filter(file => file != null); + ))).filter((file): file is DriveFile => file != null); if (files.length === 0) { throw new Error(); diff --git a/src/services/chart/core.ts b/src/services/chart/core.ts index d956d33bd7..4a554daa78 100644 --- a/src/services/chart/core.ts +++ b/src/services/chart/core.ts @@ -93,7 +93,7 @@ export default abstract class Chart> { } @autobind - private static convertFlattenColumnsToObject(x: Record) { + private static convertFlattenColumnsToObject(x: Record): Record { const obj = {} as any; for (const k of Object.keys(x).filter(k => k.startsWith(Chart.columnPrefix))) { // now k is ___x_y_z @@ -285,8 +285,7 @@ export default abstract class Chart> { const latest = await this.getLatestLog(group); if (latest != null) { - const obj = Chart.convertFlattenColumnsToObject( - latest as Record); + const obj = Chart.convertFlattenColumnsToObject(latest) as T; // 空ログデータを作成 data = this.getNewLog(obj); @@ -474,13 +473,13 @@ export default abstract class Chart> { const log = logs.find(l => isTimeSame(new Date(l.date * 1000), current)); if (log) { - const data = Chart.convertFlattenColumnsToObject(log as Record); - chart.unshift(Chart.countUniqueFields(data)); + const data = Chart.convertFlattenColumnsToObject(log); + chart.unshift(Chart.countUniqueFields(data) as T); } else { // 隙間埋め const latest = logs.find(l => isTimeBefore(new Date(l.date * 1000), current)); - const data = latest ? Chart.convertFlattenColumnsToObject(latest as Record) : null; - chart.unshift(Chart.countUniqueFields(this.getNewLog(data))); + const data = latest ? Chart.convertFlattenColumnsToObject(latest) as T : null; + chart.unshift(Chart.countUniqueFields(this.getNewLog(data)) as T); } } } else if (span === 'day') { @@ -497,14 +496,14 @@ export default abstract class Chart> { if (log) { if (logsForEachDays[currentDayIndex]) { - logsForEachDays[currentDayIndex].unshift(Chart.convertFlattenColumnsToObject(log)); + logsForEachDays[currentDayIndex].unshift(Chart.convertFlattenColumnsToObject(log) as T); } else { - logsForEachDays[currentDayIndex] = [Chart.convertFlattenColumnsToObject(log)]; + logsForEachDays[currentDayIndex] = [Chart.convertFlattenColumnsToObject(log) as T]; } } else { // 隙間埋め const latest = logs.find(l => isTimeBefore(new Date(l.date * 1000), current)); - const data = latest ? Chart.convertFlattenColumnsToObject(latest as Record) : null; + const data = latest ? Chart.convertFlattenColumnsToObject(latest) as T : null; const newLog = this.getNewLog(data); if (logsForEachDays[currentDayIndex]) { logsForEachDays[currentDayIndex].unshift(newLog); @@ -516,7 +515,7 @@ export default abstract class Chart> { for (const logs of logsForEachDays) { const log = this.aggregate(logs); - chart.unshift(Chart.countUniqueFields(log)); + chart.unshift(Chart.countUniqueFields(log) as T); } } From ffb9646ce9c3d2326a3e922e58702674eb65646c Mon Sep 17 00:00:00 2001 From: nullobsi Date: Thu, 27 May 2021 17:38:09 -0700 Subject: [PATCH 11/48] Add image description support (#7518) * recieve image descriptions under the name property * fix other components * use comment for alt and title * allow editing of file comment * allow editing of file comment in note dialog * federate note comments * use file instead of this * backend should accept comment on update * update now actually accepts comment * allow multiline descriptions * image should also have description attached * Update locales/ja-JP.yml Co-authored-by: rinsuki <428rinsuki+git@gmail.com> * Use custom component with side-by-side image * improve usability on mobile devices * revert changes * Update post-form-attaches.vue * Update drive.file.vue * Update media-caption.vue Co-authored-by: rinsuki <428rinsuki+git@gmail.com> Co-authored-by: syuilo --- locales/ja-JP.yml | 3 + src/client/components/drive.file.vue | 24 ++ src/client/components/image-viewer.vue | 2 +- src/client/components/media-caption.vue | 238 ++++++++++++++++++ src/client/components/media-image.vue | 4 +- src/client/components/post-form-attaches.vue | 25 ++ src/remote/activitypub/models/image.ts | 2 +- src/remote/activitypub/renderer/document.ts | 3 +- src/remote/activitypub/renderer/image.ts | 3 +- .../api/endpoints/drive/files/update.ts | 11 + src/services/drive/upload-from-url.ts | 6 + 11 files changed, 315 insertions(+), 6 deletions(-) create mode 100644 src/client/components/media-caption.vue diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index e869f5b015..23f3bf7296 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -279,6 +279,7 @@ emptyDrive: "ドライブは空です" emptyFolder: "フォルダーは空です" unableToDelete: "削除できません" inputNewFileName: "新しいファイル名を入力してください" +inputNewDescription: "新しいキャプションを入力してください" inputNewFolderName: "新しいフォルダ名を入力してください" circularReferenceFolder: "移動先のフォルダーは、移動するフォルダーのサブフォルダーです。" hasChildFilesOrFolders: "このフォルダは空でないため、削除できません。" @@ -546,6 +547,8 @@ disablePlayer: "プレイヤーを閉じる" expandTweet: "ツイートを展開する" themeEditor: "テーマエディター" description: "説明" +describeFile: "キャプションを付ける" +enterFileDescription: "キャプションを入力" author: "作者" leaveConfirm: "未保存の変更があります。破棄しますか?" manage: "管理" diff --git a/src/client/components/drive.file.vue b/src/client/components/drive.file.vue index 37b1afc1b3..3d20de23e9 100644 --- a/src/client/components/drive.file.vue +++ b/src/client/components/drive.file.vue @@ -87,6 +87,10 @@ export default defineComponent({ text: this.file.isSensitive ? this.$ts.unmarkAsSensitive : this.$ts.markAsSensitive, icon: this.file.isSensitive ? 'fas fa-eye' : 'fas fa-eye-slash', action: this.toggleSensitive + }, { + text: this.$ts.describeFile, + icon: 'fas fa-i-cursor', + action: this.describe }, null, { text: this.$ts.copyUrl, icon: 'fas fa-link', @@ -150,6 +154,26 @@ export default defineComponent({ }); }, + describe() { + os.popup(import('@client/components/media-caption.vue'), { + title: this.$ts.describeFile, + input: { + placeholder: this.$ts.inputNewDescription, + default: this.file.comment !== null ? this.file.comment : '', + }, + image: this.file + }, { + done: result => { + if (!result || result.canceled) return; + let comment = result.result; + os.api('drive/files/update', { + fileId: this.file.id, + comment: comment.length == 0 ? null : comment + }); + } + }, 'closed'); + }, + toggleSensitive() { os.api('drive/files/update', { fileId: this.file.id, diff --git a/src/client/components/image-viewer.vue b/src/client/components/image-viewer.vue index ec22bd98ec..7701ae926f 100644 --- a/src/client/components/image-viewer.vue +++ b/src/client/components/image-viewer.vue @@ -2,7 +2,7 @@

{{ image.name }}
- +