0002-pwa-create-WebPushRecord-and-WebPushCell-25462.patch
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 |
- |