fix: notification

This commit is contained in:
Namekuji 2023-09-05 18:30:38 -04:00
parent 1e6002cab9
commit 6063f4d7ab
No known key found for this signature in database
GPG key ID: 1D62332C07FBA532
5 changed files with 49 additions and 32 deletions

View file

@ -401,7 +401,7 @@ export async function execPaginationQuery(
filter?: {
note?: (_: ScyllaNote[]) => Promise<ScyllaNote[]>;
reaction?: (_: ScyllaNoteReaction[]) => Promise<ScyllaNoteReaction[]>;
notification?: (_: ScyllaNotification[]) => ScyllaNotification[];
notification?: (_: ScyllaNotification[]) => Promise<ScyllaNotification[]>;
},
userId?: User["id"],
maxPartitions = config.scylla?.sparseTimelineDays ?? 14,
@ -474,7 +474,7 @@ export async function execPaginationQuery(
const notifications = result.rows.map(parseScyllaNotification);
(found as ScyllaNotification[]).push(
...(filter?.notification
? filter.notification(notifications)
? await filter.notification(notifications)
: notifications),
);
untilDate = notifications[notifications.length - 1].createdAt;

View file

@ -1,4 +1,4 @@
import { In, Repository } from "typeorm";
import { In } from "typeorm";
import { Notification } from "@/models/entities/notification.js";
import { awaitAll } from "@/prelude/await-all.js";
import type { Packed } from "@/misc/schema.js";
@ -6,7 +6,6 @@ import type { Note } from "@/models/entities/note.js";
import type { NoteReaction } from "@/models/entities/note-reaction.js";
import type { User } from "@/models/entities/user.js";
import { aggregateNoteEmojis, prefetchEmojis } from "@/misc/populate-emojis.js";
import { notificationTypes } from "@/types.js";
import { db } from "@/db/postgre.js";
import {
Users,

View file

@ -14,7 +14,8 @@ import { makePaginationQuery } from "../../common/make-pagination-query.js";
import {
ScyllaNotification,
execPaginationQuery,
filterMutedUser,
parseScyllaNote,
prepared,
scyllaClient,
} from "@/db/scylla.js";
import {
@ -23,19 +24,14 @@ import {
UserBlockedCache,
UserBlockingCache,
UserMutingsCache,
userWordMuteCache,
} from "@/misc/cache.js";
import type { Client } from "cassandra-driver";
export const meta = {
tags: ["account", "notifications"],
requireCredential: true,
limit: {
duration: 60000,
max: 15,
},
kind: "read:notifications",
res: {
@ -59,6 +55,7 @@ export const paramDef = {
untilId: { type: "string", format: "misskey:id" },
following: { type: "boolean", default: false },
unreadOnly: { type: "boolean", default: false },
directOnly: { type: "boolean", default: false },
markAsRead: { type: "boolean", default: true },
includeTypes: {
type: "array",
@ -89,6 +86,7 @@ export default define(meta, paramDef, async (ps, user) => {
}
if (scyllaClient) {
const client = scyllaClient as Client;
const [
followingUserIds,
mutedUserIds,
@ -104,7 +102,7 @@ export default define(meta, paramDef, async (ps, user) => {
]);
const validUserIds = [user.id, ...followingUserIds];
const filter = (notifications: ScyllaNotification[]) => {
const filter = async (notifications: ScyllaNotification[]) => {
let filtered = notifications;
if (ps.unreadOnly) {
// FIXME: isRead is always true at the moment
@ -134,6 +132,25 @@ export default define(meta, paramDef, async (ps, user) => {
blockerIds.includes(n.notifierId))
),
);
if (
ps.directOnly &&
ps.includeTypes?.every((t) => ["mention", "reply"].includes(t))
) {
filtered = filtered.filter(({ entityId }) => !!entityId);
let notes = await client
.execute(
prepared.note.select.byIds,
[filtered.map(({ entityId }) => entityId as string)],
{ prepare: true },
)
.then((result) => result.rows.map(parseScyllaNote));
notes = notes.filter((n) => n.visibility === "specified");
const validNoteIds = notes.map(({ id }) => id);
filtered = filtered.filter(
({ entityId }) => entityId && validNoteIds.includes(entityId),
);
}
return filtered;
};
@ -173,11 +190,8 @@ export default define(meta, paramDef, async (ps, user) => {
.andWhere("notification.notifieeId = :meId", { meId: user.id })
.leftJoinAndSelect("notification.notifier", "notifier")
.leftJoinAndSelect("notification.note", "note")
.leftJoinAndSelect("note.user", "user")
.leftJoinAndSelect("note.reply", "reply")
.leftJoinAndSelect("note.renote", "renote")
.leftJoinAndSelect("reply.user", "replyUser")
.leftJoinAndSelect("renote.user", "renoteUser");
.leftJoinAndSelect("note.renote", "renote");
// muted users
query.andWhere(
@ -226,6 +240,10 @@ export default define(meta, paramDef, async (ps, user) => {
});
}
if (ps.directOnly) {
query.andWhere("note.visibility = 'specified'");
}
if (ps.unreadOnly) {
query.andWhere("notification.isRead = false");
}

View file

@ -60,6 +60,7 @@ import { i18n } from "@/i18n";
const props = defineProps<{
includeTypes?: (typeof notificationTypes)[number][];
unreadOnly?: boolean;
directOnly?: boolean;
}>();
const pagingComponent = ref<InstanceType<typeof MkPagination>>();
@ -72,6 +73,7 @@ const pagination: Paging = {
excludeTypes: props.includeTypes
? undefined
: $i.mutingNotificationTypes,
directOnly: props.directOnly,
unreadOnly: props.unreadOnly,
})),
};

View file

@ -30,6 +30,7 @@
class="notifications"
:include-types="includeTypes"
:unread-only="false"
:direct-only="false"
/>
</swiper-slide>
<swiper-slide>
@ -37,13 +38,24 @@
class="notifications"
:include-types="includeTypes"
:unread-only="true"
:direct-only="false"
/>
</swiper-slide>
<swiper-slide>
<XNotes :pagination="mentionsPagination" />
<XNotifications
class="notifications"
:include-types="['mention', 'reply']"
:unread-only="false"
:direct-only="false"
/>
</swiper-slide>
<swiper-slide>
<XNotes :pagination="directNotesPagination" />
<XNotifications
class="notifications"
:include-types="['mention', 'reply']"
:unread-only="false"
:direct-only="true"
/>
</swiper-slide>
</swiper>
</MkSpacer>
@ -56,7 +68,6 @@ import { Virtual } from "swiper/modules";
import { Swiper, SwiperSlide } from "swiper/vue";
import { notificationTypes } from "firefish-js";
import XNotifications from "@/components/MkNotifications.vue";
import XNotes from "@/components/MkNotes.vue";
import * as os from "@/os";
import { i18n } from "@/i18n";
import { definePageMetadata } from "@/scripts/page-metadata";
@ -81,19 +92,6 @@ window.addEventListener("resize", () => {
deviceKind === "smartphone" || window.innerWidth <= MOBILE_THRESHOLD;
});
const mentionsPagination = {
endpoint: "notes/mentions" as const,
limit: 10,
};
const directNotesPagination = {
endpoint: "notes/mentions" as const,
limit: 10,
params: {
visibility: "specified",
},
};
function setFilter(ev) {
const typeItems = notificationTypes.map((t) => ({
text: i18n.t(`_notification._types.${t}`),