From f0d94a76b7ca969349ffd3f26a04e5cc5d2717ec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
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 18584155..32f6f05e 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -21,7 +21,6 @@ recursive-include combo/apps/family/templates *.html
 recursive-include combo/apps/fargo/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 <http://www.gnu.org/licenses/>.
-
-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 <http://www.gnu.org/licenses/>.
-
-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 %}
-<h2>{% trans 'Mobile Application' %}</h2>
-{% endblock %}
-
-{% block breadcrumb %}
-{{ block.super }}
-<a href="{% url 'momo-manager-homepage' %}">{% trans 'Mobile Application' %}</a>
-{% 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 %}
-<h2>{% trans 'Mobile Application' %}</h2>
-{% endblock %}
-
-{% block content %}
-
-<p>
-<a rel="popup" href="{% url 'momo-manager-options' %}">{% trans 'Options' %}</a>
-</p>
-
-<p>
-<a href="{% url 'momo-manager-generate' %}">{% trans 'Generate Content Update' %}</a>
-</p>
-
-{% 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 %}
-<h2>{% trans "Options" %}</h2>
-{% endblock %}
-
-{% block content %}
-
-<form method="post" enctype="multipart/form-data">
-  {% csrf_token %}
-  {{ form.as_p }}
-  <div class="buttons">
-    <button class="submit-button">{% trans "Save" %}</button>
-    <a class="cancel" href="{% url 'momo-manager-homepage' %}">{% trans 'Cancel' %}</a>
-  </div>
-</form>
-{% 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 <http://www.gnu.org/licenses/>.
-
-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 <http://www.gnu.org/licenses/>.
-
-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 '<div class="%s">%s</div>' % (' '.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([
-            '<div id="footer-%s">%s</div>' % (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 <http://www.gnu.org/licenses/>.
-
-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 69a9656e..734d92dc 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']
-- 
2.20.1

