[mastodon-client] Unread notifications

This commit is contained in:
Laura Hausmann 2023-10-02 23:46:17 +02:00
parent b8b6206b4e
commit 557dd37fe8
Signed by: zotan
GPG key ID: D044E84C5BE01605
4 changed files with 47 additions and 7 deletions

View file

@ -1,11 +1,13 @@
import Router from "@koa/router";
import { convertId, IdType } from "../../index.js";
import { convertPaginationArgsIds, limitToInt, normalizeUrlQuery } from "./timeline.js";
import { convertNotification } from "../converters.js";
import { convertConversation, convertNotification } from "../converters.js";
import authenticate from "@/server/api/authenticate.js";
import { UserHelpers } from "@/server/api/mastodon/helpers/user.js";
import { NotificationHelpers } from "@/server/api/mastodon/helpers/notification.js";
import { NotificationConverter } from "@/server/api/mastodon/converters/notification.js";
import { TimelineHelpers } from "@/server/api/mastodon/helpers/timeline.js";
import { PaginationHelpers } from "@/server/api/mastodon/helpers/pagination.js";
export function setupEndpointsNotifications(router: Router): void {
router.get("/v1/notifications", async (ctx) => {
@ -99,4 +101,18 @@ export function setupEndpointsNotifications(router: Router): void {
ctx.body = e.response.data;
}
});
router.post("/v1/conversations/:id/read", async (ctx, reply) => {
const auth = await authenticate(ctx.headers.authorization, null);
const user = auth[0] ?? undefined;
if (!user) {
ctx.status = 401;
return;
}
const id = convertId(ctx.params.id, IdType.IceshrimpId);
await NotificationHelpers.markConversationAsRead(id, user);
ctx.body = {};
});
}

View file

@ -177,9 +177,6 @@ export function setupEndpointsTimeline(router: Router): void {
},
);
router.get("/v1/conversations", async (ctx, reply) => {
const BASE_URL = `${ctx.protocol}://${ctx.hostname}`;
const accessTokens = ctx.headers.authorization;
const client = getClient(BASE_URL, accessTokens);
try {
const auth = await authenticate(ctx.headers.authorization, null);
const user = auth[0] ?? undefined;

View file

@ -1,5 +1,5 @@
import { ILocalUser } from "@/models/entities/user.js";
import { Notifications } from "@/models/index.js";
import { Notes, Notifications } from "@/models/index.js";
import { PaginationHelpers } from "@/server/api/mastodon/helpers/pagination.js";
import { Notification } from "@/models/entities/notification.js";
@ -46,6 +46,24 @@ export class NotificationHelpers {
await Notifications.update({notifieeId: user.id}, {isRead: true});
}
public static async markConversationAsRead(id: string, user: ILocalUser): Promise<void> {
const notesQuery = Notes.createQueryBuilder("note")
.select("note.id")
.andWhere("COALESCE(note.threadId, note.id) = :conversationId");
await Notifications.createQueryBuilder("notification")
.where(`notification."noteId" IN (${notesQuery.getQuery()})`)
.andWhere(`notification."notifieeId" = :userId`)
.andWhere(`notification."isRead" = FALSE`)
.andWhere("notification.type IN (:...types)")
.setParameter("userId", user.id)
.setParameter("conversationId", id)
.setParameter("types", ['reply', 'mention'])
.update()
.set({isRead: true})
.execute();
}
private static decodeTypes(types: string[]) {
const result: string[] = [];
if (types.includes('follow')) result.push('follow');

View file

@ -1,6 +1,6 @@
import { Note } from "@/models/entities/note.js";
import { ILocalUser, User } from "@/models/entities/user.js";
import { Followings, Notes, UserListJoinings } from "@/models/index.js";
import { Followings, Notes, Notifications, UserListJoinings } from "@/models/index.js";
import { Brackets } from "typeorm";
import { generateChannelQuery } from "@/server/api/common/generate-channel-query.js";
import { generateRepliesQuery } from "@/server/api/common/generate-replies-query.js";
@ -187,12 +187,21 @@ export class TimelineHelpers {
const userIds = unique([c.userId].concat(c.visibleUserIds).filter(p => p != user.id));
const users = userIds.map(id => UserHelpers.getUserCached(id, cache).catch(_ => null));
const accounts = Promise.all(users).then(u => UserConverter.encodeMany(u.filter(u => u) as User[], cache));
const unread = Notifications.createQueryBuilder('notification')
.where("notification.noteId = :noteId")
.andWhere("notification.notifieeId = :userId")
.andWhere("notification.isRead = FALSE")
.andWhere("notification.type IN (:...types)")
.setParameter("noteId", c.id)
.setParameter("userId", user.id)
.setParameter("types", ['reply', 'mention'])
.getExists();
return {
id: c.threadId ?? c.id,
accounts: accounts.then(u => u.length > 0 ? u : UserConverter.encodeMany([user], cache)), // failsafe to prevent apps from crashing case when all participant users have been deleted
last_status: NoteConverter.encode(c, user, cache),
unread: false //FIXME implement this (also the /v1/conversations/:id/read endpoint)
unread: unread
}
});
const res = {