diff --git a/packages/backend/src/core/QueueModule.ts b/packages/backend/src/core/QueueModule.ts index 99513998ee7b..8f2df7fc462d 100644 --- a/packages/backend/src/core/QueueModule.ts +++ b/packages/backend/src/core/QueueModule.ts @@ -17,12 +17,12 @@ import { UserWebhookDeliverJobData, SystemWebhookDeliverJobData, ScheduleNotePostJobData, + ScheduledNoteDeleteJobData, } from '../queue/types.js'; import type { Provider } from '@nestjs/common'; export type SystemQueue = Bull.Queue>; export type EndedPollNotificationQueue = Bull.Queue; -export type ScheduledNoteDeleteQueue = Bull.Queue export type DeliverQueue = Bull.Queue; export type InboxQueue = Bull.Queue; export type DbQueue = Bull.Queue; @@ -31,6 +31,7 @@ export type ObjectStorageQueue = Bull.Queue; export type UserWebhookDeliverQueue = Bull.Queue; export type SystemWebhookDeliverQueue = Bull.Queue; export type ScheduleNotePostQueue = Bull.Queue; +export type ScheduledNoteDeleteQueue = Bull.Queue const $system: Provider = { provide: 'queue:system', @@ -44,12 +45,6 @@ const $endedPollNotification: Provider = { inject: [DI.config], }; -const $scheduledNoteDeleted: Provider = { - provide: 'queue:scheduledNoteDelete', - useFactory: (config: Config) => new Bull.Queue(QUEUE.SCHEDULED_NOTE_DELETE, baseQueueOptions(config, QUEUE.SCHEDULED_NOTE_DELETE)), - inject: [DI.config], -}; - const $deliver: Provider = { provide: 'queue:deliver', useFactory: (config: Config) => new Bull.Queue(QUEUE.DELIVER, baseQueueOptions(config, QUEUE.DELIVER)), @@ -98,13 +93,18 @@ const $scheduleNotePost: Provider = { inject: [DI.config], }; +const $scheduledNoteDeleted: Provider = { + provide: 'queue:scheduledNoteDelete', + useFactory: (config: Config) => new Bull.Queue(QUEUE.SCHEDULED_NOTE_DELETE, baseQueueOptions(config, QUEUE.SCHEDULED_NOTE_DELETE)), + inject: [DI.config], +}; + @Module({ imports: [ ], providers: [ $system, $endedPollNotification, - $scheduledNoteDeleted, $deliver, $inbox, $db, @@ -113,11 +113,11 @@ const $scheduleNotePost: Provider = { $userWebhookDeliver, $systemWebhookDeliver, $scheduleNotePost, + $scheduledNoteDeleted, ], exports: [ $system, $endedPollNotification, - $scheduledNoteDeleted, $deliver, $inbox, $db, @@ -126,13 +126,13 @@ const $scheduleNotePost: Provider = { $userWebhookDeliver, $systemWebhookDeliver, $scheduleNotePost, + $scheduledNoteDeleted, ], }) export class QueueModule implements OnApplicationShutdown { constructor( @Inject('queue:system') public systemQueue: SystemQueue, @Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue, - @Inject('queue:scheduledNoteDelete') public scheduledNoteDeleteQueue: ScheduledNoteDeleteQueue, @Inject('queue:deliver') public deliverQueue: DeliverQueue, @Inject('queue:inbox') public inboxQueue: InboxQueue, @Inject('queue:db') public dbQueue: DbQueue, @@ -141,6 +141,7 @@ export class QueueModule implements OnApplicationShutdown { @Inject('queue:userWebhookDeliver') public userWebhookDeliverQueue: UserWebhookDeliverQueue, @Inject('queue:systemWebhookDeliver') public systemWebhookDeliverQueue: SystemWebhookDeliverQueue, @Inject('queue:scheduleNotePost') public scheduleNotePostQueue: ScheduleNotePostQueue, + @Inject('queue:scheduledNoteDelete') public scheduledNoteDeleteQueue: ScheduledNoteDeleteQueue, ) {} public async dispose(): Promise { @@ -150,7 +151,6 @@ export class QueueModule implements OnApplicationShutdown { await Promise.all([ this.systemQueue.close(), this.endedPollNotificationQueue.close(), - this.scheduledNoteDeleteQueue.close(), this.deliverQueue.close(), this.inboxQueue.close(), this.dbQueue.close(), @@ -159,6 +159,7 @@ export class QueueModule implements OnApplicationShutdown { this.userWebhookDeliverQueue.close(), this.systemWebhookDeliverQueue.close(), this.scheduleNotePostQueue.close(), + this.scheduledNoteDeleteQueue.close(), ]); } diff --git a/packages/backend/src/core/QueueService.ts b/packages/backend/src/core/QueueService.ts index 0759ab6b7680..288ff2068751 100644 --- a/packages/backend/src/core/QueueService.ts +++ b/packages/backend/src/core/QueueService.ts @@ -35,6 +35,7 @@ import type { SystemWebhookDeliverQueue, UserWebhookDeliverQueue, ScheduleNotePostQueue, + ScheduledNoteDeleteQueue, } from './QueueModule.js'; import type httpSignature from '@peertube/http-signature'; import type * as Bull from 'bullmq'; @@ -47,7 +48,6 @@ export class QueueService { @Inject('queue:system') public systemQueue: SystemQueue, @Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue, - @Inject('queue:scheduledNoteDelete') public scheduledNoteDeleteQueue: ScheduledNoteDeleteQueue, @Inject('queue:deliver') public deliverQueue: DeliverQueue, @Inject('queue:inbox') public inboxQueue: InboxQueue, @Inject('queue:db') public dbQueue: DbQueue, @@ -56,6 +56,7 @@ export class QueueService { @Inject('queue:userWebhookDeliver') public userWebhookDeliverQueue: UserWebhookDeliverQueue, @Inject('queue:systemWebhookDeliver') public systemWebhookDeliverQueue: SystemWebhookDeliverQueue, @Inject('queue:scheduleNotePost') public ScheduleNotePostQueue: ScheduleNotePostQueue, + @Inject('queue:scheduledNoteDelete') public scheduledNoteDeleteQueue: ScheduledNoteDeleteQueue, ) { this.systemQueue.add('tickCharts', { }, { diff --git a/packages/backend/src/core/WebhookTestService.ts b/packages/backend/src/core/WebhookTestService.ts index 555a39f71c16..681a87f96a6c 100644 --- a/packages/backend/src/core/WebhookTestService.ts +++ b/packages/backend/src/core/WebhookTestService.ts @@ -131,6 +131,7 @@ function generateDummyNote(override?: Partial): MiNote { replyUserHost: null, renoteUserId: null, renoteUserHost: null, + deleteAt: null, ...override, }; } diff --git a/packages/backend/src/core/entities/ChannelEntityService.ts b/packages/backend/src/core/entities/ChannelEntityService.ts index a0347b6fdeec..5f595e106520 100644 --- a/packages/backend/src/core/entities/ChannelEntityService.ts +++ b/packages/backend/src/core/entities/ChannelEntityService.ts @@ -86,6 +86,7 @@ export class ChannelEntityService { notesCount: channel.notesCount, isSensitive: channel.isSensitive, allowRenoteToExternal: channel.allowRenoteToExternal, + announcement: channel.announcement as string | null, ...(me ? { isFollowing, @@ -95,7 +96,6 @@ export class ChannelEntityService { ...(detailed ? { pinnedNotes: (await this.noteEntityService.packMany(pinnedNotes, me)).sort((a, b) => channel.pinnedNoteIds.indexOf(a.id) - channel.pinnedNoteIds.indexOf(b.id)), - announcement: channel.announcement, } : {}), }; } diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts index 5ec3cfe631cc..30fc65f217a3 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts @@ -161,7 +161,10 @@ export default class extends Endpoint { // eslint- needConfirmationToRead: announcement.needConfirmationToRead, userId: announcement.userId, isRoleSpecified: announcement.isRoleSpecified, - roles: announcementRoles.filter(announcementRole => announcementRole.announcementId === announcement.id).map(announcementRole => announcementRole.role).filter((role): role is MiRole => role !== null), + roles: announcementRoles + .filter(announcementRole => announcementRole.announcementId === announcement.id) + .map(announcementRole => announcementRole.role) + .filter((role): role is NonNullable => role !== null), reads: reads.get(announcement)!, })); }); diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index 81b26fb0b9b1..680b466b3898 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -193,8 +193,8 @@ export const meta = { }, }, emailWhitelist: { - type: 'string', - optional: false, nullable: true, + type: 'boolean', + optional: false, nullable: false, }, preservedUsernames: { type: 'array', @@ -518,8 +518,8 @@ export const meta = { type: 'string', optional: false, nullable: false, }, - emailToReceiveAbuseReport: { - type: 'string', + federationHosts: { + type: 'array', optional: false, nullable: false, items: { type: 'string', diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index ecef42bd65f7..f988865b6162 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -188,7 +188,7 @@ export const paramDef = { }, customSplashText: { type: 'array', nullable: true, items: { type: 'string', - }}, + } }, }, required: [], } as const; diff --git a/packages/backend/src/server/api/endpoints/notes/schedule/create.ts b/packages/backend/src/server/api/endpoints/notes/schedule/create.ts index 9018e6c75705..9a4e5486145f 100644 --- a/packages/backend/src/server/api/endpoints/notes/schedule/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/schedule/create.ts @@ -26,6 +26,7 @@ import { QueueService } from '@/core/QueueService.js'; import { IdService } from '@/core/IdService.js'; import { MiScheduleNoteType } from '@/models/NoteSchedule.js'; import { RoleService } from '@/core/RoleService.js'; +import { isQuote, isRenote } from '@/misc/is-renote.js'; import { ApiError } from '../../../error.js'; export const meta = { @@ -132,6 +133,15 @@ export const meta = { }, } as const; +function checkPureRenote(note: MiNote): boolean { + return note.renoteId != null && + note.replyId == null && + note.text == null && + note.cw == null && + (!note.fileIds || note.fileIds.length === 0) && + !note.hasPoll; +} + export const paramDef = { type: 'object', properties: { @@ -275,7 +285,7 @@ export default class extends Endpoint { // eslint- if (renote == null) { throw new ApiError(meta.errors.noSuchRenoteTarget); - } else if (isPureRenote(renote)) { + } else if (isRenote(renote) && !isQuote(renote)) { throw new ApiError(meta.errors.cannotReRenote); } @@ -308,7 +318,7 @@ export default class extends Endpoint { // eslint- if (reply == null) { throw new ApiError(meta.errors.noSuchReplyTarget); - } else if (isPureRenote(reply)) { + } else if (checkPureRenote(reply)) { throw new ApiError(meta.errors.cannotReplyToPureRenote); } diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts index 2cac0e18d201..22f38448b3ee 100644 --- a/packages/backend/src/server/web/ClientServerService.ts +++ b/packages/backend/src/server/web/ClientServerService.ts @@ -35,6 +35,7 @@ import type { UserWebhookDeliverQueue, SystemWebhookDeliverQueue, ScheduleNotePostQueue, + ScheduledNoteDeleteQueue, } from '@/core/QueueModule.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; @@ -137,7 +138,6 @@ export class ClientServerService { @Inject('queue:system') public systemQueue: SystemQueue, @Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue, - @Inject('queue:scheduledNoteDelete') public scheduledNoteDeleteQueue: ScheduledNoteDeleteQueue, @Inject('queue:deliver') public deliverQueue: DeliverQueue, @Inject('queue:inbox') public inboxQueue: InboxQueue, @Inject('queue:db') public dbQueue: DbQueue, @@ -146,6 +146,7 @@ export class ClientServerService { @Inject('queue:userWebhookDeliver') public userWebhookDeliverQueue: UserWebhookDeliverQueue, @Inject('queue:systemWebhookDeliver') public systemWebhookDeliverQueue: SystemWebhookDeliverQueue, @Inject('queue:scheduleNotePost') public scheduleNotePostQueue: ScheduleNotePostQueue, + @Inject('queue:scheduledNoteDelete') public scheduledNoteDeleteQueue: ScheduledNoteDeleteQueue, ) { //this.createServer = this.createServer.bind(this); } @@ -268,7 +269,6 @@ export class ClientServerService { queues: [ this.systemQueue, this.endedPollNotificationQueue, - this.scheduledNoteDeleteQueue, this.deliverQueue, this.inboxQueue, this.dbQueue, @@ -277,6 +277,7 @@ export class ClientServerService { this.userWebhookDeliverQueue, this.systemWebhookDeliverQueue, this.scheduleNotePostQueue, + this.scheduledNoteDeleteQueue, ].map(q => new BullMQAdapter(q)), serverAdapter: bullBoardServerAdapter, }); diff --git a/packages/backend/test/unit/NoteCreateService.ts b/packages/backend/test/unit/NoteCreateService.ts index f2d4c8ffbb77..99a44c2c6c04 100644 --- a/packages/backend/test/unit/NoteCreateService.ts +++ b/packages/backend/test/unit/NoteCreateService.ts @@ -60,6 +60,7 @@ describe('NoteCreateService', () => { replyUserHost: null, renoteUserId: null, renoteUserHost: null, + deleteAt: null, }; const poll: IPoll = { diff --git a/packages/backend/test/unit/misc/is-renote.ts b/packages/backend/test/unit/misc/is-renote.ts index 0b713e8bf6b4..933879be4411 100644 --- a/packages/backend/test/unit/misc/is-renote.ts +++ b/packages/backend/test/unit/misc/is-renote.ts @@ -43,6 +43,7 @@ const base: MiNote = { replyUserHost: null, renoteUserId: null, renoteUserHost: null, + deleteAt: null, }; describe('misc:is-renote', () => { diff --git a/packages/frontend/src/pages/admin/announcements.vue b/packages/frontend/src/pages/admin/announcements.vue index 6f7290b5f1ef..04d08107b3dd 100644 --- a/packages/frontend/src/pages/admin/announcements.vue +++ b/packages/frontend/src/pages/admin/announcements.vue @@ -4,13 +4,22 @@ SPDX-License-Identifier: AGPL-3.0-only -->