import { UserConverter } from "./user.js"; import { UserHelpers } from "../helpers/user.js"; import { awaitAll } from "../../../../prelude/await-all.js"; import { NoteConverter } from "./note.js"; import { getNote } from "../../common/getters.js"; import { getStubMastoContext } from "../index.js"; import { Notifications } from "../../../../models/index.js"; import isQuote from "../../../../misc/is-quote.js"; import { unique } from "../../../../prelude/array.js"; export class NotificationConverter { static async encode(notification, ctx) { const localUser = ctx.user; if (notification.notifieeId !== localUser.id) throw new Error('User is not recipient of notification'); const account = notification.notifierId ? UserHelpers.getUserCached(notification.notifierId, ctx).then((p)=>UserConverter.encode(p, ctx)) : UserConverter.encode(localUser, ctx); let result = { id: notification.id, account: account, created_at: notification.createdAt.toISOString(), type: this.encodeNotificationType(notification.type) }; const note = notification.note ?? (notification.noteId ? await getNote(notification.noteId, localUser) : null); if (note) { const isPureRenote = note.renoteId !== null && !isQuote(note); const encodedNote = isPureRenote ? getNote(note.renoteId, localUser).then((note)=>NoteConverter.encode(note, ctx)) : NoteConverter.encode(note, ctx); result = Object.assign(result, { status: encodedNote }); if (result.type === 'poll') { result = Object.assign(result, { account: encodedNote.then((p)=>p.account) }); } if (notification.reaction) { //FIXME: Implement reactions; } } return awaitAll(result); } static async encodeMany(notifications, ctx) { await this.aggregateData(notifications, ctx); const encoded = notifications.map((u)=>this.encode(u, ctx)); return Promise.all(encoded).then((p)=>p.filter((n)=>n !== null)); } static async aggregateData(notifications, ctx) { if (notifications.length === 0) return; const notes = unique(notifications.filter((p)=>p.note != null).map((n)=>n.note)); const users = unique(notifications.filter((p)=>p.notifier != null).map((n)=>n.notifier).concat(notifications.filter((p)=>p.notifiee != null).map((n)=>n.notifiee))); await NoteConverter.aggregateData(notes, ctx); await UserConverter.aggregateData(users, ctx); } static encodeNotificationType(t) { //FIXME: Implement custom notification for followRequestAccepted //FIXME: Implement mastodon notification type 'update' on misskey side switch(t){ case "follow": return 'follow'; case "mention": case "reply": return 'mention'; case "renote": return 'reblog'; case "quote": return 'reblog'; case "reaction": return 'favourite'; case "pollEnded": return 'poll'; case "receiveFollowRequest": return 'follow_request'; case "followRequestAccepted": case "pollVote": case "groupInvited": case "app": throw new Error(`Notification type ${t} not supported`); } } static async encodeEvent(target, user, filterContext) { const ctx = getStubMastoContext(user, filterContext); const notification = await Notifications.findOneByOrFail({ id: target }); return this.encode(notification, ctx).catch((_)=>null); } }