oncall-engine/engine/apps/alerts/models/invitation.py
Michael Derynck 6b40f95033 World, meet OnCall!
Co-authored-by: Eve832 <eve.meelan@grafana.com>
    Co-authored-by: Francisco Montes de Oca <nevermind89x@gmail.com>
    Co-authored-by: Ildar Iskhakov <ildar.iskhakov@grafana.com>
    Co-authored-by: Innokentii Konstantinov <innokenty.konstantinov@grafana.com>
    Co-authored-by: Julia <ferril.darkdiver@gmail.com>
    Co-authored-by: maskin25 <kengurek@gmail.com>
    Co-authored-by: Matias Bordese <mbordese@gmail.com>
    Co-authored-by: Matvey Kukuy <motakuk@gmail.com>
    Co-authored-by: Michael Derynck <michael.derynck@grafana.com>
    Co-authored-by: Richard Hartmann <richih@richih.org>
    Co-authored-by: Robby Milo <robbymilo@fastmail.com>
    Co-authored-by: Timur Olzhabayev <timur.olzhabayev@grafana.com>
    Co-authored-by: Vadim Stepanov <vadimkerr@gmail.com>
    Co-authored-by: Yulia Shanyrova <yulia.shanyrova@grafana.com>
2022-06-03 08:09:47 -06:00

123 lines
4.2 KiB
Python

import logging
from django.apps import apps
from django.db import models, transaction
from django.utils import timezone
from apps.alerts.tasks import invite_user_to_join_incident, send_alert_group_signal
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
class Invitation(models.Model):
"""
It's an invitation of a user to join working on Alert Group
"""
ATTEMPTS_LIMIT = 10
time_deltas_by_attempts = [
timezone.timedelta(minutes=6),
timezone.timedelta(minutes=16),
timezone.timedelta(minutes=31),
timezone.timedelta(hours=1, minutes=1),
timezone.timedelta(hours=3, minutes=1),
]
author = models.ForeignKey(
"user_management.User",
null=True,
on_delete=models.SET_NULL,
related_name="author_of_invitations",
)
invitee = models.ForeignKey(
"user_management.User",
null=True,
on_delete=models.SET_NULL,
related_name="invitee_in_invitations",
)
created_at = models.DateTimeField(auto_now_add=True)
is_active = models.BooleanField(default=True)
alert_group = models.ForeignKey("alerts.AlertGroup", on_delete=models.CASCADE, related_name="invitations")
attempt = models.IntegerField(default=0)
@property
def attempts_left(self):
return Invitation.ATTEMPTS_LIMIT - self.attempt
@staticmethod
def get_delay_by_attempt(attempt):
countdown = Invitation.time_deltas_by_attempts[-1]
if attempt < len(Invitation.time_deltas_by_attempts):
countdown = Invitation.time_deltas_by_attempts[attempt]
return countdown
@staticmethod
def invite_user(invitee_user, alert_group, user):
AlertGroupLogRecord = apps.get_model("alerts", "AlertGroupLogRecord")
# RFCT - why atomic? without select for update?
with transaction.atomic():
try:
invitation = Invitation.objects.get(
invitee=invitee_user,
alert_group=alert_group,
is_active=True,
)
invitation.is_active = False
invitation.save(update_fields=["is_active"])
log_record = AlertGroupLogRecord(
type=AlertGroupLogRecord.TYPE_RE_INVITE, author=user, alert_group=alert_group
)
except Invitation.DoesNotExist:
log_record = AlertGroupLogRecord(
type=AlertGroupLogRecord.TYPE_INVITE,
author=user,
alert_group=alert_group,
)
invitation = Invitation(
invitee=invitee_user,
alert_group=alert_group,
is_active=True,
author=user,
)
invitation.save()
log_record.invitation = invitation
log_record.save()
logger.debug(
f"call send_alert_group_signal for alert_group {alert_group.pk}, "
f"log record {log_record.pk} with type '{log_record.get_type_display()}'"
)
send_alert_group_signal.apply_async((log_record.pk,))
invite_user_to_join_incident.apply_async((invitation.pk,))
@staticmethod
def stop_invitation(invitation_pk, user):
AlertGroupLogRecord = apps.get_model("alerts", "AlertGroupLogRecord")
with transaction.atomic():
try:
invitation = Invitation.objects.filter(pk=invitation_pk).select_for_update()[0]
except IndexError:
return f"stop_invitation: Invitation with pk {invitation_pk} doesn't exist"
invitation.is_active = False
invitation.save(update_fields=["is_active"])
log_record = AlertGroupLogRecord(
type=AlertGroupLogRecord.TYPE_STOP_INVITATION,
author=user,
alert_group=invitation.alert_group,
invitation=invitation,
)
log_record.save()
logger.debug(
f"call send_alert_group_signal for alert_group {invitation.alert_group.pk}, "
f"log record {log_record.pk} with type '{log_record.get_type_display()}'"
)
send_alert_group_signal.apply_async((log_record.pk,))