mirror of
https://github.com/bulwarkmail/native.git
synced 2026-10-31 16:06:32 +00:00
fix: upload a contact's removal from a group made on the phone #34
Whether a membership edit still has to go up is decided against the group cards on the server, which the engine indexes from their shadows. The index was only read before planning a download that held contacts, so in a run that downloaded no contact, such as the upload sync after an edit, it was empty: removing a contact from a group looked already done on the server, the contact was marked clean and the removal was never sent. The engine now reads the index before planning uploads too.
This commit is contained in:
@@ -185,6 +185,24 @@ describe('device sync engine with the real planners', () => {
|
||||
const uid = h.server.get('ContactCard', 'a', ada)!.uid as string;
|
||||
expect(h.server.get('ContactCard', 'a', group)!.members).toEqual({ [uid]: true });
|
||||
});
|
||||
|
||||
it('uploads a removal from a group in a run that downloads no contact', async () => {
|
||||
const h = real();
|
||||
// A keyed phone row shows the editor works in place, so a missing membership row is a removal.
|
||||
h.server.addCard('a', { uid: 'ada-uid', name: { full: 'Ada Lovelace' }, phones: { p1: { '@type': 'Phone', number: '+1 111' } } });
|
||||
const group = h.server.addCard('a', { uid: 'g1', kind: 'group', name: { full: 'Friends' }, members: { 'ada-uid': true } });
|
||||
await h.run();
|
||||
const contact = h.contactNamed('Ada Lovelace')!;
|
||||
const membership = h.device.rows('data').find((d) => Number(d.raw_contact_id) === contact.id && d.mimetype === MimeType.GROUP_MEMBERSHIP)!;
|
||||
h.device.user.deleteData(Number(membership._id));
|
||||
|
||||
// The upload sync Android requests after the edit: the server has nothing new.
|
||||
expect((await h.run(CONTACTS_AUTHORITY, { upload: true })).outcome).toBe('ok');
|
||||
|
||||
expect(h.server.get('ContactCard', 'a', group)!.members ?? {}).toEqual({});
|
||||
expect(h.contacts().find((c) => c.id === contact.id)).toMatchObject({ dirty: false });
|
||||
expect(h.device.rows('data').filter((d) => d.mimetype === MimeType.GROUP_MEMBERSHIP)).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('a device edit of an object the server moved out of every synced collection', () => {
|
||||
|
||||
@@ -576,8 +576,14 @@ export class ContactsSync extends ItemSync {
|
||||
for (const held of items) if (held.kind === this.contactKind) rows.add(held.kind.meta(held.local).rowId);
|
||||
}
|
||||
|
||||
/** The device photo of every contact about to be planned that has a photo row (JPEG, ≤ 512 px). */
|
||||
/**
|
||||
* The group index `groupsOf` answers from (a run that downloaded no
|
||||
* contact never read it: every removal from a group would look done), and
|
||||
* the device photo of every contact about to be planned that has a photo
|
||||
* row (JPEG, ≤ 512 px).
|
||||
*/
|
||||
protected async beforeUploadPlanning(items: Held[]): Promise<void> {
|
||||
if (this.groupsStale && items.some((held) => held.kind === this.contactKind)) await this.refreshGroups();
|
||||
for (const held of items) {
|
||||
if (held.kind !== this.contactKind) continue;
|
||||
const contact = held.local as LocalContact;
|
||||
|
||||
Reference in New Issue
Block a user