summaryrefslogtreecommitdiff
path: root/packages/backend/src/server/api/endpoints
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2023-08-13 20:12:29 +0900
committerGitHub <noreply@github.com>2023-08-13 20:12:29 +0900
commit948785649540e08c1610b1dcce6b37e99b5e8039 (patch)
treef5e57a0ecca79c8fb244b4c6af53be8e4b7a53fd /packages/backend/src/server/api/endpoints
parentfix(frontend/MkUrlPreview): allow fullscreen from tweets (#11712) (diff)
downloadsharkey-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')
-rw-r--r--packages/backend/src/server/api/endpoints/admin/announcements/create.ts28
-rw-r--r--packages/backend/src/server/api/endpoints/admin/announcements/list.ts12
-rw-r--r--packages/backend/src/server/api/endpoints/admin/announcements/update.ts12
-rw-r--r--packages/backend/src/server/api/endpoints/announcements.ts63
-rw-r--r--packages/backend/src/server/api/endpoints/i/read-announcement.ts55
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);
});
}
}