Update a contact on re-import rather than skipping it
#228 skipped a vCard whose UID the book already held. The reporter asked for the opposite on #174 and he is right: the reason to import a file a second time is usually that the first one was not right, so skipping means a corrected export corrects nothing. A merge, not a replacement. Properties the file carries overwrite what is here; properties it does not mention are left alone, so a phone number added in ihasmail after the first import survives a re-import of the original file. The cost is that a field genuinely deleted at the source stays here, which is the better way to be wrong -- the other way round loses work nobody asked to lose. Worth confirming with him rather than assuming. `addressBookIds` is left off the patch. The card is already in this book, so saying it again says nothing, and saying it on a card that is also in another book would move it. Creates and updates now share one batch budget. Stalwart counts every object in a /set together, so batching the halves separately would send 300 new and 300 changed as two calls of 300 and be refused for a limit of 500 that neither half exceeds. LDIF is untouched and still reports look-alikes without acting on them, since what it should match on is the question still open on #223. Both imports keep one answer shape so a caller need not know which it called; LDIF's `updated` is always 0, which is the honest number rather than a missing field. The message a vCard attached to a message shows changes with it: the newer copy now wins instead of being dropped, so it says the contact was brought up to date rather than that nothing was added. Refs #223.
This commit is contained in:
@@ -63,7 +63,7 @@ describe("importing an LDIF address book", () => {
|
||||
it("creates every entry in one call, not one call each", async () => {
|
||||
const sets = server();
|
||||
const n = await useContacts.getState().importLdif(TWO, "book1");
|
||||
expect(n).toEqual({ created: 2, skipped: 0, alike: 0 });
|
||||
expect(n).toEqual({ created: 2, updated: 0, alike: 0 });
|
||||
expect(sets).toHaveLength(1);
|
||||
expect(Object.keys(sets[0]!.create!)).toEqual(["c0", "c1"]);
|
||||
});
|
||||
@@ -105,7 +105,7 @@ describe("importing an LDIF address book", () => {
|
||||
it("skips entries too empty to be a person, and imports the rest", async () => {
|
||||
const sets = server();
|
||||
const n = await useContacts.getState().importLdif(`${TWO}\ndn: cn=Nobody\nobjectClass: top\n`, "book1");
|
||||
expect(n).toEqual({ created: 2, skipped: 0, alike: 0 });
|
||||
expect(n).toEqual({ created: 2, updated: 0, alike: 0 });
|
||||
expect(Object.keys(sets[0]!.create!)).toHaveLength(2);
|
||||
});
|
||||
|
||||
@@ -116,6 +116,6 @@ describe("importing an LDIF address book", () => {
|
||||
|
||||
it("counts what got in when only some of it did", async () => {
|
||||
server({ notCreated: { c1: { type: "invalidProperties" } } });
|
||||
await expect(useContacts.getState().importLdif(TWO, "book1")).resolves.toEqual({ created: 1, skipped: 0, alike: 0 });
|
||||
await expect(useContacts.getState().importLdif(TWO, "book1")).resolves.toEqual({ created: 1, updated: 0, alike: 0 });
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user