Add proper email notifications

This commit is contained in:
2026-05-14 23:19:50 +03:00
parent fe62575790
commit 9e16b78793
34 changed files with 1313 additions and 83 deletions

View File

@@ -8,6 +8,7 @@ from __future__ import annotations
import uuid
import namesgenerator
from django.conf import settings
from django.core.validators import FileExtensionValidator
from django.db import models
@@ -178,6 +179,29 @@ class Submission(models.Model):
# dashboard index so post-submit redirects always land somewhere real.
return reverse("dashboard:index")
def save(self, *args, **kwargs):
"""Auto-generate `slug` on first save so any creation path -- admin,
`SubmitView`, fixtures, `objects.create()` -- gets a Docker-style
codename without callers having to remember to set one."""
if not self.slug:
self.slug = self._generate_unique_slug()
super().save(*args, **kwargs)
@classmethod
def _generate_unique_slug(cls, max_attempts: int = 16) -> str:
"""`namesgenerator.get_random_name` + collision retries in Python
(rather than a DB-side loop) so the rare collision path stays
observable. If the surrounding transaction still loses a race with
a concurrent insert, the DB's `unique=True` constraint fires an
`IntegrityError` and the caller can retry."""
for _ in range(max_attempts):
candidate = namesgenerator.get_random_name()
if not cls.objects.filter(slug=candidate).exists():
return candidate
# Fall through: extremely unlikely with the size of namesgenerator's
# adjective/surname space.
return namesgenerator.get_random_name()
# --- presentation helpers (consumed by dashboard templates) -------------
SOURCE_LABEL = {
@@ -201,6 +225,20 @@ class Submission(models.Model):
Status.FAILED: "bg-red-100 text-red-800",
}
# Same palette as STATUS_BADGE_CLASS but expressed as hex pairs because
# email clients strip <style> blocks and don't load external CSS, so the
# HTML email templates use inline `background-color` / `color`.
STATUS_EMAIL_COLORS = {
Status.IDENTIFYING: {"bg": "#fef3c7", "fg": "#92400e"}, # amber
Status.PROCESSING: {"bg": "#f1f5f9", "fg": "#334155"}, # slate
Status.VERIFYING: {"bg": "#ede9fe", "fg": "#5b21b6"}, # violet
Status.QUEUED: {"bg": "#dbeafe", "fg": "#1e40af"}, # blue
Status.PRINTING: {"bg": "#ffedd5", "fg": "#9a3412"}, # orange
Status.COMPLETED: {"bg": "#d1fae5", "fg": "#065f46"}, # emerald
Status.REJECTED: {"bg": "#fee2e2", "fg": "#991b1b"}, # red
Status.FAILED: {"bg": "#fee2e2", "fg": "#991b1b"}, # red
}
@property
def source_label(self) -> str:
return self.SOURCE_LABEL.get(self.source_type, self.source_type)
@@ -208,3 +246,9 @@ class Submission(models.Model):
@property
def status_badge_class(self) -> str:
return self.STATUS_BADGE_CLASS.get(self.status, "bg-slate-100 text-slate-700")
@property
def status_email_style(self) -> dict:
return self.STATUS_EMAIL_COLORS.get(
self.status, {"bg": "#f1f5f9", "fg": "#334155"}
)