upd: improve note edit table & improve previous version view
Closes transfem-org/Sharkey#105
This commit is contained in:
parent
6b3b805a3e
commit
d50e81e475
8 changed files with 463 additions and 101 deletions
13
packages/backend/migration/1697970083000-alterNoteEdit.js
Normal file
13
packages/backend/migration/1697970083000-alterNoteEdit.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
export class AlterNoteEdit1697970083000 {
|
||||
name = "AlterNoteEdit1697970083000";
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "note_edit" RENAME COLUMN "text" TO "newText"`);
|
||||
await queryRunner.query(`ALTER TABLE "note_edit" ADD COLUMN "oldText" text`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "note_edit" RENAME COLUMN "newText" TO "text"`);
|
||||
await queryRunner.query(`ALTER TABLE "note_edit" DROP COLUMN "oldText"`);
|
||||
}
|
||||
}
|
|
@ -387,104 +387,109 @@ export class NoteEditService implements OnApplicationShutdown {
|
|||
update.hasPoll = !!data.poll;
|
||||
}
|
||||
|
||||
await this.noteEditRepository.insert({
|
||||
id: this.idService.gen(),
|
||||
noteId: oldnote.id,
|
||||
text: data.text || undefined,
|
||||
cw: data.cw,
|
||||
fileIds: undefined,
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
const note = new MiNote({
|
||||
id: oldnote.id,
|
||||
updatedAt: data.updatedAt ? data.updatedAt : new Date(),
|
||||
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,
|
||||
name: data.name,
|
||||
text: data.text,
|
||||
hasPoll: data.poll != null,
|
||||
cw: data.cw ?? null,
|
||||
tags: tags.map(tag => normalizeForSearch(tag)),
|
||||
emojis,
|
||||
reactions: oldnote.reactions,
|
||||
userId: user.id,
|
||||
localOnly: data.localOnly!,
|
||||
reactionAcceptance: data.reactionAcceptance,
|
||||
visibility: data.visibility as any,
|
||||
visibleUserIds: data.visibility === 'specified'
|
||||
? data.visibleUsers
|
||||
? data.visibleUsers.map(u => u.id)
|
||||
: []
|
||||
: [],
|
||||
|
||||
attachedFileTypes: data.files ? data.files.map(file => file.type) : [],
|
||||
|
||||
// 以下非正規化データ
|
||||
replyUserId: data.reply ? data.reply.userId : null,
|
||||
replyUserHost: data.reply ? data.reply.userHost : null,
|
||||
renoteUserId: data.renote ? data.renote.userId : null,
|
||||
renoteUserHost: data.renote ? data.renote.userHost : null,
|
||||
userHost: user.host,
|
||||
});
|
||||
|
||||
if (data.uri != null) note.uri = data.uri;
|
||||
if (data.url != null) note.url = data.url;
|
||||
|
||||
if (mentionedUsers.length > 0) {
|
||||
note.mentions = mentionedUsers.map(u => u.id);
|
||||
const profiles = await this.userProfilesRepository.findBy({ userId: In(note.mentions) });
|
||||
note.mentionedRemoteUsers = JSON.stringify(mentionedUsers.filter(u => this.userEntityService.isRemoteUser(u)).map(u => {
|
||||
const profile = profiles.find(p => p.userId === u.id);
|
||||
const url = profile != null ? profile.url : null;
|
||||
return {
|
||||
uri: u.uri,
|
||||
url: url ?? undefined,
|
||||
username: u.username,
|
||||
host: u.host,
|
||||
} as IMentionedRemoteUsers[0];
|
||||
}));
|
||||
}
|
||||
|
||||
if (data.poll != null) {
|
||||
// Start transaction
|
||||
await this.db.transaction(async transactionalEntityManager => {
|
||||
await transactionalEntityManager.update(MiNote, oldnote.id, note);
|
||||
|
||||
const poll = new MiPoll({
|
||||
noteId: note.id,
|
||||
choices: data.poll!.choices,
|
||||
expiresAt: data.poll!.expiresAt,
|
||||
multiple: data.poll!.multiple,
|
||||
votes: new Array(data.poll!.choices.length).fill(0),
|
||||
noteVisibility: note.visibility,
|
||||
userId: user.id,
|
||||
userHost: user.host,
|
||||
});
|
||||
|
||||
if (!oldnote.hasPoll) {
|
||||
await transactionalEntityManager.insert(MiPoll, poll);
|
||||
} else {
|
||||
await transactionalEntityManager.update(MiPoll, oldnote.id, poll);
|
||||
}
|
||||
if (Object.keys(update).length > 0) {
|
||||
await this.noteEditRepository.insert({
|
||||
id: this.idService.gen(),
|
||||
noteId: oldnote.id,
|
||||
oldText: update.text ? oldnote.text : undefined,
|
||||
newText: update.text || undefined,
|
||||
cw: update.cw || undefined,
|
||||
fileIds: undefined,
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
|
||||
const note = new MiNote({
|
||||
id: oldnote.id,
|
||||
updatedAt: data.updatedAt ? data.updatedAt : new Date(),
|
||||
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,
|
||||
name: data.name,
|
||||
text: data.text,
|
||||
hasPoll: data.poll != null,
|
||||
cw: data.cw ?? null,
|
||||
tags: tags.map(tag => normalizeForSearch(tag)),
|
||||
emojis,
|
||||
reactions: oldnote.reactions,
|
||||
userId: user.id,
|
||||
localOnly: data.localOnly!,
|
||||
reactionAcceptance: data.reactionAcceptance,
|
||||
visibility: data.visibility as any,
|
||||
visibleUserIds: data.visibility === 'specified'
|
||||
? data.visibleUsers
|
||||
? data.visibleUsers.map(u => u.id)
|
||||
: []
|
||||
: [],
|
||||
|
||||
attachedFileTypes: data.files ? data.files.map(file => file.type) : [],
|
||||
|
||||
// 以下非正規化データ
|
||||
replyUserId: data.reply ? data.reply.userId : null,
|
||||
replyUserHost: data.reply ? data.reply.userHost : null,
|
||||
renoteUserId: data.renote ? data.renote.userId : null,
|
||||
renoteUserHost: data.renote ? data.renote.userHost : null,
|
||||
userHost: user.host,
|
||||
});
|
||||
|
||||
if (data.uri != null) note.uri = data.uri;
|
||||
if (data.url != null) note.url = data.url;
|
||||
|
||||
if (mentionedUsers.length > 0) {
|
||||
note.mentions = mentionedUsers.map(u => u.id);
|
||||
const profiles = await this.userProfilesRepository.findBy({ userId: In(note.mentions) });
|
||||
note.mentionedRemoteUsers = JSON.stringify(mentionedUsers.filter(u => this.userEntityService.isRemoteUser(u)).map(u => {
|
||||
const profile = profiles.find(p => p.userId === u.id);
|
||||
const url = profile != null ? profile.url : null;
|
||||
return {
|
||||
uri: u.uri,
|
||||
url: url ?? undefined,
|
||||
username: u.username,
|
||||
host: u.host,
|
||||
} as IMentionedRemoteUsers[0];
|
||||
}));
|
||||
}
|
||||
|
||||
if (data.poll != null) {
|
||||
// Start transaction
|
||||
await this.db.transaction(async transactionalEntityManager => {
|
||||
await transactionalEntityManager.update(MiNote, oldnote.id, note);
|
||||
|
||||
const poll = new MiPoll({
|
||||
noteId: note.id,
|
||||
choices: data.poll!.choices,
|
||||
expiresAt: data.poll!.expiresAt,
|
||||
multiple: data.poll!.multiple,
|
||||
votes: new Array(data.poll!.choices.length).fill(0),
|
||||
noteVisibility: note.visibility,
|
||||
userId: user.id,
|
||||
userHost: user.host,
|
||||
});
|
||||
|
||||
if (!oldnote.hasPoll) {
|
||||
await transactionalEntityManager.insert(MiPoll, poll);
|
||||
} else {
|
||||
await transactionalEntityManager.update(MiPoll, oldnote.id, poll);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
await this.notesRepository.update(oldnote.id, note);
|
||||
}
|
||||
|
||||
setImmediate('post edited', { signal: this.#shutdownController.signal }).then(
|
||||
() => this.postNoteEdited(note, user, data, silent, tags!, mentionedUsers!),
|
||||
() => { /* aborted, ignore this */ },
|
||||
);
|
||||
|
||||
return note;
|
||||
} else {
|
||||
await this.notesRepository.update(oldnote.id, note);
|
||||
return oldnote;
|
||||
}
|
||||
|
||||
setImmediate('post edited', { signal: this.#shutdownController.signal }).then(
|
||||
() => this.postNoteEdited(note, user, data, silent, tags!, mentionedUsers!),
|
||||
() => { /* aborted, ignore this */ },
|
||||
);
|
||||
|
||||
return note;
|
||||
}
|
||||
|
||||
@bindThis
|
||||
|
|
|
@ -24,7 +24,12 @@ export class NoteEdit {
|
|||
@Column("text", {
|
||||
nullable: true,
|
||||
})
|
||||
public text: string | null;
|
||||
public oldText: string | null;
|
||||
|
||||
@Column("text", {
|
||||
nullable: true,
|
||||
})
|
||||
public newText: string | null;
|
||||
|
||||
@Column("varchar", {
|
||||
length: 512,
|
||||
|
|
|
@ -26,7 +26,12 @@ export const packedNoteEdit = {
|
|||
nullable: false,
|
||||
format: "id",
|
||||
},
|
||||
text: {
|
||||
oldText: {
|
||||
type: "string",
|
||||
optional: true,
|
||||
nullable: true,
|
||||
},
|
||||
newText: {
|
||||
type: "string",
|
||||
optional: true,
|
||||
nullable: true,
|
||||
|
|
|
@ -51,7 +51,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
for (const edit of edits) {
|
||||
editArray.push({
|
||||
updatedAt: new Date(edit.updatedAt).toLocaleString('UTC', { hour: 'numeric', minute: 'numeric', second: 'numeric', year: 'numeric', month: 'short', day: 'numeric' }),
|
||||
text: edit.text,
|
||||
text: edit.oldText,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue