Skip to content

angee.parties.managers

Managers that own the directory-sync write path for parties.

A directory backend parses a source into neutral ParsedContact rows; these managers turn one into a Party (a Person) and its Handle / PartyHandle / Address rows. A contact is keyed by its source UID within its folder (the idempotent (folder, source_uid) upsert), handles dedupe on (platform, value), and handle_count plus the resolved Handle.party are maintained here in the same transaction — so every directory source shares one write path (the map lives on the models, not in each backend) and a re-sync converges instead of duplicating. The sync runs under system_context, so created_by is set explicitly to the directory owner.

HandleManager

python
class HandleManager(AngeeManager)

Factory + upsert for handles (the contact-point write path).

upsert

python
def upsert(*,
           platform: str,
           value: str,
           owner_id: Any = None,
           **fields: Any) -> Any

Get-or-create a handle by its (platform, value) dedup key, refreshing display fields.

PartyHandleManager

python
class PartyHandleManager(AngeeManager)

Owns the confidence link between a party and a handle, and the resolution.

python
def link(party: Any,
         handle: Any,
         *,
         confidence: float = 1.0,
         source: str = "manual",
         owner_id: Any = None) -> Any

Link handle to party with confidence, then resolve the handle's owner.

Resolution only re-runs when the link is new or the handle's owner is not already this party, so a re-sync of an unchanged contact does no extra work.

resolve

python
def resolve(handle: Any) -> None

Materialise handle.party to the highest-confidence, non-dismissed link.

The resolution ordering (-is_confirmed, -confidence) is the contacts rule: a human-confirmed link wins, then the strongest score. A handle with no surviving link is left unowned.

PartyManager

python
class PartyManager(AngeeManager)

Factory for parties, including the idempotent directory-sync ingest.

ingest_contact

python
def ingest_contact(parsed: ParsedContact, *, folder: Any,
                   owner_id: Any) -> Any

Upsert a person and its handles/addresses from one parsed contact.

Keyed on (folder, source_uid) so a re-sync updates the same row instead of forking a duplicate, and the whole contact is written in one transaction so a partial card is never half-applied. Emails/phones still upsert as shared Handle rows and link to the person, but the person's identity is the source UID, not handle overlap. A contact with no source_uid has no stable key and is skipped — without it the (folder, "") upsert would collapse every keyless card onto one row.

purge_missing

python
def purge_missing(*, folder: Any, keep_uids: set[str]) -> int

Delete the folder's synced parties whose source UID is no longer present.

This is how a contact deleted on the source is mirrored locally: anything in folder carrying a source_uid not in keep_uids is removed (the MTI child cascades with its parent). A handle shared with a surviving party is re-resolved afterwards, since its link to the deleted party cascades away.

Released under the AGPL-3.0 License.