summaryrefslogtreecommitdiff
path: root/packages/backend/src/server/api/endpoints/i/notifications.ts
diff options
context:
space:
mode:
authoranatawa12 <anatawa12@icloud.com>2024-05-20 18:05:46 +0900
committerGitHub <noreply@github.com>2024-05-20 18:05:46 +0900
commit4d0db37d2e5baddea3995e222bddca7032052ef1 (patch)
treec62e57c0377e66c051cf441205fb28367011ec44 /packages/backend/src/server/api/endpoints/i/notifications.ts
parentFTTが有効かつsinceIdのみを指定した場合に帰って来るレス... (diff)
downloadsharkey-4d0db37d2e5baddea3995e222bddca7032052ef1.tar.gz
sharkey-4d0db37d2e5baddea3995e222bddca7032052ef1.tar.bz2
sharkey-4d0db37d2e5baddea3995e222bddca7032052ef1.zip
fix notification limit with exclude/include types (#13836)
* fix: /i/notificationsがsinceIdのみのときに正しく動かない問題 Fix #10902 again * chore: use exclusive range to fetch data * fix: フィルタによって通知が0件だった場合でもリトライするように * docs(changelog): `/i/notifications`に includeTypes`か`excludeTypes`を指定しているとき、通知が存在するのに空配列を返すことがある問題を修正
Diffstat (limited to 'packages/backend/src/server/api/endpoints/i/notifications.ts')
-rw-r--r--packages/backend/src/server/api/endpoints/i/notifications.ts60
1 files changed, 42 insertions, 18 deletions
diff --git a/packages/backend/src/server/api/endpoints/i/notifications.ts b/packages/backend/src/server/api/endpoints/i/notifications.ts
index 320d9fdb00..2f619380e9 100644
--- a/packages/backend/src/server/api/endpoints/i/notifications.ts
+++ b/packages/backend/src/server/api/endpoints/i/notifications.ts
@@ -7,7 +7,7 @@ import { In } from 'typeorm';
import * as Redis from 'ioredis';
import { Inject, Injectable } from '@nestjs/common';
import type { NotesRepository } from '@/models/_.js';
-import { obsoleteNotificationTypes, notificationTypes, FilterUnionByProperty } from '@/types.js';
+import { FilterUnionByProperty, notificationTypes, obsoleteNotificationTypes } from '@/types.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { NoteReadService } from '@/core/NoteReadService.js';
import { NotificationEntityService } from '@/core/entities/NotificationEntityService.js';
@@ -84,27 +84,51 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const includeTypes = ps.includeTypes && ps.includeTypes.filter(type => !(obsoleteNotificationTypes).includes(type as any)) as typeof notificationTypes[number][];
const excludeTypes = ps.excludeTypes && ps.excludeTypes.filter(type => !(obsoleteNotificationTypes).includes(type as any)) as typeof notificationTypes[number][];
- const limit = ps.limit + (ps.untilId ? 1 : 0) + (ps.sinceId ? 1 : 0); // untilIdに指定したものも含まれるため+1
- const notificationsRes = await this.redisClient.xrevrange(
- `notificationTimeline:${me.id}`,
- ps.untilId ? this.idService.parse(ps.untilId).date.getTime() : '+',
- ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime() : '-',
- 'COUNT', limit);
+ let sinceTime = ps.sinceId ? this.idService.parse(ps.sinceId).date.getTime().toString() : null;
+ let untilTime = ps.untilId ? this.idService.parse(ps.untilId).date.getTime().toString() : null;
- if (notificationsRes.length === 0) {
- return [];
- }
+ let notifications: MiNotification[];
+ for (;;) {
+ let notificationsRes: [id: string, fields: string[]][];
- let notifications = notificationsRes.map(x => JSON.parse(x[1][1])).filter(x => x.id !== ps.untilId && x !== ps.sinceId) as MiNotification[];
+ // sinceidのみの場合は古い順、そうでない場合は新しい順。 QueryService.makePaginationQueryも参照
+ if (sinceTime && !untilTime) {
+ notificationsRes = await this.redisClient.xrange(
+ `notificationTimeline:${me.id}`,
+ '(' + sinceTime,
+ '+',
+ 'COUNT', ps.limit);
+ } else {
+ notificationsRes = await this.redisClient.xrevrange(
+ `notificationTimeline:${me.id}`,
+ untilTime ? '(' + untilTime : '+',
+ sinceTime ? '(' + sinceTime : '-',
+ 'COUNT', ps.limit);
+ }
- if (includeTypes && includeTypes.length > 0) {
- notifications = notifications.filter(notification => includeTypes.includes(notification.type));
- } else if (excludeTypes && excludeTypes.length > 0) {
- notifications = notifications.filter(notification => !excludeTypes.includes(notification.type));
- }
+ if (notificationsRes.length === 0) {
+ return [];
+ }
- if (notifications.length === 0) {
- return [];
+ notifications = notificationsRes.map(x => JSON.parse(x[1][1])) as MiNotification[];
+
+ if (includeTypes && includeTypes.length > 0) {
+ notifications = notifications.filter(notification => includeTypes.includes(notification.type));
+ } else if (excludeTypes && excludeTypes.length > 0) {
+ notifications = notifications.filter(notification => !excludeTypes.includes(notification.type));
+ }
+
+ if (notifications.length !== 0) {
+ // 通知が1件以上ある場合は返す
+ break;
+ }
+
+ // フィルタしたことで通知が0件になった場合、次のページを取得する
+ if (ps.sinceId && !ps.untilId) {
+ sinceTime = notificationsRes[notificationsRes.length - 1][0];
+ } else {
+ untilTime = notificationsRes[notificationsRes.length - 1][0];
+ }
}
// Mark all as read