diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e525ace6..6959c8577 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,8 @@ - Feat: ユーザーごとに他ユーザーへの返信をタイムラインに含めるか設定可能になりました - Feat: ユーザーリスト内のメンバーごとに他ユーザーへの返信をユーザーリストタイムラインに含めるか設定可能になりました - Enhance: ソフトワードミュートとハードワードミュートは統合されました +- Enhance: モデレーションログ機能の強化 +- Enhance: ローカリゼーションの更新 ### Client - Enhance: 二要素認証のバックアップコード一覧をテキストファイルでダウンロード可能に diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml index 55b7cbb88..9bc30c2c2 100644 --- a/locales/ar-SA.yml +++ b/locales/ar-SA.yml @@ -1248,8 +1248,6 @@ _sfx: note: "الملاحظات" noteMy: "ملاحظتي" notification: "الإشعارات" - chat: "المحادثة" - chatBg: "المحادثة (الخلفية)" antenna: "الهوائيات" channel: "إشعارات القنات" _ago: diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml index 64b32d176..38f1f3fc7 100644 --- a/locales/bn-BD.yml +++ b/locales/bn-BD.yml @@ -1020,8 +1020,6 @@ _sfx: note: "নোটগুলি" noteMy: "নোট (আপনার)" notification: "বিজ্ঞপ্তি" - chat: "চ্যাট" - chatBg: "চ্যাট (ব্যাকগ্রাউন্ড)" antenna: "অ্যান্টেনাগুলি" channel: "চ্যানেলের বিজ্ঞপ্তি" _ago: diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index d1fd73b66..915388006 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -398,7 +398,6 @@ _theme: _sfx: note: "Notes" notification: "Notificacions" - chat: "Xat" antenna: "Antenes" _2fa: renewTOTPCancel: "No, gràcies" diff --git a/locales/cs-CZ.yml b/locales/cs-CZ.yml index 762f033b1..0f3ffb769 100644 --- a/locales/cs-CZ.yml +++ b/locales/cs-CZ.yml @@ -1647,8 +1647,6 @@ _sfx: note: "Poznámky" noteMy: "Moje poznámka" notification: "Oznámení" - chat: "Zprávy" - chatBg: "Chat (Pozadí)" antenna: "Antény" channel: "Oznámení kanálu" _ago: diff --git a/locales/de-DE.yml b/locales/de-DE.yml index e7d435a2e..27fb04bcb 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -1697,8 +1697,6 @@ _sfx: note: "Notizen" noteMy: "Meine Notizen" notification: "Benachrichtigungen" - chat: "Chat" - chatBg: "Chat (Hintergrund)" antenna: "Antennen" channel: "Kanalbenachrichtigung" _ago: diff --git a/locales/el-GR.yml b/locales/el-GR.yml index e46efcec1..9392fd12f 100644 --- a/locales/el-GR.yml +++ b/locales/el-GR.yml @@ -303,8 +303,6 @@ _theme: _sfx: note: "Σημειώματα" notification: "Ειδοποιήσεις" - chat: "Συνομιλία" - chatBg: "Συνομιλία (Παρασκήνιο)" antenna: "Αντένες" channel: "Ειδοποιήσεις καναλιών" _ago: diff --git a/locales/en-US.yml b/locales/en-US.yml index 9ed8ad9f2..200400674 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -1697,8 +1697,6 @@ _sfx: note: "New note" noteMy: "Own note" notification: "Notifications" - chat: "Chat" - chatBg: "Chat (Background)" antenna: "Antennas" channel: "Channel notifications" _ago: diff --git a/locales/es-ES.yml b/locales/es-ES.yml index d663bd829..547836fa2 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -1691,8 +1691,6 @@ _sfx: note: "Notas" noteMy: "Nota (a mí mismo)" notification: "Notificaciones" - chat: "Chat" - chatBg: "Chat (Fondo)" antenna: "Antena receptora" channel: "Notificaciones del canal" _ago: diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index db19b6688..254a1e274 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -1355,8 +1355,6 @@ _sfx: note: "Nouvelle note" noteMy: "Ma note" notification: "Notifications" - chat: "Discuter" - chatBg: "Discussion (arrière-plan)" antenna: "Réception de l’antenne" channel: "Notifications de canal" _ago: diff --git a/locales/id-ID.yml b/locales/id-ID.yml index 0e067c538..f4c54be15 100644 --- a/locales/id-ID.yml +++ b/locales/id-ID.yml @@ -1652,8 +1652,6 @@ _sfx: note: "Catatan" noteMy: "Catatan (Saya)" notification: "Notifikasi" - chat: "Pesan" - chatBg: "Obrolan (Latar Belakang)" antenna: "Penerimaan Antenna" channel: "Notifikasi Kanal" _ago: diff --git a/locales/index.d.ts b/locales/index.d.ts index 51d23436c..12ac0197f 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1808,8 +1808,6 @@ export interface Locale { "note": string; "noteMy": string; "notification": string; - "chat": string; - "chatBg": string; "antenna": string; "channel": string; }; diff --git a/locales/it-IT.yml b/locales/it-IT.yml index 83b63e15d..e7e5a9ecd 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -1692,8 +1692,6 @@ _sfx: note: "Nota" noteMy: "Mia nota" notification: "Notifiche" - chat: "Messaggi" - chatBg: "Chat (sfondo)" antenna: "Ricezione dell'antenna" channel: "Notifiche di canale" _ago: diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 2c586c753..f2190022c 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1725,8 +1725,6 @@ _sfx: note: "ノート" noteMy: "ノート(自分)" notification: "通知" - chat: "チャット" - chatBg: "チャット(バックグラウンド)" antenna: "アンテナ受信" channel: "チャンネル通知" diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml index bf945088f..672d98a19 100644 --- a/locales/ja-KS.yml +++ b/locales/ja-KS.yml @@ -1674,8 +1674,6 @@ _sfx: note: "ノート" noteMy: "ノート(自分)" notification: "通知" - chat: "チャット" - chatBg: "チャット(バックグラウンド)" antenna: "アンテナ受信" channel: "チャンネル通知" _ago: diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index af7afb2c3..7a191a5a5 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -1688,8 +1688,6 @@ _sfx: note: "새 노트" noteMy: "내 노트" notification: "알림" - chat: "대화" - chatBg: "대화 (백그라운드)" antenna: "안테나 수신" channel: "채널 알림" _ago: diff --git a/locales/lo-LA.yml b/locales/lo-LA.yml index 22cb5857f..b22e047cf 100644 --- a/locales/lo-LA.yml +++ b/locales/lo-LA.yml @@ -407,7 +407,6 @@ _theme: _sfx: note: "ບັນທຶກ" notification: "ການແຈ້ງເຕືອນ" - chat: "ແຊ໋ດ" _2fa: renewTOTPCancel: "ບໍ່​ແມ່ນ​ຕອນ​ນີ້" _widgets: diff --git a/locales/nl-NL.yml b/locales/nl-NL.yml index fd9ffa33f..6f789dff1 100644 --- a/locales/nl-NL.yml +++ b/locales/nl-NL.yml @@ -438,7 +438,6 @@ _theme: _sfx: note: "Notities" notification: "Meldingen" - chat: "Chat" _2fa: renewTOTPCancel: "Nee, bedankt" _widgets: diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml index 1c7ebe810..21e40d5c7 100644 --- a/locales/pl-PL.yml +++ b/locales/pl-PL.yml @@ -1066,8 +1066,6 @@ _sfx: note: "Wpisy" noteMy: "Mój wpis" notification: "Powiadomienia" - chat: "Wiadomości" - chatBg: "Rozmowy (tło)" antenna: "Anteny" channel: "Powiadomienia kanału" _ago: diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml index f9e777bc7..23864df1b 100644 --- a/locales/pt-PT.yml +++ b/locales/pt-PT.yml @@ -1320,7 +1320,6 @@ _theme: _sfx: note: "Posts" notification: "Notificações" - chat: "Chat" _ago: invalid: "Não há nada aqui" _timelineTutorial: diff --git a/locales/ro-RO.yml b/locales/ro-RO.yml index 51c33085a..77bccb7e6 100644 --- a/locales/ro-RO.yml +++ b/locales/ro-RO.yml @@ -647,7 +647,6 @@ _theme: _sfx: note: "Note" notification: "Notificări" - chat: "Chat" _ago: invalid: "Nu e nimic de văzut aici" _widgets: diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml index 937158978..4f4184e01 100644 --- a/locales/ru-RU.yml +++ b/locales/ru-RU.yml @@ -1576,8 +1576,6 @@ _sfx: note: "Заметки" noteMy: "Собственные заметки" notification: "Уведомления" - chat: "Сообщения" - chatBg: "Сообщения (фон)" antenna: "Антенна" channel: "Канал" _ago: diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml index e44aaafc0..9f3ddab4b 100644 --- a/locales/sk-SK.yml +++ b/locales/sk-SK.yml @@ -1127,8 +1127,6 @@ _sfx: note: "Poznámky" noteMy: "Vlastná poznámka" notification: "Oznámenia" - chat: "Chat" - chatBg: "Chat (pozadie)" antenna: "Antény" channel: "Upozornenia kanála" _ago: diff --git a/locales/sv-SE.yml b/locales/sv-SE.yml index 62e7d412a..92678afef 100644 --- a/locales/sv-SE.yml +++ b/locales/sv-SE.yml @@ -507,7 +507,6 @@ _theme: _sfx: note: "Noter" notification: "Notifikationer" - chat: "Chatt" antenna: "Antenner" _2fa: renewTOTPCancel: "Nej tack" diff --git a/locales/th-TH.yml b/locales/th-TH.yml index c2adcf8ec..f1c940a57 100644 --- a/locales/th-TH.yml +++ b/locales/th-TH.yml @@ -1686,8 +1686,6 @@ _sfx: note: "หมายเหตุ" noteMy: "โน้ตของตัวเอง" notification: "การเเจ้งเตือน" - chat: "แชท" - chatBg: "แชท (พื้นหลัง)" antenna: "เสาอากาศ" channel: "การแจ้งเตือนช่อง" _ago: diff --git a/locales/tr-TR.yml b/locales/tr-TR.yml index 1111c2309..90bee48a1 100644 --- a/locales/tr-TR.yml +++ b/locales/tr-TR.yml @@ -386,7 +386,6 @@ _theme: _sfx: note: "notlar" notification: "Bildirim" - chat: "Mesajlar" _2fa: renewTOTPCancel: "Hayır, teşekkürler" _permissions: diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml index 09b3eba74..71c159517 100644 --- a/locales/uk-UA.yml +++ b/locales/uk-UA.yml @@ -1315,8 +1315,6 @@ _sfx: note: "Нотатки" noteMy: "Мої нотатки" notification: "Сповіщення" - chat: "Чати" - chatBg: "Чати (фон)" antenna: "Прийом антени" channel: "Повідомлення каналу" _ago: diff --git a/locales/uz-UZ.yml b/locales/uz-UZ.yml index 726333958..3a9e6ec5e 100644 --- a/locales/uz-UZ.yml +++ b/locales/uz-UZ.yml @@ -910,7 +910,6 @@ _theme: _sfx: note: "Qaydlar" notification: "Xabarnomalar" - chat: "Suhbat" _ago: minutesAgo: "{n} daqiqa oldin" hoursAgo: "{n} soat oldin" diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml index 3b34e4711..c75254e6b 100644 --- a/locales/vi-VN.yml +++ b/locales/vi-VN.yml @@ -1492,8 +1492,6 @@ _sfx: note: "Tút" noteMy: "Tút của tôi" notification: "Thông báo" - chat: "Trò chuyện" - chatBg: "Chat (Nền)" antenna: "Trạm phát sóng" channel: "Kênh" _ago: diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index a04697e48..0dd21540f 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -1697,8 +1697,6 @@ _sfx: note: "帖子" noteMy: "我的帖子" notification: "通知" - chat: "聊天" - chatBg: "聊天背景" antenna: "天线接收" channel: "频道通知" _ago: diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index c0bf1f7d1..c8ae63df4 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -1695,8 +1695,6 @@ _sfx: note: "貼文" noteMy: "我的貼文" notification: "通知" - chat: "聊天" - chatBg: "聊天背景" antenna: "天線接收" channel: "頻道通知" _ago: diff --git a/packages/backend/migration/1696405744672-clean-up.js b/packages/backend/migration/1696405744672-clean-up.js new file mode 100644 index 000000000..5ec89b08f --- /dev/null +++ b/packages/backend/migration/1696405744672-clean-up.js @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class CleanUp1696405744672 { + name = 'CleanUp1696405744672' + + async up(queryRunner) { + await queryRunner.query(`DROP INDEX "public"."IDX_e7c0567f5261063592f022e9b5"`); + await queryRunner.query(`DROP INDEX "public"."IDX_25dfc71b0369b003a4cd434d0b"`); + } + + async down(queryRunner) { + await queryRunner.query(`CREATE INDEX "IDX_25dfc71b0369b003a4cd434d0b" ON "note" ("attachedFileTypes") `); + await queryRunner.query(`CREATE INDEX "IDX_e7c0567f5261063592f022e9b5" ON "note" ("createdAt") `); + } +} diff --git a/packages/backend/src/core/AnnouncementService.ts b/packages/backend/src/core/AnnouncementService.ts index ddacc0936..a5330db53 100644 --- a/packages/backend/src/core/AnnouncementService.ts +++ b/packages/backend/src/core/AnnouncementService.ts @@ -158,9 +158,13 @@ export class AnnouncementService { if (moderator) { if (announcement.userId) { + const user = await this.usersRepository.findOneByOrFail({ id: announcement.userId }); this.moderationLogService.log(moderator, 'deleteUserAnnouncement', { announcementId: announcement.id, announcement: announcement, + userId: announcement.userId, + userUsername: user.username, + userHost: user.host, }); } else { this.moderationLogService.log(moderator, 'deleteGlobalAnnouncement', { diff --git a/packages/backend/src/misc/is-user-related.ts b/packages/backend/src/misc/is-user-related.ts index edd65a3c1..6efb1194d 100644 --- a/packages/backend/src/misc/is-user-related.ts +++ b/packages/backend/src/misc/is-user-related.ts @@ -3,16 +3,16 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -export function isUserRelated(note: any, userIds: Set): boolean { - if (userIds.has(note.userId)) { +export function isUserRelated(note: any, userIds: Set, ignoreAuthor = false): boolean { + if (userIds.has(note.userId) && !ignoreAuthor) { return true; } - if (note.reply != null && userIds.has(note.reply.userId)) { + if (note.reply != null && note.reply.userId !== note.userId && userIds.has(note.reply.userId)) { return true; } - if (note.renote != null && userIds.has(note.renote.userId)) { + if (note.renote != null && note.renote.userId !== note.userId && userIds.has(note.renote.userId)) { return true; } diff --git a/packages/backend/src/models/Note.ts b/packages/backend/src/models/Note.ts index ed86d4549..0d2422c4f 100644 --- a/packages/backend/src/models/Note.ts +++ b/packages/backend/src/models/Note.ts @@ -18,7 +18,6 @@ export class MiNote { @PrimaryColumn(id()) public id: string; - @Index() @Column('timestamp with time zone', { comment: 'The created date of the Note.', }) @@ -151,7 +150,6 @@ export class MiNote { }) public fileIds: MiDriveFile['id'][]; - @Index() @Column('varchar', { length: 256, array: true, default: '{}', }) diff --git a/packages/backend/src/server/api/endpoints/users/notes.ts b/packages/backend/src/server/api/endpoints/users/notes.ts index 6be391be4..09adcf20a 100644 --- a/packages/backend/src/server/api/endpoints/users/notes.ts +++ b/packages/backend/src/server/api/endpoints/users/notes.ts @@ -13,6 +13,7 @@ import { DI } from '@/di-symbols.js'; import { GetterService } from '@/server/api/GetterService.js'; import { CacheService } from '@/core/CacheService.js'; import { IdService } from '@/core/IdService.js'; +import { isUserRelated } from '@/misc/is-user-related.js'; import { ApiError } from '../../error.js'; export const meta = { @@ -70,6 +71,12 @@ export default class extends Endpoint { // eslint- private idService: IdService, ) { super(meta, paramDef, async (ps, me) => { + const [ + userIdsWhoMeMuting, + ] = me ? await Promise.all([ + this.cacheService.userMutingsCache.fetch(me.id), + ]) : [new Set()]; + let timeline: MiNote[] = []; const limit = ps.limit + (ps.untilId ? 1 : 0); // untilIdに指定したものも含まれるため+1 @@ -118,6 +125,8 @@ export default class extends Endpoint { // eslint- timeline = await query.getMany(); timeline = timeline.filter(note => { + if (me && isUserRelated(note, userIdsWhoMeMuting, true)) return false; + if (note.renoteId) { if (note.text == null && note.fileIds.length === 0 && !note.hasPoll) { if (ps.withRenotes === false) return false; diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts index a9b9a55bc..316073c99 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -171,6 +171,9 @@ export type ModerationLogPayloads = { deleteUserAnnouncement: { announcementId: string; announcement: any; + userId: string; + userUsername: string; + userHost: string | null; }; resetPassword: { userId: string; diff --git a/packages/backend/test/e2e/timelines.ts b/packages/backend/test/e2e/timelines.ts index 6efdbd63b..a82be6365 100644 --- a/packages/backend/test/e2e/timelines.ts +++ b/packages/backend/test/e2e/timelines.ts @@ -15,6 +15,10 @@ function genHost() { return randomString() + '.example.com'; } +function waitForPushToTl() { + return sleep(300); +} + let app: INestApplicationContext; beforeAll(async () => { @@ -32,7 +36,7 @@ describe('Timelines', () => { const aliceNote = await post(alice, { text: 'hi', visibility: 'followers' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/timeline', {}, alice); @@ -44,10 +48,11 @@ describe('Timelines', () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('/following/create', { userId: bob.id }, alice); + await sleep(1000); const bobNote = await post(bob, { text: 'hi' }); const carolNote = await post(carol, { text: 'hi' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/timeline', {}, alice); @@ -59,10 +64,11 @@ describe('Timelines', () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('/following/create', { userId: bob.id }, alice); + await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'followers' }); const carolNote = await post(carol, { text: 'hi' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/timeline', {}, alice); @@ -75,10 +81,11 @@ describe('Timelines', () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('/following/create', { userId: bob.id }, alice); + await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/timeline', {}, alice); @@ -91,10 +98,11 @@ describe('Timelines', () => { await api('/following/create', { userId: bob.id }, alice); await api('/following/update', { userId: bob.id, withReplies: true }, alice); + await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/timeline', {}, alice); @@ -107,10 +115,11 @@ describe('Timelines', () => { await api('/following/create', { userId: bob.id }, alice); await api('/following/update', { userId: bob.id, withReplies: true }, alice); + await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id, visibility: 'specified', visibleUserIds: [carolNote.id] }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/timeline', {}, alice); @@ -123,10 +132,11 @@ describe('Timelines', () => { await api('/following/create', { userId: bob.id }, alice); await api('/following/update', { userId: bob.id, withReplies: true }, alice); + await sleep(1000); const carolNote = await post(carol, { text: 'hi', visibility: 'followers' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/timeline', {}, alice); @@ -140,10 +150,11 @@ describe('Timelines', () => { await api('/following/create', { userId: bob.id }, alice); await api('/following/create', { userId: carol.id }, alice); await api('/following/update', { userId: bob.id, withReplies: true }, alice); + await sleep(1000); const carolNote = await post(carol, { text: 'hi', visibility: 'followers' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/timeline', {}, alice); @@ -158,10 +169,11 @@ describe('Timelines', () => { await api('/following/create', { userId: bob.id }, alice); await api('/following/create', { userId: carol.id }, alice); await api('/following/update', { userId: bob.id, withReplies: true }, alice); + await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id, visibility: 'specified', visibleUserIds: [carolNote.id] }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/timeline', {}, alice); @@ -173,10 +185,11 @@ describe('Timelines', () => { const [alice, bob] = await Promise.all([signup(), signup()]); await api('/following/create', { userId: bob.id }, alice); + await sleep(1000); const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/timeline', {}, alice); @@ -190,7 +203,7 @@ describe('Timelines', () => { const bobNote = await post(bob, { text: 'hi' }); const aliceNote = await post(alice, { text: 'hi', replyId: bobNote.id }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/timeline', {}, alice); @@ -202,10 +215,11 @@ describe('Timelines', () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('/following/create', { userId: bob.id }, alice); + await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { renoteId: carolNote.id }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/timeline', {}, alice); @@ -217,10 +231,11 @@ describe('Timelines', () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('/following/create', { userId: bob.id }, alice); + await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { renoteId: carolNote.id }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/timeline', { withRenotes: false, @@ -234,10 +249,11 @@ describe('Timelines', () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('/following/create', { userId: bob.id }, alice); + await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/timeline', { withRenotes: false, @@ -251,9 +267,10 @@ describe('Timelines', () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('/following/create', { userId: bob.id }, alice); + await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'specified', visibleUserIds: [carol.id] }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/timeline', {}, alice); @@ -265,10 +282,11 @@ describe('Timelines', () => { await api('/following/create', { userId: bob.id }, alice); await api('/mute/create', { userId: carol.id }, alice); + await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/timeline', {}, alice); @@ -282,10 +300,11 @@ describe('Timelines', () => { await api('/following/create', { userId: bob.id }, alice); await api('/following/update', { userId: bob.id, withReplies: true }, alice); await api('/mute/create', { userId: carol.id }, alice); + await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/timeline', {}, alice); @@ -297,9 +316,10 @@ describe('Timelines', () => { const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]); await api('/following/create', { userId: bob.id }, alice); + await sleep(1000); const bobNote = await post(bob, { text: 'hi' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/timeline', {}, alice); @@ -310,9 +330,10 @@ describe('Timelines', () => { const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]); await api('/following/create', { userId: bob.id }, alice); + await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/timeline', {}, alice); @@ -323,6 +344,7 @@ describe('Timelines', () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('/following/create', { userId: bob.id }, alice); + await sleep(1000); const [bobFile, carolFile] = await Promise.all([ uploadUrl(bob, 'https://raw.githubusercontent.com/misskey-dev/assets/main/icon.png'), uploadUrl(carol, 'https://raw.githubusercontent.com/misskey-dev/assets/main/icon.png'), @@ -332,7 +354,7 @@ describe('Timelines', () => { const carolNote1 = await post(carol, { text: 'hi' }); const carolNote2 = await post(carol, { fileIds: [carolFile.id] }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/timeline', { withFiles: true }, alice); @@ -350,7 +372,7 @@ describe('Timelines', () => { const carolNote = await post(carol, { text: 'hi', visibility: 'home' }); const bobNote = await post(bob, { text: 'hi' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/local-timeline', {}, alice); @@ -363,7 +385,7 @@ describe('Timelines', () => { const bobNote = await post(bob, { text: 'hi' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/local-timeline', {}, alice); @@ -374,13 +396,12 @@ describe('Timelines', () => { test.concurrent('フォローしているユーザーの visibility: home なノートが含まれない', async () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); - await api('/following/create', { - userId: carol.id, - }, alice); + await api('/following/create', { userId: carol.id }, alice); + await sleep(1000); const carolNote = await post(carol, { text: 'hi', visibility: 'home' }); const bobNote = await post(bob, { text: 'hi' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/local-timeline', {}, alice); @@ -392,10 +413,11 @@ describe('Timelines', () => { const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); await api('/mute/create', { userId: carol.id }, alice); + await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/local-timeline', {}, alice); @@ -408,10 +430,11 @@ describe('Timelines', () => { await api('/following/create', { userId: bob.id }, alice); await api('/mute/create', { userId: carol.id }, alice); + await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/local-timeline', {}, alice); @@ -425,10 +448,11 @@ describe('Timelines', () => { await api('/following/create', { userId: bob.id }, alice); await api('/following/update', { userId: bob.id, withReplies: true }, alice); await api('/mute/create', { userId: carol.id }, alice); + await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/local-timeline', {}, alice); @@ -443,7 +467,7 @@ describe('Timelines', () => { const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { fileIds: [file.id] }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/local-timeline', { withFiles: true }, alice); @@ -458,7 +482,7 @@ describe('Timelines', () => { const bobNote = await post(bob, { text: 'hi' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/hybrid-timeline', {}, alice); @@ -470,7 +494,7 @@ describe('Timelines', () => { const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/hybrid-timeline', {}, alice); @@ -481,9 +505,10 @@ describe('Timelines', () => { const [alice, bob] = await Promise.all([signup(), signup()]); await api('/following/create', { userId: bob.id }, alice); + await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/hybrid-timeline', {}, alice); @@ -495,7 +520,7 @@ describe('Timelines', () => { const bobNote = await post(bob, { text: 'hi' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/local-timeline', {}, alice); @@ -506,9 +531,10 @@ describe('Timelines', () => { const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]); await api('/following/create', { userId: bob.id }, alice); + await sleep(1000); const bobNote = await post(bob, { text: 'hi' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/hybrid-timeline', {}, alice); @@ -519,9 +545,10 @@ describe('Timelines', () => { const [alice, bob] = await Promise.all([signup(), signup({ host: genHost() })]); await api('/following/create', { userId: bob.id }, alice); + await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/hybrid-timeline', {}, alice); @@ -535,7 +562,7 @@ describe('Timelines', () => { const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { fileIds: [file.id] }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/hybrid-timeline', { withFiles: true }, alice); @@ -550,9 +577,10 @@ describe('Timelines', () => { const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); + await sleep(1000); const bobNote = await post(bob, { text: 'hi' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); @@ -564,9 +592,10 @@ describe('Timelines', () => { const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); + await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); @@ -579,9 +608,10 @@ describe('Timelines', () => { const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); + await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'followers' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); @@ -594,9 +624,10 @@ describe('Timelines', () => { const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); + await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'followers' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); @@ -609,10 +640,11 @@ describe('Timelines', () => { const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); + await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); @@ -624,10 +656,11 @@ describe('Timelines', () => { const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); + await sleep(1000); const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); @@ -641,10 +674,11 @@ describe('Timelines', () => { const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); await api('/users/lists/update-membership', { listId: list.id, userId: bob.id, withReplies: true }, alice); + await sleep(1000); const carolNote = await post(carol, { text: 'hi' }); const bobNote = await post(bob, { text: 'hi', replyId: carolNote.id }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); @@ -657,9 +691,10 @@ describe('Timelines', () => { await api('/following/create', { userId: bob.id }, alice); const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); + await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'home' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); @@ -672,9 +707,10 @@ describe('Timelines', () => { await api('/following/create', { userId: bob.id }, alice); const list = await api('/users/lists/create', { name: 'list' }, alice).then(res => res.body); await api('/users/lists/push', { listId: list.id, userId: bob.id }, alice); + await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'followers' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/user-list-timeline', { listId: list.id }, alice); @@ -691,7 +727,7 @@ describe('Timelines', () => { const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { fileIds: [file.id] }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/notes/user-list-timeline', { listId: list.id, withFiles: true }, alice); @@ -706,7 +742,7 @@ describe('Timelines', () => { const bobNote = await post(bob, { text: 'hi' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/users/notes', { userId: bob.id }, alice); @@ -718,7 +754,7 @@ describe('Timelines', () => { const bobNote = await post(bob, { text: 'hi', visibility: 'followers' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/users/notes', { userId: bob.id }, alice); @@ -732,7 +768,7 @@ describe('Timelines', () => { await sleep(1000); const bobNote = await post(bob, { text: 'hi', visibility: 'followers' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/users/notes', { userId: bob.id }, alice); @@ -747,7 +783,7 @@ describe('Timelines', () => { const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { text: 'hi', replyId: carolNote.id }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/users/notes', { userId: bob.id }, alice); @@ -762,7 +798,7 @@ describe('Timelines', () => { const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { text: 'hi', replyId: carolNote.id }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/users/notes', { userId: bob.id, withReplies: true }, alice); @@ -777,7 +813,7 @@ describe('Timelines', () => { const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { text: 'hi', replyId: carolNote.id, visibility: 'specified' }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/users/notes', { userId: bob.id, withReplies: true }, alice); @@ -792,7 +828,7 @@ describe('Timelines', () => { const bobNote1 = await post(bob, { text: 'hi' }); const bobNote2 = await post(bob, { fileIds: [file.id] }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/users/notes', { userId: bob.id, withFiles: true }, alice); @@ -800,17 +836,37 @@ describe('Timelines', () => { assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); }, 1000 * 10); + test.concurrent('ミュートしているユーザーに関連する投稿が含まれない', async () => { + const [alice, bob, carol] = await Promise.all([signup(), signup(), signup()]); + + await api('/mute/create', { userId: carol.id }, alice); + await sleep(1000); + const carolNote = await post(carol, { text: 'hi' }); + const bobNote = await post(bob, { text: 'hi', renoteId: carolNote.id }); + + await waitForPushToTl(); + + const res = await api('/users/notes', { userId: bob.id }, alice); + + assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), false); + }); + test.concurrent('ミュートしていても userId に指定したユーザーの投稿が含まれる', async () => { const [alice, bob] = await Promise.all([signup(), signup()]); await api('/mute/create', { userId: bob.id }, alice); - const bobNote = await post(bob, { text: 'hi' }); + await sleep(1000); + const bobNote1 = await post(bob, { text: 'hi' }); + const bobNote2 = await post(bob, { text: 'hi', replyId: bobNote1.id }); + const bobNote3 = await post(bob, { text: 'hi', renoteId: bobNote1.id }); - await sleep(100); // redisに追加されるのを待つ + await waitForPushToTl(); const res = await api('/users/notes', { userId: bob.id }, alice); - assert.strictEqual(res.body.some((note: any) => note.id === bobNote.id), true); + assert.strictEqual(res.body.some((note: any) => note.id === bobNote1.id), true); + assert.strictEqual(res.body.some((note: any) => note.id === bobNote2.id), true); + assert.strictEqual(res.body.some((note: any) => note.id === bobNote3.id), true); }); }); diff --git a/packages/frontend/src/pages/admin/modlog.ModLog.vue b/packages/frontend/src/pages/admin/modlog.ModLog.vue index 66561c969..0af226f02 100644 --- a/packages/frontend/src/pages/admin/modlog.ModLog.vue +++ b/packages/frontend/src/pages/admin/modlog.ModLog.vue @@ -29,8 +29,12 @@ SPDX-License-Identifier: AGPL-3.0-only : @{{ log.info.fileUserUsername }}{{ log.info.fileUserHost ? '@' + log.info.fileUserHost : '' }} : {{ log.info.host }} : {{ log.info.host }} + : {{ log.info.announcement.title }} + : {{ log.info.before.title }} + : {{ log.info.announcement.title }} : @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }} : @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }} + : @{{ log.info.userUsername }}{{ log.info.userHost ? '@' + log.info.userHost : '' }} : @{{ log.info.noteUserUsername }}{{ log.info.noteUserHost ? '@' + log.info.noteUserHost : '' }} : @{{ log.info.fileUserUsername }}{{ log.info.fileUserHost ? '@' + log.info.fileUserHost : '' }} @@ -88,6 +92,16 @@ SPDX-License-Identifier: AGPL-3.0-only + +
raw diff --git a/packages/frontend/src/pages/settings/index.vue b/packages/frontend/src/pages/settings/index.vue index f1bd50115..cfabbbbf6 100644 --- a/packages/frontend/src/pages/settings/index.vue +++ b/packages/frontend/src/pages/settings/index.vue @@ -139,21 +139,11 @@ const menuDef = computed(() => [{ text: i18n.ts.roles, to: '/settings/roles', active: currentPage?.route.name === 'roles', - }, { - icon: 'ti ti-planet-off', - text: i18n.ts.instanceMute, - to: '/settings/instance-mute', - active: currentPage?.route.name === 'instance-mute', }, { icon: 'ti ti-ban', text: i18n.ts.muteAndBlock, to: '/settings/mute-block', active: currentPage?.route.name === 'mute-block', - }, { - icon: 'ti ti-message-off', - text: i18n.ts.wordMute, - to: '/settings/word-mute', - active: currentPage?.route.name === 'word-mute', }, { icon: 'ti ti-api', text: 'API', diff --git a/packages/frontend/src/pages/settings/instance-mute.vue b/packages/frontend/src/pages/settings/mute-block.instance-mute.vue similarity index 85% rename from packages/frontend/src/pages/settings/instance-mute.vue rename to packages/frontend/src/pages/settings/mute-block.instance-mute.vue index b76fd2c90..4b5080ea8 100644 --- a/packages/frontend/src/pages/settings/instance-mute.vue +++ b/packages/frontend/src/pages/settings/mute-block.instance-mute.vue @@ -22,7 +22,6 @@ import MkButton from '@/components/MkButton.vue'; import * as os from '@/os.js'; import { $i } from '@/account.js'; import { i18n } from '@/i18n.js'; -import { definePageMetadata } from '@/scripts/page-metadata.js'; const instanceMutes = ref($i!.mutedInstances.join('\n')); const changed = ref(false); @@ -46,13 +45,4 @@ async function save() { watch(instanceMutes, () => { changed.value = true; }); - -const headerActions = $computed(() => []); - -const headerTabs = $computed(() => []); - -definePageMetadata({ - title: i18n.ts.instanceMute, - icon: 'ti ti-planet-off', -}); diff --git a/packages/frontend/src/pages/settings/mute-block.vue b/packages/frontend/src/pages/settings/mute-block.vue index 12a5ffec4..c6cbd424e 100644 --- a/packages/frontend/src/pages/settings/mute-block.vue +++ b/packages/frontend/src/pages/settings/mute-block.vue @@ -5,6 +5,20 @@ SPDX-License-Identifier: AGPL-3.0-only