Compare commits
3 commits
Author | SHA1 | Date | |
---|---|---|---|
1d653fdb0b | |||
46629a9884 | |||
457bd5ee3f |
10 changed files with 64 additions and 21 deletions
30
packages/backend/migration/1659446758000-fix-thread-id.js
Normal file
30
packages/backend/migration/1659446758000-fix-thread-id.js
Normal 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`);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import config from '../built/config/index.js';
|
||||
|
||||
export class remoteThreadIds1667212446191 {
|
||||
name = 'remoteThreadIds1667212446191';
|
||||
|
||||
async up(queryRunner) {
|
||||
await Promise.all([
|
||||
queryRunner.query(`UPDATE "note" SET "threadId" = '${config.url}/notes/' + "threadId"`),
|
||||
queryRunner.query(`UPDATE "note_thread_muting" SET "threadId" = '${config.url}/notes/' + "threadId"`),
|
||||
]);
|
||||
}
|
||||
|
||||
async down() {
|
||||
// cannot be undone:
|
||||
// after this migration other instances threadIds may be stored in the database
|
||||
}
|
||||
}
|
|
@ -51,7 +51,7 @@ export class Note {
|
|||
@Column('varchar', {
|
||||
length: 256, nullable: true,
|
||||
})
|
||||
public threadId: string | null;
|
||||
public threadId: string;
|
||||
|
||||
@Column('text', {
|
||||
nullable: true,
|
||||
|
|
|
@ -131,6 +131,7 @@ export default async function renderNote(note: Note, dive = true, isTalk = false
|
|||
|
||||
return {
|
||||
id: `${config.url}/notes/${note.id}`,
|
||||
context: note.threadId,
|
||||
type: 'Note',
|
||||
attributedTo,
|
||||
summary,
|
||||
|
|
|
@ -7,11 +7,7 @@ export function generateMutedNoteThreadQuery(q: SelectQueryBuilder<any>, me: { i
|
|||
.select('threadMuted.threadId')
|
||||
.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());
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}),
|
||||
|
|
|
@ -41,9 +41,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,
|
||||
}],
|
||||
});
|
||||
|
||||
|
@ -52,7 +50,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,
|
||||
mutingNotificationTypes: ps.mutingNotificationTypes,
|
||||
});
|
||||
|
|
|
@ -29,7 +29,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
});
|
||||
|
||||
await NoteThreadMutings.delete({
|
||||
threadId: note.threadId || note.id,
|
||||
threadId: note.threadId,
|
||||
userId: user.id,
|
||||
});
|
||||
});
|
||||
|
|
|
@ -369,7 +369,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) {
|
||||
|
@ -500,15 +500,16 @@ function incRenoteCount(renote: Note): void {
|
|||
|
||||
async function insertNote(user: { id: User['id']; host: User['host']; }, data: Option, tags: string[], emojis: string[], mentionedUsers: MinimumUser[]): Promise<Note> {
|
||||
const createdAt = data.createdAt ?? new Date();
|
||||
const id = genId(createdAt);
|
||||
|
||||
const insert = new Note({
|
||||
id: genId(createdAt),
|
||||
id,
|
||||
createdAt,
|
||||
fileIds: data.files?.map(file => file.id) ?? [],
|
||||
replyId: data.reply?.id ?? null,
|
||||
renoteId: data.renote?.id ?? null,
|
||||
channelId: data.channel?.id ?? null,
|
||||
threadId: data.reply?.threadId ?? data.reply?.id ?? null,
|
||||
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?.threadId ?? `${config.url}/notes/${id}`,
|
||||
name: data.name,
|
||||
text: data.text,
|
||||
hasPoll: data.poll != null,
|
||||
|
@ -616,7 +617,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) {
|
||||
|
|
|
@ -20,7 +20,7 @@ export async function insertNoteUnread(userId: User['id'], note: Note, params: {
|
|||
// スレッドミュート
|
||||
const threadMute = await NoteThreadMutings.findOneBy({
|
||||
userId,
|
||||
threadId: note.threadId || note.id,
|
||||
threadId: note.threadId,
|
||||
});
|
||||
if (threadMute) return;
|
||||
|
||||
|
|
Loading…
Reference in a new issue