Skip to content

Commit

Permalink
Refactored Alert model to support alerts without observer.
Browse files Browse the repository at this point in the history
This change includes a slight api change in the way how Alert.set and
Alert.clear is called. In addtion, the way how waiting_period works is
improved and more clear. A waiting_period of zero means immediate
critical notification without warning.
  • Loading branch information
stephrdev committed Feb 10, 2016
1 parent e4e6f0e commit 2ce1aae
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 80 deletions.
8 changes: 1 addition & 7 deletions howl/admin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from django.contrib import admin
from django.utils.translation import ugettext_lazy as _

from .models import Alert, Observer

Expand All @@ -11,10 +10,5 @@ class ObserverAdmin(admin.ModelAdmin):

@admin.register(Alert)
class AlertAdmin(admin.ModelAdmin):
list_display = ('get_observer_name', 'timestamp', 'value', 'state')
list_display = ('identifier', 'timestamp', 'value', 'state')
list_filter = ('state',)

def get_observer_name(self, obj):
return obj.observer.name

get_observer_name.short_description = _('Observer')
Binary file modified howl/locale/de/LC_MESSAGES/django.mo
Binary file not shown.
44 changes: 24 additions & 20 deletions howl/locale/de/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,17 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-02-10 08:14+0100\n"
"PO-Revision-Date: 2016-02-10 08:14+0100\n"
"POT-Creation-Date: 2016-02-10 21:40+0100\n"
"PO-Revision-Date: 2016-02-10 21:40+0100\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Last-Translator: \n"
"Language-Team: \n"
"X-Generator: Poedit 1.8.6\n"

#: admin.py:20 models.py:20 models.py:47
msgid "Observer"
msgstr "Beobachter"

#: apps.py:7
msgid "Howl"
msgstr "Howl"
Expand All @@ -34,50 +30,58 @@ msgstr "Name"
msgid "Operator type"
msgstr "Operator Typ"

#: models.py:15 models.py:49
#: models.py:15 models.py:52
msgid "Value"
msgstr "Wert"

#: models.py:16
#: models.py:17
msgid "Waiting period"
msgstr "Wartezeit"

#: models.py:16
#: models.py:17
msgid "In seconds"
msgstr "In Sekunden"

#: models.py:17
#: models.py:18
msgid "Alert every time"
msgstr "Jedes mal alarmieren"

#: models.py:21
msgid "Observer"
msgstr "Beobachter"

#: models.py:22
msgid "Observers"
msgstr "Beobachter"

#: models.py:43
#: models.py:47
msgid "Waiting"
msgstr "Wartend"

#: models.py:44
#: models.py:48
msgid "Notified"
msgstr "Benachrichtigt"

#: models.py:51
#: models.py:50
msgid "Identifier"
msgstr "Kennung"

#: models.py:54
msgid "State"
msgstr "Status"

#: models.py:54
#: models.py:57
msgid "Alert"
msgstr "Alarm"

#: models.py:55
#: models.py:58
msgid "Alerts"
msgstr "Alarme"

#: models.py:59
#: models.py:62
#, python-brace-format
msgid "Alert (ID: {0}) for {1}"
msgstr "Alarm (ID: {0}) für {1}"
msgid "Alert for {0}"
msgstr "Alarm für {0}"

#: operators.py:50
msgid "Equals"
Expand Down
34 changes: 34 additions & 0 deletions howl/migrations/0005_auto_20160210_2042.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('howl', '0004_auto_20160210_0811'),
]

operations = [
migrations.RemoveField(
model_name='alert',
name='observer',
),
migrations.AddField(
model_name='alert',
name='identifier',
field=models.CharField(default='', verbose_name='Identifier', max_length=64, unique=True),
preserve_default=False,
),
migrations.AlterField(
model_name='alert',
name='value',
field=models.CharField(verbose_name='Value', blank=True, null=True, max_length=255),
),
migrations.AlterField(
model_name='observer',
name='value',
field=models.IntegerField(verbose_name='Value'),
),
]
65 changes: 42 additions & 23 deletions howl/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ class Observer(models.Model):
name = models.CharField(_('Name'), max_length=255)
operator = models.CharField(
_('Operator type'), max_length=32, choices=get_operator_types())
value = models.PositiveIntegerField(_('Value'))
waiting_period = models.PositiveIntegerField(_('Waiting period'), help_text=_('In seconds'))
value = models.IntegerField(_('Value'))
waiting_period = models.PositiveIntegerField(
_('Waiting period'), help_text=_('In seconds'))
alert_every_time = models.BooleanField(_('Alert every time'), default=False)

class Meta:
Expand All @@ -24,14 +25,17 @@ class Meta:
def __str__(self):
return self.name

def get_alert_identifier(self):
return 'howl-observer:{0}'.format(self.pk)

def get_alert(self, compare_value, **kwargs):
operator_class = get_operator_class(self.operator)

if operator_class(self).compare(compare_value):
Alert.clear(self, compare_value, **kwargs)
Alert.clear(compare_value, observer=self, **kwargs)
return None

return Alert.set(self, compare_value, **kwargs)
return Alert.set(compare_value, observer=self, **kwargs)

def compare(self, compare_value, **kwargs):
return self.get_alert(compare_value, **kwargs) is None
Expand All @@ -43,10 +47,9 @@ class Alert(models.Model):
(STATE_WAITING, _('Waiting')),
(STATE_NOTIFIED, _('Notified')),
)

observer = models.ForeignKey(Observer, verbose_name=_('Observer'))
identifier = models.CharField(_('Identifier'), max_length=64, unique=True)
timestamp = models.DateTimeField(auto_now_add=True)
value = models.CharField(_('Value'), max_length=255)
value = models.CharField(_('Value'), max_length=255, blank=True, null=True)
state = models.PositiveSmallIntegerField(
_('State'), choices=STATE_CHOICES, default=STATE_WAITING)

Expand All @@ -56,40 +59,56 @@ class Meta:
ordering = ('-timestamp',)

def __str__(self):
return _('Alert (ID: {0}) for {1}').format(self.pk, self.observer.name)
return _('Alert for {0}').format(self.identifier)

@classmethod
def set(cls, observer, compare_value, **kwargs):
def set(cls, value=None, **kwargs):
if 'observer' in kwargs:
identifier = kwargs['observer'].get_alert_identifier()
waiting_period = kwargs['observer'].waiting_period
alert_every_time = kwargs['observer'].alert_every_time
else:
if 'identifier' not in kwargs:
raise ValueError('`observer` or `identifier` required.')
identifier = kwargs['identifier']
waiting_period = kwargs.get('waiting_period', 0)
alert_every_time = kwargs.get('alert_every_time', False)

obj, created = Alert.objects.get_or_create(
observer=observer, defaults={'value': compare_value})
identifier=identifier, defaults={'value': value})

if created:
alert_wait.send(sender=cls, instance=obj, compare_value=compare_value, **kwargs)
if created and waiting_period > 0:
alert_wait.send(sender=cls, instance=obj, value=value, **kwargs)
return obj

alert_time = obj.timestamp + timedelta(seconds=observer.waiting_period)
alert_time = obj.timestamp + timedelta(seconds=waiting_period)

if alert_time < timezone.now():
if obj.state == obj.STATE_NOTIFIED and observer.alert_every_time:
obj.value = compare_value
if obj.state == obj.STATE_NOTIFIED and alert_every_time:
obj.value = value
obj.save(update_fields=['value'])
alert_notify.send(
sender=cls, instance=obj, compare_value=compare_value, **kwargs)
alert_notify.send(sender=cls, instance=obj, value=value, **kwargs)

if obj.state == obj.STATE_WAITING:
obj.value = compare_value
obj.value = value
obj.state = obj.STATE_NOTIFIED
obj.save(update_fields=['value', 'state'])
alert_notify.send(
sender=cls, instance=obj, compare_value=compare_value, **kwargs)
alert_notify.send(sender=cls, instance=obj, value=value, **kwargs)

return obj

@classmethod
def clear(cls, observer, compare_value, **kwargs):
def clear(cls, value=None, **kwargs):
if 'observer' in kwargs:
identifier = kwargs['observer'].get_alert_identifier()
else:
if 'identifier' not in kwargs:
raise ValueError('`observer` or `identifier` required.')
identifier = kwargs['identifier']

try:
obj = Alert.objects.get(observer=observer)
alert_clear.send(sender=cls, instance=obj, compare_value=compare_value, **kwargs)
obj = Alert.objects.get(identifier=identifier)
alert_clear.send(sender=cls, instance=obj, value=value, **kwargs)
obj.delete()
except Alert.DoesNotExist:
pass
2 changes: 1 addition & 1 deletion howl/tests/factories/observers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class Meta:


class AlertFactory(factory.DjangoModelFactory):
observer = factory.SubFactory(ObserverFactory)
identifier = factory.Sequence(lambda i: 'alert-{0}')
value = FuzzyChoice(range(1, 10))

class Meta:
Expand Down
10 changes: 1 addition & 9 deletions howl/tests/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

from howl.admin import AlertAdmin, ObserverAdmin
from howl.models import Alert, Observer
from howl.tests.factories.observers import AlertFactory, ObserverFactory


@pytest.mark.django_db
Expand All @@ -19,11 +18,4 @@ class TestAlertAdmin:

def test_list_display(self, rf):
modeladmin = AlertAdmin(Alert, admin.site)
assert modeladmin.list_display == ('get_observer_name', 'timestamp', 'value', 'state')

def test_get_observer_name(self, rf):
observer = ObserverFactory.create()
alert = AlertFactory.create(observer=observer)

modeladmin = AlertAdmin(Alert, admin.site)
assert modeladmin.get_observer_name(alert) == observer.name
assert modeladmin.list_display == ('identifier', 'timestamp', 'value', 'state')

0 comments on commit 2ce1aae

Please sign in to comment.