angee.social.models
Source models for the social addon — public feeds, engagement, and following.
Social is the public-social surface layered on messaging. It reuses the one idempotent Message.objects.ingest write path (a public post is a messaging.Message in a messaging.Thread) and adds the social overlay:
- :class:
Feed— anintegrate.Integrationchild +Bridge(exactly likemessaging.Channel) that polls an external platform for public posts; itsFeedBackenddoes the transport+parse, andsync()maps each post onto the messaging ingest, then overlays engagement. - :class:
FeedFollow— the following / timeline subscription edge. - :class:
PostMetrics— rolled-up public engagement counts for a message. - per-actor social reactions (like / repost / emoji) reuse the single
messaging.Reactiontable — social writeslike/repostas reaction values on the sharedmessaging.Messagerather than owning a parallel table. - :class:
Quota— the per-handle, per-platform API-unit ledger feed backends spend. - :class:
ThreadPublic/ :class:MessagePublic— the public-thread fields social contributes ontomessaging.Thread/messaging.Messagethrough the same-rowextendsseam.
The dependency points one way (social → messaging → parties/integrate/storage); social never edits or forks messaging.
Feed
class Feed(Bridge)A connected public-content source that polls an external platform for posts.
An integrate.Integration child (identity / credential / status / owner from the connection substrate) and a Bridge (the scheduler + run_sync drive it through sync; integrate.scheduler.run_due_bridges auto-discovers any concrete Bridge subclass, so no registration is needed). backend_class selects the platform — youtube / facebook are contributed by downstream social_integrate_* addons; manual is the neutral null-object.
A paused feed carries a NULL next_sync_at (not scheduled); activating it schedules the first poll. handle is the parties.Handle the feed monitors and posts as (its OAuth token lives on the handle / the integration credential).
backend_class
Registry key for the feed backend bound to this feed.
external_id
The external channel/page/account id this feed follows on its platform.
Meta
class Meta()Django model options for the feed child model.
backend
@property
def backend() -> FeedBackendReturn this feed's selected backend, bound to this row.
sync
def sync() -> intFetch new posts, ingest their message core, and overlay engagement.
The message core (thread/message/parts) is the messaging owner's job, so a public post shares email's one idempotent write path; social only writes the overlay it owns (public payload / metrics / reactions / social edges). The ingest is told the facts a public feed differs on, each set through the messaging owner rather than bulk-patched afterward: every thread is born a PUBLIC_THREAD with PUBLIC visibility, each message lands under the COMMENT kind (a public post, not email), and the RFC-5322 quotation builder is skipped (quote_edges=False) so a post's short shared text does not mint spurious email quote edges.
FeedFollow
class FeedFollow(SqidMixin, AuditMixin, AngeeModel)A follow of a :class:Feed by a parties.Handle — the timeline subscription.
The following edge behind a public timeline: a handle subscribes to a feed's posts. ended_at closes a follow (an open/closed interval), so unfollowing is an update, not a delete, and the history is retained. The timeline itself is the derived join FeedFollow → Feed → Thread → Message (a downstream query owner).
Meta
class Meta()Django model options for the feed-follow source model.
__str__
def __str__() -> strReturn a readable follow label for Django displays.
PostMetrics
class PostMetrics(SqidMixin, AuditMixin, AngeeModel)Rolled-up public engagement counts for one message (the platform snapshot).
Flat one-to-one, not MTI — the counter set overlaps heavily across platforms; platform extras go in metadata. Counters are overwritten with the latest platform snapshot (no F() delta), so the feed sync is the single writer.
Meta
class Meta()Django model options for the post-metrics source model.
__str__
def __str__() -> strReturn a readable metrics label for Django displays.
Quota
class Quota(SqidMixin, AuditMixin, AngeeModel)A per-handle, per-platform API-unit ledger for one billing period.
Feed backends spend platform API units (search, list, insert) against a per-period budget; :meth:~angee.social.managers.QuotaManager.consume atomically debits this ledger and refuses when the budget is insufficient. Enforcement is cooperative — the backend must ask before it spends.
Meta
class Meta()Django model options for the quota source model.
__str__
def __str__() -> strReturn a readable quota label for Django displays.
ThreadPublic
class ThreadPublic(AngeeModel)Public-post payload fields social contributes onto messaging.Thread (same row).
A public thread's row is its subject post: subject_url/body/tags carry the post payload and parent nests a thread under another (a reply/quote thread). These have no producer in base messaging, so social owns them; the structural modality/visibility discriminators stay owned by messaging.
Meta
class Meta()Abstract same-row extension composed into messaging.Thread.
MessagePublic
class MessagePublic(AngeeModel)Public-post fields social contributes onto messaging.Message (same row).
is_original_post marks the root post of a public thread (a post with no parent). It has no producer in base messaging, so social owns it and the composer folds it onto the single messaging.Message table.
Meta
class Meta()Abstract same-row extension composed into messaging.Message.