fix: notification
This commit is contained in:
parent
1e6002cab9
commit
6063f4d7ab
5 changed files with 49 additions and 32 deletions
|
@ -401,7 +401,7 @@ export async function execPaginationQuery(
|
||||||
filter?: {
|
filter?: {
|
||||||
note?: (_: ScyllaNote[]) => Promise<ScyllaNote[]>;
|
note?: (_: ScyllaNote[]) => Promise<ScyllaNote[]>;
|
||||||
reaction?: (_: ScyllaNoteReaction[]) => Promise<ScyllaNoteReaction[]>;
|
reaction?: (_: ScyllaNoteReaction[]) => Promise<ScyllaNoteReaction[]>;
|
||||||
notification?: (_: ScyllaNotification[]) => ScyllaNotification[];
|
notification?: (_: ScyllaNotification[]) => Promise<ScyllaNotification[]>;
|
||||||
},
|
},
|
||||||
userId?: User["id"],
|
userId?: User["id"],
|
||||||
maxPartitions = config.scylla?.sparseTimelineDays ?? 14,
|
maxPartitions = config.scylla?.sparseTimelineDays ?? 14,
|
||||||
|
@ -474,7 +474,7 @@ export async function execPaginationQuery(
|
||||||
const notifications = result.rows.map(parseScyllaNotification);
|
const notifications = result.rows.map(parseScyllaNotification);
|
||||||
(found as ScyllaNotification[]).push(
|
(found as ScyllaNotification[]).push(
|
||||||
...(filter?.notification
|
...(filter?.notification
|
||||||
? filter.notification(notifications)
|
? await filter.notification(notifications)
|
||||||
: notifications),
|
: notifications),
|
||||||
);
|
);
|
||||||
untilDate = notifications[notifications.length - 1].createdAt;
|
untilDate = notifications[notifications.length - 1].createdAt;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { In, Repository } from "typeorm";
|
import { In } from "typeorm";
|
||||||
import { Notification } from "@/models/entities/notification.js";
|
import { Notification } from "@/models/entities/notification.js";
|
||||||
import { awaitAll } from "@/prelude/await-all.js";
|
import { awaitAll } from "@/prelude/await-all.js";
|
||||||
import type { Packed } from "@/misc/schema.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 { NoteReaction } from "@/models/entities/note-reaction.js";
|
||||||
import type { User } from "@/models/entities/user.js";
|
import type { User } from "@/models/entities/user.js";
|
||||||
import { aggregateNoteEmojis, prefetchEmojis } from "@/misc/populate-emojis.js";
|
import { aggregateNoteEmojis, prefetchEmojis } from "@/misc/populate-emojis.js";
|
||||||
import { notificationTypes } from "@/types.js";
|
|
||||||
import { db } from "@/db/postgre.js";
|
import { db } from "@/db/postgre.js";
|
||||||
import {
|
import {
|
||||||
Users,
|
Users,
|
||||||
|
|
|
@ -14,7 +14,8 @@ import { makePaginationQuery } from "../../common/make-pagination-query.js";
|
||||||
import {
|
import {
|
||||||
ScyllaNotification,
|
ScyllaNotification,
|
||||||
execPaginationQuery,
|
execPaginationQuery,
|
||||||
filterMutedUser,
|
parseScyllaNote,
|
||||||
|
prepared,
|
||||||
scyllaClient,
|
scyllaClient,
|
||||||
} from "@/db/scylla.js";
|
} from "@/db/scylla.js";
|
||||||
import {
|
import {
|
||||||
|
@ -23,19 +24,14 @@ import {
|
||||||
UserBlockedCache,
|
UserBlockedCache,
|
||||||
UserBlockingCache,
|
UserBlockingCache,
|
||||||
UserMutingsCache,
|
UserMutingsCache,
|
||||||
userWordMuteCache,
|
|
||||||
} from "@/misc/cache.js";
|
} from "@/misc/cache.js";
|
||||||
|
import type { Client } from "cassandra-driver";
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ["account", "notifications"],
|
tags: ["account", "notifications"],
|
||||||
|
|
||||||
requireCredential: true,
|
requireCredential: true,
|
||||||
|
|
||||||
limit: {
|
|
||||||
duration: 60000,
|
|
||||||
max: 15,
|
|
||||||
},
|
|
||||||
|
|
||||||
kind: "read:notifications",
|
kind: "read:notifications",
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
|
@ -59,6 +55,7 @@ export const paramDef = {
|
||||||
untilId: { type: "string", format: "misskey:id" },
|
untilId: { type: "string", format: "misskey:id" },
|
||||||
following: { type: "boolean", default: false },
|
following: { type: "boolean", default: false },
|
||||||
unreadOnly: { type: "boolean", default: false },
|
unreadOnly: { type: "boolean", default: false },
|
||||||
|
directOnly: { type: "boolean", default: false },
|
||||||
markAsRead: { type: "boolean", default: true },
|
markAsRead: { type: "boolean", default: true },
|
||||||
includeTypes: {
|
includeTypes: {
|
||||||
type: "array",
|
type: "array",
|
||||||
|
@ -89,6 +86,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scyllaClient) {
|
if (scyllaClient) {
|
||||||
|
const client = scyllaClient as Client;
|
||||||
const [
|
const [
|
||||||
followingUserIds,
|
followingUserIds,
|
||||||
mutedUserIds,
|
mutedUserIds,
|
||||||
|
@ -104,7 +102,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
]);
|
]);
|
||||||
const validUserIds = [user.id, ...followingUserIds];
|
const validUserIds = [user.id, ...followingUserIds];
|
||||||
|
|
||||||
const filter = (notifications: ScyllaNotification[]) => {
|
const filter = async (notifications: ScyllaNotification[]) => {
|
||||||
let filtered = notifications;
|
let filtered = notifications;
|
||||||
if (ps.unreadOnly) {
|
if (ps.unreadOnly) {
|
||||||
// FIXME: isRead is always true at the moment
|
// FIXME: isRead is always true at the moment
|
||||||
|
@ -134,6 +132,25 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
blockerIds.includes(n.notifierId))
|
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;
|
return filtered;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -173,11 +190,8 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
.andWhere("notification.notifieeId = :meId", { meId: user.id })
|
.andWhere("notification.notifieeId = :meId", { meId: user.id })
|
||||||
.leftJoinAndSelect("notification.notifier", "notifier")
|
.leftJoinAndSelect("notification.notifier", "notifier")
|
||||||
.leftJoinAndSelect("notification.note", "note")
|
.leftJoinAndSelect("notification.note", "note")
|
||||||
.leftJoinAndSelect("note.user", "user")
|
|
||||||
.leftJoinAndSelect("note.reply", "reply")
|
.leftJoinAndSelect("note.reply", "reply")
|
||||||
.leftJoinAndSelect("note.renote", "renote")
|
.leftJoinAndSelect("note.renote", "renote");
|
||||||
.leftJoinAndSelect("reply.user", "replyUser")
|
|
||||||
.leftJoinAndSelect("renote.user", "renoteUser");
|
|
||||||
|
|
||||||
// muted users
|
// muted users
|
||||||
query.andWhere(
|
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) {
|
if (ps.unreadOnly) {
|
||||||
query.andWhere("notification.isRead = false");
|
query.andWhere("notification.isRead = false");
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ import { i18n } from "@/i18n";
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
includeTypes?: (typeof notificationTypes)[number][];
|
includeTypes?: (typeof notificationTypes)[number][];
|
||||||
unreadOnly?: boolean;
|
unreadOnly?: boolean;
|
||||||
|
directOnly?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const pagingComponent = ref<InstanceType<typeof MkPagination>>();
|
const pagingComponent = ref<InstanceType<typeof MkPagination>>();
|
||||||
|
@ -72,6 +73,7 @@ const pagination: Paging = {
|
||||||
excludeTypes: props.includeTypes
|
excludeTypes: props.includeTypes
|
||||||
? undefined
|
? undefined
|
||||||
: $i.mutingNotificationTypes,
|
: $i.mutingNotificationTypes,
|
||||||
|
directOnly: props.directOnly,
|
||||||
unreadOnly: props.unreadOnly,
|
unreadOnly: props.unreadOnly,
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
class="notifications"
|
class="notifications"
|
||||||
:include-types="includeTypes"
|
:include-types="includeTypes"
|
||||||
:unread-only="false"
|
:unread-only="false"
|
||||||
|
:direct-only="false"
|
||||||
/>
|
/>
|
||||||
</swiper-slide>
|
</swiper-slide>
|
||||||
<swiper-slide>
|
<swiper-slide>
|
||||||
|
@ -37,13 +38,24 @@
|
||||||
class="notifications"
|
class="notifications"
|
||||||
:include-types="includeTypes"
|
:include-types="includeTypes"
|
||||||
:unread-only="true"
|
:unread-only="true"
|
||||||
|
:direct-only="false"
|
||||||
/>
|
/>
|
||||||
</swiper-slide>
|
</swiper-slide>
|
||||||
<swiper-slide>
|
<swiper-slide>
|
||||||
<XNotes :pagination="mentionsPagination" />
|
<XNotifications
|
||||||
|
class="notifications"
|
||||||
|
:include-types="['mention', 'reply']"
|
||||||
|
:unread-only="false"
|
||||||
|
:direct-only="false"
|
||||||
|
/>
|
||||||
</swiper-slide>
|
</swiper-slide>
|
||||||
<swiper-slide>
|
<swiper-slide>
|
||||||
<XNotes :pagination="directNotesPagination" />
|
<XNotifications
|
||||||
|
class="notifications"
|
||||||
|
:include-types="['mention', 'reply']"
|
||||||
|
:unread-only="false"
|
||||||
|
:direct-only="true"
|
||||||
|
/>
|
||||||
</swiper-slide>
|
</swiper-slide>
|
||||||
</swiper>
|
</swiper>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
|
@ -56,7 +68,6 @@ import { Virtual } from "swiper/modules";
|
||||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||||
import { notificationTypes } from "firefish-js";
|
import { notificationTypes } from "firefish-js";
|
||||||
import XNotifications from "@/components/MkNotifications.vue";
|
import XNotifications from "@/components/MkNotifications.vue";
|
||||||
import XNotes from "@/components/MkNotes.vue";
|
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
import { definePageMetadata } from "@/scripts/page-metadata";
|
import { definePageMetadata } from "@/scripts/page-metadata";
|
||||||
|
@ -81,19 +92,6 @@ window.addEventListener("resize", () => {
|
||||||
deviceKind === "smartphone" || window.innerWidth <= MOBILE_THRESHOLD;
|
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) {
|
function setFilter(ev) {
|
||||||
const typeItems = notificationTypes.map((t) => ({
|
const typeItems = notificationTypes.map((t) => ({
|
||||||
text: i18n.t(`_notification._types.${t}`),
|
text: i18n.t(`_notification._types.${t}`),
|
||||||
|
|
Loading…
Reference in a new issue