summaryrefslogtreecommitdiff
path: root/packages/backend/src/core
diff options
context:
space:
mode:
authorかっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>2024-05-27 17:15:11 +0900
committerGitHub <noreply@github.com>2024-05-27 17:15:11 +0900
commit3ffbf6296f44c6f8837f0b8533a3b60b64403bf9 (patch)
tree8c550ce179f61238f2a0beaf0209bdcce2799ba5 /packages/backend/src/core
parentfix(backend): `read:admin:show-user` と `read:admin:show-users` を統合 (#... (diff)
downloadsharkey-3ffbf6296f44c6f8837f0b8533a3b60b64403bf9.tar.gz
sharkey-3ffbf6296f44c6f8837f0b8533a3b60b64403bf9.tar.bz2
sharkey-3ffbf6296f44c6f8837f0b8533a3b60b64403bf9.zip
feat: 個別のお知らせにリンクで飛べるように (#13885)
* feat(announcement): 個別のお知らせにリンクで飛べるように (MisskeyIO#639) (cherry picked from commit f6bf7f992a78e54d86a4701dbd1e4fda7ef4eb27) * fix Co-authored-by: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com> * fix Co-authored-by: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com> * 一覧ページではお知らせpanel全体を押せるように * お知らせバーは個別ページに飛ばすように * Update Changelog * spdx * attempt to fox test * remove unnecessary thong * `announcement` → `announcements/show` * リンクを押せる場所をタイトルと日付部分のみに変更 --------- Co-authored-by: まっちゃとーにゅ <17376330+u1-liquid@users.noreply.github.com>
Diffstat (limited to 'packages/backend/src/core')
-rw-r--r--packages/backend/src/core/AnnouncementService.ts49
-rw-r--r--packages/backend/src/core/CoreModule.ts6
-rw-r--r--packages/backend/src/core/entities/AnnouncementEntityService.ts71
3 files changed, 99 insertions, 27 deletions
diff --git a/packages/backend/src/core/AnnouncementService.ts b/packages/backend/src/core/AnnouncementService.ts
index b298a70929..9b60df2cae 100644
--- a/packages/backend/src/core/AnnouncementService.ts
+++ b/packages/backend/src/core/AnnouncementService.ts
@@ -4,13 +4,14 @@
*/
import { Inject, Injectable } from '@nestjs/common';
-import { Brackets } from 'typeorm';
+import { Brackets, EntityNotFoundError } from 'typeorm';
import { DI } from '@/di-symbols.js';
import type { MiUser } from '@/models/User.js';
import type { AnnouncementReadsRepository, AnnouncementsRepository, MiAnnouncement, MiAnnouncementRead, UsersRepository } from '@/models/_.js';
import { bindThis } from '@/decorators.js';
import { Packed } from '@/misc/json-schema.js';
import { IdService } from '@/core/IdService.js';
+import { AnnouncementEntityService } from '@/core/entities/AnnouncementEntityService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
@@ -29,6 +30,7 @@ export class AnnouncementService {
private idService: IdService,
private globalEventService: GlobalEventService,
private moderationLogService: ModerationLogService,
+ private announcementEntityService: AnnouncementEntityService,
) {
}
@@ -79,7 +81,7 @@ export class AnnouncementService {
userId: values.userId,
}).then(x => this.announcementsRepository.findOneByOrFail(x.identifiers[0]));
- const packed = (await this.packMany([announcement]))[0];
+ const packed = await this.announcementEntityService.pack(announcement);
if (values.userId) {
this.globalEventService.publishMainStream(values.userId, 'announcementCreated', {
@@ -178,6 +180,24 @@ export class AnnouncementService {
}
@bindThis
+ public async getAnnouncement(announcementId: MiAnnouncement['id'], me: MiUser | null): Promise<Packed<'Announcement'>> {
+ const announcement = await this.announcementsRepository.findOneByOrFail({ id: announcementId });
+ if (me) {
+ if (announcement.userId && announcement.userId !== me.id) {
+ throw new EntityNotFoundError(this.announcementsRepository.metadata.target, { id: announcementId });
+ }
+
+ const read = await this.announcementReadsRepository.findOneBy({
+ announcementId: announcement.id,
+ userId: me.id,
+ });
+ return this.announcementEntityService.pack({ ...announcement, isRead: read !== null }, me);
+ } else {
+ return this.announcementEntityService.pack(announcement, null);
+ }
+ }
+
+ @bindThis
public async read(user: MiUser, announcementId: MiAnnouncement['id']): Promise<void> {
try {
await this.announcementReadsRepository.insert({
@@ -193,29 +213,4 @@ export class AnnouncementService {
this.globalEventService.publishMainStream(user.id, 'readAllAnnouncements');
}
}
-
- @bindThis
- public async packMany(
- announcements: MiAnnouncement[],
- me?: { id: MiUser['id'] } | null | undefined,
- options?: {
- reads?: MiAnnouncementRead[];
- },
- ): Promise<Packed<'Announcement'>[]> {
- const reads = me ? (options?.reads ?? await this.getReads(me.id)) : [];
- return announcements.map(announcement => ({
- id: announcement.id,
- createdAt: this.idService.parse(announcement.id).date.toISOString(),
- updatedAt: announcement.updatedAt?.toISOString() ?? null,
- text: announcement.text,
- title: announcement.title,
- imageUrl: announcement.imageUrl,
- icon: announcement.icon,
- display: announcement.display,
- needConfirmationToRead: announcement.needConfirmationToRead,
- silence: announcement.silence,
- forYou: announcement.userId === me?.id,
- isRead: reads.some(read => read.announcementId === announcement.id),
- }));
- }
}
diff --git a/packages/backend/src/core/CoreModule.ts b/packages/backend/src/core/CoreModule.ts
index 5953155872..be80df6f1c 100644
--- a/packages/backend/src/core/CoreModule.ts
+++ b/packages/backend/src/core/CoreModule.ts
@@ -84,6 +84,7 @@ import ApRequestChart from './chart/charts/ap-request.js';
import { ChartManagementService } from './chart/ChartManagementService.js';
import { AbuseUserReportEntityService } from './entities/AbuseUserReportEntityService.js';
+import { AnnouncementEntityService } from './entities/AnnouncementEntityService.js';
import { AntennaEntityService } from './entities/AntennaEntityService.js';
import { AppEntityService } from './entities/AppEntityService.js';
import { AuthSessionEntityService } from './entities/AuthSessionEntityService.js';
@@ -223,6 +224,7 @@ const $ApRequestChart: Provider = { provide: 'ApRequestChart', useExisting: ApRe
const $ChartManagementService: Provider = { provide: 'ChartManagementService', useExisting: ChartManagementService };
const $AbuseUserReportEntityService: Provider = { provide: 'AbuseUserReportEntityService', useExisting: AbuseUserReportEntityService };
+const $AnnouncementEntityService: Provider = { provide: 'AnnouncementEntityService', useExisting: AnnouncementEntityService };
const $AntennaEntityService: Provider = { provide: 'AntennaEntityService', useExisting: AntennaEntityService };
const $AppEntityService: Provider = { provide: 'AppEntityService', useExisting: AppEntityService };
const $AuthSessionEntityService: Provider = { provide: 'AuthSessionEntityService', useExisting: AuthSessionEntityService };
@@ -363,6 +365,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
ChartManagementService,
AbuseUserReportEntityService,
+ AnnouncementEntityService,
AntennaEntityService,
AppEntityService,
AuthSessionEntityService,
@@ -499,6 +502,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$ChartManagementService,
$AbuseUserReportEntityService,
+ $AnnouncementEntityService,
$AntennaEntityService,
$AppEntityService,
$AuthSessionEntityService,
@@ -635,6 +639,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
ChartManagementService,
AbuseUserReportEntityService,
+ AnnouncementEntityService,
AntennaEntityService,
AppEntityService,
AuthSessionEntityService,
@@ -770,6 +775,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$ChartManagementService,
$AbuseUserReportEntityService,
+ $AnnouncementEntityService,
$AntennaEntityService,
$AppEntityService,
$AuthSessionEntityService,
diff --git a/packages/backend/src/core/entities/AnnouncementEntityService.ts b/packages/backend/src/core/entities/AnnouncementEntityService.ts
new file mode 100644
index 0000000000..90b04d0229
--- /dev/null
+++ b/packages/backend/src/core/entities/AnnouncementEntityService.ts
@@ -0,0 +1,71 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Inject, Injectable } from '@nestjs/common';
+import { DI } from '@/di-symbols.js';
+import type { AnnouncementsRepository, AnnouncementReadsRepository, MiAnnouncement, MiUser } from '@/models/_.js';
+import type { Packed } from '@/misc/json-schema.js';
+import { bindThis } from '@/decorators.js';
+import { IdService } from '@/core/IdService.js';
+
+@Injectable()
+export class AnnouncementEntityService {
+ constructor(
+ @Inject(DI.announcementsRepository)
+ private announcementsRepository: AnnouncementsRepository,
+
+ @Inject(DI.announcementReadsRepository)
+ private announcementReadsRepository: AnnouncementReadsRepository,
+
+ private idService: IdService,
+ ) {
+ }
+
+ @bindThis
+ public async pack(
+ src: MiAnnouncement['id'] | MiAnnouncement & { isRead?: boolean | null },
+ me?: { id: MiUser['id'] } | null | undefined,
+ ): Promise<Packed<'Announcement'>> {
+ const announcement = typeof src === 'object'
+ ? src
+ : await this.announcementsRepository.findOneByOrFail({
+ id: src,
+ }) as MiAnnouncement & { isRead?: boolean | null };
+
+ if (me && announcement.isRead === undefined) {
+ announcement.isRead = await this.announcementReadsRepository
+ .countBy({
+ announcementId: announcement.id,
+ userId: me.id,
+ })
+ .then((count: number) => count > 0);
+ }
+
+ return {
+ id: announcement.id,
+ createdAt: this.idService.parse(announcement.id).date.toISOString(),
+ updatedAt: announcement.updatedAt?.toISOString() ?? null,
+ title: announcement.title,
+ text: announcement.text,
+ imageUrl: announcement.imageUrl,
+ icon: announcement.icon,
+ display: announcement.display,
+ forYou: announcement.userId === me?.id,
+ needConfirmationToRead: announcement.needConfirmationToRead,
+ silence: announcement.silence,
+ isRead: announcement.isRead !== null ? announcement.isRead : undefined,
+ };
+ }
+
+ @bindThis
+ public async packMany(
+ announcements: (MiAnnouncement['id'] | MiAnnouncement & { isRead?: boolean | null } | MiAnnouncement)[],
+ me?: { id: MiUser['id'] } | null | undefined,
+ ) : Promise<Packed<'Announcement'>[]> {
+ return (await Promise.allSettled(announcements.map(x => this.pack(x, me))))
+ .filter(result => result.status === 'fulfilled')
+ .map(result => (result as PromiseFulfilledResult<Packed<'Announcement'>>).value);
+ }
+}