Add Django site, Docker packaging, and beta/prod Gitea deploys.
Unignore site/ (was blocked by mkdocs /site rule), add compose/Docker/uv tooling, and split deploys so push to main goes to beta while prod stays manual.
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class CoreConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "core"
|
||||
@@ -0,0 +1,38 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils import timezone
|
||||
|
||||
from messaging.models import Message
|
||||
from messaging.tasks import send_campaign_message
|
||||
from social.models import SocialPost
|
||||
from social.tasks import publish_social_post
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = (
|
||||
"Enqueue due scheduled campaign messages and social posts. "
|
||||
"Optional when the task backend supports run_after defer; useful as a safety net."
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
now = timezone.now()
|
||||
enqueued = 0
|
||||
|
||||
for message in Message.objects.filter(
|
||||
status=Message.Status.SCHEDULED,
|
||||
scheduled_for__lte=now,
|
||||
).iterator():
|
||||
message.status = Message.Status.QUEUED
|
||||
message.save(update_fields=["status", "updated_at"])
|
||||
send_campaign_message.enqueue(message_id=str(message.pk))
|
||||
enqueued += 1
|
||||
|
||||
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
|
||||
|
||||
self.stdout.write(self.style.SUCCESS(f"Enqueued {enqueued} due item(s)."))
|
||||
@@ -0,0 +1,20 @@
|
||||
import uuid
|
||||
|
||||
from django.db import models
|
||||
|
||||
|
||||
class TimeStampedModel(models.Model):
|
||||
"""Abstract base with created/updated timestamps (mirrors company_site TimeInfoBase)."""
|
||||
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class UUIDPrimaryKeyModel(models.Model):
|
||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
@@ -0,0 +1,29 @@
|
||||
from django.test import Client, TestCase, override_settings
|
||||
from django.urls import reverse
|
||||
|
||||
|
||||
class HealthzTests(TestCase):
|
||||
def test_healthz_ok(self):
|
||||
response = Client().get("/healthz/")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.json()["status"], "ok")
|
||||
|
||||
|
||||
class UnderConstructionTests(TestCase):
|
||||
@override_settings(SITE_UNDER_CONSTRUCTION=True)
|
||||
def test_home_redirects_when_gated(self):
|
||||
response = Client().get("/")
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertIn("/under-construction", response["Location"])
|
||||
|
||||
@override_settings(SITE_UNDER_CONSTRUCTION=False)
|
||||
def test_home_ok_when_open(self):
|
||||
response = Client().get("/")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
|
||||
class PublicSmokeTests(TestCase):
|
||||
def test_about_and_contact_get(self):
|
||||
client = Client()
|
||||
self.assertEqual(client.get(reverse("public:about")).status_code, 200)
|
||||
self.assertEqual(client.get(reverse("public:contact")).status_code, 200)
|
||||
@@ -0,0 +1,6 @@
|
||||
from django.http import JsonResponse
|
||||
|
||||
|
||||
def healthz(_request):
|
||||
"""Liveness probe for deploy / NPM health checks."""
|
||||
return JsonResponse({"status": "ok"})
|
||||
Reference in New Issue
Block a user