Template
Extract always-on public/portal/UTM plus optional email_sms, directmail, blog, payments, social, and social_ai so new client sites can be bootstrapped from this seed. Refs #1 Refs #2 Co-authored-by: Cursor <cursoragent@cursor.com>
58 lines
1.4 KiB
Python
58 lines
1.4 KiB
Python
"""Register portal nav, dashboard widgets, and due-work dispatch."""
|
|
|
|
from django.utils import timezone
|
|
|
|
from core.registry import (
|
|
register_dashboard_collector,
|
|
register_dispatcher,
|
|
register_feature,
|
|
register_portal_nav,
|
|
)
|
|
|
|
|
|
def register() -> None:
|
|
register_feature("social")
|
|
register_portal_nav(
|
|
section="social",
|
|
label="Compose & preview",
|
|
url_name="social:composer",
|
|
group="Social",
|
|
order=10,
|
|
)
|
|
register_portal_nav(
|
|
section="social_accounts",
|
|
label="Accounts",
|
|
url_name="social:account_list",
|
|
group="Social",
|
|
order=20,
|
|
)
|
|
register_dashboard_collector(_dashboard)
|
|
register_dispatcher(_dispatch_due)
|
|
|
|
|
|
def _dashboard(request) -> dict:
|
|
from social.models import SocialPost
|
|
|
|
return {
|
|
"scheduled_posts": SocialPost.objects.filter(
|
|
status__in=[SocialPost.Status.SCHEDULED, SocialPost.Status.QUEUED]
|
|
).count()
|
|
}
|
|
|
|
|
|
def _dispatch_due() -> int:
|
|
from social.models import SocialPost
|
|
from social.tasks import publish_social_post
|
|
|
|
now = timezone.now()
|
|
enqueued = 0
|
|
for post in SocialPost.objects.filter(
|
|
status=SocialPost.Status.SCHEDULED,
|
|
scheduled_for__lte=now,
|
|
).iterator():
|
|
post.status = SocialPost.Status.QUEUED
|
|
post.save(update_fields=["status", "updated_at"])
|
|
publish_social_post.enqueue(post_id=str(post.pk))
|
|
enqueued += 1
|
|
return enqueued
|