From b7763d995f434c0bca009dcc1d7faefaa07420c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Wed, 8 May 2019 17:50:45 +0200 Subject: [PATCH] general: remove combo.apps.momo (#32913) --- MANIFEST.in | 1 - combo/apps/momo/README | 15 - combo/apps/momo/__init__.py | 64 ----- combo/apps/momo/migrations/0001_initial.py | 32 --- .../apps/momo/migrations/0002_momooptions.py | 27 -- .../migrations/0003_auto_20151021_1616.py | 20 -- .../0004_momoiconcell_description.py | 25 -- .../0005_momoiconcell_embed_page.py | 20 -- .../migrations/0006_momooptions_extra_css.py | 20 -- ...007_momoiconcell_restricted_to_unlogged.py | 20 -- .../migrations/0008_momoiconcell_style.py | 20 -- .../migrations/0009_auto_20160504_1036.py | 19 -- .../migrations/0010_auto_20160928_1152.py | 24 -- ...0011_momoiconcell_last_update_timestamp.py | 28 -- combo/apps/momo/migrations/__init__.py | 0 combo/apps/momo/models.py | 90 ------ .../momo/templates/momo/manager_base.html | 11 - .../momo/templates/momo/manager_home.html | 18 -- .../momo/templates/momo/momooptions_form.html | 19 -- combo/apps/momo/urls.py | 32 --- combo/apps/momo/utils.py | 260 ------------------ combo/apps/momo/views.py | 48 ---- combo/settings.py | 1 - tests/test_momo.py | 103 ------- 24 files changed, 917 deletions(-) delete mode 100644 combo/apps/momo/README delete mode 100644 combo/apps/momo/__init__.py delete mode 100644 combo/apps/momo/migrations/0001_initial.py delete mode 100644 combo/apps/momo/migrations/0002_momooptions.py delete mode 100644 combo/apps/momo/migrations/0003_auto_20151021_1616.py delete mode 100644 combo/apps/momo/migrations/0004_momoiconcell_description.py delete mode 100644 combo/apps/momo/migrations/0005_momoiconcell_embed_page.py delete mode 100644 combo/apps/momo/migrations/0006_momooptions_extra_css.py delete mode 100644 combo/apps/momo/migrations/0007_momoiconcell_restricted_to_unlogged.py delete mode 100644 combo/apps/momo/migrations/0008_momoiconcell_style.py delete mode 100644 combo/apps/momo/migrations/0009_auto_20160504_1036.py delete mode 100644 combo/apps/momo/migrations/0010_auto_20160928_1152.py delete mode 100644 combo/apps/momo/migrations/0011_momoiconcell_last_update_timestamp.py delete mode 100644 combo/apps/momo/migrations/__init__.py delete mode 100644 combo/apps/momo/models.py delete mode 100644 combo/apps/momo/templates/momo/manager_base.html delete mode 100644 combo/apps/momo/templates/momo/manager_home.html delete mode 100644 combo/apps/momo/templates/momo/momooptions_form.html delete mode 100644 combo/apps/momo/urls.py delete mode 100644 combo/apps/momo/utils.py delete mode 100644 combo/apps/momo/views.py delete mode 100644 tests/test_momo.py diff --git a/MANIFEST.in b/MANIFEST.in index 1815bb05..7c3965ce 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -25,7 +25,6 @@ recursive-include combo/apps/fargo/templates *.html recursive-include combo/apps/gallery/templates *.html recursive-include combo/apps/lingo/templates *.html recursive-include combo/apps/maps/templates *.html -recursive-include combo/apps/momo/templates *.html recursive-include combo/apps/newsletters/templates *.html recursive-include combo/apps/notifications/templates *.html recursive-include combo/apps/pwa/templates *.html *.js *.json diff --git a/combo/apps/momo/README b/combo/apps/momo/README deleted file mode 100644 index a87afb47..00000000 --- a/combo/apps/momo/README +++ /dev/null @@ -1,15 +0,0 @@ -Combo/momo integration -====================== - -Support is off by default, set ENABLE_MOMO = True to activate it. - - -The application hierarchy is structured that way: - - - the home screen is the homepage - - the application pages are created from the homepage siblings and their - children - - the application menu is created from direct children of the homepage - - -Link cells are rendered as "see also" links. diff --git a/combo/apps/momo/__init__.py b/combo/apps/momo/__init__.py deleted file mode 100644 index 94b5c6a6..00000000 --- a/combo/apps/momo/__init__.py +++ /dev/null @@ -1,64 +0,0 @@ -# combo - content management system -# Copyright (C) 2015 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 . - -import django.apps -from django.conf import settings -from django.core.urlresolvers import reverse -from django.db import connection -from django.test.client import RequestFactory -from django.utils import translation -from django.utils.six.moves.urllib.parse import urlparse -from django.utils.translation import ugettext_lazy as _ - -class AppConfig(django.apps.AppConfig): - name = 'combo.apps.momo' - verbose_name = _('Mobile Application') - - def is_enabled(self): - return getattr(settings, 'ENABLE_MOMO', False) - - def get_before_urls(self): - from . import urls - return urls.urlpatterns - - def get_extra_manager_actions(self): - return [{'href': reverse('momo-manager-homepage'), - 'text': _('Mobile Application')}] - - def hourly(self): - from .utils import GenerationInfo - try: - self.update_momo_manifest() - except GenerationInfo: - pass - - def update_momo_manifest(self): - from .utils import generate_manifest - tenant = connection.get_tenant() - parsed_base_url = urlparse(tenant.get_base_url()) - if ':' in parsed_base_url.netloc: - server_name, server_port = parsed_base_url.netloc.split(':') - else: - server_name = parsed_base_url.netloc - server_port = '80' if parsed_base_url.scheme == 'http' else '443' - request = RequestFactory().get('/', SERVER_NAME=server_name, - SERVER_PORT=server_port) - request._get_scheme = lambda: parsed_base_url.scheme - - with translation.override(settings.LANGUAGE_CODE): - generate_manifest(request) - -default_app_config = 'combo.apps.momo.AppConfig' diff --git a/combo/apps/momo/migrations/0001_initial.py b/combo/apps/momo/migrations/0001_initial.py deleted file mode 100644 index f5b03444..00000000 --- a/combo/apps/momo/migrations/0001_initial.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import models, migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('auth', '0001_initial'), - ('data', '0010_feedcell'), - ] - - operations = [ - migrations.CreateModel( - name='MomoIconCell', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('placeholder', models.CharField(max_length=20)), - ('order', models.PositiveIntegerField()), - ('slug', models.SlugField(verbose_name='Slug', blank=True)), - ('public', models.BooleanField(default=True, verbose_name='Public')), - ('icon', models.CharField(default=b'', max_length=50, verbose_name='Icon', blank=True, choices=[(b'fa-home', 'Home'), (b'fa-globe', 'Globe'), (b'fa-mobile', 'Mobile'), (b'fa-comments', 'Comments'), (b'fa-map', 'Map'), (b'fa-users', 'Users'), (b'fa-institution', 'Institution'), (b'fa-bullhorn', 'Bull Horn'), (b'fa-calendar', 'Calendar'), (b'fa-map-marker', 'Map Marker'), (b'fa-book', 'Book')])), - ('groups', models.ManyToManyField(to='auth.Group', verbose_name='Groups', blank=True)), - ('page', models.ForeignKey(to='data.Page')), - ], - options={ - 'verbose_name': 'Icon for mobile', - }, - bases=(models.Model,), - ), - ] diff --git a/combo/apps/momo/migrations/0002_momooptions.py b/combo/apps/momo/migrations/0002_momooptions.py deleted file mode 100644 index 2679b153..00000000 --- a/combo/apps/momo/migrations/0002_momooptions.py +++ /dev/null @@ -1,27 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import models, migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('momo', '0001_initial'), - ] - - operations = [ - migrations.CreateModel( - name='MomoOptions', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('title', models.CharField(max_length=100, null=True, verbose_name='Application Title')), - ('contact_email', models.EmailField(max_length=75, null=True, verbose_name='Contact Email')), - ('update_freq', models.PositiveIntegerField(default=86400, null=True, verbose_name='Update Frequency (in seconds)')), - ('icons_on_homepage', models.BooleanField(default=False, verbose_name='Use icons on the homepage')), - ], - options={ - }, - bases=(models.Model,), - ), - ] diff --git a/combo/apps/momo/migrations/0003_auto_20151021_1616.py b/combo/apps/momo/migrations/0003_auto_20151021_1616.py deleted file mode 100644 index ef3e5fb6..00000000 --- a/combo/apps/momo/migrations/0003_auto_20151021_1616.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import models, migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('momo', '0002_momooptions'), - ] - - operations = [ - migrations.AlterField( - model_name='momoiconcell', - name='icon', - field=models.CharField(default=b'', max_length=50, verbose_name='Icon', blank=True, choices=[(b'fa-home', 'Home'), (b'fa-globe', 'Globe'), (b'fa-mobile', 'Mobile'), (b'fa-comments', 'Comments'), (b'fa-map', 'Map'), (b'fa-users', 'Users'), (b'fa-institution', 'Institution'), (b'fa-bullhorn', 'Bull Horn'), (b'fa-calendar', 'Calendar'), (b'fa-map-marker', 'Map Marker'), (b'fa-book', 'Book'), (b'fa-envelope', 'Envelope'), (b'fa-car', 'Car'), (b'fa-road', 'Road')]), - preserve_default=True, - ), - ] diff --git a/combo/apps/momo/migrations/0004_momoiconcell_description.py b/combo/apps/momo/migrations/0004_momoiconcell_description.py deleted file mode 100644 index fecc210c..00000000 --- a/combo/apps/momo/migrations/0004_momoiconcell_description.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import models, migrations -import ckeditor.fields - - -class Migration(migrations.Migration): - - dependencies = [ - ('momo', '0003_auto_20151021_1616'), - ] - - operations = [ - migrations.AlterModelOptions( - name='momoiconcell', - options={'verbose_name': 'Meta for mobile'}, - ), - migrations.AddField( - model_name='momoiconcell', - name='description', - field=ckeditor.fields.RichTextField(null=True, verbose_name='Description', blank=True), - preserve_default=True, - ), - ] diff --git a/combo/apps/momo/migrations/0005_momoiconcell_embed_page.py b/combo/apps/momo/migrations/0005_momoiconcell_embed_page.py deleted file mode 100644 index 47d41613..00000000 --- a/combo/apps/momo/migrations/0005_momoiconcell_embed_page.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import models, migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('momo', '0004_momoiconcell_description'), - ] - - operations = [ - migrations.AddField( - model_name='momoiconcell', - name='embed_page', - field=models.BooleanField(default=False, verbose_name='Embed redirection URL'), - preserve_default=True, - ), - ] diff --git a/combo/apps/momo/migrations/0006_momooptions_extra_css.py b/combo/apps/momo/migrations/0006_momooptions_extra_css.py deleted file mode 100644 index d67f7d45..00000000 --- a/combo/apps/momo/migrations/0006_momooptions_extra_css.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import models, migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('momo', '0005_momoiconcell_embed_page'), - ] - - operations = [ - migrations.AddField( - model_name='momooptions', - name='extra_css', - field=models.CharField(max_length=100, null=True, verbose_name='Extra CSS', blank=True), - preserve_default=True, - ), - ] diff --git a/combo/apps/momo/migrations/0007_momoiconcell_restricted_to_unlogged.py b/combo/apps/momo/migrations/0007_momoiconcell_restricted_to_unlogged.py deleted file mode 100644 index 65065789..00000000 --- a/combo/apps/momo/migrations/0007_momoiconcell_restricted_to_unlogged.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import models, migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('momo', '0006_momooptions_extra_css'), - ] - - operations = [ - migrations.AddField( - model_name='momoiconcell', - name='restricted_to_unlogged', - field=models.BooleanField(default=False, verbose_name='Restrict to unlogged users'), - preserve_default=True, - ), - ] diff --git a/combo/apps/momo/migrations/0008_momoiconcell_style.py b/combo/apps/momo/migrations/0008_momoiconcell_style.py deleted file mode 100644 index a0eb5304..00000000 --- a/combo/apps/momo/migrations/0008_momoiconcell_style.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import models, migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('momo', '0007_momoiconcell_restricted_to_unlogged'), - ] - - operations = [ - migrations.AddField( - model_name='momoiconcell', - name='style', - field=models.CharField(default=b'', max_length=128, verbose_name='Style', blank=True), - preserve_default=True, - ), - ] diff --git a/combo/apps/momo/migrations/0009_auto_20160504_1036.py b/combo/apps/momo/migrations/0009_auto_20160504_1036.py deleted file mode 100644 index 32ab19fa..00000000 --- a/combo/apps/momo/migrations/0009_auto_20160504_1036.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('momo', '0008_momoiconcell_style'), - ] - - operations = [ - migrations.AlterField( - model_name='momoiconcell', - name='icon', - field=models.CharField(default=b'', max_length=50, verbose_name='Icon', blank=True, choices=[(b'fa-home', 'Home'), (b'fa-globe', 'Globe'), (b'fa-mobile', 'Mobile'), (b'fa-comments', 'Comments'), (b'fa-map', 'Map'), (b'fa-users', 'Users'), (b'fa-institution', 'Institution'), (b'fa-bullhorn', 'Bull Horn'), (b'fa-calendar', 'Calendar'), (b'fa-map-marker', 'Map Marker'), (b'fa-book', 'Book'), (b'fa-envelope', 'Envelope'), (b'fa-car', 'Car'), (b'fa-road', 'Road'), (b'fa-heart', 'Heart')]), - ), - ] diff --git a/combo/apps/momo/migrations/0010_auto_20160928_1152.py b/combo/apps/momo/migrations/0010_auto_20160928_1152.py deleted file mode 100644 index 3dde3eec..00000000 --- a/combo/apps/momo/migrations/0010_auto_20160928_1152.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('momo', '0009_auto_20160504_1036'), - ] - - operations = [ - migrations.AddField( - model_name='momoiconcell', - name='extra_css_class', - field=models.CharField(max_length=100, verbose_name='Extra classes for CSS styling', blank=True), - ), - migrations.AlterField( - model_name='momooptions', - name='contact_email', - field=models.EmailField(max_length=254, null=True, verbose_name='Contact Email'), - ), - ] diff --git a/combo/apps/momo/migrations/0011_momoiconcell_last_update_timestamp.py b/combo/apps/momo/migrations/0011_momoiconcell_last_update_timestamp.py deleted file mode 100644 index 0aa575e5..00000000 --- a/combo/apps/momo/migrations/0011_momoiconcell_last_update_timestamp.py +++ /dev/null @@ -1,28 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import migrations, models -import datetime -from django.utils.timezone import utc -import combo.data.fields - - -class Migration(migrations.Migration): - - dependencies = [ - ('momo', '0010_auto_20160928_1152'), - ] - - operations = [ - migrations.AddField( - model_name='momoiconcell', - name='last_update_timestamp', - field=models.DateTimeField(default=datetime.datetime.now(utc), auto_now=True), - preserve_default=False, - ), - migrations.AlterField( - model_name='momoiconcell', - name='description', - field=combo.data.fields.RichTextField(null=True, verbose_name='Description', blank=True), - ), - ] diff --git a/combo/apps/momo/migrations/__init__.py b/combo/apps/momo/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/combo/apps/momo/models.py b/combo/apps/momo/models.py deleted file mode 100644 index 564bb9a8..00000000 --- a/combo/apps/momo/models.py +++ /dev/null @@ -1,90 +0,0 @@ -# combo - content management system -# Copyright (C) 2014-2015 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 . - -from django.apps import apps -from django.db import models -from django.forms import models as model_forms -from django.forms import Select -from django.utils.translation import ugettext_lazy as _ - -from combo.data.fields import RichTextField -from combo.data.models import CellBase -from combo.data.library import register_cell_class - - -class MomoOptions(models.Model): - title = models.CharField(_('Application Title'), max_length=100, null=True) - contact_email = models.EmailField(_('Contact Email'), null=True) - update_freq = models.PositiveIntegerField(_('Update Frequency (in seconds)'), - default=86400, null=True) - icons_on_homepage = models.BooleanField( - _('Use icons on the homepage'), default=False) - extra_css = models.CharField(_('Extra CSS'), max_length=100, blank=True, null=True) - - def save(self, *args, **kwargs): - self.id = 1 - return super(MomoOptions, self).save(*args, **kwargs) - - @classmethod - def get_object(cls, *args, **kwargs): - obj, created = cls.objects.get_or_create(pk=1) - return obj - - -@register_cell_class -class MomoIconCell(CellBase): - # initially for icons, now it holds additional page metadata such as - # description. - - icon = models.CharField(_('Icon'), max_length=50, - default='', blank=True, - choices=[ - ('fa-home', _('Home')), - ('fa-globe', _('Globe')), - ('fa-mobile', _('Mobile')), - ('fa-comments', _('Comments')), - ('fa-map', _('Map')), - ('fa-users', _('Users')), - ('fa-institution', _('Institution')), - ('fa-bullhorn', _('Bull Horn')), - ('fa-calendar', _('Calendar')), - ('fa-map-marker', _('Map Marker')), - ('fa-book', _('Book')), - ('fa-envelope', _('Envelope')), - ('fa-car', _('Car')), - ('fa-road', _('Road')), - ('fa-heart', _('Heart')), - ]) - description = RichTextField(_('Description'), blank=True, null=True) - style = models.CharField(_('Style'), max_length=128, default='', blank=True) - embed_page = models.BooleanField(_('Embed redirection URL'), default=False) - - class Meta: - verbose_name = _('Meta for mobile') - - def render(self, context): - return '' - - @classmethod - def is_enabled(cls): - return apps.get_app_config('momo').is_enabled() - - def get_default_form_class(self): - sorted_icons = self._meta.get_field('icon').choices - sorted_icons.sort(key=lambda x: x[1]) - return model_forms.modelform_factory(self.__class__, - fields=['icon', 'style', 'description', 'embed_page'], - widgets={'icon': Select(choices=sorted_icons)}) diff --git a/combo/apps/momo/templates/momo/manager_base.html b/combo/apps/momo/templates/momo/manager_base.html deleted file mode 100644 index eaf3b995..00000000 --- a/combo/apps/momo/templates/momo/manager_base.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends "combo/manager_base.html" %} -{% load i18n %} - -{% block appbar %} -

{% trans 'Mobile Application' %}

-{% endblock %} - -{% block breadcrumb %} -{{ block.super }} -{% trans 'Mobile Application' %} -{% endblock %} diff --git a/combo/apps/momo/templates/momo/manager_home.html b/combo/apps/momo/templates/momo/manager_home.html deleted file mode 100644 index 5f3297e3..00000000 --- a/combo/apps/momo/templates/momo/manager_home.html +++ /dev/null @@ -1,18 +0,0 @@ -{% extends "momo/manager_base.html" %} -{% load i18n %} - -{% block appbar %} -

{% trans 'Mobile Application' %}

-{% endblock %} - -{% block content %} - -

-{% trans 'Options' %} -

- -

-{% trans 'Generate Content Update' %} -

- -{% endblock %} diff --git a/combo/apps/momo/templates/momo/momooptions_form.html b/combo/apps/momo/templates/momo/momooptions_form.html deleted file mode 100644 index 35c14c90..00000000 --- a/combo/apps/momo/templates/momo/momooptions_form.html +++ /dev/null @@ -1,19 +0,0 @@ -{% extends "momo/manager_base.html" %} -{% load i18n %} - -{% block appbar %} -

{% trans "Options" %}

-{% endblock %} - -{% block content %} - -
- {% csrf_token %} - {{ form.as_p }} -
- - {% trans 'Cancel' %} -
-
-{% endblock %} - diff --git a/combo/apps/momo/urls.py b/combo/apps/momo/urls.py deleted file mode 100644 index 89145a24..00000000 --- a/combo/apps/momo/urls.py +++ /dev/null @@ -1,32 +0,0 @@ -# combo - content management system -# Copyright (C) 2015 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 . - -from django.conf.urls import url, include - -from combo.urls_utils import decorated_includes, manager_required - -from .views import MomoManagerView, OptionsUpdateView, generate - -momo_manager_urls = [ - url('^$', MomoManagerView.as_view(), name='momo-manager-homepage'), - url('^options/$', OptionsUpdateView.as_view(), name='momo-manager-options'), - url('^generate/$', generate, name='momo-manager-generate'), -] - -urlpatterns = [ - url(r'^manage/momo/', decorated_includes(manager_required, - include(momo_manager_urls))), -] diff --git a/combo/apps/momo/utils.py b/combo/apps/momo/utils.py deleted file mode 100644 index abb25f18..00000000 --- a/combo/apps/momo/utils.py +++ /dev/null @@ -1,260 +0,0 @@ -# combo - content management system -# Copyright (C) 2016 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 . - -import datetime -import json -import os -import shutil -import zipfile - -from django.core.files.storage import default_storage -from django.utils.translation import ugettext as _ - -import ckeditor -import ckeditor.views - -from combo.data.models import CellBase, LinkCell, FeedCell, Page -from .models import MomoIconCell, MomoOptions - - -class GenerationError(Exception): - pass - - -class GenerationInfo(Exception): - pass - - -def render_cell(cell, context): - classnames = ['cell', cell.css_class_names] - if cell.slug: - classnames.append(cell.slug) - return '
%s
' % (' '.join(classnames), cell.render(context)) - - -def get_page_dict(request, page, manifest): - cells = [x for x in CellBase.get_cells(page_id=page.id) if x.placeholder != 'footer'] - - page_dict = { - 'title': page.title, - 'id': 'page-%s-%s' % (page.slug, page.id), - } - - link_cells = [x for x in cells if isinstance(x, LinkCell)] - icon_cells = [x for x in cells if isinstance(x, MomoIconCell)] - feed_cells = [x for x in cells if isinstance(x, FeedCell)] - cells = [x for x in cells if not (isinstance(x, LinkCell) or isinstance(x, FeedCell))] - - if cells: - context = { - 'synchronous': True, - 'page': page, - 'page_cells': cells, - 'request': request, - 'site_base': request.build_absolute_uri('/')[:-1], - } - page_dict['content'] = '\n'.join([render_cell(cell, context) for cell in cells]) - - if link_cells: - page_dict['seealso'] = [] - for cell in link_cells: - if cell.link_page: - # internal link - page_dict['seealso'].append('page-%s-%s' % - (cell.link_page.slug, cell.link_page.id)) - else: - # external link - page_dict['seealso'].append('seealso-%s' % cell.id) - manifest['_pages'].append({ - 'title': cell.title, - 'external': True, - 'url': cell.url, - 'id': 'seealso-%s' % cell.id}) - - if page.redirect_url: - page_dict['external'] = True - page_dict['url'] = page.get_redirect_url() - - if icon_cells: - page_dict['icon'] = icon_cells[0].icon - page_dict['style'] = icon_cells[0].style - page_dict['description'] = icon_cells[0].description - if page_dict.get('external') and icon_cells[0].embed_page: - page_dict['external'] = False - - if page.slug == 'index' and page.parent_id is None: # home - children = page.get_siblings()[1:] - else: - children = page.get_children() - - if children: - page_dict['pages'] = [] - for child in children: - page_dict['pages'].append(get_page_dict(request, child, manifest)) - - if feed_cells: - if not 'pages' in page_dict: - page_dict['pages'] = [] - # turn feed entries in external pages - for feed_cell in feed_cells: - feed_context = feed_cell.get_cell_extra_context({}) - if feed_context.get('feed'): - for entry in feed_context.get('feed').entries: - feed_entry_page = { - 'title': entry.title, - 'id': 'feed-entry-%s-%s' % (feed_cell.id, entry.id), - 'url': entry.link, - 'external': True, - } - if entry.description: - feed_entry_page['description'] = entry.description - page_dict['pages'].append(feed_entry_page) - - return page_dict - - - - -def generate_manifest(request): - if not default_storage.exists('assets-base.zip'): - raise GenerationError(_('Missing base assets file')) - - manifest = { - 'menu': [], - '_pages': [] - } - level0_pages = Page.objects.filter(parent=None) - - # the application hierarchy is structured that way: - # - the home screen is the homepage - # - the application pages are created from the homepage siblings and their - # children - # - the application menu is created from direct children of the homepage - try: - homepage = Page.objects.get(slug='index', parent_id=None) - except Page.DoesNotExist: - raise GenerationError(_('The homepage needs to be created first.')) - - manifest.update(get_page_dict(request, homepage, manifest)) - - # footer - footer_cells = CellBase.get_cells(page_id=homepage.id, placeholder='footer') - if footer_cells: - context = { - 'synchronous': True, - 'page': homepage, - 'page_cells': footer_cells, - 'request': request, - 'site_base': request.build_absolute_uri('/')[:-1], - } - manifest['footer'] = '\n'.join([ - '' % (cell.slug, cell.render(context)) for cell in footer_cells]) - - # construct the application menu - manifest['menu'].append('home') # link to home screen - - # add real homepage children - menu_children = homepage.get_children() - for menu_child in menu_children: - link_cells = LinkCell.objects.filter(page_id=menu_child.id) - if link_cells: - # use link info instead of redirect url - link_cell = link_cells[0] - if link_cell.link_page: # internal link - menu_id = 'page-%s-%s' % (link_cell.link_page.slug, link_cell.link_page.id) - else: - menu_id = 'menu-%s-%s' % (menu_child.slug, menu_child.id) - link_context = link_cell.get_cell_extra_context({}) - manifest['_pages'].append({ - 'title': link_context['title'], - 'external': True, - 'url': link_context['url'], - 'id': menu_id, - }) - else: - menu_id = 'menu-%s-%s' % (menu_child.slug, menu_child.id) - manifest['_pages'].append({ - 'title': menu_child.title, - 'external': True, - 'url': menu_child.redirect_url, - 'id': menu_id, - }) - manifest['menu'].append(menu_id) - - # last item, application refresh - manifest['menu'].append({ - 'icon': 'fa-refresh', - 'id': 'momo-update', - 'title': _('Update Application')}) - - options = MomoOptions.get_object() - manifest['meta'] = { - 'title': options.title or homepage.title, - 'icon': 'icon.png', - 'contact': options.contact_email or 'info@entrouvert.com', - 'updateFreq': options.update_freq or 86400, - 'manifestUrl': request.build_absolute_uri(default_storage.url('index.json')), - 'assetsUrl': request.build_absolute_uri(default_storage.url('assets.zip')), - 'stylesheets': ["assets/index.css"], - } - - if options.extra_css: - manifest['meta']['stylesheets'].append('assets/%s' % options.extra_css) - - if options.icons_on_homepage: - manifest['display'] = 'icons' - - current_manifest = None - if default_storage.exists('index.json'): - with default_storage.open('index.json', mode='r') as fp: - current_manifest = fp.read() - - new_manifest = json.dumps(manifest, indent=2) - if new_manifest != current_manifest: - with default_storage.open('index.json', mode='w') as fp: - fp.write(new_manifest) - else: - raise GenerationInfo(_('No changes were detected.')) - - # assets.zip - if default_storage.exists('assets.zip'): - zf = zipfile.ZipFile(default_storage.open('assets.zip')) - existing_files = set([x for x in zf.namelist() if x[0] != '/' and x[-1] != '/']) - zf.close() - assets_mtime = default_storage.modified_time('assets.zip') - else: - existing_files = set([]) - assets_mtime = datetime.datetime(2015, 1, 1) - - ckeditor_filenames = set(ckeditor.views.get_image_files()) - media_ckeditor_filenames = set(['media/' + x for x in ckeditor_filenames]) - - if not media_ckeditor_filenames.issubset(existing_files) or default_storage.modified_time('assets-base.zip') > assets_mtime: - # if there are new files, or if the base assets file changed, we - # generate a new assets.zip - shutil.copy(default_storage.path('assets-base.zip'), - default_storage.path('assets.zip.tmp')) - zf = zipfile.ZipFile(default_storage.path('assets.zip.tmp'), 'a') - for filename in ckeditor_filenames: - zf.write(default_storage.path(filename), 'media/' + filename) - zf.close() - if os.path.exists(default_storage.path('assets.zip')): - os.unlink(default_storage.path('assets.zip')) - os.rename(default_storage.path('assets.zip.tmp'), default_storage.path('assets.zip')) - - raise GenerationInfo(_('A new update (including new assets) has been generated.')) - else: - raise GenerationInfo(_('A new update has been generated.')) diff --git a/combo/apps/momo/views.py b/combo/apps/momo/views.py deleted file mode 100644 index 64d5709a..00000000 --- a/combo/apps/momo/views.py +++ /dev/null @@ -1,48 +0,0 @@ -# combo - content management system -# Copyright (C) 2015 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 . - -from django.contrib import messages -from django.core.urlresolvers import reverse -from django.http import HttpResponseRedirect -from django.utils.encoding import force_text -from django.views.generic import TemplateView, UpdateView - -from .models import MomoOptions -from .utils import generate_manifest, GenerationError, GenerationInfo - - -class MomoManagerView(TemplateView): - template_name = 'momo/manager_home.html' - -def generate(request, **kwargs): - try: - generate_manifest(request) - except GenerationError as e: - messages.error(request, force_text(e)) - except GenerationInfo as e: - messages.info(request, force_text(e)) - return HttpResponseRedirect(reverse('momo-manager-homepage')) - - -class OptionsUpdateView(UpdateView): - model = MomoOptions - fields = '__all__' - - def get_object(self, *args, **kwargs): - return MomoOptions.get_object() - - def get_success_url(self): - return reverse('momo-manager-homepage') diff --git a/combo/settings.py b/combo/settings.py index 015ae4aa..d859cb30 100644 --- a/combo/settings.py +++ b/combo/settings.py @@ -68,7 +68,6 @@ INSTALLED_APPS = ( 'combo.apps.family', 'combo.apps.dataviz', 'combo.apps.lingo', - 'combo.apps.momo', 'combo.apps.newsletters', 'combo.apps.fargo', 'combo.apps.notifications', diff --git a/tests/test_momo.py b/tests/test_momo.py deleted file mode 100644 index b0c681cb..00000000 --- a/tests/test_momo.py +++ /dev/null @@ -1,103 +0,0 @@ -import json -import os -import zipfile - -import pytest -from webtest import TestApp - -from django.conf import settings - -from combo.data.models import Page, CellBase, TextCell, LinkCell, FeedCell - -from .test_manager import login - -pytestmark = pytest.mark.django_db - - -class MomoEnabled(object): - def __enter__(self): - settings.ENABLE_MOMO = True - - def __exit__(self, *args, **kwargs): - settings.ENABLE_MOMO = False - - -@pytest.fixture -def assets_base(): - assets_base_path = os.path.join(settings.MEDIA_ROOT, 'assets-base.zip') - if not os.path.exists(assets_base_path): - fd = open(assets_base_path, 'wb') - z = zipfile.ZipFile(fd, 'w') - z.close() - - -def test_no_menu_if_not_enabled(app, admin_user): - app = login(app) - resp = app.get('/manage/', status=200) - assert not 'Mobile Application' in resp.text - - -def test_menu_if_enabled(app, admin_user): - with MomoEnabled(): - app = login(app) - resp = app.get('/manage/', status=200) - assert 'Mobile Application' in resp.text - -def test_options(app, admin_user): - with MomoEnabled(): - app = login(app) - resp = app.get('/manage/', status=200) - resp = resp.click('Mobile Application') - resp = resp.click('Options') - resp.form['title'] = 'Momo Test' - resp.form['contact_email'] = 'foobar@localhost' - resp = resp.form.submit() - resp = resp.follow() - resp = resp.click('Options') - assert resp.form['title'].value == 'Momo Test' - -def test_generate_no_assets_base(app, admin_user): - with MomoEnabled(): - app = login(app) - resp = app.get('/manage/', status=200) - resp = resp.click('Mobile Application') - resp = resp.click('Generate Content Update') - assert not os.path.exists(os.path.join(settings.MEDIA_ROOT, 'index.json')) - -def test_generate_no_homepage(app, admin_user, assets_base): - with MomoEnabled(): - app = login(app) - resp = app.get('/manage/', status=200) - resp = resp.click('Mobile Application') - resp = resp.click('Generate Content Update') - assert not os.path.exists(os.path.join(settings.MEDIA_ROOT, 'index.json')) - -def test_generate_simple(app, admin_user, assets_base): - Page.objects.all().delete() - page1 = Page(title='My Mobile App', slug='index', template_name='standard') - page1.save() - page2 = Page(title='Two', slug='two', template_name='standard') - page2.save() - page3 = Page(title='Three', slug='three', parent=page1, template_name='standard') - page3.save() - - cell = TextCell(page=page2, placeholder='content', text='Lorem ipsum', order=0) - cell.save() - - cell = TextCell(page=page1, placeholder='footer', text='This is the footer', order=0) - cell.save() - - with MomoEnabled(): - app = login(app) - resp = app.get('/manage/', status=200) - resp = resp.click('Mobile Application') - resp = resp.click('Generate Content Update') - assert os.path.exists(os.path.join(settings.MEDIA_ROOT, 'index.json')) - assert os.path.exists(os.path.join(settings.MEDIA_ROOT, 'assets.zip')) - content = json.load(open(os.path.join(settings.MEDIA_ROOT, 'index.json'))) - assert content['meta']['title'] == 'My Mobile App' - assert 'This is the footer' in content['footer'] - assert len(content['pages']) == 1 - assert content['pages'][0]['title'] == 'Two' - assert 'Lorem ipsum' in content['pages'][0]['content'] - assert 'menu-three-%s' % page3.id in content['menu']