momo: add management command to regenerate manifest (#10858)
This commit is contained in:
parent
ad995eaf4c
commit
9d0b3d8d8a
|
@ -0,0 +1,50 @@
|
||||||
|
# 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/>.
|
||||||
|
|
||||||
|
from urlparse import urlparse
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
from django.db import connection
|
||||||
|
from django.test.client import RequestFactory
|
||||||
|
from django.utils import translation
|
||||||
|
|
||||||
|
from combo.apps.momo.utils import generate_manifest, GenerationError, GenerationInfo
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
def handle(self, *args, **kwargs):
|
||||||
|
if not getattr(settings, 'ENABLE_MOMO', False):
|
||||||
|
return
|
||||||
|
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
|
||||||
|
|
||||||
|
translation.activate(settings.LANGUAGE_CODE)
|
||||||
|
try:
|
||||||
|
generate_manifest(request)
|
||||||
|
except GenerationError as e:
|
||||||
|
raise CommandError(e.message)
|
||||||
|
except GenerationInfo as e:
|
||||||
|
if kwargs.get('verbosity') > 0:
|
||||||
|
print e.message
|
||||||
|
translation.deactivate()
|
|
@ -0,0 +1,268 @@
|
||||||
|
# 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.template import RequestContext
|
||||||
|
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_name]
|
||||||
|
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 = RequestContext(request, {
|
||||||
|
'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.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 hasattr(page, '_children') and page._children:
|
||||||
|
children = page._children
|
||||||
|
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
|
||||||
|
children = []
|
||||||
|
homepage = None
|
||||||
|
for page in level0_pages:
|
||||||
|
if page.slug == 'index':
|
||||||
|
homepage = page
|
||||||
|
else:
|
||||||
|
children.append(page)
|
||||||
|
|
||||||
|
if not homepage:
|
||||||
|
raise GenerationError(_('The homepage needs to be created first.'))
|
||||||
|
|
||||||
|
homepage._children = children
|
||||||
|
manifest.update(get_page_dict(request, homepage, manifest))
|
||||||
|
|
||||||
|
# footer
|
||||||
|
footer_cells = CellBase.get_cells(page_id=homepage.id, placeholder='footer')
|
||||||
|
if footer_cells:
|
||||||
|
context = RequestContext(request, {
|
||||||
|
'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.'))
|
|
@ -14,259 +14,27 @@
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# 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/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import datetime
|
|
||||||
import json
|
|
||||||
import shutil
|
|
||||||
import os
|
|
||||||
import zipfile
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.files.storage import default_storage
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.template import RequestContext
|
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.views.generic import TemplateView, UpdateView
|
from django.views.generic import TemplateView, UpdateView
|
||||||
|
|
||||||
import ckeditor
|
from .models import MomoOptions
|
||||||
|
from .utils import generate_manifest, GenerationError, GenerationInfo
|
||||||
from combo.data.models import CellBase, LinkCell, FeedCell, Page
|
|
||||||
from .models import MomoIconCell, MomoOptions
|
|
||||||
|
|
||||||
|
|
||||||
class MomoManagerView(TemplateView):
|
class MomoManagerView(TemplateView):
|
||||||
template_name = 'momo/manager_home.html'
|
template_name = 'momo/manager_home.html'
|
||||||
|
|
||||||
|
|
||||||
def render_cell(cell, context):
|
|
||||||
classnames = ['cell', cell.css_class_name]
|
|
||||||
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 = RequestContext(request, {
|
|
||||||
'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.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 hasattr(page, '_children') and page._children:
|
|
||||||
children = page._children
|
|
||||||
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(request, **kwargs):
|
def generate(request, **kwargs):
|
||||||
if not default_storage.exists('assets-base.zip'):
|
try:
|
||||||
messages.error(request, _('Missing base assets file'))
|
generate_manifest(request)
|
||||||
return HttpResponseRedirect(reverse('momo-manager-homepage'))
|
except GenerationError as e:
|
||||||
|
message.error(request, e.message)
|
||||||
manifest = {
|
except GenerationInfo as e:
|
||||||
'menu': [],
|
messages.info(request, e.message)
|
||||||
'_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
|
|
||||||
children = []
|
|
||||||
homepage = None
|
|
||||||
for page in level0_pages:
|
|
||||||
if page.slug == 'index':
|
|
||||||
homepage = page
|
|
||||||
else:
|
|
||||||
children.append(page)
|
|
||||||
|
|
||||||
if not homepage:
|
|
||||||
messages.error(request, _('The homepage needs to be created first.'))
|
|
||||||
return HttpResponseRedirect(reverse('momo-manager-homepage'))
|
|
||||||
|
|
||||||
homepage._children = children
|
|
||||||
manifest.update(get_page_dict(request, homepage, manifest))
|
|
||||||
|
|
||||||
# footer
|
|
||||||
footer_cells = CellBase.get_cells(page_id=homepage.id, placeholder='footer')
|
|
||||||
if footer_cells:
|
|
||||||
context = RequestContext(request, {
|
|
||||||
'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:
|
|
||||||
messages.info(request, _('No changes were detected.'))
|
|
||||||
return HttpResponseRedirect(reverse('momo-manager-homepage'))
|
|
||||||
|
|
||||||
# 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'))
|
|
||||||
|
|
||||||
messages.info(request, _('A new update (including new assets) has been generated.'))
|
|
||||||
else:
|
|
||||||
messages.info(request, _('A new update has been generated.'))
|
|
||||||
|
|
||||||
return HttpResponseRedirect(reverse('momo-manager-homepage'))
|
return HttpResponseRedirect(reverse('momo-manager-homepage'))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
su combo -s /bin/sh -c "/usr/bin/combo-manage tenant_command update_transactions --all-tenants"
|
su combo -s /bin/sh -c "/usr/bin/combo-manage tenant_command update_transactions --all-tenants"
|
||||||
|
su combo -s /bin/sh -c "/usr/bin/combo-manage tenant_command update_momo_manifest --all-tenants -v0"
|
||||||
|
|
Loading…
Reference in New Issue