import logging import uuid from django.contrib.auth.models import User from django.db import models from django.urls import reverse from django.utils import timezone from django.utils.translation import gettext_lazy, pgettext_lazy from django_celery_beat.models import PeriodicTask from rest_framework.authtoken.models import Token from sequences import get_next_value from solo.models import SingletonModel from console.models import SensorConnectedMixin, UniqueNameDescriptionModel from core.fields import IntegerField _log = logging.getLogger(__name__) class IncidentCategory(UniqueNameDescriptionModel): """ Category of incident """ pass class IncidentEffect(UniqueNameDescriptionModel): """ Possible incident effect """ pass class Meta: verbose_name = gettext_lazy('Incident effect') class IncidentRecommendations(UniqueNameDescriptionModel): """ Recommendations how to close incident """ pass class Meta: verbose_name = gettext_lazy('Incident recommendation') class Incident(SensorConnectedMixin): """ Incident model """ IMPORTANCE_MIN = 0 IMPORTANCE_MAX = 100 class Status(models.IntegerChoices): NOT_ASSIGNED = 0, gettext_lazy('Not assigned') ASSIGNED = 1, gettext_lazy('Assigned') DELAYED = 2, gettext_lazy('Delayed') RESOLVED = 3, gettext_lazy('Resolved') FALSE_ALARM = 4, gettext_lazy('False alarm') user_friendly_id = IntegerField(blank=True, null=True) timestamp = models.DateTimeField(default=timezone.now, verbose_name=gettext_lazy('Timestamp'), help_text=gettext_lazy('Date and time, when incident occurs')) incident_id = models.UUIDField(primary_key=True, default=uuid.uuid4, verbose_name=gettext_lazy('ID'), help_text=gettext_lazy('ID of incident')) title = models.CharField(max_length=128, verbose_name=gettext_lazy('Title'), help_text=gettext_lazy('Title')) category = models.ForeignKey(IncidentCategory, on_delete=models.SET_NULL, verbose_name=gettext_lazy('Category'), help_text=gettext_lazy("Incident's category"), null=True, blank=True) importance = IntegerField(min_value=IMPORTANCE_MIN, max_value=IMPORTANCE_MAX, verbose_name=gettext_lazy('Importance'), help_text=gettext_lazy('Hazard level of incident')) status = IntegerField(choices=Status.choices, verbose_name=gettext_lazy('Status'), help_text=gettext_lazy('Incident status'), default=Status.NOT_ASSIGNED) assigned_to = models.ForeignKey(User, on_delete=models.SET_NULL, verbose_name=gettext_lazy('Assigned'), help_text=gettext_lazy('User assigned to resolve incident'), null=True, blank=True) event_count = IntegerField(min_value=1, verbose_name=gettext_lazy("Event's number"), help_text=gettext_lazy("Amount of events in the incident")) created = models.DateTimeField(auto_now_add=True, verbose_name=gettext_lazy('Created'), help_text=gettext_lazy('Date and time, when incident was created')) updated = models.DateTimeField(auto_now=True, verbose_name=gettext_lazy('Updated'), help_text=gettext_lazy('Date and time, when incident was updated')) description = models.TextField(verbose_name=gettext_lazy('Description'), help_text=gettext_lazy('Incident description'), null=True, blank=True) deadline = models.DateField(verbose_name=gettext_lazy('Deadline'), help_text=gettext_lazy("Deadline when incident must be resolved"), null=True, blank=True) comment = models.TextField(verbose_name=gettext_lazy('Comment'), help_text=gettext_lazy('Incident comment'), null=True, blank=True) close_recommendations = models.ManyToManyField(IncidentRecommendations, verbose_name=gettext_lazy('Resolve recommendations'), help_text=gettext_lazy('How to resolve the incident'), blank=True) effects = models.ManyToManyField(IncidentEffect, verbose_name=pgettext_lazy('as consequences', 'Effects'), help_text=gettext_lazy('Consequences of the incident'), blank=True) events = models.JSONField(verbose_name=gettext_lazy("Events"), help_text=gettext_lazy("List of events, related to incident")) def save(self, *args, **kwargs): if self._state.adding: self.user_friendly_id = get_next_value('incidents_user_friendly_id') else: self.user_friendly_id = self.user_friendly_id if self.assigned_to is not None and self.status < self.Status.ASSIGNED: self.status = self.Status.ASSIGNED if self.assigned_to is None and self.status <= self.Status.ASSIGNED: self.status = self.Status.NOT_ASSIGNED super(Incident, self).save(*args, **kwargs) def get_absolute_url(self): return reverse('incident_view', kwargs={'incident_id': self.incident_id}) class Meta: ordering = ['-timestamp']