feat(email): HTML branded templates with inline logo, wire remaining notification types
Aegis CI / lint-and-test (push) Has been cancelled
Snyk Security Scan / Python vulnerabilities (backend) (push) Has been cancelled
Snyk Security Scan / npm vulnerabilities (frontend) (push) Has been cancelled
Snyk Security Scan / Docker image vulnerabilities (backend) (push) Has been cancelled

- All webhook emails now render as branded HTML (dark header, inline base64
  Aegis logo, card layout, CTA-button links) instead of plain text.
- Wired the 7 remaining notification-preference keys that had no trigger:
  stale coverage alerts, campaign-activated assignment emails, generic
  test-state-change steps (execution started / blue evaluating / in review),
  all-team-validation broadcasts on every lead vote, webhook delivery
  failures (3rd consecutive failure), new user registration, and background
  job errors (APScheduler global error listener).
- New notify_roles_by_email() helper for role-scoped, preference-gated,
  actor-excludable broadcasts.
- Fixed apscheduler.events stubbing gaps in several test files' sys.modules
  fakes that broke full-suite collection after adding the APScheduler
  error-listener import.
This commit is contained in:
kitos
2026-07-20 11:49:21 +02:00
parent 1d0d880929
commit 91442ede60
21 changed files with 403 additions and 18 deletions
+13 -1
View File
@@ -124,7 +124,7 @@ from app.services.campaign_crud_service import (
from app.services.audit_service import log_action
# Import notify_role from app.services.notification_service
from app.services.notification_service import notify_role
from app.services.notification_service import notify_role, notify_roles_by_email
from app.services.webhook_service import dispatch_webhook
# Assign logger = logging.getLogger(__name__)
@@ -543,6 +543,12 @@ def approve_campaign_endpoint(
entity_id=campaign.id,
details={"start_date": payload.start_date},
)
notify_roles_by_email(
db, roles=["red_tech"],
preference_key="email_on_assigned_to_campaign",
subject=f"Campaign Activated: {campaign.name}",
message=f'Campaign "{campaign.name}" has been approved and activated. You may have tests assigned.',
)
uow.commit()
db.refresh(campaign)
@@ -868,6 +874,12 @@ def activate_campaign(
# Keyword argument: entity_id
entity_id=campaign.id,
)
notify_roles_by_email(
db, roles=["red_tech"],
preference_key="email_on_assigned_to_campaign",
subject=f"Campaign Activated: {campaign.name}",
message=f'Campaign "{campaign.name}" has been activated. You may have tests assigned.',
)
# Call log_action()
log_action(
db,
+12
View File
@@ -185,6 +185,18 @@ def create_user_route(
# Reload ORM object attributes from the database
db.refresh(user)
from app.services.notification_service import notify_roles_by_email
notify_roles_by_email(
db, roles=["admin"],
preference_key="email_on_new_users",
subject=f"New User Created: {user.full_name or user.email}",
message=(
f'A new user account was created: {user.full_name or user.email} '
f"({user.email}), role: {user.role}."
),
exclude_user_id=current_user.id,
)
# Return user
return user