fix: keep favourites and joins when the server refuses an edit #34

When the server refused an edit made on the device (a book or calendar
that turned read-only, an event in a calendar where only one's own
events may be changed), the engine put the item back by deleting its
rows and inserting a fresh copy. A contact lost its star, ringtone and
the link to the contacts it was joined with; an event got a new row id.

The rows are now rewritten in place from the server's version, as after
an accepted upload. A refused deletion still brings the item back as a
new copy.
This commit is contained in:
Linus Rath
2026-09-27 07:53:36 +02:00
parent 2e9e5bb785
commit 7701a67dff
2 changed files with 76 additions and 0 deletions
+19
View File
@@ -1390,6 +1390,8 @@ export abstract class ItemSync {
}];
}
await this.beforePlanning(acct, [object]);
// An edit is undone in place, so what only the device keeps stays: a star, a ringtone, a joined contact, row ids.
if (objectKind === kind && !p.meta.deleted) return [this.overwriteWork(acct, kind, local, object)];
const insert = objectKind.planDownload(object, null, acct);
return [{
group: concatGroups(ref, remove, insert.ops),
@@ -1398,6 +1400,23 @@ export abstract class ItemSync {
}];
}
/** The rows become `object` where they are and DIRTY is cleared (the planner's write of an accepted version). */
private overwriteWork(acct: string, kind: Kind, local: unknown, object: ServerObject): Work {
return {
group: kind.planAccepted(local, object, acct).ops,
state: this.listing(kind, acct, object.id, true),
applied: () => this.onDownloaded(kind, acct, object),
replan: async () => {
const again = await this.reload(kind, local);
return again === null ? null : this.overwriteWork(acct, kind, again, object);
},
failed: (reason, message) => {
this.markStale(acct, object.id);
this.env.report.itemError({ ref: refOf(acct, object.id), side: 'upload', type: reason, description: message });
},
};
}
/**
* `invalidProperties` on `uid`: the object exists (a lost response, or the
* client's automatic retry of the create). Cards name it in the error;