oncall-engine/engine/apps/alerts/models/alert_manager_models.py
Joey Orlando f77a54b518
Shift Swap Requests in Slack + improve typing for Slack django app (#2653)
# What this PR does

**Shift Swap Requests**

https://www.loom.com/share/860c3337b338412cbd2ac4024260f3e8?sid=3d91b558-b4de-4351-8b45-8a99b7302346

**Other**
- Drastically improve the typing in the `slack` Django app, and several
other models/functions that were consumed by logic within the `slack`
Django app (ex. setting `RelatedManager` type hints on various models)
https://www.loom.com/share/da6b9984519c48d59a45d3c93c08d7dc

## Checklist

- [x] Unit, integration, and e2e (if applicable) tests updated
- [x] Documentation added (or `pr:no public docs` PR label added if not
required)
- [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not
required)
2023-07-28 15:11:38 +00:00

76 lines
2.8 KiB
Python

import hashlib
import json
from django.db import transaction
from apps.alerts.models import Alert, AlertGroup
# NOTE: mypy was complaining about the following for both of these models. Likely because they subclass
# a model and django-mypy can't yet properly handle this
#
# error: Couldn't resolve related manager for relation 'users'
# (from apps.user_management.models.user.User.user_management.User.notification). [django-manager-missing]
#
# error: Couldn't resolve related manager for relation 'dependent_alert_groups'
# (from apps.alerts.models.alert_group.AlertGroup.alerts.AlertGroup.root_alert_group). [django-manager-missing]
class AlertGroupForAlertManager(AlertGroup): # type: ignore[django-manager-missing]
MAX_ALERTS_IN_GROUP_FOR_AUTO_RESOLVE = 500
def is_alert_a_resolve_signal(self, alert):
non_resolved_hashes = set()
hash = alert.get_integration_optimization_hash()
if alert.calculated_is_resolve_signal:
# Calculate leftover hashes
for alert in AlertForAlertManager.objects.filter(group=self).exclude(pk=alert.pk)[
: AlertGroupForAlertManager.MAX_ALERTS_IN_GROUP_FOR_AUTO_RESOLVE
]:
if alert.calculated_is_resolve_signal:
try:
non_resolved_hashes.remove(alert.get_integration_optimization_hash())
except KeyError:
pass
else:
non_resolved_hashes.add(alert.get_integration_optimization_hash())
# Remove last hash
try:
non_resolved_hashes.remove(hash)
except KeyError:
pass
return len(non_resolved_hashes) == 0
else:
return False
class Meta:
app_label = "alerts"
proxy = True
class AlertForAlertManager(Alert): # type: ignore[django-manager-missing]
def get_integration_optimization_hash(self):
if self.integration_optimization_hash is None:
with transaction.atomic():
if self.id is not None:
alert = AlertForAlertManager.objects.filter(id=self.id).select_for_update().get()
else:
alert = self
_hash = dict(alert.raw_request_data.get("labels", {}))
_hash = json.dumps(_hash, sort_keys=True)
_hash = hashlib.md5(str(_hash).encode()).hexdigest()
alert.integration_optimization_hash = _hash
if self.id is not None:
alert.save()
return alert.integration_optimization_hash
else:
return self.integration_optimization_hash
@property
def calculated_is_resolve_signal(self):
return self.raw_request_data.get("status", "") == "resolved"
class Meta:
app_label = "alerts"
proxy = True