diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2023-08-13 20:12:29 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-08-13 20:12:29 +0900 |
| commit | 948785649540e08c1610b1dcce6b37e99b5e8039 (patch) | |
| tree | f5e57a0ecca79c8fb244b4c6af53be8e4b7a53fd /packages/backend/src/server/api/endpoints | |
| parent | fix(frontend/MkUrlPreview): allow fullscreen from tweets (#11712) (diff) | |
| download | sharkey-948785649540e08c1610b1dcce6b37e99b5e8039.tar.gz sharkey-948785649540e08c1610b1dcce6b37e99b5e8039.tar.bz2 sharkey-948785649540e08c1610b1dcce6b37e99b5e8039.zip | |
feat: refine announcement (#11497)
* wip
* Update read-announcement.ts
* wip
* wip
* wip
* Update index.d.ts
* wip
* Create 1691649257651-refine-announcement.js
* wip
* wip
* wip
* wip
* wip
* wip
* Update announcements.vue
* wip
* wip
* Update announcements.vue
* wip
* Update announcements.vue
* wip
* Update misskey-js.api.md
* Update users.ts
* Create MkAnnouncementDialog.stories.impl.ts
* wip
* wip
* Create AnnouncementService.ts
Diffstat (limited to 'packages/backend/src/server/api/endpoints')
5 files changed, 55 insertions, 115 deletions
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 8addffc6a8..6c5520c2ef 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'], @@ -57,6 +55,11 @@ export const paramDef = { title: { type: 'string', minLength: 1 }, text: { type: 'string', minLength: 1 }, imageUrl: { type: 'string', nullable: true, minLength: 1 }, + icon: { type: 'string', enum: ['info', 'warning', 'error', 'success'], default: 'info' }, + display: { type: 'string', enum: ['normal', 'banner', 'dialog'], default: 'normal' }, + forExistingUsers: { type: 'boolean', default: false }, + needConfirmationToRead: { type: 'boolean', default: false }, + userId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, }, required: ['title', 'text', 'imageUrl'], } as const; @@ -65,22 +68,23 @@ export const paramDef = { @Injectable() export default class extends Endpoint<typeof meta, typeof paramDef> { 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, text: ps.text, imageUrl: ps.imageUrl, - }).then(x => this.announcementsRepository.findOneByOrFail(x.identifiers[0])); + icon: ps.icon, + display: ps.display, + forExistingUsers: ps.forExistingUsers, + needConfirmationToRead: ps.needConfirmationToRead, + userId: ps.userId, + }); - return Object.assign({}, announcement, { createdAt: announcement.createdAt.toISOString(), updatedAt: null }); + return packed; }); } } 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 ec0d4061a6..4da3f457f9 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts @@ -66,6 +66,7 @@ export const paramDef = { limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, sinceId: { type: 'string', format: 'misskey:id' }, untilId: { type: 'string', format: 'misskey:id' }, + userId: { type: 'string', format: 'misskey:id', nullable: true }, }, required: [], } as const; @@ -84,6 +85,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { ) { super(meta, paramDef, async (ps, me) => { const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId); + if (ps.userId) { + query.andWhere('announcement.userId = :userId', { userId: ps.userId }); + } else { + query.andWhere('announcement.userId IS NULL'); + } const announcements = await query.limit(ps.limit).getMany(); @@ -102,6 +108,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { title: announcement.title, text: announcement.text, imageUrl: announcement.imageUrl, + icon: announcement.icon, + display: announcement.display, + isActive: announcement.isActive, + forExistingUsers: announcement.forExistingUsers, + needConfirmationToRead: announcement.needConfirmationToRead, + userId: announcement.userId, reads: reads.get(announcement)!, })); }); diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts index b3df14320f..7efc7c0402 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts @@ -31,8 +31,13 @@ export const paramDef = { title: { type: 'string', minLength: 1 }, text: { type: 'string', minLength: 1 }, imageUrl: { type: 'string', nullable: true, minLength: 0 }, + icon: { type: 'string', enum: ['info', 'warning', 'error', 'success'] }, + display: { type: 'string', enum: ['normal', 'banner', 'dialog'] }, + forExistingUsers: { type: 'boolean' }, + needConfirmationToRead: { type: 'boolean' }, + isActive: { type: 'boolean' }, }, - required: ['id', 'title', 'text', 'imageUrl'], + required: ['id'], } as const; // eslint-disable-next-line import/no-default-export @@ -53,6 +58,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { text: ps.text, /* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- 空の文字列の場合、nullを渡すようにするため */ imageUrl: ps.imageUrl || null, + display: ps.display, + icon: ps.icon, + forExistingUsers: ps.forExistingUsers, + needConfirmationToRead: ps.needConfirmationToRead, + isActive: ps.isActive, }); }); } diff --git a/packages/backend/src/server/api/endpoints/announcements.ts b/packages/backend/src/server/api/endpoints/announcements.ts index df0a0afb09..070e6f0d77 100644 --- a/packages/backend/src/server/api/endpoints/announcements.ts +++ b/packages/backend/src/server/api/endpoints/announcements.ts @@ -4,8 +4,10 @@ */ 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 { AnnouncementService } from '@/core/AnnouncementService.js'; import { DI } from '@/di-symbols.js'; import type { AnnouncementReadsRepository, AnnouncementsRepository } from '@/models/index.js'; @@ -20,40 +22,7 @@ export const meta = { items: { type: 'object', optional: false, nullable: false, - properties: { - id: { - type: 'string', - optional: false, nullable: false, - format: 'id', - example: 'xxxxxxxxxx', - }, - createdAt: { - type: 'string', - optional: false, nullable: false, - format: 'date-time', - }, - updatedAt: { - type: 'string', - optional: false, nullable: true, - format: 'date-time', - }, - text: { - type: 'string', - optional: false, nullable: false, - }, - title: { - type: 'string', - optional: false, nullable: false, - }, - imageUrl: { - type: 'string', - optional: false, nullable: true, - }, - isRead: { - type: 'boolean', - optional: true, nullable: false, - }, - }, + ref: 'Announcement', }, }, } as const; @@ -62,9 +31,9 @@ export const paramDef = { type: 'object', properties: { limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, - withUnreads: { type: 'boolean', default: false }, sinceId: { type: 'string', format: 'misskey:id' }, untilId: { type: 'string', format: 'misskey:id' }, + isActive: { type: 'boolean', default: true }, }, required: [], } as const; @@ -80,27 +49,19 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { private announcementReadsRepository: AnnouncementReadsRepository, private queryService: QueryService, + private announcementService: AnnouncementService, ) { super(meta, paramDef, async (ps, me) => { - const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId); + const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId) + .where('announcement.isActive = :isActive', { isActive: ps.isActive }) + .andWhere(new Brackets(qb => { + if (me) qb.orWhere('announcement.userId = :meId', { meId: me.id }); + qb.orWhere('announcement.userId IS NULL'); + })); const announcements = await query.limit(ps.limit).getMany(); - if (me) { - const reads = (await this.announcementReadsRepository.findBy({ - userId: me.id, - })).map(x => x.announcementId); - - for (const announcement of announcements) { - (announcement as any).isRead = reads.includes(announcement.id); - } - } - - return (ps.withUnreads ? announcements.filter((a: any) => !a.isRead) : announcements).map((a) => ({ - ...a, - createdAt: a.createdAt.toISOString(), - updatedAt: a.updatedAt?.toISOString() ?? null, - })); + return this.announcementService.packMany(announcements, me); }); } } diff --git a/packages/backend/src/server/api/endpoints/i/read-announcement.ts b/packages/backend/src/server/api/endpoints/i/read-announcement.ts index 7bda6e2627..412532939c 100644 --- a/packages/backend/src/server/api/endpoints/i/read-announcement.ts +++ b/packages/backend/src/server/api/endpoints/i/read-announcement.ts @@ -3,14 +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 { IdService } from '@/core/IdService.js'; -import type { AnnouncementReadsRepository, AnnouncementsRepository } from '@/models/index.js'; -import { GlobalEventService } from '@/core/GlobalEventService.js'; -import { UserEntityService } from '@/core/entities/UserEntityService.js'; -import { DI } from '@/di-symbols.js'; -import { ApiError } from '../../error.js'; +import { AnnouncementService } from '@/core/AnnouncementService.js'; export const meta = { tags: ['account'], @@ -20,11 +15,6 @@ export const meta = { kind: 'write:account', errors: { - noSuchAnnouncement: { - message: 'No such announcement.', - code: 'NO_SUCH_ANNOUNCEMENT', - id: '184663db-df88-4bc2-8b52-fb85f0681939', - }, }, } as const; @@ -40,47 +30,10 @@ export const paramDef = { @Injectable() export default class extends Endpoint<typeof meta, typeof paramDef> { constructor( - @Inject(DI.announcementsRepository) - private announcementsRepository: AnnouncementsRepository, - - @Inject(DI.announcementReadsRepository) - private announcementReadsRepository: AnnouncementReadsRepository, - - private userEntityService: UserEntityService, - private idService: IdService, - private globalEventService: GlobalEventService, + private announcementService: AnnouncementService, ) { super(meta, paramDef, async (ps, me) => { - // Check if announcement exists - const announcementExist = await this.announcementsRepository.exist({ where: { id: ps.announcementId } }); - - if (!announcementExist) { - throw new ApiError(meta.errors.noSuchAnnouncement); - } - - // Check if already read - const alreadyRead = await this.announcementReadsRepository.exist({ - where: { - announcementId: ps.announcementId, - userId: me.id, - }, - }); - - if (alreadyRead) { - return; - } - - // Create read - await this.announcementReadsRepository.insert({ - id: this.idService.genId(), - createdAt: new Date(), - announcementId: ps.announcementId, - userId: me.id, - }); - - if (!await this.userEntityService.getHasUnreadAnnouncement(me.id)) { - this.globalEventService.publishMainStream(me.id, 'readAllAnnouncements'); - } + await this.announcementService.read(me, ps.announcementId); }); } } |