Compare commits
2 commits
Author | SHA1 | Date | |
---|---|---|---|
1dd0b6aece | |||
9384ce8cf5 |
9 changed files with 44 additions and 20 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`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -51,7 +51,7 @@ export class Note {
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 256, nullable: true,
|
length: 256, nullable: true,
|
||||||
})
|
})
|
||||||
public threadId: string | null;
|
public threadId: string;
|
||||||
|
|
||||||
@Column('text', {
|
@Column('text', {
|
||||||
nullable: true,
|
nullable: true,
|
||||||
|
|
|
@ -132,6 +132,7 @@ export default async function renderNote(note: Note, dive = true, isTalk = false
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: `${config.url}/notes/${note.id}`,
|
id: `${config.url}/notes/${note.id}`,
|
||||||
|
context: `${config.url}/notes/${note.threadId}`,
|
||||||
type: 'Note',
|
type: 'Note',
|
||||||
attributedTo,
|
attributedTo,
|
||||||
summary,
|
summary,
|
||||||
|
|
|
@ -8,10 +8,7 @@ export function generateMutedNoteThreadQuery(q: SelectQueryBuilder<any>, me: { i
|
||||||
.where('threadMuted.userId = :userId', { userId: me.id });
|
.where('threadMuted.userId = :userId', { userId: me.id });
|
||||||
|
|
||||||
q.andWhere(`note.id NOT IN (${ mutedQuery.getQuery() })`);
|
q.andWhere(`note.id NOT IN (${ mutedQuery.getQuery() })`);
|
||||||
q.andWhere(new Brackets(qb => { qb
|
q.andWhere(`note.threadId NOT IN (${ mutedQuery.getQuery() })`);
|
||||||
.where(`note.threadId IS NULL`)
|
|
||||||
.orWhere(`note.threadId NOT IN (${ mutedQuery.getQuery() })`);
|
|
||||||
}));
|
|
||||||
|
|
||||||
q.setParameters(mutedQuery.getParameters());
|
q.setParameters(mutedQuery.getParameters());
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
NoteThreadMutings.count({
|
NoteThreadMutings.count({
|
||||||
where: {
|
where: {
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
threadId: note.threadId || note.id,
|
threadId: note.threadId,
|
||||||
},
|
},
|
||||||
take: 1,
|
take: 1,
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -38,9 +38,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
|
|
||||||
const mutedNotes = await Notes.find({
|
const mutedNotes = await Notes.find({
|
||||||
where: [{
|
where: [{
|
||||||
id: note.threadId || note.id,
|
threadId: note.threadId,
|
||||||
}, {
|
|
||||||
threadId: note.threadId || note.id,
|
|
||||||
}],
|
}],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -49,7 +47,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
await NoteThreadMutings.insert({
|
await NoteThreadMutings.insert({
|
||||||
id: genId(),
|
id: genId(),
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
threadId: note.threadId || note.id,
|
threadId: note.threadId,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -35,7 +35,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
await NoteThreadMutings.delete({
|
await NoteThreadMutings.delete({
|
||||||
threadId: note.threadId || note.id,
|
threadId: note.threadId,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -364,7 +364,7 @@ export default async (user: { id: User['id']; username: User['username']; host:
|
||||||
if (data.reply.userHost === null) {
|
if (data.reply.userHost === null) {
|
||||||
const threadMuted = await NoteThreadMutings.findOneBy({
|
const threadMuted = await NoteThreadMutings.findOneBy({
|
||||||
userId: data.reply.userId,
|
userId: data.reply.userId,
|
||||||
threadId: data.reply.threadId || data.reply.id,
|
threadId: data.reply.threadId,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!threadMuted) {
|
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[]) {
|
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({
|
const insert = new Note({
|
||||||
id: genId(data.createdAt!),
|
id,
|
||||||
createdAt: data.createdAt!,
|
createdAt: data.createdAt!,
|
||||||
fileIds: data.files ? data.files.map(file => file.id) : [],
|
fileIds: data.files ? data.files.map(file => file.id) : [],
|
||||||
replyId: data.reply ? data.reply.id : null,
|
replyId: data.reply ? data.reply.id : null,
|
||||||
renoteId: data.renote ? data.renote.id : null,
|
renoteId: data.renote ? data.renote.id : null,
|
||||||
channelId: data.channel ? data.channel.id : null,
|
channelId: data.channel ? data.channel.id : null,
|
||||||
threadId: data.reply
|
threadId: data.reply?.threadId ?? id,
|
||||||
? data.reply.threadId
|
|
||||||
? data.reply.threadId
|
|
||||||
: data.reply.id
|
|
||||||
: null,
|
|
||||||
name: data.name,
|
name: data.name,
|
||||||
text: data.text,
|
text: data.text,
|
||||||
hasPoll: data.poll != null,
|
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))) {
|
for (const u of mentionedUsers.filter(u => Users.isLocalUser(u))) {
|
||||||
const threadMuted = await NoteThreadMutings.findOneBy({
|
const threadMuted = await NoteThreadMutings.findOneBy({
|
||||||
userId: u.id,
|
userId: u.id,
|
||||||
threadId: note.threadId || note.id,
|
threadId: note.threadId,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (threadMuted) {
|
if (threadMuted) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ export async function insertNoteUnread(userId: User['id'], note: Note, params: {
|
||||||
// スレッドミュート
|
// スレッドミュート
|
||||||
const threadMute = await NoteThreadMutings.findOneBy({
|
const threadMute = await NoteThreadMutings.findOneBy({
|
||||||
userId: userId,
|
userId: userId,
|
||||||
threadId: note.threadId || note.id,
|
threadId: note.threadId,
|
||||||
});
|
});
|
||||||
if (threadMute) return;
|
if (threadMute) return;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue