Skip to content

angee.parties.models

Source models for the parties addon.

Parties are the people and organisations a project keeps track of. A party is reached through one or more :class:Handle rows (an email address, a phone number, a social handle) — the same handle that messaging uses as a participant, so this addon is the contacts foundation the messaging addon builds on. The link between a party and a handle is itself confidence-bearing (:class:PartyHandle) so a sync can record an uncertain match as a weak candidate instead of guessing.

Party is a multi-table-inheritance parent; the concrete kind is the child model (:class:Person, :class:Organization), not a column — a person carries name parts and a link to its :class:~angee.iam.models.User, an organisation carries its legal name and domain.

Party

python
class Party(SqidMixin, AuditMixin, AngeeModel)

A person or organisation the project tracks.

The parent owns the common contact identity — the public id, ownership, the display name, avatar, notes, and the lossless-vCard carriers. The concrete kind (and its kind-specific fields) lives on the :class:Person / :class:Organization child row.

Meta

python
class Meta()

Django model options for the party source model.

__str__

python
def __str__() -> str

Return the party's display name for Django displays.

Person

python
class Person(AngeeModel)

A human party — carries name parts and an optional platform-user link.

Meta

python
class Meta()

Django model options for the person child model.

Organization

python
class Organization(AngeeModel)

An organisation party — carries its legal name and primary domain.

Meta

python
class Meta()

Django model options for the organization child model.

Handle

python
class Handle(SqidMixin, AuditMixin, AngeeModel)

A reachable address or handle of a party on one platform.

Keyed on (platform, value) and, when present, (platform, external_id) — those unique constraints are the ingestion-dedup keys that make re-sync idempotent. party is the resolved owner the :class:PartyHandle manager materialises; it is null until a handle is linked, so a handle synced for an unknown sender is still a valid row.

Platform

python
class Platform(models.TextChoices)

The kind of channel a handle reaches a party through.

Meta

python
class Meta()

Django model options for the handle source model.

__str__

python
def __str__() -> str

Return the handle value for Django displays.

resolved_confidence

python
@property
def resolved_confidence() -> float | None

Confidence of the link that resolved this handle's owner.

party is materialised from the winning :class:PartyHandle (see :meth:PartyHandleManager.resolve) and (party, handle) is unique, so the link matching the resolved party is that winner — its score is the resolution confidence. None when the handle is unowned or, under actor-scoped loading, the resolving link is not readable by the actor.

PartyHandle

python
class PartyHandle(SqidMixin, AuditMixin, AngeeModel)

A confidence-bearing link between a party and one of its handles.

A handle may carry several scored candidate parties, so a sync can surface an uncertain match as a weak link (a conflicting claim is recorded at 0.3 confidence) instead of silently reassigning. The resolved owner is the highest-confidence, non-dismissed link — the value the manager materialises onto :attr:Handle.party.

Source

python
class Source(models.TextChoices)

Where a party↔handle link came from.

Meta

python
class Meta()

Django model options for the party-handle link source model.

__str__

python
def __str__() -> str

Return a readable link description for Django displays.

Address

python
class Address(SqidMixin, AuditMixin, AngeeModel)

A physical or postal address of a party (the vCard ADR property).

There is intentionally no (party, label) uniqueness — a party may carry two same-labelled addresses — so a CardDAV mapper keys idempotency on the address content, not the label.

Meta

python
class Meta()

Django model options for the address source model.

__str__

python
def __str__() -> str

Return a one-line address for Django displays.

Affiliation

python
class Affiliation(SqidMixin, AuditMixin, AngeeModel)

A party's membership of an organisation (the vCard ORG/TITLE/ROLE).

The organisation is an organisation-kind :class:Party when known, falling back to a free-text organization_name when the organisation is not itself a tracked party.

Meta

python
class Meta()

Django model options for the affiliation source model.

__str__

python
def __str__() -> str

Return the affiliation title/org for Django displays.

Folder

python
class Folder(SqidMixin, AuditMixin, AngeeModel)

A group of parties — the local mirror of a synced address book.

The contacts counterpart of storage's Drive/Folder and knowledge's Vault container idea, kept to exactly what sync needs today: the directory it mirrors, the collection source_href (one folder per (directory, source_href) makes the folder upsert idempotent), and the incremental cursors (ctag / sync_token). Owned via created_by; deleting a folder leaves its parties (SET_NULL on :attr:Party.folder). Manual creation and a folder tree (parent) are deferred until a create path lands to exercise them.

Meta

python
class Meta()

Django model options for the folder source model.

__str__

python
def __str__() -> str

Return the folder name for Django displays.

Directory

python
class Directory(Bridge)

A connected contacts source that syncs parties from an external directory.

An integrate.Integration child (so it draws its credential / owner / status from the connection substrate) and a Bridge (so the scheduler and the eager syncIntegration mutation drive it). backend_class selects the protocol — carddav (contributed by parties_integrate_carddav) — and config carries the source URL. sync() fetches + parses the source, then maps each contact onto the parties managers.

backend_class

Registry key for the directory backend bound to this directory.

Meta

python
class Meta()

Django model options for the directory child model.

backend

python
@property
def backend() -> DirectoryBackend

Return this directory's selected backend, bound to this row.

sync

python
def sync() -> int

Discover address books and resolve every contact into parties (the Bridge contract).

Idempotent: each address book mirrors to one :class:Folder (keyed by its source_href), every contact upserts by (folder, source_uid), and a contact that vanished from the source is purged from its folder — so a re-sync converges to the source instead of duplicating it. A collection whose ctag is unchanged is skipped wholesale.

Released under the AGPL-3.0 License.