Projet

Général

Profil

0002-pwa-create-WebPushRecord-and-WebPushCell-25462.patch

Anonyme, 24 août 2018 17:21

Télécharger (9,25 ko)

Voir les différences:

Subject: [PATCH 2/6] pwa: create WebPushRecord and WebPushCell (#25462)

 combo/apps/pwa/migrations/0001_initial.py     |  55 ++++++++
 combo/apps/pwa/migrations/__init__.py         |   0
 combo/apps/pwa/models.py                      | 120 ++++++++++++++++++
 .../apps/pwa/templates/combo/webpushcell.html |  17 +++
 4 files changed, 192 insertions(+)
 create mode 100644 combo/apps/pwa/migrations/0001_initial.py
 create mode 100644 combo/apps/pwa/migrations/__init__.py
 create mode 100644 combo/apps/pwa/models.py
 create mode 100644 combo/apps/pwa/templates/combo/webpushcell.html
combo/apps/pwa/migrations/0001_initial.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.14 on 2018-08-23 12:39
3
from __future__ import unicode_literals
4

  
5
import django
6
from django.db import migrations, models
7
import django.db.models.deletion
8
import jsonfield.fields
9

  
10

  
11
class Migration(migrations.Migration):
12

  
13
    initial = True
14

  
15
    dependencies = [
16
        ('auth', '0008_alter_user_username_max_length'),
17
        ('push_notifications', '0006_webpushdevice'),
18
        ('notifications', '0005_auto_20180324_0025'),
19
    ]
20

  
21
    operations = [
22
        migrations.CreateModel(
23
            name='WebpushCell',
24
            fields=[
25
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
26
                ('placeholder', models.CharField(max_length=20)),
27
                ('order', models.PositiveIntegerField()),
28
                ('slug', models.SlugField(blank=True, verbose_name='Slug')),
29
                ('extra_css_class', models.CharField(blank=True, max_length=100, verbose_name='Extra classes for CSS styling')),
30
                ('public', models.BooleanField(default=True, verbose_name='Public')),
31
                ('restricted_to_unlogged', models.BooleanField(default=False, verbose_name='Restrict to unlogged users')),
32
                ('last_update_timestamp', models.DateTimeField(auto_now=True)),
33
                ('groups', models.ManyToManyField(blank=True, to='auth.Group', verbose_name='Groups')),
34
                ('page', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='data.Page')),
35
            ],
36
            options={
37
                'verbose_name': 'Push notifications subscription cell',
38
            },
39
        ),
40
        migrations.CreateModel(
41
            name='WebPushRecord',
42
            fields=[
43
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
44
                ('creation_date', models.DateTimeField(auto_now_add=True)),
45
                ('status', models.CharField(blank=True, choices=[(b'NEW', b'Not-sent notification'), (b'SENT', b'Sent notification'), (b'ERR', b'Invalid notification')], default=b'NEW', max_length=4)),
46
                ('response', jsonfield.fields.JSONField(null=True)),
47
                ('notification', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='notifications.Notification')),
48
                ('subscription', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='push_notifications.WebPushDevice')),
49
            ],
50
        ),
51
        migrations.AlterUniqueTogether(
52
            name='webpushrecord',
53
            unique_together=set([('subscription', 'notification')]),
54
        ),
55
    ]
combo/apps/pwa/models.py
1
# -*- coding: utf-8 -*-
2
# combo - Combo PWA App
3
# Copyright (C) 2018  Entr'ouvert
4
#
5
# This program is free software: you can redistribute it and/or modify it
6
# under the terms of the GNU Affero General Public License as published
7
# by the Free Software Foundation, either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU Affero General Public License for more details.
14
#
15
# You should have received a copy of the GNU Affero General Public License
16
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17

  
18
import json
19

  
20
from django.db import models
21
from django.conf import settings
22
from django.core.urlresolvers import reverse
23
from django.utils.translation import ugettext_lazy as _
24

  
25
from jsonfield import JSONField
26

  
27
from combo.apps.notifications.models import Notification
28
from combo.data.models import CellBase
29
from combo.data.library import register_cell_class
30

  
31
from push_notifications.models import WebPushDevice
32

  
33

  
34
class WebPushRecord(models.Model):
35
    '''
36
    Store the state of a user's push notification
37
    '''
38
    DEFAULT_STATUS = 'NEW'
39
    ERR_STATUS = 'ERR'
40
    OK_STATUS = 'SENT'
41
    STATUS = (
42
        (DEFAULT_STATUS, 'Not-sent notification'),
43
        (OK_STATUS, 'Sent notification'),
44
        (ERR_STATUS, 'Invalid notification'),
45
    )
46

  
47
    subscription = models.ForeignKey(WebPushDevice, null=False)
48
    notification = models.ForeignKey(Notification, null=False)
49
    creation_date = models.DateTimeField(blank=True, auto_now_add=True)
50
    status = models.CharField(blank=True, max_length=4, choices=STATUS, default=DEFAULT_STATUS)
51
    response = JSONField(null=True)
52

  
53
    class Meta:
54
        unique_together = ('subscription', 'notification')
55

  
56
    @property
57
    def ttl(self):
58
        delta = self.notification.end_timestamp - self.notification.start_timestamp
59
        return int(delta.total_seconds())
60

  
61
    @property
62
    def payload(self):
63
        '''
64
        JSON string sent to the push service.
65
        Every options are not supported by all browsers, adoption is progressive
66
        '''
67
        return json.dumps({
68
            'title': self.notification.summary,
69
            'body': "%s\n - %s" % (self.notification.body, self.notification.url),
70
            'actions': [
71
                {'action': 'ack', 'title': _('OK').encode('utf8'), 'icon': ''},
72
                {'action': 'forget', 'title': _('Forget').encode('utf8'), 'icon': ''}
73
            ],
74
            'data': {
75
                'callback_url': reverse('webpush-notification-callback', args=[self.notification.id, self.notification.user.id, self.subscription.p256dh]),
76
                'open_url': self.notification.url
77
            },
78
            'vibrate': [200, 100, 400],
79
        })
80

  
81
    def set_status_ok(self):
82
        self.status = self.OK_STATUS
83
        self.save()
84

  
85
    def set_status_err(self):
86
        self.status = self.ERR_STATUS
87
        self.save()
88

  
89
@register_cell_class
90
class WebpushCell(CellBase):
91
    '''
92
    Combo Cell for webpush subscription management
93
    '''
94
    user_dependant = True
95
    loading_message = _('Loading your active subscriptions to push notifications')
96

  
97
    class Meta:
98
        verbose_name = _('Push notifications subscription cell')
99

  
100
    def is_visible(self, user=None):
101
        if user is None or not user.is_authenticated():
102
            return False
103
        return super(WebpushCell, self).is_visible(user)
104

  
105
    def get_cell_extra_context(self, context):
106
        extra_context = super(WebpushCell, self).get_cell_extra_context(context)
107
        user = getattr(context.get('request'), 'user', None)
108
        if user and user.is_authenticated():
109
            url = reverse('create_webpush_subscription')
110
            user_active_devices = [{
111
                'browser': device.browser,
112
                'registration_id': device.registration_id,
113
            } for device in WebPushDevice.objects.filter(user=user, active=True)]
114

  
115
            extra_context.update({
116
                'url': url,
117
                'application_server_key': settings.PUSH_NOTIFICATIONS_SETTINGS['APP_SERVER_KEY'],
118
                'user_active_devices': json.dumps(user_active_devices),
119
            })
120
        return extra_context
combo/apps/pwa/templates/combo/webpushcell.html
1
{% load i18n static %}
2
{% block cell-content %}
3
<div class="notification-dialog">
4
{% if request.user.is_authenticated %}
5
  <script type="text/javascript" src="{{site_base}}{% static 'js/webpush.js' %}?{{statics_hash}}"></script>
6
  <label class="checkbox">
7
    <input id="webpush-subscribe-checkbox" class="checkbox_input" type="checkbox"
8
      data-combo-api-url="{{ url }}"
9
      data-user-devices="{{ user_active_devices }}"
10
      data-application-server-key="{{ application_server_key }}">
11
    <span id="webpush-subscribe-message" class="checkbox_text"></span>
12
  </label>
13
{% else %}
14
  <label class="checkbox">{% trans "Please login to receive push notifications" %}</label>
15
{% endif %}
16
</div>
17
{% endblock %}
0
-