pwa: create WebPushRecord and WebPushCell (#25462)

This commit is contained in:
Elias Showk 2018-08-23 16:26:46 +02:00
parent 1a570ea805
commit 947f479949
4 changed files with 192 additions and 0 deletions

View File

@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.14 on 2018-08-23 12:39
from __future__ import unicode_literals
import django
from django.db import migrations, models
import django.db.models.deletion
import jsonfield.fields
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0008_alter_user_username_max_length'),
('push_notifications', '0006_webpushdevice'),
('notifications', '0005_auto_20180324_0025'),
]
operations = [
migrations.CreateModel(
name='WebpushCell',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('placeholder', models.CharField(max_length=20)),
('order', models.PositiveIntegerField()),
('slug', models.SlugField(blank=True, verbose_name='Slug')),
('extra_css_class', models.CharField(blank=True, max_length=100, verbose_name='Extra classes for CSS styling')),
('public', models.BooleanField(default=True, verbose_name='Public')),
('restricted_to_unlogged', models.BooleanField(default=False, verbose_name='Restrict to unlogged users')),
('last_update_timestamp', models.DateTimeField(auto_now=True)),
('groups', models.ManyToManyField(blank=True, to='auth.Group', verbose_name='Groups')),
('page', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='data.Page')),
],
options={
'verbose_name': 'Push notifications subscription cell',
},
),
migrations.CreateModel(
name='WebPushRecord',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('creation_date', models.DateTimeField(auto_now_add=True)),
('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)),
('response', jsonfield.fields.JSONField(null=True)),
('notification', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='notifications.Notification')),
('subscription', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='push_notifications.WebPushDevice')),
],
),
migrations.AlterUniqueTogether(
name='webpushrecord',
unique_together=set([('subscription', 'notification')]),
),
]

View File

120
combo/apps/pwa/models.py Normal file
View File

@ -0,0 +1,120 @@
# -*- coding: utf-8 -*-
# combo - Combo PWA App
# Copyright (C) 2018 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import json
from django.db import models
from django.conf import settings
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from jsonfield import JSONField
from combo.apps.notifications.models import Notification
from combo.data.models import CellBase
from combo.data.library import register_cell_class
from push_notifications.models import WebPushDevice
class WebPushRecord(models.Model):
'''
Store the state of a user's push notification
'''
DEFAULT_STATUS = 'NEW'
ERR_STATUS = 'ERR'
OK_STATUS = 'SENT'
STATUS = (
(DEFAULT_STATUS, 'Not-sent notification'),
(OK_STATUS, 'Sent notification'),
(ERR_STATUS, 'Invalid notification'),
)
subscription = models.ForeignKey(WebPushDevice, null=False)
notification = models.ForeignKey(Notification, null=False)
creation_date = models.DateTimeField(blank=True, auto_now_add=True)
status = models.CharField(blank=True, max_length=4, choices=STATUS, default=DEFAULT_STATUS)
response = JSONField(null=True)
class Meta:
unique_together = ('subscription', 'notification')
@property
def ttl(self):
delta = self.notification.end_timestamp - self.notification.start_timestamp
return int(delta.total_seconds())
@property
def payload(self):
'''
JSON string sent to the push service.
Every options are not supported by all browsers, adoption is progressive
'''
return json.dumps({
'title': self.notification.summary,
'body': "%s\n - %s" % (self.notification.body, self.notification.url),
'actions': [
{'action': 'ack', 'title': _('OK').encode('utf8'), 'icon': ''},
{'action': 'forget', 'title': _('Forget').encode('utf8'), 'icon': ''}
],
'data': {
'callback_url': reverse('webpush-notification-callback', args=[self.notification.id, self.notification.user.id, self.subscription.p256dh]),
'open_url': self.notification.url
},
'vibrate': [200, 100, 400],
})
def set_status_ok(self):
self.status = self.OK_STATUS
self.save()
def set_status_err(self):
self.status = self.ERR_STATUS
self.save()
@register_cell_class
class WebpushCell(CellBase):
'''
Combo Cell for webpush subscription management
'''
user_dependant = True
loading_message = _('Loading your active subscriptions to push notifications')
class Meta:
verbose_name = _('Push notifications subscription cell')
def is_visible(self, user=None):
if user is None or not user.is_authenticated():
return False
return super(WebpushCell, self).is_visible(user)
def get_cell_extra_context(self, context):
extra_context = super(WebpushCell, self).get_cell_extra_context(context)
user = getattr(context.get('request'), 'user', None)
if user and user.is_authenticated():
url = reverse('create_webpush_subscription')
user_active_devices = [{
'browser': device.browser,
'registration_id': device.registration_id,
} for device in WebPushDevice.objects.filter(user=user, active=True)]
extra_context.update({
'url': url,
'application_server_key': settings.PUSH_NOTIFICATIONS_SETTINGS['APP_SERVER_KEY'],
'user_active_devices': json.dumps(user_active_devices),
})
return extra_context

View File

@ -0,0 +1,17 @@
{% load i18n static %}
{% block cell-content %}
<div class="notification-dialog">
{% if request.user.is_authenticated %}
<script type="text/javascript" src="{{site_base}}{% static 'js/webpush.js' %}?{{statics_hash}}"></script>
<label class="checkbox">
<input id="webpush-subscribe-checkbox" class="checkbox_input" type="checkbox"
data-combo-api-url="{{ url }}"
data-user-devices="{{ user_active_devices }}"
data-application-server-key="{{ application_server_key }}">
<span id="webpush-subscribe-message" class="checkbox_text"></span>
</label>
{% else %}
<label class="checkbox">{% trans "Please login to receive push notifications" %}</label>
{% endif %}
</div>
{% endblock %}