2025-09-12 13:04:04 +02:00
|
|
|
|
import datetime
|
|
|
|
|
import json
|
2025-09-07 20:52:19 +02:00
|
|
|
|
from django.conf import settings
|
|
|
|
|
from django.contrib.auth.models import AbstractUser
|
2025-09-12 13:04:04 +02:00
|
|
|
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
|
|
|
|
from django.contrib.contenttypes.models import ContentType
|
2025-09-09 12:00:29 +02:00
|
|
|
|
from django.core.serializers.json import DjangoJSONEncoder
|
2025-09-07 20:52:19 +02:00
|
|
|
|
from django.db import models
|
2025-09-12 13:04:04 +02:00
|
|
|
|
from django.urls import reverse
|
Refactor risk management application with enhanced localization, user authentication, and UI improvements
- Added verbose names for Incident and ResidualRisk models for better clarity in admin interface.
- Updated impact choices for ResidualRisk and Risk models to ensure consistency and clarity.
- Implemented gettext_lazy for translatable strings in models and choices.
- Enhanced the Risk, ResidualRisk, Control, AuditLog, and Incident models with Meta options for better admin representation.
- Added login required decorators to views for improved security.
- Introduced new CSS variables and classes for better visual representation of risk levels.
- Created custom template tags for dynamic CSS class assignment based on risk likelihood and impact.
- Improved dashboard and statistics views with user authentication checks.
- Updated templates for risks, controls, incidents, and admin interface to include edit and delete options for staff users.
- Added new login and logout templates for user authentication.
- Enhanced list views for risks, controls, and incidents to include action buttons for staff users.
- Improved overall UI/UX with Bulma CSS framework for a more modern look and feel.
2025-09-09 14:25:59 +02:00
|
|
|
|
from django.utils.translation import gettext_lazy as _
|
2025-09-07 20:52:19 +02:00
|
|
|
|
from multiselectfield import MultiSelectField
|
2025-09-09 12:00:29 +02:00
|
|
|
|
|
2025-09-12 13:04:04 +02:00
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
# SafeJSONEncoder
|
|
|
|
|
# ---------------------------------------------------------------------------
|
2025-09-09 12:00:29 +02:00
|
|
|
|
class SafeJSONEncoder(DjangoJSONEncoder):
|
2025-09-12 13:04:04 +02:00
|
|
|
|
"""JSON encoder that can handle datetime.date properly."""
|
2025-09-09 12:00:29 +02:00
|
|
|
|
def default(self, obj):
|
|
|
|
|
if isinstance(obj, datetime.date):
|
|
|
|
|
return obj.isoformat()
|
|
|
|
|
return super().default(obj)
|
2025-09-07 20:52:19 +02:00
|
|
|
|
|
2025-09-12 13:04:04 +02:00
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
# User
|
|
|
|
|
# ---------------------------------------------------------------------------
|
2025-09-07 20:52:19 +02:00
|
|
|
|
class User(AbstractUser):
|
2025-09-12 13:04:04 +02:00
|
|
|
|
"""Custom user model to support both local and SSO users."""
|
2025-09-07 20:52:19 +02:00
|
|
|
|
is_sso_user = models.BooleanField(default=False)
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def risks_owned(self):
|
2025-09-12 13:04:04 +02:00
|
|
|
|
"""All risks where the user is the risk owner."""
|
2025-09-07 20:52:19 +02:00
|
|
|
|
return self.owned_risks.all()
|
2025-09-12 13:04:04 +02:00
|
|
|
|
|
2025-09-07 20:52:19 +02:00
|
|
|
|
@property
|
|
|
|
|
def controls_responsible(self):
|
2025-09-12 13:04:04 +02:00
|
|
|
|
"""All controls where the user is responsible."""
|
2025-09-07 20:52:19 +02:00
|
|
|
|
return self.responsible_controls.all()
|
|
|
|
|
|
2025-09-12 13:04:04 +02:00
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
# Risk
|
|
|
|
|
# ---------------------------------------------------------------------------
|
2025-09-07 20:52:19 +02:00
|
|
|
|
class Risk(models.Model):
|
Refactor risk management application with enhanced localization, user authentication, and UI improvements
- Added verbose names for Incident and ResidualRisk models for better clarity in admin interface.
- Updated impact choices for ResidualRisk and Risk models to ensure consistency and clarity.
- Implemented gettext_lazy for translatable strings in models and choices.
- Enhanced the Risk, ResidualRisk, Control, AuditLog, and Incident models with Meta options for better admin representation.
- Added login required decorators to views for improved security.
- Introduced new CSS variables and classes for better visual representation of risk levels.
- Created custom template tags for dynamic CSS class assignment based on risk likelihood and impact.
- Improved dashboard and statistics views with user authentication checks.
- Updated templates for risks, controls, incidents, and admin interface to include edit and delete options for staff users.
- Added new login and logout templates for user authentication.
- Enhanced list views for risks, controls, and incidents to include action buttons for staff users.
- Improved overall UI/UX with Bulma CSS framework for a more modern look and feel.
2025-09-09 14:25:59 +02:00
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = _("Risk")
|
|
|
|
|
verbose_name_plural = _("Risks")
|
2025-09-07 20:52:19 +02:00
|
|
|
|
|
Add risk status and notification preferences
- Introduced a new `status` field to the `Risk` model with choices for "open", "in_progress", "closed", and "review_required".
- Created a `NotificationPreference` model to manage user notification settings for various events related to risks, controls, residual risks, reviews, users, and incidents.
- Updated the admin interface to include `NotificationPreference` inline with the `User` admin.
- Enhanced signal handlers to send notifications based on user preferences for created, updated, and deleted events for users, risks, controls, and incidents.
- Modified the `check_risk_followups` utility function to update risk status and create notifications for follow-ups.
- Updated serializers and views to accommodate the new `status` field and improved risk listing functionality.
- Added a new section in the risk detail template to display related incidents.
- Removed the unused statistics view from URLs.
2025-09-10 11:54:08 +02:00
|
|
|
|
STATUS_CHOICES = [
|
|
|
|
|
("open", _("Open")),
|
|
|
|
|
("in_progress", _("In Progress")),
|
|
|
|
|
("closed", _("Closed")),
|
|
|
|
|
("review_required", _("Review required")),
|
|
|
|
|
]
|
2025-09-07 20:52:19 +02:00
|
|
|
|
LIKELIHOOD_CHOICES = [
|
Refactor risk management application with enhanced localization, user authentication, and UI improvements
- Added verbose names for Incident and ResidualRisk models for better clarity in admin interface.
- Updated impact choices for ResidualRisk and Risk models to ensure consistency and clarity.
- Implemented gettext_lazy for translatable strings in models and choices.
- Enhanced the Risk, ResidualRisk, Control, AuditLog, and Incident models with Meta options for better admin representation.
- Added login required decorators to views for improved security.
- Introduced new CSS variables and classes for better visual representation of risk levels.
- Created custom template tags for dynamic CSS class assignment based on risk likelihood and impact.
- Improved dashboard and statistics views with user authentication checks.
- Updated templates for risks, controls, incidents, and admin interface to include edit and delete options for staff users.
- Added new login and logout templates for user authentication.
- Enhanced list views for risks, controls, and incidents to include action buttons for staff users.
- Improved overall UI/UX with Bulma CSS framework for a more modern look and feel.
2025-09-09 14:25:59 +02:00
|
|
|
|
(1, _("Very low – occurs less than once every 5 years")),
|
|
|
|
|
(2, _("Low – once every 1–5 years")),
|
|
|
|
|
(3, _("Likely – once per year or more")),
|
|
|
|
|
(4, _("Very likely – multiple times per year/monthly")),
|
2025-09-07 20:52:19 +02:00
|
|
|
|
]
|
|
|
|
|
IMPACT_CHOICES = [
|
Refactor risk management application with enhanced localization, user authentication, and UI improvements
- Added verbose names for Incident and ResidualRisk models for better clarity in admin interface.
- Updated impact choices for ResidualRisk and Risk models to ensure consistency and clarity.
- Implemented gettext_lazy for translatable strings in models and choices.
- Enhanced the Risk, ResidualRisk, Control, AuditLog, and Incident models with Meta options for better admin representation.
- Added login required decorators to views for improved security.
- Introduced new CSS variables and classes for better visual representation of risk levels.
- Created custom template tags for dynamic CSS class assignment based on risk likelihood and impact.
- Improved dashboard and statistics views with user authentication checks.
- Updated templates for risks, controls, incidents, and admin interface to include edit and delete options for staff users.
- Added new login and logout templates for user authentication.
- Enhanced list views for risks, controls, and incidents to include action buttons for staff users.
- Improved overall UI/UX with Bulma CSS framework for a more modern look and feel.
2025-09-09 14:25:59 +02:00
|
|
|
|
(1, _("Very Low (< 1,000 € – minor operational impact)")),
|
|
|
|
|
(2, _("Low (1,000–5,000 € – local impact)")),
|
|
|
|
|
(3, _("High (5,000–15,000 € – team-level impact)")),
|
|
|
|
|
(4, _("Severe (50,000–100,000 € – regional impact)")),
|
|
|
|
|
(5, _("Critical (> 100,000 € – existential threat)")),
|
2025-09-07 20:52:19 +02:00
|
|
|
|
]
|
|
|
|
|
CIA_CHOICES = [
|
Refactor risk management application with enhanced localization, user authentication, and UI improvements
- Added verbose names for Incident and ResidualRisk models for better clarity in admin interface.
- Updated impact choices for ResidualRisk and Risk models to ensure consistency and clarity.
- Implemented gettext_lazy for translatable strings in models and choices.
- Enhanced the Risk, ResidualRisk, Control, AuditLog, and Incident models with Meta options for better admin representation.
- Added login required decorators to views for improved security.
- Introduced new CSS variables and classes for better visual representation of risk levels.
- Created custom template tags for dynamic CSS class assignment based on risk likelihood and impact.
- Improved dashboard and statistics views with user authentication checks.
- Updated templates for risks, controls, incidents, and admin interface to include edit and delete options for staff users.
- Added new login and logout templates for user authentication.
- Enhanced list views for risks, controls, and incidents to include action buttons for staff users.
- Improved overall UI/UX with Bulma CSS framework for a more modern look and feel.
2025-09-09 14:25:59 +02:00
|
|
|
|
("1", _("Confidentiality")),
|
|
|
|
|
("2", _("Integrity")),
|
|
|
|
|
("3", _("Availability")),
|
2025-09-07 20:52:19 +02:00
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
# Basic information
|
Refactor risk management application with enhanced localization, user authentication, and UI improvements
- Added verbose names for Incident and ResidualRisk models for better clarity in admin interface.
- Updated impact choices for ResidualRisk and Risk models to ensure consistency and clarity.
- Implemented gettext_lazy for translatable strings in models and choices.
- Enhanced the Risk, ResidualRisk, Control, AuditLog, and Incident models with Meta options for better admin representation.
- Added login required decorators to views for improved security.
- Introduced new CSS variables and classes for better visual representation of risk levels.
- Created custom template tags for dynamic CSS class assignment based on risk likelihood and impact.
- Improved dashboard and statistics views with user authentication checks.
- Updated templates for risks, controls, incidents, and admin interface to include edit and delete options for staff users.
- Added new login and logout templates for user authentication.
- Enhanced list views for risks, controls, and incidents to include action buttons for staff users.
- Improved overall UI/UX with Bulma CSS framework for a more modern look and feel.
2025-09-09 14:25:59 +02:00
|
|
|
|
title = models.CharField(_("Title"), max_length=255)
|
|
|
|
|
description = models.TextField(_("Description"), max_length=225, blank=True, null=True)
|
|
|
|
|
asset = models.CharField(_("Asset"), max_length=255, blank=True, null=True)
|
|
|
|
|
process = models.CharField(_("Process"), max_length=255, blank=True, null=True)
|
|
|
|
|
category = models.CharField(_("Category"), max_length=255, blank=True, null=True)
|
|
|
|
|
created_at = models.DateTimeField(_("Created at"), auto_now_add=True)
|
|
|
|
|
updated_at = models.DateTimeField(_("Updated at"), auto_now=True)
|
2025-09-10 15:00:59 +02:00
|
|
|
|
effects = models.TextField(_("Effects"), blank=True, null=True)
|
Add risk status and notification preferences
- Introduced a new `status` field to the `Risk` model with choices for "open", "in_progress", "closed", and "review_required".
- Created a `NotificationPreference` model to manage user notification settings for various events related to risks, controls, residual risks, reviews, users, and incidents.
- Updated the admin interface to include `NotificationPreference` inline with the `User` admin.
- Enhanced signal handlers to send notifications based on user preferences for created, updated, and deleted events for users, risks, controls, and incidents.
- Modified the `check_risk_followups` utility function to update risk status and create notifications for follow-ups.
- Updated serializers and views to accommodate the new `status` field and improved risk listing functionality.
- Added a new section in the risk detail template to display related incidents.
- Removed the unused statistics view from URLs.
2025-09-10 11:54:08 +02:00
|
|
|
|
status = models.CharField(
|
|
|
|
|
_("Status"),
|
|
|
|
|
max_length=20,
|
|
|
|
|
choices=STATUS_CHOICES,
|
|
|
|
|
default="open",
|
|
|
|
|
db_index=True,
|
|
|
|
|
)
|
|
|
|
|
|
2025-09-07 20:52:19 +02:00
|
|
|
|
# CIA Protection Goals
|
|
|
|
|
cia = MultiSelectField(choices=CIA_CHOICES, max_length=100, blank=True, null=True)
|
|
|
|
|
|
|
|
|
|
# Risk evaluation before controls
|
2025-09-12 13:04:04 +02:00
|
|
|
|
likelihood = models.IntegerField(choices=LIKELIHOOD_CHOICES, default=1)
|
|
|
|
|
impact = models.IntegerField(choices=IMPACT_CHOICES, default=1)
|
2025-09-07 20:52:19 +02:00
|
|
|
|
|
|
|
|
|
# Calculated fields
|
|
|
|
|
score = models.IntegerField(editable=False)
|
|
|
|
|
level = models.CharField(max_length=50, editable=False)
|
|
|
|
|
|
|
|
|
|
# Ownership
|
|
|
|
|
owner = models.ForeignKey(
|
|
|
|
|
settings.AUTH_USER_MODEL,
|
|
|
|
|
on_delete=models.SET_NULL,
|
|
|
|
|
null=True,
|
|
|
|
|
related_name="owned_risks"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Reminder / follow-up date
|
|
|
|
|
follow_up = models.DateField(blank=True, null=True)
|
|
|
|
|
|
|
|
|
|
def save(self, *args, **kwargs):
|
2025-09-15 13:18:33 +02:00
|
|
|
|
# Mark for review if likelihood/impact changed
|
|
|
|
|
if self.pk:
|
|
|
|
|
old = Risk.objects.get(pk=self.pk)
|
|
|
|
|
if old.likelihood != self.likelihood or old.impact != self.impact:
|
|
|
|
|
self.review_required = True
|
|
|
|
|
self.status = "review_required"
|
|
|
|
|
|
2025-09-12 13:04:04 +02:00
|
|
|
|
# Calculate risk score and level
|
2025-09-07 20:52:19 +02:00
|
|
|
|
self.score = self.likelihood * self.impact
|
|
|
|
|
if self.score <= 4:
|
|
|
|
|
self.level = "Low"
|
|
|
|
|
elif self.score <= 8:
|
|
|
|
|
self.level = "Medium"
|
|
|
|
|
elif self.score <= 12:
|
|
|
|
|
self.level = "High"
|
|
|
|
|
else:
|
|
|
|
|
self.level = "Critical"
|
|
|
|
|
super().save(*args, **kwargs)
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"{self.title} (Score: {self.score}, Level: {self.level})"
|
|
|
|
|
|
2025-09-12 13:04:04 +02:00
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
# Residual Risk
|
|
|
|
|
# ---------------------------------------------------------------------------
|
2025-09-07 20:52:19 +02:00
|
|
|
|
class ResidualRisk(models.Model):
|
2025-09-12 13:04:04 +02:00
|
|
|
|
"""Residual risk after implementing controls."""
|
2025-09-07 20:52:19 +02:00
|
|
|
|
|
Refactor risk management application with enhanced localization, user authentication, and UI improvements
- Added verbose names for Incident and ResidualRisk models for better clarity in admin interface.
- Updated impact choices for ResidualRisk and Risk models to ensure consistency and clarity.
- Implemented gettext_lazy for translatable strings in models and choices.
- Enhanced the Risk, ResidualRisk, Control, AuditLog, and Incident models with Meta options for better admin representation.
- Added login required decorators to views for improved security.
- Introduced new CSS variables and classes for better visual representation of risk levels.
- Created custom template tags for dynamic CSS class assignment based on risk likelihood and impact.
- Improved dashboard and statistics views with user authentication checks.
- Updated templates for risks, controls, incidents, and admin interface to include edit and delete options for staff users.
- Added new login and logout templates for user authentication.
- Enhanced list views for risks, controls, and incidents to include action buttons for staff users.
- Improved overall UI/UX with Bulma CSS framework for a more modern look and feel.
2025-09-09 14:25:59 +02:00
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = _("Residual Risk")
|
|
|
|
|
verbose_name_plural = _("Residual Risks")
|
|
|
|
|
|
2025-09-12 13:04:04 +02:00
|
|
|
|
risk = models.OneToOneField(Risk, on_delete=models.CASCADE, related_name="residual_risk")
|
|
|
|
|
likelihood = models.IntegerField(choices=Risk.LIKELIHOOD_CHOICES, default=1)
|
|
|
|
|
impact = models.IntegerField(choices=Risk.IMPACT_CHOICES, default=1)
|
2025-09-07 20:52:19 +02:00
|
|
|
|
score = models.IntegerField(editable=False)
|
|
|
|
|
level = models.CharField(max_length=50, editable=False)
|
|
|
|
|
review_required = models.BooleanField(default=False)
|
2025-09-12 13:04:04 +02:00
|
|
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
2025-09-09 12:00:29 +02:00
|
|
|
|
updated_at = models.DateTimeField(auto_now=True)
|
|
|
|
|
|
2025-09-07 20:52:19 +02:00
|
|
|
|
def save(self, *args, **kwargs):
|
|
|
|
|
if self.pk:
|
|
|
|
|
old = ResidualRisk.objects.get(pk=self.pk)
|
|
|
|
|
if old.likelihood != self.likelihood or old.impact != self.impact:
|
2025-09-09 12:00:29 +02:00
|
|
|
|
self.review_required = True
|
2025-09-15 13:18:33 +02:00
|
|
|
|
self.status = "review_required"
|
2025-09-07 20:52:19 +02:00
|
|
|
|
|
2025-09-12 13:04:04 +02:00
|
|
|
|
# Calculate residual risk score and level
|
2025-09-07 20:52:19 +02:00
|
|
|
|
self.score = self.likelihood * self.impact
|
|
|
|
|
if self.score <= 4:
|
|
|
|
|
self.level = "Low"
|
|
|
|
|
elif self.score <= 8:
|
|
|
|
|
self.level = "Medium"
|
|
|
|
|
elif self.score <= 12:
|
|
|
|
|
self.level = "High"
|
|
|
|
|
else:
|
|
|
|
|
self.level = "Critical"
|
2025-09-12 13:04:04 +02:00
|
|
|
|
|
2025-09-07 20:52:19 +02:00
|
|
|
|
super().save(*args, **kwargs)
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"Residual Risk for {self.risk.title} (Score: {self.score}, Level: {self.level})"
|
|
|
|
|
|
2025-09-12 13:04:04 +02:00
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
# Control
|
|
|
|
|
# ---------------------------------------------------------------------------
|
2025-09-07 20:52:19 +02:00
|
|
|
|
class Control(models.Model):
|
2025-09-12 13:04:04 +02:00
|
|
|
|
"""Security control/measure linked to a risk."""
|
|
|
|
|
|
Refactor risk management application with enhanced localization, user authentication, and UI improvements
- Added verbose names for Incident and ResidualRisk models for better clarity in admin interface.
- Updated impact choices for ResidualRisk and Risk models to ensure consistency and clarity.
- Implemented gettext_lazy for translatable strings in models and choices.
- Enhanced the Risk, ResidualRisk, Control, AuditLog, and Incident models with Meta options for better admin representation.
- Added login required decorators to views for improved security.
- Introduced new CSS variables and classes for better visual representation of risk levels.
- Created custom template tags for dynamic CSS class assignment based on risk likelihood and impact.
- Improved dashboard and statistics views with user authentication checks.
- Updated templates for risks, controls, incidents, and admin interface to include edit and delete options for staff users.
- Added new login and logout templates for user authentication.
- Enhanced list views for risks, controls, and incidents to include action buttons for staff users.
- Improved overall UI/UX with Bulma CSS framework for a more modern look and feel.
2025-09-09 14:25:59 +02:00
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = _("Control")
|
|
|
|
|
verbose_name_plural = _("Controls")
|
|
|
|
|
|
2025-09-07 20:52:19 +02:00
|
|
|
|
STATUS_CHOICES = [
|
Refactor risk management application with enhanced localization, user authentication, and UI improvements
- Added verbose names for Incident and ResidualRisk models for better clarity in admin interface.
- Updated impact choices for ResidualRisk and Risk models to ensure consistency and clarity.
- Implemented gettext_lazy for translatable strings in models and choices.
- Enhanced the Risk, ResidualRisk, Control, AuditLog, and Incident models with Meta options for better admin representation.
- Added login required decorators to views for improved security.
- Introduced new CSS variables and classes for better visual representation of risk levels.
- Created custom template tags for dynamic CSS class assignment based on risk likelihood and impact.
- Improved dashboard and statistics views with user authentication checks.
- Updated templates for risks, controls, incidents, and admin interface to include edit and delete options for staff users.
- Added new login and logout templates for user authentication.
- Enhanced list views for risks, controls, and incidents to include action buttons for staff users.
- Improved overall UI/UX with Bulma CSS framework for a more modern look and feel.
2025-09-09 14:25:59 +02:00
|
|
|
|
("planned", _("Planned")),
|
|
|
|
|
("in_progress", _("In progress")),
|
|
|
|
|
("completed", _("Completed")),
|
|
|
|
|
("verified", _("Verified")),
|
|
|
|
|
("rejected", _("Rejected")),
|
2025-09-07 20:52:19 +02:00
|
|
|
|
]
|
|
|
|
|
|
Refactor risk management application with enhanced localization, user authentication, and UI improvements
- Added verbose names for Incident and ResidualRisk models for better clarity in admin interface.
- Updated impact choices for ResidualRisk and Risk models to ensure consistency and clarity.
- Implemented gettext_lazy for translatable strings in models and choices.
- Enhanced the Risk, ResidualRisk, Control, AuditLog, and Incident models with Meta options for better admin representation.
- Added login required decorators to views for improved security.
- Introduced new CSS variables and classes for better visual representation of risk levels.
- Created custom template tags for dynamic CSS class assignment based on risk likelihood and impact.
- Improved dashboard and statistics views with user authentication checks.
- Updated templates for risks, controls, incidents, and admin interface to include edit and delete options for staff users.
- Added new login and logout templates for user authentication.
- Enhanced list views for risks, controls, and incidents to include action buttons for staff users.
- Improved overall UI/UX with Bulma CSS framework for a more modern look and feel.
2025-09-09 14:25:59 +02:00
|
|
|
|
title = models.CharField(_("Title"), max_length=255)
|
2025-09-07 20:52:19 +02:00
|
|
|
|
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="planned")
|
|
|
|
|
due_date = models.DateField(blank=True, null=True)
|
|
|
|
|
responsible = models.ForeignKey(
|
|
|
|
|
settings.AUTH_USER_MODEL,
|
|
|
|
|
on_delete=models.SET_NULL,
|
|
|
|
|
null=True,
|
|
|
|
|
related_name="responsible_controls"
|
|
|
|
|
)
|
|
|
|
|
description = models.TextField(blank=True, null=True)
|
|
|
|
|
wiki_link = models.URLField(blank=True, null=True)
|
2025-09-12 13:04:04 +02:00
|
|
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
2025-09-09 12:00:29 +02:00
|
|
|
|
updated_at = models.DateTimeField(auto_now=True)
|
2025-09-07 20:52:19 +02:00
|
|
|
|
|
|
|
|
|
# Relation to risk
|
2025-09-12 13:04:04 +02:00
|
|
|
|
risks = models.ManyToManyField(Risk, related_name="controls", blank=True)
|
2025-09-07 20:52:19 +02:00
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"{self.title} ({self.get_status_display()})"
|
|
|
|
|
|
2025-09-12 13:04:04 +02:00
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
# AuditLog
|
|
|
|
|
# ---------------------------------------------------------------------------
|
2025-09-07 20:52:19 +02:00
|
|
|
|
class AuditLog(models.Model):
|
2025-09-12 13:04:04 +02:00
|
|
|
|
"""Generic audit log entry for tracking changes."""
|
Refactor risk management application with enhanced localization, user authentication, and UI improvements
- Added verbose names for Incident and ResidualRisk models for better clarity in admin interface.
- Updated impact choices for ResidualRisk and Risk models to ensure consistency and clarity.
- Implemented gettext_lazy for translatable strings in models and choices.
- Enhanced the Risk, ResidualRisk, Control, AuditLog, and Incident models with Meta options for better admin representation.
- Added login required decorators to views for improved security.
- Introduced new CSS variables and classes for better visual representation of risk levels.
- Created custom template tags for dynamic CSS class assignment based on risk likelihood and impact.
- Improved dashboard and statistics views with user authentication checks.
- Updated templates for risks, controls, incidents, and admin interface to include edit and delete options for staff users.
- Added new login and logout templates for user authentication.
- Enhanced list views for risks, controls, and incidents to include action buttons for staff users.
- Improved overall UI/UX with Bulma CSS framework for a more modern look and feel.
2025-09-09 14:25:59 +02:00
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = _("Auditlog")
|
|
|
|
|
verbose_name_plural = _("Auditlogs")
|
|
|
|
|
|
2025-09-07 20:52:19 +02:00
|
|
|
|
ACTION_CHOICES = [
|
|
|
|
|
("create", "Created"),
|
|
|
|
|
("update", "Updated"),
|
|
|
|
|
("delete", "Deleted"),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
user = models.ForeignKey(
|
|
|
|
|
settings.AUTH_USER_MODEL,
|
|
|
|
|
null=True, blank=True,
|
|
|
|
|
on_delete=models.SET_NULL,
|
|
|
|
|
related_name="audit_logs"
|
|
|
|
|
)
|
|
|
|
|
action = models.CharField(max_length=10, choices=ACTION_CHOICES)
|
|
|
|
|
model = models.CharField(max_length=100)
|
|
|
|
|
object_id = models.CharField(max_length=50)
|
2025-09-09 12:00:29 +02:00
|
|
|
|
changes = models.JSONField(null=True, blank=True, encoder=SafeJSONEncoder)
|
2025-09-07 20:52:19 +02:00
|
|
|
|
timestamp = models.DateTimeField(auto_now_add=True)
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"[{self.timestamp}] {self.user} {self.action} {self.model}({self.object_id})"
|
2025-09-12 13:04:04 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
# Incident
|
|
|
|
|
# ---------------------------------------------------------------------------
|
2025-09-07 20:52:19 +02:00
|
|
|
|
class Incident(models.Model):
|
2025-09-12 13:04:04 +02:00
|
|
|
|
"""Incidents and related risks."""
|
Refactor risk management application with enhanced localization, user authentication, and UI improvements
- Added verbose names for Incident and ResidualRisk models for better clarity in admin interface.
- Updated impact choices for ResidualRisk and Risk models to ensure consistency and clarity.
- Implemented gettext_lazy for translatable strings in models and choices.
- Enhanced the Risk, ResidualRisk, Control, AuditLog, and Incident models with Meta options for better admin representation.
- Added login required decorators to views for improved security.
- Introduced new CSS variables and classes for better visual representation of risk levels.
- Created custom template tags for dynamic CSS class assignment based on risk likelihood and impact.
- Improved dashboard and statistics views with user authentication checks.
- Updated templates for risks, controls, incidents, and admin interface to include edit and delete options for staff users.
- Added new login and logout templates for user authentication.
- Enhanced list views for risks, controls, and incidents to include action buttons for staff users.
- Improved overall UI/UX with Bulma CSS framework for a more modern look and feel.
2025-09-09 14:25:59 +02:00
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = _("Incident")
|
|
|
|
|
verbose_name_plural = _("Incidents")
|
|
|
|
|
|
2025-09-07 20:52:19 +02:00
|
|
|
|
STATUS_CHOICES = [
|
Refactor risk management application with enhanced localization, user authentication, and UI improvements
- Added verbose names for Incident and ResidualRisk models for better clarity in admin interface.
- Updated impact choices for ResidualRisk and Risk models to ensure consistency and clarity.
- Implemented gettext_lazy for translatable strings in models and choices.
- Enhanced the Risk, ResidualRisk, Control, AuditLog, and Incident models with Meta options for better admin representation.
- Added login required decorators to views for improved security.
- Introduced new CSS variables and classes for better visual representation of risk levels.
- Created custom template tags for dynamic CSS class assignment based on risk likelihood and impact.
- Improved dashboard and statistics views with user authentication checks.
- Updated templates for risks, controls, incidents, and admin interface to include edit and delete options for staff users.
- Added new login and logout templates for user authentication.
- Enhanced list views for risks, controls, and incidents to include action buttons for staff users.
- Improved overall UI/UX with Bulma CSS framework for a more modern look and feel.
2025-09-09 14:25:59 +02:00
|
|
|
|
("open", _("Opened")),
|
|
|
|
|
("in_progress", _("In Progress")),
|
|
|
|
|
("closed", _("Closed")),
|
2025-09-07 20:52:19 +02:00
|
|
|
|
]
|
2025-09-12 13:04:04 +02:00
|
|
|
|
|
Refactor risk management application with enhanced localization, user authentication, and UI improvements
- Added verbose names for Incident and ResidualRisk models for better clarity in admin interface.
- Updated impact choices for ResidualRisk and Risk models to ensure consistency and clarity.
- Implemented gettext_lazy for translatable strings in models and choices.
- Enhanced the Risk, ResidualRisk, Control, AuditLog, and Incident models with Meta options for better admin representation.
- Added login required decorators to views for improved security.
- Introduced new CSS variables and classes for better visual representation of risk levels.
- Created custom template tags for dynamic CSS class assignment based on risk likelihood and impact.
- Improved dashboard and statistics views with user authentication checks.
- Updated templates for risks, controls, incidents, and admin interface to include edit and delete options for staff users.
- Added new login and logout templates for user authentication.
- Enhanced list views for risks, controls, and incidents to include action buttons for staff users.
- Improved overall UI/UX with Bulma CSS framework for a more modern look and feel.
2025-09-09 14:25:59 +02:00
|
|
|
|
title = models.CharField(_("Title"), max_length=255)
|
|
|
|
|
description = models.TextField(_("Description"), blank=True, null=True)
|
|
|
|
|
date_reported = models.DateField(_("Date reported"), blank=True, null=True)
|
|
|
|
|
reported_by = models.ForeignKey(
|
2025-09-12 13:04:04 +02:00
|
|
|
|
settings.AUTH_USER_MODEL,
|
|
|
|
|
verbose_name=_("Reported by"),
|
|
|
|
|
null=True, blank=True,
|
|
|
|
|
on_delete=models.SET_NULL,
|
|
|
|
|
related_name="incidents"
|
Refactor risk management application with enhanced localization, user authentication, and UI improvements
- Added verbose names for Incident and ResidualRisk models for better clarity in admin interface.
- Updated impact choices for ResidualRisk and Risk models to ensure consistency and clarity.
- Implemented gettext_lazy for translatable strings in models and choices.
- Enhanced the Risk, ResidualRisk, Control, AuditLog, and Incident models with Meta options for better admin representation.
- Added login required decorators to views for improved security.
- Introduced new CSS variables and classes for better visual representation of risk levels.
- Created custom template tags for dynamic CSS class assignment based on risk likelihood and impact.
- Improved dashboard and statistics views with user authentication checks.
- Updated templates for risks, controls, incidents, and admin interface to include edit and delete options for staff users.
- Added new login and logout templates for user authentication.
- Enhanced list views for risks, controls, and incidents to include action buttons for staff users.
- Improved overall UI/UX with Bulma CSS framework for a more modern look and feel.
2025-09-09 14:25:59 +02:00
|
|
|
|
)
|
2025-09-07 20:52:19 +02:00
|
|
|
|
status = models.CharField(max_length=12, choices=STATUS_CHOICES)
|
2025-09-12 13:04:04 +02:00
|
|
|
|
related_risks = models.ManyToManyField(Risk, blank=True, related_name="incidents")
|
2025-09-07 20:52:19 +02:00
|
|
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
2025-09-12 13:04:04 +02:00
|
|
|
|
updated_at = models.DateTimeField(auto_now=True)
|
2025-09-07 20:52:19 +02:00
|
|
|
|
|
Add risk status and notification preferences
- Introduced a new `status` field to the `Risk` model with choices for "open", "in_progress", "closed", and "review_required".
- Created a `NotificationPreference` model to manage user notification settings for various events related to risks, controls, residual risks, reviews, users, and incidents.
- Updated the admin interface to include `NotificationPreference` inline with the `User` admin.
- Enhanced signal handlers to send notifications based on user preferences for created, updated, and deleted events for users, risks, controls, and incidents.
- Modified the `check_risk_followups` utility function to update risk status and create notifications for follow-ups.
- Updated serializers and views to accommodate the new `status` field and improved risk listing functionality.
- Added a new section in the risk detail template to display related incidents.
- Removed the unused statistics view from URLs.
2025-09-10 11:54:08 +02:00
|
|
|
|
|
2025-09-12 13:04:04 +02:00
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
# NotificationKind
|
|
|
|
|
# ---------------------------------------------------------------------------
|
2025-09-10 14:26:29 +02:00
|
|
|
|
class NotificationKind(models.TextChoices):
|
2025-09-12 13:04:04 +02:00
|
|
|
|
"""Event types for notifications."""
|
2025-09-10 14:26:29 +02:00
|
|
|
|
RISK_CREATED = "risk.created", _("Risk created")
|
|
|
|
|
RISK_UPDATED = "risk.updated", _("Risk updated")
|
|
|
|
|
RISK_DELETED = "risk.deleted", _("Risk deleted")
|
|
|
|
|
RISK_REVIEW_REQUIRED = "risk.review_required", _("Risk review required")
|
|
|
|
|
RISK_REVIEW_COMPLETED = "risk.review_completed", _("Risk review completed")
|
|
|
|
|
|
|
|
|
|
CONTROL_CREATED = "control.created", _("Control created")
|
|
|
|
|
CONTROL_UPDATED = "control.updated", _("Control updated")
|
|
|
|
|
CONTROL_DELETED = "control.deleted", _("Control deleted")
|
|
|
|
|
|
|
|
|
|
RESIDUAL_CREATED = "residual.created", _("Residual created")
|
|
|
|
|
RESIDUAL_UPDATED = "residual.updated", _("Residual updated")
|
|
|
|
|
RESIDUAL_DELETED = "residual.deleted", _("Residual deleted")
|
|
|
|
|
RESIDUAL_REVIEW_REQUIRED = "residual.review_required", _("Residual review required")
|
|
|
|
|
RESIDUAL_REVIEW_COMPLETED = "residual.review_completed", _("Residual review completed")
|
|
|
|
|
|
|
|
|
|
INCIDENT_CREATED = "incident.created", _("Incident created")
|
|
|
|
|
INCIDENT_UPDATED = "incident.updated", _("Incident updated")
|
|
|
|
|
INCIDENT_DELETED = "incident.deleted", _("Incident deleted")
|
|
|
|
|
|
|
|
|
|
USER_CREATED = "user.created", _("User created")
|
|
|
|
|
USER_DELETED = "user.deleted", _("User deleted")
|
|
|
|
|
|
2025-09-12 13:04:04 +02:00
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
# Notification
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
class Notification(models.Model):
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = _("Notification")
|
|
|
|
|
verbose_name_plural = _("Notifications")
|
|
|
|
|
|
|
|
|
|
user = models.ForeignKey(
|
|
|
|
|
settings.AUTH_USER_MODEL,
|
|
|
|
|
on_delete=models.SET_NULL,
|
|
|
|
|
null=True, blank=True,
|
|
|
|
|
related_name="notifications"
|
|
|
|
|
)
|
|
|
|
|
message = models.TextField()
|
|
|
|
|
kind = models.CharField(max_length=40, choices=NotificationKind.choices, default="")
|
|
|
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
|
|
|
read = models.BooleanField(default=False) # Read in WebApp
|
|
|
|
|
sent = models.BooleanField(default=False) # Sent via Mail (optional)
|
|
|
|
|
|
|
|
|
|
# Optional relation to any object
|
|
|
|
|
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=True, blank=True)
|
|
|
|
|
object_id = models.PositiveIntegerField(null=True, blank=True)
|
|
|
|
|
related_object = GenericForeignKey("content_type", "object_id")
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
user_display = self.user.username if self.user else "System"
|
|
|
|
|
return f"{user_display}: {self.message[:50]}..."
|
|
|
|
|
|
|
|
|
|
def get_link(self):
|
|
|
|
|
"""Return URL to the related object if available."""
|
|
|
|
|
if not self.related_object:
|
|
|
|
|
return None
|
|
|
|
|
model_name = self.content_type.model
|
|
|
|
|
if model_name == "risk":
|
|
|
|
|
return reverse("risks:show_risk", args=[self.object_id])
|
|
|
|
|
if model_name == "control":
|
|
|
|
|
return reverse("risks:show_control", args=[self.object_id])
|
|
|
|
|
if model_name == "incident":
|
|
|
|
|
return reverse("risks:show_incident", args=[self.object_id])
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
# NotificationPreference
|
|
|
|
|
# ---------------------------------------------------------------------------
|
Add risk status and notification preferences
- Introduced a new `status` field to the `Risk` model with choices for "open", "in_progress", "closed", and "review_required".
- Created a `NotificationPreference` model to manage user notification settings for various events related to risks, controls, residual risks, reviews, users, and incidents.
- Updated the admin interface to include `NotificationPreference` inline with the `User` admin.
- Enhanced signal handlers to send notifications based on user preferences for created, updated, and deleted events for users, risks, controls, and incidents.
- Modified the `check_risk_followups` utility function to update risk status and create notifications for follow-ups.
- Updated serializers and views to accommodate the new `status` field and improved risk listing functionality.
- Added a new section in the risk detail template to display related incidents.
- Removed the unused statistics view from URLs.
2025-09-10 11:54:08 +02:00
|
|
|
|
class NotificationPreference(models.Model):
|
2025-09-12 13:04:04 +02:00
|
|
|
|
"""User-specific notification preferences."""
|
|
|
|
|
|
Add risk status and notification preferences
- Introduced a new `status` field to the `Risk` model with choices for "open", "in_progress", "closed", and "review_required".
- Created a `NotificationPreference` model to manage user notification settings for various events related to risks, controls, residual risks, reviews, users, and incidents.
- Updated the admin interface to include `NotificationPreference` inline with the `User` admin.
- Enhanced signal handlers to send notifications based on user preferences for created, updated, and deleted events for users, risks, controls, and incidents.
- Modified the `check_risk_followups` utility function to update risk status and create notifications for follow-ups.
- Updated serializers and views to accommodate the new `status` field and improved risk listing functionality.
- Added a new section in the risk detail template to display related incidents.
- Removed the unused statistics view from URLs.
2025-09-10 11:54:08 +02:00
|
|
|
|
user = models.OneToOneField(
|
|
|
|
|
settings.AUTH_USER_MODEL,
|
|
|
|
|
on_delete=models.CASCADE,
|
|
|
|
|
related_name="notification_preference",
|
|
|
|
|
verbose_name=_("User"),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Risks
|
2025-09-12 13:04:04 +02:00
|
|
|
|
risk_created = models.BooleanField(default=True)
|
|
|
|
|
risk_updated = models.BooleanField(default=True)
|
|
|
|
|
risk_deleted = models.BooleanField(default=True)
|
Add risk status and notification preferences
- Introduced a new `status` field to the `Risk` model with choices for "open", "in_progress", "closed", and "review_required".
- Created a `NotificationPreference` model to manage user notification settings for various events related to risks, controls, residual risks, reviews, users, and incidents.
- Updated the admin interface to include `NotificationPreference` inline with the `User` admin.
- Enhanced signal handlers to send notifications based on user preferences for created, updated, and deleted events for users, risks, controls, and incidents.
- Modified the `check_risk_followups` utility function to update risk status and create notifications for follow-ups.
- Updated serializers and views to accommodate the new `status` field and improved risk listing functionality.
- Added a new section in the risk detail template to display related incidents.
- Removed the unused statistics view from URLs.
2025-09-10 11:54:08 +02:00
|
|
|
|
|
|
|
|
|
# Controls
|
|
|
|
|
control_created = models.BooleanField(default=True)
|
|
|
|
|
control_updated = models.BooleanField(default=True)
|
|
|
|
|
control_deleted = models.BooleanField(default=True)
|
|
|
|
|
|
|
|
|
|
# Residual risks
|
2025-09-12 13:04:04 +02:00
|
|
|
|
residual_created = models.BooleanField(default=True)
|
|
|
|
|
residual_updated = models.BooleanField(default=True)
|
|
|
|
|
residual_deleted = models.BooleanField(default=True)
|
Add risk status and notification preferences
- Introduced a new `status` field to the `Risk` model with choices for "open", "in_progress", "closed", and "review_required".
- Created a `NotificationPreference` model to manage user notification settings for various events related to risks, controls, residual risks, reviews, users, and incidents.
- Updated the admin interface to include `NotificationPreference` inline with the `User` admin.
- Enhanced signal handlers to send notifications based on user preferences for created, updated, and deleted events for users, risks, controls, and incidents.
- Modified the `check_risk_followups` utility function to update risk status and create notifications for follow-ups.
- Updated serializers and views to accommodate the new `status` field and improved risk listing functionality.
- Added a new section in the risk detail template to display related incidents.
- Removed the unused statistics view from URLs.
2025-09-10 11:54:08 +02:00
|
|
|
|
|
|
|
|
|
# Reviews
|
2025-09-12 13:04:04 +02:00
|
|
|
|
review_required = models.BooleanField(default=True)
|
|
|
|
|
review_completed = models.BooleanField(default=True)
|
Add risk status and notification preferences
- Introduced a new `status` field to the `Risk` model with choices for "open", "in_progress", "closed", and "review_required".
- Created a `NotificationPreference` model to manage user notification settings for various events related to risks, controls, residual risks, reviews, users, and incidents.
- Updated the admin interface to include `NotificationPreference` inline with the `User` admin.
- Enhanced signal handlers to send notifications based on user preferences for created, updated, and deleted events for users, risks, controls, and incidents.
- Modified the `check_risk_followups` utility function to update risk status and create notifications for follow-ups.
- Updated serializers and views to accommodate the new `status` field and improved risk listing functionality.
- Added a new section in the risk detail template to display related incidents.
- Removed the unused statistics view from URLs.
2025-09-10 11:54:08 +02:00
|
|
|
|
|
|
|
|
|
# Users
|
2025-09-12 13:04:04 +02:00
|
|
|
|
user_created = models.BooleanField(default=False)
|
|
|
|
|
user_deleted = models.BooleanField(default=False)
|
Add risk status and notification preferences
- Introduced a new `status` field to the `Risk` model with choices for "open", "in_progress", "closed", and "review_required".
- Created a `NotificationPreference` model to manage user notification settings for various events related to risks, controls, residual risks, reviews, users, and incidents.
- Updated the admin interface to include `NotificationPreference` inline with the `User` admin.
- Enhanced signal handlers to send notifications based on user preferences for created, updated, and deleted events for users, risks, controls, and incidents.
- Modified the `check_risk_followups` utility function to update risk status and create notifications for follow-ups.
- Updated serializers and views to accommodate the new `status` field and improved risk listing functionality.
- Added a new section in the risk detail template to display related incidents.
- Removed the unused statistics view from URLs.
2025-09-10 11:54:08 +02:00
|
|
|
|
|
|
|
|
|
# Incidents
|
|
|
|
|
incident_created = models.BooleanField(default=True)
|
|
|
|
|
incident_updated = models.BooleanField(default=True)
|
|
|
|
|
incident_deleted = models.BooleanField(default=True)
|
|
|
|
|
|
|
|
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
|
|
|
updated_at = models.DateTimeField(auto_now=True)
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f"Prefs({self.user})"
|
|
|
|
|
|
|
|
|
|
def should_notify(self, event_code: str) -> bool:
|
2025-09-12 13:04:04 +02:00
|
|
|
|
"""Return True if user wants notifications for this event code."""
|
2025-09-10 14:26:29 +02:00
|
|
|
|
return bool(getattr(self, event_code, False))
|
|
|
|
|
|
2025-09-12 13:04:04 +02:00
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
# NotificationRule
|
|
|
|
|
# ---------------------------------------------------------------------------
|
2025-09-10 14:26:29 +02:00
|
|
|
|
class NotificationRule(models.Model):
|
2025-09-12 13:04:04 +02:00
|
|
|
|
"""Global rules: Which events trigger in-app and/or email notifications."""
|
|
|
|
|
|
2025-09-10 14:26:29 +02:00
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = _("Notification rule")
|
|
|
|
|
verbose_name_plural = _("Notification rules")
|
|
|
|
|
|
|
|
|
|
kind = models.CharField(
|
|
|
|
|
_("Event"),
|
|
|
|
|
max_length=40,
|
|
|
|
|
choices=NotificationKind.choices,
|
|
|
|
|
unique=True,
|
|
|
|
|
)
|
|
|
|
|
enabled_in_app = models.BooleanField(_("Show in app"), default=True)
|
|
|
|
|
enabled_email = models.BooleanField(_("Send via email"), default=False)
|
|
|
|
|
|
2025-09-12 13:04:04 +02:00
|
|
|
|
# Recipient groups
|
2025-09-10 14:26:29 +02:00
|
|
|
|
to_owner = models.BooleanField(
|
|
|
|
|
_("Send to owner/responsible/reporter (if available)"),
|
2025-09-12 13:04:04 +02:00
|
|
|
|
default=True,
|
2025-09-10 14:26:29 +02:00
|
|
|
|
)
|
2025-09-12 13:04:04 +02:00
|
|
|
|
to_staff = models.BooleanField(_("Send to all staff"), default=False)
|
2025-09-10 14:26:29 +02:00
|
|
|
|
extra_recipients = models.TextField(
|
|
|
|
|
_("Extra recipients (emails, comma or newline separated)"),
|
2025-09-12 13:04:04 +02:00
|
|
|
|
blank=True,
|
2025-09-10 14:26:29 +02:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return self.get_kind_display() or self.kind
|