Merge remote-tracking branch 'upstream/develop' into nodeinfostats

This commit is contained in:
Kinetix 2025-01-26 13:20:26 -08:00
commit 326bc0a24f
27 changed files with 179 additions and 148 deletions

View file

@ -68,6 +68,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
for (let i = 0; i < ps.count; i++) {
ticketsPromises.push(this.registrationTicketsRepository.insertOne({
id: this.idService.gen(),
createdBy: me,
createdById: me.id,
expiresAt: ps.expiresAt ? new Date(ps.expiresAt) : null,
code: generateInviteCode(),
}));

View file

@ -3,7 +3,6 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { IsNull } from 'typeorm';
import { Inject, Injectable } from '@nestjs/common';
import type { EmojisRepository } from '@/models/_.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
@ -59,7 +58,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const emojis = await this.emojisRepository.createQueryBuilder()
.where('host IS NULL')
.orderBy('LOWER(category)', 'ASC')
.orderBy('LOWER(name)', 'ASC')
.addOrderBy('LOWER(name)', 'ASC')
.getMany();
return {
emojis: await this.emojiEntityService.packSimpleMany(emojis),

View file

@ -103,11 +103,42 @@ export default abstract class Channel {
public onMessage?(type: string, body: JsonValue): void;
public async assignMyReaction(note: Packed<'Note'>, noteEntityService: NoteEntityService) {
if (this.user && Object.keys(note.reactions).length > 0) {
const myReaction = await noteEntityService.populateMyReaction(note, this.user.id);
note.myReaction = myReaction;
public async assignMyReaction(note: Packed<'Note'>, noteEntityService: NoteEntityService): Promise<Packed<'Note'>> {
let changed = false;
// StreamingApiServerService creates a single EventEmitter per server process,
// so a new note arriving from redis gets de-serialised once per server process,
// and then that single object is passed to all active channels on each connection.
// If we didn't clone the notes here, different connections would asynchronously write
// different values to the same object, resulting in a random value being sent to each frontend. -- Dakkar
const clonedNote = { ...note };
if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
if (note.renote && Object.keys(note.renote.reactions).length > 0) {
const myReaction = await noteEntityService.populateMyReaction(note.renote, this.user.id);
if (myReaction) {
changed = true;
clonedNote.renote = { ...note.renote };
clonedNote.renote.myReaction = myReaction;
}
}
if (note.renote?.reply && Object.keys(note.renote.reply.reactions).length > 0) {
const myReaction = await noteEntityService.populateMyReaction(note.renote.reply, this.user.id);
if (myReaction) {
changed = true;
clonedNote.renote = { ...note.renote };
clonedNote.renote.reply = { ...note.renote.reply };
clonedNote.renote.reply.myReaction = myReaction;
}
}
}
if (this.user && note.reply && Object.keys(note.reply.reactions).length > 0) {
const myReaction = await noteEntityService.populateMyReaction(note.reply, this.user.id);
if (myReaction) {
changed = true;
clonedNote.reply = { ...note.reply };
clonedNote.reply.myReaction = myReaction;
}
}
return changed ? clonedNote : note;
}
}

View file

@ -65,24 +65,11 @@ class BubbleTimelineChannel extends Channel {
if (this.isNoteMutedOrBlocked(note)) return;
const reactionsToFetch = [];
if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
if (note.renote) {
reactionsToFetch.push(this.assignMyReaction(note.renote, this.noteEntityService));
if (note.renote.reply) {
reactionsToFetch.push(this.assignMyReaction(note.renote.reply, this.noteEntityService));
}
}
}
if (this.user && note.reply) {
reactionsToFetch.push(this.assignMyReaction(note.reply, this.noteEntityService));
}
const clonedNote = await this.assignMyReaction(note, this.noteEntityService);
await Promise.all(reactionsToFetch);
this.connection.cacheNote(clonedNote);
this.connection.cacheNote(note);
this.send('note', note);
this.send('note', clonedNote);
}
@bindThis

View file

@ -60,24 +60,11 @@ class GlobalTimelineChannel extends Channel {
if (this.isNoteMutedOrBlocked(note)) return;
const reactionsToFetch = [];
if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
if (note.renote) {
reactionsToFetch.push(this.assignMyReaction(note.renote, this.noteEntityService));
if (note.renote.reply) {
reactionsToFetch.push(this.assignMyReaction(note.renote.reply, this.noteEntityService));
}
}
}
if (this.user && note.reply) {
reactionsToFetch.push(this.assignMyReaction(note.reply, this.noteEntityService));
}
const clonedNote = await this.assignMyReaction(note, this.noteEntityService);
await Promise.all(reactionsToFetch);
this.connection.cacheNote(clonedNote);
this.connection.cacheNote(note);
this.send('note', note);
this.send('note', clonedNote);
}
@bindThis

View file

@ -81,24 +81,11 @@ class HomeTimelineChannel extends Channel {
if (this.isNoteMutedOrBlocked(note)) return;
const reactionsToFetch = [];
if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
if (note.renote) {
reactionsToFetch.push(this.assignMyReaction(note.renote, this.noteEntityService));
if (note.renote.reply) {
reactionsToFetch.push(this.assignMyReaction(note.renote.reply, this.noteEntityService));
}
}
}
if (this.user && note.reply) {
reactionsToFetch.push(this.assignMyReaction(note.reply, this.noteEntityService));
}
const clonedNote = await this.assignMyReaction(note, this.noteEntityService);
await Promise.all(reactionsToFetch);
this.connection.cacheNote(clonedNote);
this.connection.cacheNote(note);
this.send('note', note);
this.send('note', clonedNote);
}
@bindThis

View file

@ -98,24 +98,11 @@ class HybridTimelineChannel extends Channel {
}
}
const reactionsToFetch = [];
if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
if (note.renote) {
reactionsToFetch.push(this.assignMyReaction(note.renote, this.noteEntityService));
if (note.renote.reply) {
reactionsToFetch.push(this.assignMyReaction(note.renote.reply, this.noteEntityService));
}
}
}
if (this.user && note.reply) {
reactionsToFetch.push(this.assignMyReaction(note.reply, this.noteEntityService));
}
const clonedNote = await this.assignMyReaction(note, this.noteEntityService);
await Promise.all(reactionsToFetch);
this.connection.cacheNote(clonedNote);
this.connection.cacheNote(note);
this.send('note', note);
this.send('note', clonedNote);
}
@bindThis

View file

@ -70,24 +70,11 @@ class LocalTimelineChannel extends Channel {
if (this.isNoteMutedOrBlocked(note)) return;
const reactionsToFetch = [];
if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
if (note.renote) {
reactionsToFetch.push(this.assignMyReaction(note.renote, this.noteEntityService));
if (note.renote.reply) {
reactionsToFetch.push(this.assignMyReaction(note.renote.reply, this.noteEntityService));
}
}
}
if (this.user && note.reply) {
reactionsToFetch.push(this.assignMyReaction(note.reply, this.noteEntityService));
}
const clonedNote = await this.assignMyReaction(note, this.noteEntityService);
await Promise.all(reactionsToFetch);
this.connection.cacheNote(clonedNote);
this.connection.cacheNote(note);
this.send('note', note);
this.send('note', clonedNote);
}
@bindThis