Compare commits

...

2 Commits

Author SHA1 Message Date
Johann150 1dd0b6aece
federation: add context property to notes 2022-08-02 17:04:44 +02:00
Johann150 9384ce8cf5
refactor: properly migrate thread ids
Commit fc65190ef7 introduced thread ids but
did not add the thread id to previous notes. This is fixed by this commit.

The original notes in each thread should also have a thread id set which will
be the same as their ID.

These two migrations allow the threadId column be a NOT NULL column.
2022-08-02 16:59:21 +02:00
9 changed files with 44 additions and 20 deletions

View File

@ -0,0 +1,30 @@
export class fixThreadId1659446758000 {
name = 'fixThreadId1659446758000'
async up(queryRunner) {
await Promise.all([
queryRunner.query(`UPDATE "note" SET "threadId" = "id" WHERE "replyId" IS NULL`),
queryRunner.query(`WITH "threads" ("noteId", "thread") AS (
SELECT "id" as "noteId", "parent" as "thread" FROM (
WITH RECURSIVE "parents" ("id", "parent", "height") AS (
SELECT "id", "replyId", 0 FROM "note" WHERE "replyId" IS NOT NULL AND "threadId" IS NULL
UNION ALL
SELECT "parents"."id", "note"."replyId", "parents"."height" + 1
FROM "parents"
JOIN "note" ON "parents"."parent" = "note"."id"
WHERE "note"."replyId" IS NOT NULL
) SELECT *, MAX("height") OVER (PARTITION BY "id") AS "maxheight" FROM "parents"
) AS "x"
WHERE "height" = "maxheight"
) UPDATE "note" SET "threadId" = "threads"."thread" FROM "threads" WHERE "id" = "threads"."noteId"`),
]);
await queryRunner.query(`ALTER TABLE "note" ALTER COLUMN "threadId" SET NOT NULL`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "note" ALTER COLUMN "threaadId" DROP NOT NULL`);
// Cannot un-fix thread id's for ones that just were not migrated (2nd query above)
// but can remove the thread ids for the root notes of each thread.
await queryRunner.query(`UPDATE "note" SET "threadId" = NULL WHERE "replyId" IS NULL`);
}
}

View File

@ -51,7 +51,7 @@ export class Note {
@Column('varchar', {
length: 256, nullable: true,
})
public threadId: string | null;
public threadId: string;
@Column('text', {
nullable: true,

View File

@ -132,6 +132,7 @@ export default async function renderNote(note: Note, dive = true, isTalk = false
return {
id: `${config.url}/notes/${note.id}`,
context: `${config.url}/notes/${note.threadId}`,
type: 'Note',
attributedTo,
summary,

View File

@ -8,10 +8,7 @@ export function generateMutedNoteThreadQuery(q: SelectQueryBuilder<any>, me: { i
.where('threadMuted.userId = :userId', { userId: me.id });
q.andWhere(`note.id NOT IN (${ mutedQuery.getQuery() })`);
q.andWhere(new Brackets(qb => { qb
.where(`note.threadId IS NULL`)
.orWhere(`note.threadId NOT IN (${ mutedQuery.getQuery() })`);
}));
q.andWhere(`note.threadId NOT IN (${ mutedQuery.getQuery() })`);
q.setParameters(mutedQuery.getParameters());
}

View File

@ -57,7 +57,7 @@ export default define(meta, paramDef, async (ps, user) => {
NoteThreadMutings.count({
where: {
userId: user.id,
threadId: note.threadId || note.id,
threadId: note.threadId,
},
take: 1,
}),

View File

@ -38,9 +38,7 @@ export default define(meta, paramDef, async (ps, user) => {
const mutedNotes = await Notes.find({
where: [{
id: note.threadId || note.id,
}, {
threadId: note.threadId || note.id,
threadId: note.threadId,
}],
});
@ -49,7 +47,7 @@ export default define(meta, paramDef, async (ps, user) => {
await NoteThreadMutings.insert({
id: genId(),
createdAt: new Date(),
threadId: note.threadId || note.id,
threadId: note.threadId,
userId: user.id,
});
});

View File

@ -35,7 +35,7 @@ export default define(meta, paramDef, async (ps, user) => {
});
await NoteThreadMutings.delete({
threadId: note.threadId || note.id,
threadId: note.threadId,
userId: user.id,
});
});

View File

@ -364,7 +364,7 @@ export default async (user: { id: User['id']; username: User['username']; host:
if (data.reply.userHost === null) {
const threadMuted = await NoteThreadMutings.findOneBy({
userId: data.reply.userId,
threadId: data.reply.threadId || data.reply.id,
threadId: data.reply.threadId,
});
if (!threadMuted) {
@ -494,18 +494,16 @@ function incRenoteCount(renote: Note) {
}
async function insertNote(user: { id: User['id']; host: User['host']; }, data: Option, tags: string[], emojis: string[], mentionedUsers: MinimumUser[]) {
const id = genId(data.createdAt!);
const insert = new Note({
id: genId(data.createdAt!),
id,
createdAt: data.createdAt!,
fileIds: data.files ? data.files.map(file => file.id) : [],
replyId: data.reply ? data.reply.id : null,
renoteId: data.renote ? data.renote.id : null,
channelId: data.channel ? data.channel.id : null,
threadId: data.reply
? data.reply.threadId
? data.reply.threadId
: data.reply.id
: null,
threadId: data.reply?.threadId ?? id,
name: data.name,
text: data.text,
hasPoll: data.poll != null,
@ -628,7 +626,7 @@ async function createMentionedEvents(mentionedUsers: MinimumUser[], note: Note,
for (const u of mentionedUsers.filter(u => Users.isLocalUser(u))) {
const threadMuted = await NoteThreadMutings.findOneBy({
userId: u.id,
threadId: note.threadId || note.id,
threadId: note.threadId,
});
if (threadMuted) {

View File

@ -20,7 +20,7 @@ export async function insertNoteUnread(userId: User['id'], note: Note, params: {
// スレッドミュート
const threadMute = await NoteThreadMutings.findOneBy({
userId: userId,
threadId: note.threadId || note.id,
threadId: note.threadId,
});
if (threadMute) return;