[backend] Return isRenoted status in Notes.pack instead of requesting it individually

This commit is contained in:
Laura Hausmann 2023-11-20 23:48:27 +01:00
parent efde111779
commit a6fa393359
No known key found for this signature in database
GPG key ID: D044E84C5BE01605
5 changed files with 49 additions and 9 deletions

View file

@ -10,6 +10,7 @@ import {
Followings, Followings,
Polls, Polls,
Channels, Channels,
Notes,
} from "../index.js"; } from "../index.js";
import type { Packed } from "@/misc/schema.js"; import type { Packed } from "@/misc/schema.js";
import { nyaize } from "@/misc/nyaize.js"; import { nyaize } from "@/misc/nyaize.js";
@ -95,6 +96,19 @@ async function populateMyReaction(
return undefined; return undefined;
} }
async function populateIsRenoted(
note: Note,
meId: User["id"],
_hint_?: {
myRenotes: Map<Note["id"], boolean>;
},
) {
return _hint_?.myRenotes
? _hint_.myRenotes.get(note.id) ? true : undefined
: Notes.exist({ where: { renoteId: note.id, userId: meId } })
.then(res => res ? true : undefined);
}
export const NoteRepository = db.getRepository(Note).extend({ export const NoteRepository = db.getRepository(Note).extend({
async isVisibleForMe(note: Note, meId: User["id"] | null): Promise<boolean> { async isVisibleForMe(note: Note, meId: User["id"] | null): Promise<boolean> {
// This code must always be synchronized with the checks in generateVisibilityQuery. // This code must always be synchronized with the checks in generateVisibilityQuery.
@ -156,6 +170,7 @@ export const NoteRepository = db.getRepository(Note).extend({
detail?: boolean; detail?: boolean;
_hint_?: { _hint_?: {
myReactions: Map<Note["id"], NoteReaction | null>; myReactions: Map<Note["id"], NoteReaction | null>;
myRenotes: Map<Note["id"], boolean>;
}; };
}, },
): Promise<Packed<"Note">> { ): Promise<Packed<"Note">> {
@ -240,6 +255,7 @@ export const NoteRepository = db.getRepository(Note).extend({
...(meId ...(meId
? { ? {
myReaction: populateMyReaction(note, meId, options?._hint_), myReaction: populateMyReaction(note, meId, options?._hint_),
isRenoted: populateIsRenoted(note, meId, options?._hint_)
} }
: {}), : {}),
@ -290,6 +306,7 @@ export const NoteRepository = db.getRepository(Note).extend({
detail?: boolean; detail?: boolean;
_hint_?: { _hint_?: {
myReactions: Map<Note["id"], NoteReaction | null>; myReactions: Map<Note["id"], NoteReaction | null>;
myRenotes: Map<Note["id"], boolean>;
}; };
}, },
): Promise<Packed<"Note"> | undefined> { ): Promise<Packed<"Note"> | undefined> {
@ -311,6 +328,7 @@ export const NoteRepository = db.getRepository(Note).extend({
const meId = me ? me.id : null; const meId = me ? me.id : null;
const myReactionsMap = new Map<Note["id"], NoteReaction | null>(); const myReactionsMap = new Map<Note["id"], NoteReaction | null>();
const myRenotesMap = new Map<Note["id"], boolean>();
if (meId) { if (meId) {
const renoteIds = notes const renoteIds = notes
.filter((n) => n.renoteId != null) .filter((n) => n.renoteId != null)
@ -320,12 +338,22 @@ export const NoteRepository = db.getRepository(Note).extend({
userId: meId, userId: meId,
noteId: In(targets), noteId: In(targets),
}); });
const myRenotes = await Notes.createQueryBuilder('note')
.select('note.renoteId')
.where('note.userId = :meId', { meId })
.andWhere('note.renoteId IN (:...targets)', { targets })
.getMany();
for (const target of targets) { for (const target of targets) {
myReactionsMap.set( myReactionsMap.set(
target, target,
myReactions.find((reaction) => reaction.noteId === target) || null, myReactions.find((reaction) => reaction.noteId === target) || null,
); );
myRenotesMap.set(
target,
!!myRenotes.find(p => p.renoteId == target),
);
} }
} }
@ -337,6 +365,7 @@ export const NoteRepository = db.getRepository(Note).extend({
...options, ...options,
_hint_: { _hint_: {
myReactions: myReactionsMap, myReactions: myReactionsMap,
myRenotes: myRenotesMap
}, },
}), }),
), ),

View file

@ -22,6 +22,7 @@ export const NotificationRepository = db.getRepository(Notification).extend({
options: { options: {
_hintForEachNotes_?: { _hintForEachNotes_?: {
myReactions: Map<Note["id"], NoteReaction | null>; myReactions: Map<Note["id"], NoteReaction | null>;
myRenotes: Map<Note["id"], boolean>;
}; };
}, },
): Promise<Packed<"Notification">> { ): Promise<Packed<"Notification">> {
@ -153,6 +154,7 @@ export const NotificationRepository = db.getRepository(Notification).extend({
.map((x) => x.note!); .map((x) => x.note!);
const noteIds = notes.map((n) => n.id); const noteIds = notes.map((n) => n.id);
const myReactionsMap = new Map<Note["id"], NoteReaction | null>(); const myReactionsMap = new Map<Note["id"], NoteReaction | null>();
const myRenotesMap = new Map<Note["id"], boolean>();
const renoteIds = notes const renoteIds = notes
.filter((n) => n.renoteId != null) .filter((n) => n.renoteId != null)
.map((n) => n.renoteId!); .map((n) => n.renoteId!);
@ -161,12 +163,22 @@ export const NotificationRepository = db.getRepository(Notification).extend({
userId: meId, userId: meId,
noteId: In(targets), noteId: In(targets),
}); });
const myRenotes = await Notes.createQueryBuilder('note')
.select('note.renoteId')
.where('note.userId = :meId', { meId })
.andWhere('note.renoteId IN array[:...targets]', { targets })
.getMany();
for (const target of targets) { for (const target of targets) {
myReactionsMap.set( myReactionsMap.set(
target, target,
myReactions.find((reaction) => reaction.noteId === target) || null, myReactions.find((reaction) => reaction.noteId === target) || null,
); );
myRenotesMap.set(
target,
!!myRenotes.find(p => p.renoteId == target),
);
} }
await prefetchEmojis(aggregateNoteEmojis(notes)); await prefetchEmojis(aggregateNoteEmojis(notes));
@ -176,6 +188,7 @@ export const NotificationRepository = db.getRepository(Notification).extend({
this.pack(x, { this.pack(x, {
_hintForEachNotes_: { _hintForEachNotes_: {
myReactions: myReactionsMap, myReactions: myReactionsMap,
myRenotes: myRenotesMap
}, },
}).catch((e) => null), }).catch((e) => null),
), ),

View file

@ -190,11 +190,15 @@ export const packedNoteSchema = {
optional: true, optional: true,
nullable: false, nullable: false,
}, },
myReaction: { myReaction: {
type: "object", type: "object",
optional: true, optional: true,
nullable: true, nullable: true,
}, },
isRenoted: {
type: "boolean",
optional: true,
nullable: true,
}
}, },
} as const; } as const;

View file

@ -70,14 +70,7 @@ useTooltip(buttonRef, async (showing) => {
); );
}); });
let hasRenotedBefore = $ref(false); let hasRenotedBefore = $ref(props.note.isRenoted ?? false);
os.api("notes/renotes", {
noteId: props.note.id,
userId: $i.id,
limit: 1,
}).then((res) => {
hasRenotedBefore = res.length > 0;
});
const renote = (viaKeyboard = false, ev?: MouseEvent) => { const renote = (viaKeyboard = false, ev?: MouseEvent) => {
pleaseLogin(); pleaseLogin();

View file

@ -151,6 +151,7 @@ export type Note = {
localOnly?: boolean; localOnly?: boolean;
channel?: Channel["id"]; channel?: Channel["id"];
myReaction?: string; myReaction?: string;
isRenoted?: boolean;
reactions: Record<string, number>; reactions: Record<string, number>;
renoteCount: number; renoteCount: number;
repliesCount: number; repliesCount: number;