models.py 5.95 KB
Newer Older
1
"""The models defined by the pushnotifications package"""
2
3
import datetime

4
from django.conf import settings
5
from django.db import models
6
from django.utils.translation import override
7
from django.utils.translation import ugettext_lazy as _
8
from firebase_admin import messaging
9

10
11
12
13
from utils.translation import MultilingualField, ModelTranslateMeta


class Category(models.Model, metaclass=ModelTranslateMeta):
14
15
    """Describes a Message category"""

16
17
18
19
20
21
22
23
    key = models.CharField(max_length=16, primary_key=True)

    name = MultilingualField(
        models.CharField,
        _("name"),
        max_length=32,
    )

Luko van der Maas's avatar
Luko van der Maas committed
24
25
26
27
28
29
    description = MultilingualField(
        models.TextField,
        _("description"),
        default=""
    )

30
31
    def __str__(self):
        return self.name_en
32
33


34
35
36
37
def default_receive_category():
    return Category.objects.filter(key="general")


38
class Device(models.Model):
39
40
    """Describes a device"""

41
42
43
44
45
    DEVICE_TYPES = (
        ('ios', 'iOS'),
        ('android', 'Android')
    )

46
    registration_id = models.TextField(verbose_name=_("registration token"))
47
48
    type = models.CharField(choices=DEVICE_TYPES, max_length=10)
    active = models.BooleanField(
49
        verbose_name=_("active"), default=True,
50
51
        help_text=_("Inactive devices will not be sent notifications")
    )
52
    user = models.ForeignKey(settings.AUTH_USER_MODEL,
Thom Wiggers's avatar
Thom Wiggers committed
53
54
55
                             on_delete=models.CASCADE,
                             blank=False,
                             null=False)
56
    date_created = models.DateTimeField(
57
58
59
60
61
62
        verbose_name=_("registration date"), auto_now_add=True, null=False
    )
    language = models.CharField(
        verbose_name=_('language'),
        max_length=2,
        choices=settings.LANGUAGES,
63
        default='en',
64
65
    )

66
67
68
69
70
    receive_category = models.ManyToManyField(
        Category,
        default=default_receive_category
    )

71
72
73
74
    class Meta:
        unique_together = ('registration_id', 'user',)


75
76
77
78
79
80
81
82
class MessageManager(models.Manager):
    """Returns manual messages only"""

    def get_queryset(self):
        return (super().get_queryset()
                .filter(scheduledmessage__task_id=None))


83
class Message(models.Model, metaclass=ModelTranslateMeta):
84
85
86
87
    """Describes a push notification"""

    objects = MessageManager()

88
    users = models.ManyToManyField(settings.AUTH_USER_MODEL)
89
90
    title = MultilingualField(
        models.CharField,
91
92
93
        max_length=150,
        verbose_name=_('title')
    )
94
95
    body = MultilingualField(
        models.TextField,
96
97
        verbose_name=_('body')
    )
98
99
100
    url = models.CharField(
        verbose_name=_('url'),
        max_length=256,
101
102
        null=True,
        blank=True,
103
    )
104
105
    category = models.ForeignKey(
        Category,
106
        on_delete=models.CASCADE,
107
        verbose_name=_('category'),
Luko van der Maas's avatar
Luko van der Maas committed
108
109
        default="general"
    )
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
    sent = models.BooleanField(
        verbose_name=_('sent'),
        default=False
    )
    failure = models.IntegerField(
        verbose_name=_('failure'),
        blank=True,
        null=True,
    )
    success = models.IntegerField(
        verbose_name=_('success'),
        blank=True,
        null=True,
    )

    def __str__(self):
        return '{}: {}'.format(self.title, self.body)

    def send(self, **kwargs):
        if self:
130
131
            success_total = 0
            failure_total = 0
132
            ttl = kwargs.get('ttl', 3600)
133
134
135
136

            for lang in settings.LANGUAGES:
                with override(lang[0]):
                    reg_ids = list(
137
                        Device.objects.filter(
138
139
140
141
142
143
                            user__in=self.users.all(),
                            receive_category__key=self.category_id,
                            active=True,
                            language=lang[0]
                        ).values_list('registration_id', flat=True))

144
                    data = kwargs.get('data', {})
145
                    if self.url is not None:
146
                        data['url'] = self.url
147

148
149
150
151
152
153
154
155
156
157
158
159
160
161
                    message = messaging.Message(
                        notification=messaging.Notification(
                            title=self.title,
                            body=str(self.body),
                        ),
                        data=data,
                        android=messaging.AndroidConfig(
                            ttl=datetime.timedelta(seconds=ttl),
                            priority='normal',
                            notification=messaging.AndroidNotification(
                                color='#E62272',
                                sound='default',
                            ),
                        ),
162
163
                    )

164
165
166
                    for reg_id in reg_ids:
                        message.token = reg_id
                        try:
167
168
                            messaging.send(message,dry_run=kwargs.get(
                                'dry_run', False))
169
170
171
172
173
174
175
176
177
178
179
                            success_total += 1
                        except messaging.ApiCallError as e:
                            failure_total += 1
                            d = Device.objects.filter(registration_id=reg_id)
                            if e.code == 'registration-token-not-registered':
                                d.delete()
                            elif (e.code == 'invalid-argument'
                                    or e.code == 'invalid-recipient'
                                    or e.code == 'invalid-registration-token'):
                                d.update(active=False)

180
181
182
183
            self.sent = True
            self.success = success_total
            self.failure = failure_total
            self.save()
184
        return None
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199


class ScheduledMessageManager(models.Manager):
    """Returns scheduled messages only"""

    def get_queryset(self):
        return super().get_queryset()


class ScheduledMessage(Message, metaclass=ModelTranslateMeta):
    """Describes a scheduled push notification"""

    objects = ScheduledMessageManager()

    time = models.DateTimeField()
200
    executed = models.DateTimeField(null=True)