combo/combo/apps/pwa/models.py

153 lines
5.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*
#
# combo - content management system
# Copyright (C) 2015-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 base64
import json
from django.conf import settings
from django.core import serializers
from django.core.files.base import ContentFile
from django.core.files.storage import default_storage
from django.db import models
from django.utils import six
from django.utils.encoding import force_text, force_bytes
from django.utils.six import BytesIO
from django.utils.translation import ugettext_lazy as _
from jsonfield import JSONField
from combo.data.fields import RichTextField
from combo import utils
class PwaSettings(models.Model):
APPLICATION_ICON_SIZES = ['%sx%s' % (x, x) for x in (48, 96, 192, 256, 512)]
application_icon = models.FileField(
verbose_name=_('Application Icon'),
help_text=_(u'Should be a square of at least 512×512 pixels.'),
upload_to='pwa',
blank=True,
null=True)
offline_text = RichTextField(
verbose_name=_('Offline Information Text'),
default=_('You are currently offline.'),
config_name='small')
offline_retry_button = models.BooleanField(_('Include Retry Button'), default=True)
last_update_timestamp = models.DateTimeField(auto_now=True)
@classmethod
def singleton(cls):
return cls.objects.first() or cls()
@classmethod
def export_for_json(cls):
obj = cls.singleton()
if not obj.id:
return {}
serialized_settings = json.loads(serializers.serialize('json', [obj]))
return serialized_settings[0].get('fields')
@classmethod
def load_serialized_settings(cls, json_settings):
if not json_settings:
return
obj = cls.singleton()
for attr in json_settings:
setattr(obj, attr, json_settings[attr])
obj.save()
class PwaNavigationEntry(models.Model):
label = models.CharField(verbose_name=_('Label'), max_length=150, blank=True)
url = models.CharField(verbose_name=_('External URL'), max_length=200, blank=True)
link_page = models.ForeignKey('data.Page', blank=True,
null=True, verbose_name=_('Internal link'))
icon = models.FileField(_('Icon'), upload_to='pwa', blank=True, null=True)
extra_css_class = models.CharField(_('Extra classes for CSS styling'), max_length=100, blank=True)
order = models.PositiveIntegerField()
notification_count = models.BooleanField(
verbose_name=_('Display notification count'),
default=False)
use_user_name_as_label = models.BooleanField(
verbose_name=_('Use user name as label'),
default=False)
class Meta:
ordering = ('order',)
def get_label(self):
return self.label or self.link_page.title
def get_url(self):
if self.link_page:
return self.link_page.get_online_url()
else:
return utils.get_templated_url(self.url)
def css_class_names(self):
css_class_names = self.extra_css_class or ''
if self.link_page:
css_class_names += ' page-%s' % self.link_page.slug
return css_class_names
@classmethod
def export_all_for_json(cls):
return [x.get_as_serialized_object() for x in cls.objects.all()]
def get_as_serialized_object(self):
serialized_entry = json.loads(serializers.serialize('json', [self],
use_natural_foreign_keys=True, use_natural_primary_keys=True))[0]
if self.icon:
encode = base64.encodestring if six.PY2 else base64.encodebytes
serialized_entry['icon:base64'] = force_text(encode(self.icon.read()))
del serialized_entry['model']
del serialized_entry['pk']
return serialized_entry
@classmethod
def load_serialized_objects(cls, json_site):
for json_entry in json_site:
cls.load_serialized_object(json_entry)
@classmethod
def load_serialized_object(cls, json_entry):
json_entry['model'] = 'pwa.pwanavigationentry'
# deserialize once to get link_page by natural key
fake_entry = [x for x in serializers.deserialize('json', json.dumps([json_entry]))][0]
entry, created = cls.objects.get_or_create(
label=json_entry['fields']['label'],
url=json_entry['fields']['url'],
link_page=fake_entry.object.link_page,
defaults={'order': 0})
json_entry['pk'] = entry.id
entry = [x for x in serializers.deserialize('json', json.dumps([json_entry]))][0]
entry.save()
if json_entry.get('icon:base64'):
decode = base64.decodestring if six.PY2 else base64.decodebytes
decoded_icon = decode(force_bytes(json_entry['icon:base64']))
if not default_storage.exists(entry.object.icon.name) or entry.object.icon.read() != decoded_icon:
# save new file
entry.object.icon.save(entry.object.icon.name, ContentFile(decoded_icon))
class PushSubscription(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
subscription_info = JSONField()
creation_timestamp = models.DateTimeField(auto_now_add=True)