mirror of
https://github.com/paricafe/misskey.git
synced 2024-11-28 09:36:43 -06:00
chore: tweak note update handler
to prevent possible version corruption caused by deliver delay
This commit is contained in:
parent
678aa493de
commit
7dc31a3ac1
3 changed files with 49 additions and 17 deletions
|
@ -68,6 +68,15 @@ export class NoteUpdateService {
|
||||||
* @param ps New note info
|
* @param ps New note info
|
||||||
*/
|
*/
|
||||||
async update(user: { id: MiUser['id']; uri: MiUser['uri']; host: MiUser['host']; isBot: MiUser['isBot']; }, note: MiNote, ps: Pick<MiNote, 'text' | 'cw' | 'updatedAt'>, quiet = false, updater?: MiUser) {
|
async update(user: { id: MiUser['id']; uri: MiUser['uri']; host: MiUser['host']; isBot: MiUser['isBot']; }, note: MiNote, ps: Pick<MiNote, 'text' | 'cw' | 'updatedAt'>, quiet = false, updater?: MiUser) {
|
||||||
|
if (!ps.updatedAt) {
|
||||||
|
throw new Error('update time is required');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (note.history?.findIndex(h => h.createdAt === ps.updatedAt?.toISOString()) !== -1) {
|
||||||
|
// Same history already exists, skip this
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const newNote = {
|
const newNote = {
|
||||||
...note,
|
...note,
|
||||||
...ps, // Overwrite updated fields
|
...ps, // Overwrite updated fields
|
||||||
|
@ -90,18 +99,33 @@ export class NoteUpdateService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.searchService.indexNote(newNote);
|
// Check if is latest or previous version
|
||||||
|
const history = [...(note.history || []), {
|
||||||
await this.notesRepository.update({ id: note.id }, {
|
|
||||||
updatedAt: ps.updatedAt,
|
|
||||||
history: [...(note.history || []), {
|
|
||||||
createdAt: (note.updatedAt || this.idService.parse(note.id).date).toISOString(),
|
createdAt: (note.updatedAt || this.idService.parse(note.id).date).toISOString(),
|
||||||
cw: note.cw,
|
cw: note.cw,
|
||||||
text: note.text,
|
text: note.text,
|
||||||
}],
|
}];
|
||||||
|
if (note.updatedAt && note.updatedAt >= ps.updatedAt) {
|
||||||
|
// Previous version, just update history
|
||||||
|
history.sort((h1, h2) => new Date(h1.createdAt).getTime() - new Date(h2.createdAt).getTime()); // earliest -> latest
|
||||||
|
|
||||||
|
await this.notesRepository.update({ id: note.id }, {
|
||||||
|
history,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Latest version
|
||||||
|
|
||||||
|
// Update index
|
||||||
|
this.searchService.indexNote(newNote);
|
||||||
|
|
||||||
|
// Update note info
|
||||||
|
await this.notesRepository.update({ id: note.id }, {
|
||||||
|
updatedAt: ps.updatedAt,
|
||||||
|
history,
|
||||||
cw: ps.cw,
|
cw: ps.cw,
|
||||||
text: ps.text,
|
text: ps.text,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Currently not implemented
|
// Currently not implemented
|
||||||
// if (updater && (note.userId !== updater.id)) {
|
// if (updater && (note.userId !== updater.id)) {
|
||||||
|
|
|
@ -335,17 +335,22 @@ export class ApNoteService {
|
||||||
const uri = typeof value === 'string' ? value : value.id;
|
const uri = typeof value === 'string' ? value : value.id;
|
||||||
if (uri == null) throw new Error('uri is null');
|
if (uri == null) throw new Error('uri is null');
|
||||||
|
|
||||||
// Is from local
|
// Check if note is from local
|
||||||
if (uri.startsWith(`${this.config.url}/`)) throw new Error('uri points local');
|
if (uri.startsWith(`${this.config.url}/`)) throw new Error('uri points local');
|
||||||
|
|
||||||
const originNote = await this.notesRepository.findOneBy({ uri });
|
const originNote = await this.notesRepository.findOneBy({ uri });
|
||||||
if (originNote == null) throw new Error('Note is not registered');
|
if (originNote === null) throw new Error('note is not registered');
|
||||||
|
|
||||||
// Process new note
|
// Process new note
|
||||||
const note = value as IPost;
|
const note = value as IPost;
|
||||||
|
|
||||||
|
// Check updated timestamp
|
||||||
|
if (!note.updated) {
|
||||||
|
throw new Error('note.updated field is required');
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch note author
|
// Fetch note author
|
||||||
if (note.attributedTo == null) {
|
if (!note.attributedTo) {
|
||||||
throw new Error('invalid note.attributedTo: ' + note.attributedTo);
|
throw new Error('invalid note.attributedTo: ' + note.attributedTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,12 +368,10 @@ export class ApNoteService {
|
||||||
text = this.apMfmService.htmlToMfm(note.content, note.tag);
|
text = this.apMfmService.htmlToMfm(note.content, note.tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedAt = note.updated || new Date();
|
|
||||||
|
|
||||||
await this.noteUpdateService.update(actor, originNote, {
|
await this.noteUpdateService.update(actor, originNote, {
|
||||||
cw,
|
cw,
|
||||||
text,
|
text,
|
||||||
updatedAt,
|
updatedAt: note.updated,
|
||||||
}, silent);
|
}, silent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw new ApiError(meta.errors.noSuchNote);
|
throw new ApiError(meta.errors.noSuchNote);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (note.text === ps.text && note.cw === ps.cw) {
|
||||||
|
// The same as old note, nothing to do
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await this.noteUpdateService.update(await this.usersRepository.findOneByOrFail({ id: note.userId }), note, {
|
await this.noteUpdateService.update(await this.usersRepository.findOneByOrFail({ id: note.userId }), note, {
|
||||||
text: ps.text,
|
text: ps.text,
|
||||||
cw: ps.cw,
|
cw: ps.cw,
|
||||||
|
|
Loading…
Reference in a new issue