From 2b19e1f7326e61ab53b85c4f155b189ee32d79d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Sun, 9 Apr 2023 13:16:56 +0900 Subject: [PATCH 01/28] test: add `/@:acct` stories (#10517) * test: add `/@:acct` stories * test: add mocks --- packages/frontend/.storybook/fakes.ts | 1 + packages/frontend/.storybook/generate.tsx | 1 + .../src/pages/user/home.stories.impl.ts | 74 +++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 packages/frontend/src/pages/user/home.stories.impl.ts diff --git a/packages/frontend/.storybook/fakes.ts b/packages/frontend/.storybook/fakes.ts index 23b82a8ac..5fd21cdf0 100644 --- a/packages/frontend/.storybook/fakes.ts +++ b/packages/frontend/.storybook/fakes.ts @@ -77,6 +77,7 @@ export function userDetailed(id = 'someuserid', username = 'miskist', host = 'mi createdAt: '2016-12-28T22:49:51.000Z', description: 'I am a cool user!', ffVisibility: 'public', + roles: [], fields: [ { name: 'Website', diff --git a/packages/frontend/.storybook/generate.tsx b/packages/frontend/.storybook/generate.tsx index b3bbeeb51..dd40bac2c 100644 --- a/packages/frontend/.storybook/generate.tsx +++ b/packages/frontend/.storybook/generate.tsx @@ -398,6 +398,7 @@ function toStories(component: string): string { Promise.all([ glob('src/components/global/*.vue'), glob('src/components/MkGalleryPostPreview.vue'), + glob('src/pages/user/home.vue'), ]) .then((globs) => globs.flat()) .then((components) => Promise.all(components.map((component) => { diff --git a/packages/frontend/src/pages/user/home.stories.impl.ts b/packages/frontend/src/pages/user/home.stories.impl.ts new file mode 100644 index 000000000..50da0c699 --- /dev/null +++ b/packages/frontend/src/pages/user/home.stories.impl.ts @@ -0,0 +1,74 @@ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ +import { StoryObj } from '@storybook/vue3'; +import { rest } from 'msw'; +import { userDetailed } from '../../../.storybook/fakes'; +import { commonHandlers } from '../../../.storybook/mocks'; +import home_ from './home.vue'; +export const Default = { + render(args) { + return { + components: { + home_, + }, + setup() { + return { + args, + }; + }, + computed: { + props() { + return { + ...this.args, + }; + }, + }, + template: '', + }; + }, + args: { + user: userDetailed(), + disableNotes: false, + }, + parameters: { + layout: 'fullscreen', + msw: { + handlers: [ + ...commonHandlers, + rest.post('/api/users/notes', (req, res, ctx) => { + return res(ctx.json([])); + }), + rest.get('/api/charts/user/notes', (req, res, ctx) => { + const length = Math.max(Math.min(parseInt(req.url.searchParams.get('limit') ?? '30', 10), 1), 300); + return res(ctx.json({ + total: Array.from({ length }, () => 0), + inc: Array.from({ length }, () => 0), + dec: Array.from({ length }, () => 0), + diffs: { + normal: Array.from({ length }, () => 0), + reply: Array.from({ length }, () => 0), + renote: Array.from({ length }, () => 0), + withFile: Array.from({ length }, () => 0), + }, + })); + }), + rest.get('/api/charts/user/pv', (req, res, ctx) => { + const length = Math.max(Math.min(parseInt(req.url.searchParams.get('limit') ?? '30', 10), 1), 300); + return res(ctx.json({ + upv: { + user: Array.from({ length }, () => 0), + visitor: Array.from({ length }, () => 0), + }, + pv: { + user: Array.from({ length }, () => 0), + visitor: Array.from({ length }, () => 0), + }, + })); + }), + ], + }, + chromatic: { + // `XActivity` is not compatible with Chromatic for now + disableSnapshot: true, + }, + }, +} satisfies StoryObj; From b56f4b27ee8accbff040de5679fbf1c85481556b Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 9 Apr 2023 17:01:03 +0900 Subject: [PATCH 02/28] =?UTF-8?q?fix(backend):=20=E3=82=B9=E3=83=88?= =?UTF-8?q?=E3=83=AA=E3=83=BC=E3=83=9F=E3=83=B3=E3=82=B0=E3=81=AELTL?= =?UTF-8?q?=E3=83=81=E3=83=A3=E3=83=B3=E3=83=8D=E3=83=AB=E3=81=A7=E3=82=B5?= =?UTF-8?q?=E3=83=BC=E3=83=90=E3=83=BC=E5=81=B4=E3=81=AB=E3=82=A8=E3=83=A9?= =?UTF-8?q?=E3=83=BC=E3=83=AD=E3=82=B0=E3=81=8C=E5=87=BA=E3=82=8B=E3=81=AE?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/src/server/api/stream/channels/local-timeline.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/server/api/stream/channels/local-timeline.ts b/packages/backend/src/server/api/stream/channels/local-timeline.ts index 836c5aae6..09b0005ac 100644 --- a/packages/backend/src/server/api/stream/channels/local-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/local-timeline.ts @@ -54,10 +54,10 @@ class LocalTimelineChannel extends Channel { } // 関係ない返信は除外 - if (note.reply && !this.user!.showTimelineReplies) { + if (note.reply && this.user && !this.user.showTimelineReplies) { const reply = note.reply; // 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合 - if (reply.userId !== this.user!.id && note.userId !== this.user!.id && reply.userId !== note.userId) return; + if (reply.userId !== this.user.id && note.userId !== this.user.id && reply.userId !== note.userId) return; } // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する From 39cf80e19f10676b263004e0a1402fdc5a9613f9 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 9 Apr 2023 17:09:27 +0900 Subject: [PATCH 03/28] =?UTF-8?q?fix(backend):=20=E3=82=A4=E3=83=99?= =?UTF-8?q?=E3=83=B3=E3=83=88=E7=94=A8redis=E5=88=86=E9=9B=A2=E3=81=8C?= =?UTF-8?q?=E4=B8=8A=E6=89=8B=E3=81=8F=E5=8B=95=E3=81=8B=E3=81=AA=E3=81=84?= =?UTF-8?q?=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/src/GlobalModule.ts | 30 +++++++++++++++---- packages/backend/src/core/AntennaService.ts | 8 ++--- packages/backend/src/core/CacheService.ts | 8 ++--- .../backend/src/core/GlobalEventService.ts | 6 ++-- packages/backend/src/core/MetaService.ts | 8 ++--- packages/backend/src/core/RoleService.ts | 8 ++--- packages/backend/src/core/WebhookService.ts | 8 ++--- packages/backend/src/di-symbols.ts | 3 +- .../server/api/StreamingApiServerService.ts | 8 ++--- 9 files changed, 53 insertions(+), 34 deletions(-) diff --git a/packages/backend/src/GlobalModule.ts b/packages/backend/src/GlobalModule.ts index cb713b25a..174d0d8be 100644 --- a/packages/backend/src/GlobalModule.ts +++ b/packages/backend/src/GlobalModule.ts @@ -37,8 +37,24 @@ const $redis: Provider = { inject: [DI.config], }; -const $redisForPubsub: Provider = { - provide: DI.redisForPubsub, +const $redisForPub: Provider = { + provide: DI.redisForPub, + useFactory: (config) => { + const redis = new Redis({ + port: config.redisForPubsub.port, + host: config.redisForPubsub.host, + family: config.redisForPubsub.family == null ? 0 : config.redisForPubsub.family, + password: config.redisForPubsub.pass, + keyPrefix: `${config.redisForPubsub.prefix}:`, + db: config.redisForPubsub.db ?? 0, + }); + return redis; + }, + inject: [DI.config], +}; + +const $redisForSub: Provider = { + provide: DI.redisForSub, useFactory: (config) => { const redis = new Redis({ port: config.redisForPubsub.port, @@ -57,14 +73,15 @@ const $redisForPubsub: Provider = { @Global() @Module({ imports: [RepositoryModule], - providers: [$config, $db, $redis, $redisForPubsub], - exports: [$config, $db, $redis, $redisForPubsub, RepositoryModule], + providers: [$config, $db, $redis, $redisForPub, $redisForSub], + exports: [$config, $db, $redis, $redisForPub, $redisForSub, RepositoryModule], }) export class GlobalModule implements OnApplicationShutdown { constructor( @Inject(DI.db) private db: DataSource, @Inject(DI.redis) private redisClient: Redis.Redis, - @Inject(DI.redisForPubsub) private redisForPubsub: Redis.Redis, + @Inject(DI.redisForPub) private redisForPub: Redis.Redis, + @Inject(DI.redisForSub) private redisForSub: Redis.Redis, ) {} async onApplicationShutdown(signal: string): Promise { @@ -79,7 +96,8 @@ export class GlobalModule implements OnApplicationShutdown { await Promise.all([ this.db.destroy(), this.redisClient.disconnect(), - this.redisForPubsub.disconnect(), + this.redisForPub.disconnect(), + this.redisForSub.disconnect(), ]); } } diff --git a/packages/backend/src/core/AntennaService.ts b/packages/backend/src/core/AntennaService.ts index 35266ac16..47ebd4c74 100644 --- a/packages/backend/src/core/AntennaService.ts +++ b/packages/backend/src/core/AntennaService.ts @@ -27,8 +27,8 @@ export class AntennaService implements OnApplicationShutdown { @Inject(DI.redis) private redisClient: Redis.Redis, - @Inject(DI.redisForPubsub) - private redisForPubsub: Redis.Redis, + @Inject(DI.redisForSub) + private redisForSub: Redis.Redis, @Inject(DI.mutingsRepository) private mutingsRepository: MutingsRepository, @@ -52,12 +52,12 @@ export class AntennaService implements OnApplicationShutdown { this.antennasFetched = false; this.antennas = []; - this.redisForPubsub.on('message', this.onRedisMessage); + this.redisForSub.on('message', this.onRedisMessage); } @bindThis public onApplicationShutdown(signal?: string | undefined) { - this.redisForPubsub.off('message', this.onRedisMessage); + this.redisForSub.off('message', this.onRedisMessage); } @bindThis diff --git a/packages/backend/src/core/CacheService.ts b/packages/backend/src/core/CacheService.ts index d74f3e878..561face5c 100644 --- a/packages/backend/src/core/CacheService.ts +++ b/packages/backend/src/core/CacheService.ts @@ -27,8 +27,8 @@ export class CacheService implements OnApplicationShutdown { @Inject(DI.redis) private redisClient: Redis.Redis, - @Inject(DI.redisForPubsub) - private redisForPubsub: Redis.Redis, + @Inject(DI.redisForSub) + private redisForSub: Redis.Redis, @Inject(DI.usersRepository) private usersRepository: UsersRepository, @@ -116,7 +116,7 @@ export class CacheService implements OnApplicationShutdown { fromRedisConverter: (value) => new Set(JSON.parse(value)), }); - this.redisForPubsub.on('message', this.onMessage); + this.redisForSub.on('message', this.onMessage); } @bindThis @@ -167,6 +167,6 @@ export class CacheService implements OnApplicationShutdown { @bindThis public onApplicationShutdown(signal?: string | undefined) { - this.redisForPubsub.off('message', this.onMessage); + this.redisForSub.off('message', this.onMessage); } } diff --git a/packages/backend/src/core/GlobalEventService.ts b/packages/backend/src/core/GlobalEventService.ts index 25c064a2b..9f4de5f98 100644 --- a/packages/backend/src/core/GlobalEventService.ts +++ b/packages/backend/src/core/GlobalEventService.ts @@ -26,8 +26,8 @@ export class GlobalEventService { @Inject(DI.config) private config: Config, - @Inject(DI.redis) - private redisClient: Redis.Redis, + @Inject(DI.redisForPub) + private redisForPub: Redis.Redis, ) { } @@ -37,7 +37,7 @@ export class GlobalEventService { { type: type, body: null } : { type: type, body: value }; - this.redisClient.publish(this.config.host, JSON.stringify({ + this.redisForPub.publish(this.config.host, JSON.stringify({ channel: channel, message: message, })); diff --git a/packages/backend/src/core/MetaService.ts b/packages/backend/src/core/MetaService.ts index 2b6160c82..1322927c2 100644 --- a/packages/backend/src/core/MetaService.ts +++ b/packages/backend/src/core/MetaService.ts @@ -14,8 +14,8 @@ export class MetaService implements OnApplicationShutdown { private intervalId: NodeJS.Timer; constructor( - @Inject(DI.redisForPubsub) - private redisForPubsub: Redis.Redis, + @Inject(DI.redisForSub) + private redisForSub: Redis.Redis, @Inject(DI.db) private db: DataSource, @@ -33,7 +33,7 @@ export class MetaService implements OnApplicationShutdown { }, 1000 * 60 * 5); } - this.redisForPubsub.on('message', this.onMessage); + this.redisForSub.on('message', this.onMessage); } @bindThis @@ -122,6 +122,6 @@ export class MetaService implements OnApplicationShutdown { @bindThis public onApplicationShutdown(signal?: string | undefined) { clearInterval(this.intervalId); - this.redisForPubsub.off('message', this.onMessage); + this.redisForSub.off('message', this.onMessage); } } diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index c8ebe1adb..77645e3f0 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -64,8 +64,8 @@ export class RoleService implements OnApplicationShutdown { public static NotAssignedError = class extends Error {}; constructor( - @Inject(DI.redisForPubsub) - private redisForPubsub: Redis.Redis, + @Inject(DI.redisForSub) + private redisForSub: Redis.Redis, @Inject(DI.usersRepository) private usersRepository: UsersRepository, @@ -87,7 +87,7 @@ export class RoleService implements OnApplicationShutdown { this.rolesCache = new MemorySingleCache(1000 * 60 * 60 * 1); this.roleAssignmentByUserIdCache = new MemoryKVCache(1000 * 60 * 60 * 1); - this.redisForPubsub.on('message', this.onMessage); + this.redisForSub.on('message', this.onMessage); } @bindThis @@ -400,6 +400,6 @@ export class RoleService implements OnApplicationShutdown { @bindThis public onApplicationShutdown(signal?: string | undefined) { - this.redisForPubsub.off('message', this.onMessage); + this.redisForSub.off('message', this.onMessage); } } diff --git a/packages/backend/src/core/WebhookService.ts b/packages/backend/src/core/WebhookService.ts index 85594f855..926115613 100644 --- a/packages/backend/src/core/WebhookService.ts +++ b/packages/backend/src/core/WebhookService.ts @@ -13,14 +13,14 @@ export class WebhookService implements OnApplicationShutdown { private webhooks: Webhook[] = []; constructor( - @Inject(DI.redisForPubsub) - private redisForPubsub: Redis.Redis, + @Inject(DI.redisForSub) + private redisForSub: Redis.Redis, @Inject(DI.webhooksRepository) private webhooksRepository: WebhooksRepository, ) { //this.onMessage = this.onMessage.bind(this); - this.redisForPubsub.on('message', this.onMessage); + this.redisForSub.on('message', this.onMessage); } @bindThis @@ -82,6 +82,6 @@ export class WebhookService implements OnApplicationShutdown { @bindThis public onApplicationShutdown(signal?: string | undefined) { - this.redisForPubsub.off('message', this.onMessage); + this.redisForSub.off('message', this.onMessage); } } diff --git a/packages/backend/src/di-symbols.ts b/packages/backend/src/di-symbols.ts index 482e8f83e..d4b1fb31b 100644 --- a/packages/backend/src/di-symbols.ts +++ b/packages/backend/src/di-symbols.ts @@ -2,7 +2,8 @@ export const DI = { config: Symbol('config'), db: Symbol('db'), redis: Symbol('redis'), - redisForPubsub: Symbol('redisForPubsub'), + redisForPub: Symbol('redisForPub'), + redisForSub: Symbol('redisForSub'), //#region Repositories usersRepository: Symbol('usersRepository'), diff --git a/packages/backend/src/server/api/StreamingApiServerService.ts b/packages/backend/src/server/api/StreamingApiServerService.ts index e0e5b71a8..769a4490d 100644 --- a/packages/backend/src/server/api/StreamingApiServerService.ts +++ b/packages/backend/src/server/api/StreamingApiServerService.ts @@ -22,8 +22,8 @@ export class StreamingApiServerService { @Inject(DI.config) private config: Config, - @Inject(DI.redisForPubsub) - private redisForPubsub: Redis.Redis, + @Inject(DI.redisForSub) + private redisForSub: Redis.Redis, @Inject(DI.usersRepository) private usersRepository: UsersRepository, @@ -81,7 +81,7 @@ export class StreamingApiServerService { ev.emit(parsed.channel, parsed.message); } - this.redisForPubsub.on('message', onRedisMessage); + this.redisForSub.on('message', onRedisMessage); const main = new MainStreamConnection( this.channelsService, @@ -111,7 +111,7 @@ export class StreamingApiServerService { connection.once('close', () => { ev.removeAllListeners(); main.dispose(); - this.redisForPubsub.off('message', onRedisMessage); + this.redisForSub.off('message', onRedisMessage); if (intervalId) clearInterval(intervalId); }); From 3ec060f0dce00d73e80e32bc35cc04145a4997aa Mon Sep 17 00:00:00 2001 From: YS <47836716+yszkst@users.noreply.github.com> Date: Mon, 10 Apr 2023 08:31:06 +0900 Subject: [PATCH 04/28] =?UTF-8?q?MkContainer.vue=20i18n=20=E3=82=92templat?= =?UTF-8?q?e=E3=81=8B=E3=82=89=E8=A6=8B=E3=81=88=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=20(#10560)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/components/MkContainer.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/frontend/src/components/MkContainer.vue b/packages/frontend/src/components/MkContainer.vue index 1834224b8..a6372b7b6 100644 --- a/packages/frontend/src/components/MkContainer.vue +++ b/packages/frontend/src/components/MkContainer.vue @@ -82,6 +82,7 @@ export default defineComponent({ omitted: null, ignoreOmit: false, defaultStore, + i18n, }; }, mounted() { From 70a06e30d52cfacdfdc4122f9c1a9e09c4bc7e1d Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 10 Apr 2023 10:03:53 +0900 Subject: [PATCH 05/28] =?UTF-8?q?fix(backend):=20=E3=82=A2=E3=83=B3?= =?UTF-8?q?=E3=83=86=E3=83=8A=E3=81=AE=E3=83=8E=E3=83=BC=E3=83=88=E3=80=81?= =?UTF-8?q?=E3=83=81=E3=83=A3=E3=83=B3=E3=83=8D=E3=83=AB=E3=81=AE=E3=83=8E?= =?UTF-8?q?=E3=83=BC=E3=83=88=E3=80=81=E9=80=9A=E7=9F=A5=E3=81=8C=E6=AD=A3?= =?UTF-8?q?=E5=B8=B8=E3=81=AB=E4=BD=9C=E6=88=90=E3=81=A7=E3=81=8D=E3=81=AA?= =?UTF-8?q?=E3=81=84=E3=81=93=E3=81=A8=E3=81=8C=E3=81=82=E3=82=8B=E5=95=8F?= =?UTF-8?q?=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix #10482 --- CHANGELOG.md | 11 +++++++++++ packages/backend/src/core/AntennaService.ts | 2 +- packages/backend/src/core/NoteCreateService.ts | 2 +- packages/backend/src/core/NotificationService.ts | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e6fa2cf4..114bdc4d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,17 @@ --> +## 13.x.x (unreleased) + +### General +- + +### Client +- + +### Server +- アンテナのノート、チャンネルのノート、通知が正常に作成できないことがある問題を修正 + ## 13.11.1 ### General diff --git a/packages/backend/src/core/AntennaService.ts b/packages/backend/src/core/AntennaService.ts index 47ebd4c74..02e0b455f 100644 --- a/packages/backend/src/core/AntennaService.ts +++ b/packages/backend/src/core/AntennaService.ts @@ -95,7 +95,7 @@ export class AntennaService implements OnApplicationShutdown { this.redisClient.xadd( `antennaTimeline:${antenna.id}`, 'MAXLEN', '~', '200', - `${this.idService.parse(note.id).date.getTime()}-*`, + '*', 'note', note.id); this.globalEventService.publishAntennaStream(antenna.id, 'note', note); diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 5c4d13f17..fb7ee7080 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -329,7 +329,7 @@ export class NoteCreateService implements OnApplicationShutdown { this.redisClient.xadd( `channelTimeline:${data.channel.id}`, 'MAXLEN', '~', '1000', - `${this.idService.parse(note.id).date.getTime()}-*`, + '*', 'note', note.id); } diff --git a/packages/backend/src/core/NotificationService.ts b/packages/backend/src/core/NotificationService.ts index c44dddea4..c7dac061b 100644 --- a/packages/backend/src/core/NotificationService.ts +++ b/packages/backend/src/core/NotificationService.ts @@ -99,7 +99,7 @@ export class NotificationService implements OnApplicationShutdown { const redisIdPromise = this.redisClient.xadd( `notificationTimeline:${notifieeId}`, 'MAXLEN', '~', '300', - `${this.idService.parse(notification.id).date.getTime()}-*`, + '*', 'data', JSON.stringify(notification)); const packed = await this.notificationEntityService.pack(notification, notifieeId, {}); From f8315a40b4aa85a54fb3ce72176f8065e85b0f1d Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 10 Apr 2023 10:04:16 +0900 Subject: [PATCH 06/28] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 114bdc4d7..2f5995298 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ ### Server - アンテナのノート、チャンネルのノート、通知が正常に作成できないことがある問題を修正 +- ストリーミングのLTLチャンネルでサーバー側にエラーログが出るのを修正 ## 13.11.1 From eba42230eed67630e567165cbccc24a3c351d875 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 10 Apr 2023 10:12:05 +0900 Subject: [PATCH 07/28] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f5995298..832130a79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ - ### Client -- +- ユーザーページの画像一覧が表示されない問題を修正 ### Server - アンテナのノート、チャンネルのノート、通知が正常に作成できないことがある問題を修正 From 29c9a7d71a6d4af4f8d7d6a1c31a3734ca234180 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 10 Apr 2023 10:22:25 +0900 Subject: [PATCH 08/28] =?UTF-8?q?enhance(frontend):=20=E5=B8=B8=E3=81=AB?= =?UTF-8?q?=E5=BA=83=E5=91=8A=E3=82=92=E8=A6=8B=E3=82=89=E3=82=8C=E3=82=8B?= =?UTF-8?q?=E3=82=AA=E3=83=97=E3=82=B7=E3=83=A7=E3=83=B3=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + locales/ja-JP.yml | 1 + packages/frontend/src/components/global/MkAd.vue | 2 +- packages/frontend/src/pages/settings/general.vue | 2 ++ packages/frontend/src/store.ts | 4 ++++ 5 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 832130a79..683ee3db8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - ### Client +- 常に広告を見られるオプションを追加 - ユーザーページの画像一覧が表示されない問題を修正 ### Server diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 32bf47c20..b01699cab 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -991,6 +991,7 @@ largeNoteReactions: "ノートのリアクションを大きく表示" noteIdOrUrl: "ノートIDまたはURL" accountMigration: "アカウントの引っ越し" accountMoved: "このユーザーは新しいアカウントに引っ越しました:" +forceShowAds: "常に広告を表示する" _accountMigration: moveTo: "このアカウントを新しいアカウントに引っ越す" diff --git a/packages/frontend/src/components/global/MkAd.vue b/packages/frontend/src/components/global/MkAd.vue index 5799f99d5..aa975600f 100644 --- a/packages/frontend/src/components/global/MkAd.vue +++ b/packages/frontend/src/components/global/MkAd.vue @@ -83,7 +83,7 @@ const choseAd = (): Ad | null => { }; const chosen = ref(choseAd()); -const shouldHide = $ref($i && $i.policies.canHideAds && (props.specify == null)); +const shouldHide = $ref(!defaultStore.state.forceShowAds && $i && $i.policies.canHideAds && (props.specify == null)); function reduceFrequency(): void { if (chosen.value == null) return; diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index f88e934e1..904fd3f95 100644 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -61,6 +61,7 @@ {{ i18n.ts.squareAvatars }} {{ i18n.ts.useSystemFont }} {{ i18n.ts.disableDrawer }} + {{ i18n.ts.forceShowAds }}
@@ -157,6 +158,7 @@ const advancedMfm = computed(defaultStore.makeGetterSetter('advancedMfm')); const emojiStyle = computed(defaultStore.makeGetterSetter('emojiStyle')); const disableDrawer = computed(defaultStore.makeGetterSetter('disableDrawer')); const disableShowingAnimatedImages = computed(defaultStore.makeGetterSetter('disableShowingAnimatedImages')); +const forceShowAds = computed(defaultStore.makeGetterSetter('forceShowAds')); const loadRawImages = computed(defaultStore.makeGetterSetter('loadRawImages')); const imageNewTab = computed(defaultStore.makeGetterSetter('imageNewTab')); const nsfw = computed(defaultStore.makeGetterSetter('nsfw')); diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index e5558829d..0728fc84e 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -298,6 +298,10 @@ export const defaultStore = markRaw(new Storage('base', { where: 'device', default: false, }, + forceShowAds: { + where: 'device', + default: false, + }, aiChanMode: { where: 'device', default: false, From e0431aed28a2a974e2e9a9251685d212be56d9ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=97=A4?= <100684884+Fuji-P@users.noreply.github.com> Date: Mon, 10 Apr 2023 10:23:56 +0900 Subject: [PATCH 09/28] =?UTF-8?q?fix=20issue=20#10195=20=E8=A8=AD=E5=AE=9A?= =?UTF-8?q?=E3=81=AE=E3=83=90=E3=83=83=E3=82=AF=E3=82=A2=E3=83=83=E3=83=97?= =?UTF-8?q?=20=E3=81=AE=E3=80=8C=E5=89=8A=E9=99=A4=E3=80=8D=E3=81=AE?= =?UTF-8?q?=E6=96=87=E5=AD=97=E3=81=8C=E3=81=AA=E3=81=84=20(#10559)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 藤 --- packages/frontend/src/pages/settings/preferences-backups.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/pages/settings/preferences-backups.vue b/packages/frontend/src/pages/settings/preferences-backups.vue index 28e39236f..092b9a9cc 100644 --- a/packages/frontend/src/pages/settings/preferences-backups.vue +++ b/packages/frontend/src/pages/settings/preferences-backups.vue @@ -399,7 +399,7 @@ function menu(ev: MouseEvent, profileId: string) { icon: 'ti ti-device-floppy', action: () => save(profileId), }, null, { - text: ts._preferencesBackups.delete, + text: ts.delete, icon: 'ti ti-trash', action: () => deleteProfile(profileId), danger: true, From 511dab061874c62987cd9b4be8298a98a858d1e7 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 10 Apr 2023 18:56:38 +0900 Subject: [PATCH 10/28] =?UTF-8?q?fix(frontend):=20webhook,=20=E9=80=A3?= =?UTF-8?q?=E6=90=BA=E3=82=A2=E3=83=97=E3=83=AA=E4=B8=80=E8=A6=A7=E3=81=A7?= =?UTF-8?q?=E3=82=B3=E3=83=B3=E3=83=86=E3=83=B3=E3=83=84=E3=81=8C=E9=87=8D?= =?UTF-8?q?=E8=A4=87=E3=81=97=E3=81=A6=E8=A1=A8=E7=A4=BA=E3=81=95=E3=82=8C?= =?UTF-8?q?=E3=82=8B=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix #10564 --- CHANGELOG.md | 1 + packages/frontend/src/pages/settings/apps.vue | 45 ++++++++++--------- .../frontend/src/pages/settings/webhook.vue | 29 ++++++------ 3 files changed, 41 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 683ee3db8..56e34427c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ ### Client - 常に広告を見られるオプションを追加 - ユーザーページの画像一覧が表示されない問題を修正 +- webhook, 連携アプリ一覧でコンテンツが重複して表示される問題を修正 ### Server - アンテナのノート、チャンネルのノート、通知が正常に作成できないことがある問題を修正 diff --git a/packages/frontend/src/pages/settings/apps.vue b/packages/frontend/src/pages/settings/apps.vue index 955d81215..599d6329e 100644 --- a/packages/frontend/src/pages/settings/apps.vue +++ b/packages/frontend/src/pages/settings/apps.vue @@ -8,27 +8,29 @@
@@ -91,4 +91,8 @@ function updateWidgets(thisWidgets) { .widgets { width: 300px; } + +.edit { + width: 100%; +} From 838625edcd90da82a67825ce21bc4132671dcf27 Mon Sep 17 00:00:00 2001 From: tamaina Date: Mon, 10 Apr 2023 17:26:52 +0000 Subject: [PATCH 15/28] update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56e34427c..03d6ccf42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ - 常に広告を見られるオプションを追加 - ユーザーページの画像一覧が表示されない問題を修正 - webhook, 連携アプリ一覧でコンテンツが重複して表示される問題を修正 +- iPhoneで絵文字ピッカーの表示が崩れる問題を修正 +- iPhoneでウィジェットドロワーの「ウィジェットを編集」が押しにくい問題を修正 ### Server - アンテナのノート、チャンネルのノート、通知が正常に作成できないことがある問題を修正 From 0702f9775a58900a7a827c23aaaa6aec85b80c50 Mon Sep 17 00:00:00 2001 From: Chimorium <130294972+Chimorium@users.noreply.github.com> Date: Tue, 11 Apr 2023 07:39:46 +0900 Subject: [PATCH 16/28] =?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=81=AE=E3=82=AD=E3=83=A3=E3=83=83?= =?UTF-8?q?=E3=82=B7=E3=83=A5=E6=99=82=E3=81=AB"{}"=E3=81=8C=E5=85=A5?= =?UTF-8?q?=E3=81=A3=E3=81=A6=E3=81=97=E3=81=BE=E3=81=86=E5=95=8F=E9=A1=8C?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3=20(#10573)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/src/core/CustomEmojiService.ts | 8 ++------ packages/backend/src/misc/cache.ts | 4 ++-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/backend/src/core/CustomEmojiService.ts b/packages/backend/src/core/CustomEmojiService.ts index dc365986f..3de936dd6 100644 --- a/packages/backend/src/core/CustomEmojiService.ts +++ b/packages/backend/src/core/CustomEmojiService.ts @@ -43,12 +43,8 @@ export class CustomEmojiService { lifetime: 1000 * 60 * 30, // 30m memoryCacheLifetime: 1000 * 60 * 3, // 3m fetcher: () => this.emojisRepository.find({ where: { host: IsNull() } }).then(emojis => new Map(emojis.map(emoji => [emoji.name, emoji]))), - toRedisConverter: (value) => JSON.stringify(value.values()), - fromRedisConverter: (value) => { - // 原因不明だが配列以外が入ってくることがあるため - if (!Array.isArray(JSON.parse(value))) return undefined; - return new Map(JSON.parse(value).map((x: Emoji) => [x.name, x])); - }, // TODO: Date型の変換 + toRedisConverter: (value) => JSON.stringify(Array.from(value.values())), + fromRedisConverter: (value) => new Map(JSON.parse(value).map((x: Emoji) => [x.name, x])), // TODO: Date型の変換 }); } diff --git a/packages/backend/src/misc/cache.ts b/packages/backend/src/misc/cache.ts index a4abd4f87..d35414acf 100644 --- a/packages/backend/src/misc/cache.ts +++ b/packages/backend/src/misc/cache.ts @@ -8,7 +8,7 @@ export class RedisKVCache { private memoryCache: MemoryKVCache; private fetcher: (key: string) => Promise; private toRedisConverter: (value: T) => string; - private fromRedisConverter: (value: string) => T | undefined; // undefined means no cache + private fromRedisConverter: (value: string) => T; constructor(redisClient: RedisKVCache['redisClient'], name: RedisKVCache['name'], opts: { lifetime: RedisKVCache['lifetime']; @@ -92,7 +92,7 @@ export class RedisSingleCache { private memoryCache: MemorySingleCache; private fetcher: () => Promise; private toRedisConverter: (value: T) => string; - private fromRedisConverter: (value: string) => T | undefined; // undefined means no cache + private fromRedisConverter: (value: string) => T; constructor(redisClient: RedisSingleCache['redisClient'], name: RedisSingleCache['name'], opts: { lifetime: RedisSingleCache['lifetime']; From f6dc100748ef403be1fdde8dd28b62ab4e11c5b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=9F=E3=83=BC=E3=81=B3=E3=82=93?= Date: Tue, 11 Apr 2023 07:42:27 +0900 Subject: [PATCH 17/28] =?UTF-8?q?fix=20#10554=20=E3=83=81=E3=83=A3?= =?UTF-8?q?=E3=83=B3=E3=83=8D=E3=83=AB=E3=81=AE=E6=A4=9C=E7=B4=A2=E7=94=A8?= =?UTF-8?q?=E3=83=9A=E3=83=BC=E3=82=B8=E3=81=A8API=E3=81=AE=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=20(#10555)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add channel search * move channel search to channel list page --------- Co-authored-by: tamaina Co-authored-by: syuilo Co-authored-by: atsuchan <83960488+atsu1125@users.noreply.github.com> Co-authored-by: Masaya Suzuki <15100604+massongit@users.noreply.github.com> Co-authored-by: Kagami Sascha Rosylight Co-authored-by: taiy <53635909+taiyme@users.noreply.github.com> Co-authored-by: xianon Co-authored-by: kabo2468 <28654659+kabo2468@users.noreply.github.com> Co-authored-by: YS <47836716+yszkst@users.noreply.github.com> Co-authored-by: Khsmty Co-authored-by: Soni L Co-authored-by: mei23 Co-authored-by: daima3629 <52790780+daima3629@users.noreply.github.com> Co-authored-by: Windymelt <1113940+windymelt@users.noreply.github.com> --- locales/ja-JP.yml | 2 + .../backend/src/server/api/EndpointsModule.ts | 4 ++ packages/backend/src/server/api/endpoints.ts | 2 + .../server/api/endpoints/channels/search.ts | 67 +++++++++++++++++++ .../frontend/src/components/MkChannelList.vue | 31 +++++++++ packages/frontend/src/pages/channels.vue | 62 ++++++++++++++++- 6 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 packages/backend/src/server/api/endpoints/channels/search.ts create mode 100644 packages/frontend/src/components/MkChannelList.vue diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index b01699cab..bdf2cada8 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1427,6 +1427,8 @@ _channel: following: "フォロー中" usersCount: "{n}人が参加中" notesCount: "{n}投稿があります" + nameAndDescription: "名前と説明" + nameOnly: "名前のみ" _menuDisplay: sideFull: "横" diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts index 5a53b3faf..ca89d8285 100644 --- a/packages/backend/src/server/api/EndpointsModule.ts +++ b/packages/backend/src/server/api/EndpointsModule.ts @@ -98,6 +98,7 @@ import * as ep___channels_update from './endpoints/channels/update.js'; import * as ep___channels_favorite from './endpoints/channels/favorite.js'; import * as ep___channels_unfavorite from './endpoints/channels/unfavorite.js'; import * as ep___channels_myFavorites from './endpoints/channels/my-favorites.js'; +import * as ep___channels_search from './endpoints/channels/search.js'; import * as ep___charts_activeUsers from './endpoints/charts/active-users.js'; import * as ep___charts_apRequest from './endpoints/charts/ap-request.js'; import * as ep___charts_drive from './endpoints/charts/drive.js'; @@ -431,6 +432,7 @@ const $channels_update: Provider = { provide: 'ep:channels/update', useClass: ep const $channels_favorite: Provider = { provide: 'ep:channels/favorite', useClass: ep___channels_favorite.default }; const $channels_unfavorite: Provider = { provide: 'ep:channels/unfavorite', useClass: ep___channels_unfavorite.default }; const $channels_myFavorites: Provider = { provide: 'ep:channels/my-favorites', useClass: ep___channels_myFavorites.default }; +const $channels_search: Provider = { provide: 'ep:channels/search', useClass: ep___channels_search.default }; const $charts_activeUsers: Provider = { provide: 'ep:charts/active-users', useClass: ep___charts_activeUsers.default }; const $charts_apRequest: Provider = { provide: 'ep:charts/ap-request', useClass: ep___charts_apRequest.default }; const $charts_drive: Provider = { provide: 'ep:charts/drive', useClass: ep___charts_drive.default }; @@ -768,6 +770,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $channels_favorite, $channels_unfavorite, $channels_myFavorites, + $channels_search, $charts_activeUsers, $charts_apRequest, $charts_drive, @@ -1099,6 +1102,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $channels_favorite, $channels_unfavorite, $channels_myFavorites, + $channels_search, $charts_activeUsers, $charts_apRequest, $charts_drive, diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index fd268c791..dab897117 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -98,6 +98,7 @@ import * as ep___channels_update from './endpoints/channels/update.js'; import * as ep___channels_favorite from './endpoints/channels/favorite.js'; import * as ep___channels_unfavorite from './endpoints/channels/unfavorite.js'; import * as ep___channels_myFavorites from './endpoints/channels/my-favorites.js'; +import * as ep___channels_search from './endpoints/channels/search.js'; import * as ep___charts_activeUsers from './endpoints/charts/active-users.js'; import * as ep___charts_apRequest from './endpoints/charts/ap-request.js'; import * as ep___charts_drive from './endpoints/charts/drive.js'; @@ -429,6 +430,7 @@ const eps = [ ['channels/favorite', ep___channels_favorite], ['channels/unfavorite', ep___channels_unfavorite], ['channels/my-favorites', ep___channels_myFavorites], + ['channels/search', ep___channels_search], ['charts/active-users', ep___charts_activeUsers], ['charts/ap-request', ep___charts_apRequest], ['charts/drive', ep___charts_drive], diff --git a/packages/backend/src/server/api/endpoints/channels/search.ts b/packages/backend/src/server/api/endpoints/channels/search.ts new file mode 100644 index 000000000..a954ba224 --- /dev/null +++ b/packages/backend/src/server/api/endpoints/channels/search.ts @@ -0,0 +1,67 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { Brackets } from 'typeorm'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { QueryService } from '@/core/QueryService.js'; +import type { ChannelsRepository } from '@/models/index.js'; +import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js'; +import { DI } from '@/di-symbols.js'; +import { sqlLikeEscape } from '@/misc/sql-like-escape.js'; + +export const meta = { + tags: ['channels'], + + requireCredential: false, + + res: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + ref: 'Channel', + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + query: { type: 'string' }, + type: { type: 'string', enum: ['nameAndDescription', 'nameOnly'], default: 'nameAndDescription' }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 5 }, + }, + required: ['query'], +} as const; + +// eslint-disable-next-line import/no-default-export +@Injectable() +export default class extends Endpoint { + constructor( + @Inject(DI.channelsRepository) + private channelsRepository: ChannelsRepository, + + private channelEntityService: ChannelEntityService, + private queryService: QueryService, + ) { + super(meta, paramDef, async (ps, me) => { + const query = this.queryService.makePaginationQuery(this.channelsRepository.createQueryBuilder('channel'), ps.sinceId, ps.untilId); + + if (ps.type === 'nameAndDescription') { + query.andWhere(new Brackets(qb => { qb + .where('channel.name ILIKE :q', { q: `%${ sqlLikeEscape(ps.query) }%` }) + .orWhere('channel.description ILIKE :q', { q: `%${ sqlLikeEscape(ps.query) }%` }); + })); + } else { + query.andWhere('channel.name ILIKE :q', { q: `%${ sqlLikeEscape(ps.query) }%` }); + } + + const channels = await query + .take(ps.limit) + .getMany(); + + return await Promise.all(channels.map(x => this.channelEntityService.pack(x, me))); + }); + } +} diff --git a/packages/frontend/src/components/MkChannelList.vue b/packages/frontend/src/components/MkChannelList.vue new file mode 100644 index 000000000..408eab739 --- /dev/null +++ b/packages/frontend/src/components/MkChannelList.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/packages/frontend/src/pages/channels.vue b/packages/frontend/src/pages/channels.vue index 3a5aa00c5..bc6a6e495 100644 --- a/packages/frontend/src/pages/channels.vue +++ b/packages/frontend/src/pages/channels.vue @@ -2,6 +2,23 @@ +
+
+ + + + + + + + {{ i18n.ts.search }} +
+ + + + + +
@@ -28,17 +45,35 @@