releaser.subscriptions - подписки на события, отправка уведомлений

Идея: уведомление пользователю формируется из данных объекта-события и объекта-подписки на это событие в базе.


ПОДПИСКИ

Объекты-подписки описываются django-моделью releaser.subscriptions.models.Subscription. Подписка описывает
события, которые ей соответствуют, и способ уведомления.

События, которые соответствуют подписке, описываются полями event_type и param. Внутри param какая-то строчка;
какой формат этой строчки, библиотека не указывает. Например, если пользователю интересно знать, когда
на определённый сервер поставят пакеты, собранные из определённой ветки, значения event_type и param можно
сделать такие:

event_type : "branch_packages_deployed"
param      : "{'host':'ppcdev1.yandex.ru','branch':'my-cool-branch'}"
(в param json)


СОБЫТИЯ

Чтобы отправлить уведомление с помощью этой библиотеки, нужно сначала описать событие, о котором уведомление
будет рассказывать. Пример:

from releaser.subscriptions.events_base import BaseEvent, event
from releaser.subscriptions.models import Subscription

@event
class AchievementUnlockedEvent(BaseEvent):
    event_type = 'achievement_unlocked'

    @staticmethod
    def display_subscription(sub):
        return u'Achievement unlocked'

    def notification_content(self, notification_type, recipient):
        achievement_name = self.event_data['achievement_name']
        message = 'Achievement unlocked: {name}'.format(name=achievement_name)

        if notification_type == Subscription.NOTIFICATION_TYPE_YAMB:
            return message

        if notification_type == Subscription.NOTIFICATION_TYPE_EMAIL:
            return { 'subject': 'Achievement unlocked', 'body': message }

        if notification_type == Subscription.NOTIFICATION_TYPE_STARTREK:
            return message

        # если новых методов уведомления не будет, код сюда не доберётся
        return message

(конец примера)

Такой класс нужно добавить в файл events.py в каталоге подходящего приложения; если у подходящего
приложения этого файла нет, его нужно создать.

Можно пример скопировать и вставить в нужный файл, вот что потом нужно поменять:
  1. название класса: нужно, чтобы создать объект события
  2. event_type: нужен для связи с этим событием объектов Subscription в базе
  3. тело display_subscription: нужен, чтобы показать подписку на событие этого типа в интерфейсе
     может быть, здесь нужно будет разобрать sub.param
  4. тело notification_content: возвращает информацию о том, что же нужно отправить пользователю
     формат возвращаемого значения зависит от типа транспорта
     здесь наверняка нужно будет воспользоваться значением self.event_data, которое передал в конструктор код,
     который создал объект события


УВЕДОМЛЕНИЯ

Когда в какой-то момент про событие нужно сообщить пользователю, нужно:

1. создать его объект:
from releaser.app.events import AchievementUnlockedEvent
event_data = { 'achievement_name' : 'Rock the boat' }
event = AchievementUnlockedEvent(event_data)

2. каким-то образом найти в базе все подписки, для которых подходит это событие:

# Вариант A: явно найти подписки, исходя из какой-то сложной логики
from releaser.subscriptions.models import Subscription
subscriptions = Subscriptions.objects.filter(event_type=event.event_type, ...)

# Вариант B: не искать подписки, потому что о событии нужно уведомить вообще всех пользователей,
# подписанных на этот тип события (event_type).
# (тогда кода поиска нет)

3. отправить уведомления:
# вариант A
event.send_notifications(subscriptions)
# вариант B
event.send_notifications()

Иногда лучше работает альтернативная последовательность:
1. найти в базе подписки, по которым сейчас нужно отправить уведомления

2. для каждой подписки создать событие, отправить уведомление:
for sub in subscriptions:
    event = AchievementUnlockedEvent(...)
    event.send_notifications([sub])

Такой код может быть в каком-то контроллере веб-приложения (процедуре в одном из views.py) или в какой-то
процедуре, которая регулярно запускается из cron-скрипта. Для регулярно запускаемых процедур рекомендуется
использовать планировщик задач, см. releaser/scheduler/README.

