pwa: create WebPushRecord and WebPushCell (#25462)
This commit is contained in:
parent
1a570ea805
commit
947f479949
|
@ -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')]),
|
||||
),
|
||||
]
|
|
@ -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
|
|
@ -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 %}
|
Loading…
Reference in New Issue