From 00b68de7619730a854b48535f38cea8028b359d6 Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 9 Aug 2023 18:43:34 +0900 Subject: [PATCH] wip --- locales/ja-JP.yml | 5 +++ .../backend/src/core/AnnouncementService.ts | 5 ++- .../src/models/entities/Announcement.ts | 6 +++ .../endpoints/admin/announcements/create.ts | 2 + .../api/endpoints/admin/announcements/list.ts | 9 ++++ .../endpoints/admin/announcements/update.ts | 8 +++- .../src/pages/admin/announcements.vue | 41 ++++++++----------- 7 files changed, 50 insertions(+), 26 deletions(-) diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index cab5c8f97a..58b61cf445 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1096,6 +1096,11 @@ doYouAgree: "同意しますか?" beSureToReadThisAsItIsImportant: "重要ですので必ずお読みください。" iHaveReadXCarefullyAndAgree: "「{x}」の内容をよく読み、同意します。" +_announcement: + forExistingUsers: "既存ユーザーのみ" + forExistingUsersDescription: "有効にすると、このお知らせ作成時点で存在するユーザーにのみお知らせが表示されます。無効にすると、このお知らせ作成後にアカウントを作成したユーザーにもお知らせが表示されます。" + deactivate: "お知らせを終了" + _initialAccountSetting: accountCreated: "アカウントの作成が完了しました!" letsStartAccountSetup: "アカウントの初期設定を行いましょう。" diff --git a/packages/backend/src/core/AnnouncementService.ts b/packages/backend/src/core/AnnouncementService.ts index 77be1e5c1a..07bfdd3bd5 100644 --- a/packages/backend/src/core/AnnouncementService.ts +++ b/packages/backend/src/core/AnnouncementService.ts @@ -46,7 +46,10 @@ export class AnnouncementService { qb.orWhere('announcement.userId = :userId', { userId: user.id }); qb.orWhere('announcement.userId IS NULL'); })) - .andWhere('announcement.createdAt > :createdAt', { createdAt: user.createdAt }) + .andWhere(new Brackets(qb => { + qb.orWhere('announcement.forExistingUsers = false'); + qb.orWhere('announcement.createdAt > :createdAt', { createdAt: user.createdAt }); + })) .andWhere(`announcement.id NOT IN (${ readsQuery.getQuery() })`); q.setParameters(readsQuery.getParameters()); diff --git a/packages/backend/src/models/entities/Announcement.ts b/packages/backend/src/models/entities/Announcement.ts index 1d15631cb6..86484f7770 100644 --- a/packages/backend/src/models/entities/Announcement.ts +++ b/packages/backend/src/models/entities/Announcement.ts @@ -54,6 +54,12 @@ export class Announcement { }) public isActive: boolean; + @Index() + @Column('boolean', { + default: false, + }) + public forExistingUsers: boolean; + @Index() @Column({ ...id(), 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 4042a0e16e..31da1b9fa6 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts @@ -58,6 +58,7 @@ export const paramDef = { text: { type: 'string', minLength: 1 }, imageUrl: { type: 'string', nullable: true, minLength: 1 }, display: { type: 'string', enum: ['normal', 'banner', 'dialog'], default: 'normal' }, + forExistingUsers: { type: 'boolean', default: false }, userId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, }, required: ['title', 'text', 'imageUrl'], @@ -81,6 +82,7 @@ export default class extends Endpoint { text: ps.text, imageUrl: ps.imageUrl, display: ps.display, + forExistingUsers: ps.forExistingUsers, userId: ps.userId, }).then(x => this.announcementsRepository.findOneByOrFail(x.identifiers[0])); 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..882f1ba7fe 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' }, }, required: [], } as const; @@ -84,6 +85,11 @@ export default class extends Endpoint { ) { 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,9 @@ export default class extends Endpoint { title: announcement.title, text: announcement.text, imageUrl: announcement.imageUrl, + display: announcement.display, + isActive: announcement.isActive, + forExistingUsers: announcement.forExistingUsers, 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..8a88ea91b5 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,11 @@ export const paramDef = { title: { type: 'string', minLength: 1 }, text: { type: 'string', minLength: 1 }, imageUrl: { type: 'string', nullable: true, minLength: 0 }, + display: { type: 'string', enum: ['normal', 'banner', 'dialog'] }, + forExistingUsers: { type: 'boolean' }, + isActive: { type: 'boolean' }, }, - required: ['id', 'title', 'text', 'imageUrl'], + required: ['id', 'title', 'text', 'imageUrl', 'display', 'forExistingUsers', 'isActive'], } as const; // eslint-disable-next-line import/no-default-export @@ -53,6 +56,9 @@ export default class extends Endpoint { text: ps.text, /* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- 空の文字列の場合、nullを渡すようにするため */ imageUrl: ps.imageUrl || null, + display: ps.display, + forExistingUsers: ps.forExistingUsers, + isActive: ps.isActive, }); }); } diff --git a/packages/frontend/src/pages/admin/announcements.vue b/packages/frontend/src/pages/admin/announcements.vue index 2e80d028f7..d62f572279 100644 --- a/packages/frontend/src/pages/admin/announcements.vue +++ b/packages/frontend/src/pages/admin/announcements.vue @@ -19,9 +19,14 @@ SPDX-License-Identifier: AGPL-3.0-only + + {{ i18n.ts._announcement.forExistingUsers }} + +

{{ i18n.t('nUsersRead', { n: announcement.reads }) }}

{{ i18n.ts.save }} + {{ i18n.ts._announcement.deactivate }} {{ i18n.ts.remove }}
@@ -67,32 +72,20 @@ function remove(announcement) { }); } -function save(announcement) { +async function deactivate(announcement) { + await os.apiWithDialog('admin/announcements/update', { + ...announcement, + isActive: false, + }); + refresh(); +} + +async function save(announcement) { if (announcement.id == null) { - os.api('admin/announcements/create', announcement).then(() => { - os.alert({ - type: 'success', - text: i18n.ts.saved, - }); - refresh(); - }).catch(err => { - os.alert({ - type: 'error', - text: err, - }); - }); + await os.apiWithDialog('admin/announcements/create', announcement); + refresh(); } else { - os.api('admin/announcements/update', announcement).then(() => { - os.alert({ - type: 'success', - text: i18n.ts.saved, - }); - }).catch(err => { - os.alert({ - type: 'error', - text: err, - }); - }); + os.apiWithDialog('admin/announcements/update', announcement); } }