diff --git a/packages/backend/src/core/AnnouncementService.ts b/packages/backend/src/core/AnnouncementService.ts index c2eb3d596f..f8e1433d8f 100644 --- a/packages/backend/src/core/AnnouncementService.ts +++ b/packages/backend/src/core/AnnouncementService.ts @@ -57,6 +57,33 @@ export class AnnouncementService { return q.getMany(); } + @bindThis + public async create(values: Partial): Promise<{ raw: Announcement; packed: Packed<'Announcement'> }> { + const announcement = await this.announcementsRepository.insert({ + id: this.idService.genId(), + createdAt: new Date(), + updatedAt: null, + title: values.title, + text: values.text, + imageUrl: values.imageUrl, + display: values.display, + forExistingUsers: values.forExistingUsers, + needConfirmationToRead: values.needConfirmationToRead, + userId: values.userId, + }).then(x => this.announcementsRepository.findOneByOrFail(x.identifiers[0])); + + const packed = (await this.packMany([announcement]))[0]; + + this.globalEventService.publishBroadcastStream('announcementCreated', { + announcement: packed, + }); + + return { + raw: announcement, + packed: packed, + }; + } + @bindThis public async read(user: User, announcementId: Announcement['id']): Promise { try { @@ -87,12 +114,13 @@ export class AnnouncementService { return announcements.map(announcement => ({ id: announcement.id, createdAt: announcement.createdAt.toISOString(), - updatedAt: announcement.updatedAt?.toISOString(), + updatedAt: announcement.updatedAt?.toISOString() ?? null, text: announcement.text, title: announcement.title, imageUrl: announcement.imageUrl, display: announcement.display, needConfirmationToRead: announcement.needConfirmationToRead, + forYou: announcement.userId === me?.id, isRead: reads.some(read => read.announcementId === announcement.id), })); } diff --git a/packages/backend/src/misc/json-schema.ts b/packages/backend/src/misc/json-schema.ts index 90d5faeac0..80c1041c62 100644 --- a/packages/backend/src/misc/json-schema.ts +++ b/packages/backend/src/misc/json-schema.ts @@ -35,6 +35,7 @@ import { packedQueueCountSchema } from '@/models/json-schema/queue.js'; import { packedGalleryPostSchema } from '@/models/json-schema/gallery-post.js'; import { packedEmojiDetailedSchema, packedEmojiSimpleSchema } from '@/models/json-schema/emoji.js'; import { packedFlashSchema } from '@/models/json-schema/flash.js'; +import { packedAnnouncementSchema } from '@/models/json-schema/announcement.js'; export const refs = { UserLite: packedUserLiteSchema, diff --git a/packages/backend/src/models/json-schema/announcement.ts b/packages/backend/src/models/json-schema/announcement.ts index 625bc057a0..12dec96f3c 100644 --- a/packages/backend/src/models/json-schema/announcement.ts +++ b/packages/backend/src/models/json-schema/announcement.ts @@ -38,13 +38,17 @@ export const packedAnnouncementSchema = { type: 'string', optional: false, nullable: false, }, - isRead: { + forYou: { type: 'boolean', - optional: true, nullable: false, + optional: false, nullable: false, }, needConfirmationToRead: { type: 'boolean', optional: false, nullable: false, }, + isRead: { + type: 'boolean', + optional: true, nullable: false, + }, }, } as const; diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts index 63d68c2e96..454379cbe6 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts @@ -3,11 +3,9 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { Inject, Injectable } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; -import type { AnnouncementsRepository } from '@/models/index.js'; -import { IdService } from '@/core/IdService.js'; -import { DI } from '@/di-symbols.js'; +import { AnnouncementService } from '@/core/AnnouncementService.js'; export const meta = { tags: ['admin'], @@ -69,14 +67,10 @@ export const paramDef = { @Injectable() export default class extends Endpoint { constructor( - @Inject(DI.announcementsRepository) - private announcementsRepository: AnnouncementsRepository, - - private idService: IdService, + private announcementService: AnnouncementService, ) { super(meta, paramDef, async (ps, me) => { - const announcement = await this.announcementsRepository.insert({ - id: this.idService.genId(), + const { raw, packed } = await this.announcementService.create({ createdAt: new Date(), updatedAt: null, title: ps.title, @@ -86,9 +80,9 @@ export default class extends Endpoint { forExistingUsers: ps.forExistingUsers, needConfirmationToRead: ps.needConfirmationToRead, userId: ps.userId, - }).then(x => this.announcementsRepository.findOneByOrFail(x.identifiers[0])); + }); - return Object.assign({}, announcement, { createdAt: announcement.createdAt.toISOString(), updatedAt: null }); + return packed; }); } } diff --git a/packages/backend/src/server/api/stream/types.ts b/packages/backend/src/server/api/stream/types.ts index 82ccd91c88..1f0dea03b1 100644 --- a/packages/backend/src/server/api/stream/types.ts +++ b/packages/backend/src/server/api/stream/types.ts @@ -64,6 +64,9 @@ export interface BroadcastTypes { [other: string]: any; }[]; }; + announcementCreated: { + announcement: Packed<'Announcement'>; + }; } export interface MainStreamTypes {