diff --git a/MANIFEST.in b/MANIFEST.in index 71675dd95..f6497fdd9 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,8 +4,6 @@ include wcs.cfg-sample recursive-include wcs/locale *.po *.mo recursive-include extra/ *.py recursive-include data/web/ *.html *.css *.png -recursive-include data/themes/default/ *.html *.css *.png *.gif *.jpg *.js *.ezt *.xml -recursive-include data/themes/alto/ *.html *.css *.png *.gif *.jpg *.js *.ezt *.xml recursive-include data/vendor/ *.dat recursive-include wcs/qommon/static/ *.css *.scss *.png *.gif *.jpg *.js *.eot *.svg *.ttf *.woff *.map recursive-include wcs/templates *.html *.txt diff --git a/data/themes/alto/desc.xml b/data/themes/alto/desc.xml deleted file mode 100644 index d04d745a7..000000000 --- a/data/themes/alto/desc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - Alto theme - Frederic Peters (original Dotclear theme (alto studio) by David Jubert) - diff --git a/data/themes/alto/icon.png b/data/themes/alto/icon.png deleted file mode 100644 index 4276e319e..000000000 Binary files a/data/themes/alto/icon.png and /dev/null differ diff --git a/data/themes/alto/img/bottom.jpg b/data/themes/alto/img/bottom.jpg deleted file mode 100644 index f01a9db42..000000000 Binary files a/data/themes/alto/img/bottom.jpg and /dev/null differ diff --git a/data/themes/alto/img/page.jpg b/data/themes/alto/img/page.jpg deleted file mode 100644 index 47413f7bf..000000000 Binary files a/data/themes/alto/img/page.jpg and /dev/null differ diff --git a/data/themes/alto/img/top.jpg b/data/themes/alto/img/top.jpg deleted file mode 100644 index fc2d41a55..000000000 Binary files a/data/themes/alto/img/top.jpg and /dev/null differ diff --git a/data/themes/alto/template.ezt b/data/themes/alto/template.ezt deleted file mode 100644 index aca3e9009..000000000 --- a/data/themes/alto/template.ezt +++ /dev/null @@ -1,18 +0,0 @@ - - - - [page_title] - - [script] - - -
-

[if-any title][title][else][site_name][end]

-
- [if-any breadcrumb][end] - [body] -
- -
- - diff --git a/data/themes/alto/wcs.css b/data/themes/alto/wcs.css deleted file mode 100644 index 00188ae05..000000000 --- a/data/themes/alto/wcs.css +++ /dev/null @@ -1,270 +0,0 @@ -/* adapted from alto dotclear theme */ - -@import url(/static/xstatic/themes/smoothness/jquery-ui.min.css); -@import url(/static/css/qommon.css); - -html, body { - background: #CCCCCC; - font-family: sans-serif; - color: #333333; - margin: 0; - padding: 0; - text-align: center; - height: 100%; - margin-bottom: 1px; -} - -fieldset { - border: none; -} - -label { - cursor: pointer; - cursor: hand; -} - -img { - border: 0; -} - -input,textarea { - border: 1px solid #999; -} - -textarea { - width: 99%; -} - -a { - color: #000; - text-decoration : none; -} - -a:hover { - color: #0273B9; - text-decoration : underline; -} - -a:visited { - color: #0273B9; - text-decoration : none; -} - -#page { - background: #fff url(img/page.jpg) repeat-y center top; - color: inherit; - width: 886px; - margin: 0 auto; - text-align: left; - padding: 0px; -} - -#top { - margin: 0; - padding: 0; - background: #CCCCCC url(img/top.jpg) no-repeat left top; - margin-bottom: 2em; -} - -#top h1 { - width: 706px; - margin: 0 auto; - padding-top: 70px; -} - -#side { - float: right; - width: 204px; - padding: 0; - margin: 0 -20px 0 20px; -} - -#side #tracking-code { - margin-bottom: 1em; - border: 1px solid #bfbfbf; - color: #333333; - background: #e6e6e6; - padding: 1ex; -} - -#side #tracking-code h3 { - margin: 0; -} - -#side #tracking-code button, -#side #tracking-code a { - margin: 1ex auto; - display: block; - text-align: center; - font-size: 120%; - background: white; - border: 1px solid black; - padding: 0.5ex 0; - width: 10em; -} - -#side #tracking-code button { - background: #0273B9; - color: white; -} - -input[name=savedraft] { - display: none; -} - -#steps { - background: white; - border: 1px solid #bfbfbf; - color: #333333; - background: #e6e6e6; - -moz-border-radius: 6px; - text-align: left; -} - - -#footer { - width: 886px; - height: 123px; - background: #CCCCCC url(img/bottom.jpg) no-repeat left top; - margin: 0; - margin-top: 1em; - color: #666; - clear: both; -} - -#footer p { - width: 706px; - margin: 0 auto; - padding-top: 24px; - text-align: right; - font-size: 80%; -} - - -#main-content { - width: 735px; - padding-left: 65px; - text-align: justify; -} - - -div#steps ol { - list-style: none; - margin: 0; - padding: 0.5em; -} - -div#steps li { - display: block; - border: 1px solid #ddd; - margin: 0.5em 0; - background: #eee; - color: #aaa; -} - -#steps span.marker { - padding: 0 1ex 0 1ex; - font-weight: bold; - color: white; - text-align: center; - background: #ddd; -} - -#steps li.current span.marker { - background: #0273b9; -} - - -#steps li.current { - font-weight: bold; - border: 1px solid #333333; -} - -#steps li.current span.label { - color: #333333; -} - -#steps ol ul { - margin-right: 1em; - font-size: 90%; -} - -#steps ol ul li { - padding: 0 2px; - font-weight: normal; - margin-left: -1ex; -} - -#steps ol ul li.current { - border-color: inherit; - color: #333333; -} - - -div.widget { - clear: none; - margin-bottom: 1.5em; -} - -hr { - visibility: hidden; -} - -textarea { -} - -p#breadcrumb { - background: #e6e6e6; - -moz-border-radius: 6px; - width: 750px; - padding: 3px; - font-size: 90%; - border: 1px solid #bfbfbf; -} - -div#receipt { -} - -div#receipt span.label { - font-weight: bold; - display: block; -} - -div#receipt span.value { - display: block; - margin-left: 1em; -} - -form div.page, -div#receipt div.page { - border: 1px solid #bfbfbf; - padding: 1ex; - margin-bottom: 1em; -} - -form div.page p, -div#receipt div.page p { - margin-top: 0; -} - -form div.page h3, -div#receipt div.page h3 { - margin: 0; - margin-bottom: 1ex; -} - - -p#receiver { - margin: 0; - margin-left: 2em; - margin-top: -0.7em; - margin-bottom: 1em; - padding: 2px 5px; - font-weight: bold; -} - -table#listing { - background: white; - border: 1px solid #888; -} - diff --git a/data/themes/default/desc.xml b/data/themes/default/desc.xml deleted file mode 100644 index 1c4571a8e..000000000 --- a/data/themes/default/desc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - Default theme - Frederic Peters & Dotclear Team - diff --git a/data/themes/default/icon.png b/data/themes/default/icon.png deleted file mode 100644 index f6838d250..000000000 Binary files a/data/themes/default/icon.png and /dev/null differ diff --git a/data/themes/default/mobile.css b/data/themes/default/mobile.css deleted file mode 100644 index e69de29bb..000000000 diff --git a/data/themes/django/templates/wcs/base.html b/data/themes/django/templates/wcs/base.html index 243ff32b6..2b3db1b4e 100644 --- a/data/themes/django/templates/wcs/base.html +++ b/data/themes/django/templates/wcs/base.html @@ -12,7 +12,7 @@
{% block header %} -

WIP/DJANGO - {% if title %}{{ title }}{% else %}{{ site_name }}{% endif %}

+

{% if title %}{{ title }}{% else %}{{ site_name }}{% endif %}

{% endblock %}
diff --git a/tests/admin_pages/test_settings.py b/tests/admin_pages/test_settings.py index cf002a655..801094b3c 100644 --- a/tests/admin_pages/test_settings.py +++ b/tests/admin_pages/test_settings.py @@ -28,7 +28,6 @@ from wcs.data_sources import NamedDataSource from wcs.formdef import FormDef from wcs.qommon.form import UploadedFile from wcs.qommon.http_request import HTTPRequest -from wcs.qommon.template import get_current_theme from wcs.wf.export_to_model import ExportToModel from wcs.workflows import Workflow from wcs.wscalls import NamedWsCall @@ -74,16 +73,14 @@ def test_settings_disabled_screens(pub): app = login(get_app(pub)) resp = app.get('/backoffice/settings/') assert 'Identification' in resp.text - assert 'Theme' in resp.text if not pub.site_options.has_section('options'): pub.site_options.add_section('options') - pub.site_options.set('options', 'settings-disabled-screens', 'identification, theme') + pub.site_options.set('options', 'settings-disabled-screens', 'identification') with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd: pub.site_options.write(fd) resp = app.get('/backoffice/settings/') assert 'Identification' not in resp.text - assert 'Theme' not in resp.text def test_settings_export_import(pub): @@ -318,61 +315,6 @@ def test_settings_export_import(pub): assert 'Unknown referenced objects [Unknown fields blocks: unknown]' in resp -def test_settings_themes(pub): - create_superuser(pub) - app = login(get_app(pub)) - - # create mock theme - os.mkdir(os.path.join(pub.app_dir, 'themes')) - os.mkdir(os.path.join(pub.app_dir, 'themes', 'test')) - with open(os.path.join(pub.app_dir, 'themes', 'test', 'desc.xml'), 'w') as fd: - fd.write( - '' - '' - ' ' - '' - ) - - resp = app.get('/backoffice/settings/themes') - assert 'biglist themes' in resp.text - assert 'Test Theme (1.0)' in resp.text - - # just for the kick, there's no support for uploading file in webtest 1.3 - resp = app.get('/backoffice/settings/themes') - resp.click('Install New Theme') - - # select the theme - resp = app.get('/backoffice/settings/themes') - resp.forms[0]['theme'].value = 'test' - resp = resp.forms[0].submit() - assert resp.location == 'http://example.net/backoffice/settings/' - - resp = app.get('/backoffice/settings/themes') - assert 'checked' in resp.text - assert get_current_theme()['name'] == 'test' - - -def test_settings_template(pub): - create_superuser(pub) - app = login(get_app(pub)) - resp = app.get('/backoffice/settings/template') - - # change template - orig_value = resp.forms[0]['template'].value - assert 'foobar' not in orig_value - resp.forms[0]['template'] = orig_value + '' - resp = resp.forms[0].submit('submit') - - # restore default template - resp = app.get('/backoffice/settings/template') - assert 'foobar' in resp.forms[0]['template'].value - resp = resp.forms[0].submit('restore-default') - - # check - resp = app.get('/backoffice/settings/template') - assert resp.forms[0]['template'].value == orig_value - - def test_settings_user(pub): user = create_superuser(pub) app = login(get_app(pub)) @@ -829,68 +771,6 @@ def test_settings_permissions(pub): assert pub.cfg['admin-permissions']['workflows'] == [] -def test_settings_theme_preview(pub): - create_superuser(pub) - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - app = login(get_app(pub)) - assert 'alto/wcs.css' not in app.get('/').text - resp = app.get('/backoffice/settings/themes') - assert resp.form['theme'].value in ('default', 'django') - - # visit theme preview - resp = resp.click(href='theme_preview/alto/') - assert 'alto/wcs.css' in resp.text - - # get into a form, making sure we are kept in theme preview - resp = resp.click('form title') - assert 'alto/wcs.css' in resp.text - - # verify submits are not allowed - resp = resp.form.submit('submit') - assert "The theme preview doesn't support this." in resp.text - - -def test_settings_theme_download_upload(pub): - create_superuser(pub) - - # download existing theme - app = login(get_app(pub)) - resp = app.get('/backoffice/settings/themes') - resp = resp.click('download', index=0) - assert resp.headers['content-type'] == 'application/zip' - - zip_content = io.BytesIO(resp.body) - with zipfile.ZipFile(zip_content, 'a') as zipf: - filelist = zipf.namelist() - assert 'alto/icon.png' in filelist - assert 'alto/desc.xml' in filelist - assert 'alto/template.ezt' in filelist - assert 'alto/wcs.css' in filelist - - # modify it - zipf.writestr('alto/foobar.txt', 'XXX') - - # upload it - resp = app.get('/backoffice/settings/themes') - resp = resp.click('Install New Theme') - resp.form['file'] = Upload('alto-modified.zip', zip_content.getvalue()) - resp = resp.form.submit() - assert os.path.exists(os.path.join(pub.app_dir, 'themes/alto/foobar.txt')) - - assert app.get('/themes/alto/foobar.txt').text == 'XXX' - assert 'Directory listing denied' in app.get('/themes/alto/', status=200).text - - assert app.get('/themes/alto/plop', status=404) - assert app.get('/themes/alto/../', status=404) - assert app.get('/themes/xxx/../', status=404) - - def test_postgresql_settings(pub): create_superuser(pub) diff --git a/tests/form_pages/test_all.py b/tests/form_pages/test_all.py index b94a479f4..05d6facc9 100644 --- a/tests/form_pages/test_all.py +++ b/tests/form_pages/test_all.py @@ -343,28 +343,6 @@ def test_category_page_redirect_var(pub): assert resp.location == 'http://www.example.com/en/foobar/' -def test_legacy_theme_misc(): - pub = create_temporary_pub(legacy_theme_mode=True) - pub.cfg['language'] = {'language': 'en'} - pub.write_cfg() - - formdef = create_formdef() - formdef.fields = [fields.StringField(id='1', label='string')] - formdef.store() - - resp = get_app(pub).get('/') - assert '' in resp.text - assert '/static/js/qommon.forms.js' not in resp.text - assert '<a class="" href="test/">test</a>' in resp.text - resp = resp.click('test') - assert '/static/js/qommon.forms.js' in resp.text - resp.form['f1'] = 'TEST' - resp = resp.form.submit('submit') - assert 'Check values then click submit.' in resp.text - resp = resp.form.submit('submit').follow() - assert 'The form has been recorded on' in resp.text - - def test_form_access(pub): formdef = create_formdef() get_app(pub).get('/test/', status=200) diff --git a/tests/test_hobo.py b/tests/test_hobo.py index a5157f308..91895c0aa 100644 --- a/tests/test_hobo.py +++ b/tests/test_hobo.py @@ -314,14 +314,14 @@ def test_update_configuration(setuptest): def test_update_themes(setuptest): pub, hobo_cmd = setuptest - pub.cfg['branding'] = {'theme': 'default'} + pub.cfg['branding'] = {'theme': 'django'} service = [x for x in HOBO_JSON.get('services', []) if x.get('service-id') == 'wcs'][0] hobo_cmd.update_configuration(service, pub) - assert pub.cfg['branding']['theme'] == 'default' + assert pub.cfg['branding']['theme'] == 'django' service['variables']['theme'] = 'foobar' hobo_cmd.update_configuration(service, pub) - assert pub.cfg['branding']['theme'] == 'default' + assert pub.cfg['branding']['theme'] == 'django' hobo_cmd.THEMES_DIRECTORY = os.path.join(os.path.dirname(__file__), 'themes') hobo_cmd.update_configuration(service, pub) diff --git a/tests/utilities.py b/tests/utilities.py index 3544b6c0d..21d9a55c7 100644 --- a/tests/utilities.py +++ b/tests/utilities.py @@ -33,30 +33,25 @@ class KnownElements: pickle_app_dir = None sql_app_dir = None sql_db_name = None - legacy_theme_app_dir = None lazy_app_dir = None known_elements = KnownElements() -def create_temporary_pub(pickle_mode=False, legacy_theme_mode=False, lazy_mode=False): +def create_temporary_pub(pickle_mode=False, lazy_mode=False): if get_publisher(): get_publisher().cleanup() cleanup() - if legacy_theme_mode and known_elements.legacy_theme_app_dir: - APP_DIR = known_elements.legacy_theme_app_dir - elif lazy_mode and known_elements.lazy_app_dir: + if lazy_mode and known_elements.lazy_app_dir: APP_DIR = known_elements.lazy_app_dir elif pickle_mode and known_elements.pickle_app_dir: APP_DIR = known_elements.pickle_app_dir - elif not (legacy_theme_mode or lazy_mode or pickle_mode) and known_elements.sql_app_dir: + elif not (lazy_mode or pickle_mode) and known_elements.sql_app_dir: APP_DIR = known_elements.sql_app_dir else: APP_DIR = tempfile.mkdtemp() - if legacy_theme_mode: - known_elements.legacy_theme_app_dir = APP_DIR - elif lazy_mode: + if lazy_mode: known_elements.lazy_app_dir = APP_DIR elif pickle_mode: known_elements.pickle_app_dir = APP_DIR @@ -124,12 +119,6 @@ def create_temporary_pub(pickle_mode=False, legacy_theme_mode=False, lazy_mode=F 'frontoffice-url': 'http://example.net', } pub.cfg['language'] = {'language': 'en'} - - if legacy_theme_mode: - pub.cfg['branding'] = {'theme': 'default'} - else: - pub.cfg['branding'] = {'theme': 'django'} - pub.write_cfg() if not created: @@ -183,9 +172,6 @@ def create_temporary_pub(pickle_mode=False, legacy_theme_mode=False, lazy_mode=F def clean_temporary_pub(): if get_publisher(): get_publisher().cleanup() - if known_elements.legacy_theme_app_dir and os.path.exists(known_elements.legacy_theme_app_dir): - shutil.rmtree(known_elements.legacy_theme_app_dir) - known_elements.legacy_theme_app_dir = None if known_elements.pickle_app_dir and os.path.exists(known_elements.pickle_app_dir): shutil.rmtree(known_elements.pickle_app_dir) known_elements.pickle_app_dir = None diff --git a/wcs/admin/settings.py b/wcs/admin/settings.py index 709fa4ff6..b414c4c83 100644 --- a/wcs/admin/settings.py +++ b/wcs/admin/settings.py @@ -24,11 +24,10 @@ try: import lasso except ImportError: lasso = None -import shutil import xml.etree.ElementTree as ET import zipfile -from django.utils.encoding import force_bytes, force_text +from django.utils.encoding import force_bytes from quixote import get_publisher, get_request, get_response, get_session, redirect from quixote.directory import Directory from quixote.html import TemplateIO, htmltext @@ -41,7 +40,6 @@ from wcs.formdef import FormDef, FormdefImportError from wcs.qommon import _, errors, get_cfg, ident, misc, template from wcs.qommon.admin.cfg import cfg_submit from wcs.qommon.admin.emails import EmailsDirectory -from wcs.qommon.admin.menu import error_page from wcs.qommon.admin.settings import SettingsDirectory as QommonSettingsDirectory from wcs.qommon.admin.texts import TextsDirectory from wcs.qommon.afterjobs import AfterJob @@ -59,7 +57,6 @@ from wcs.qommon.form import ( SingleSelectWidget, StringWidget, TextWidget, - UrlWidget, WidgetList, ) from wcs.workflows import Workflow, WorkflowImportError @@ -449,51 +446,9 @@ class FileTypesDirectory(Directory): return r.getvalue() -class ThemePreviewDirectory(Directory): - def _q_traverse(self, path): - if len(path) < 2: - return error_page('settings', _('Invalid URL')) - - theme_id = path[0] - branding = get_publisher().cfg.get('branding', {}) - original_branding = branding.copy() - get_publisher().cfg['branding'] = branding - get_publisher().cfg['branding']['theme'] = theme_id - if 'template' in get_publisher().cfg['branding']: - del get_publisher().cfg['branding']['template'] - - root_directory = get_publisher().root_directory_class() - - response = get_response() - response.reset_includes() - response.filter = {} - del response.breadcrumb - - if path[1] in ('backoffice', 'admin') or get_request().get_method() == 'POST': - from wcs.qommon.template import error_page as base_error_page - - output = base_error_page(_("The theme preview doesn't support this.")) - else: - output = root_directory._q_traverse(path[1:]) - - from wcs.qommon.template import decorate - - if isinstance(output, template.QommonTemplateResponse): - output = template.render(output.templates, output.context) - theme_preview = decorate(output, response) - - # restore original branding in case it has been changed - get_publisher().cfg['branding'] = original_branding - get_publisher().write_cfg() - response.filter['raw'] = True - - return theme_preview - - class SettingsDirectory(QommonSettingsDirectory): _q_exports = [ '', - 'themes', 'users', 'template', 'emails', @@ -506,12 +461,9 @@ class SettingsDirectory(QommonSettingsDirectory): 'sms', 'certificates', 'texts', - 'install_theme', - 'download_theme', 'postgresql', ('admin-permissions', 'admin_permissions'), 'geolocation', - 'theme_preview', 'filetypes', ('user-templates', 'user_templates'), ('data-sources', 'data_sources'), @@ -523,7 +475,6 @@ class SettingsDirectory(QommonSettingsDirectory): identification = IdentificationDirectory() users = UsersDirectory() texts = TextsDirectory() - theme_preview = ThemePreviewDirectory() filetypes = FileTypesDirectory() data_sources = NamedDataSourcesDirectory() wscalls = NamedWsCallsDirectory() @@ -636,13 +587,6 @@ class SettingsDirectory(QommonSettingsDirectory): _('Language'), _('Configure site language'), ) - if enabled('theme'): - r += htmltext('<dt><a href="themes">%s</a></dt> <dd>%s</dd>') % (_('Theme'), _('Configure theme')) - if enabled('template'): - r += htmltext('<dt><a href="template">%s</a></dt> <dd>%s</dd>') % ( - _('Template'), - _('Configure template'), - ) if enabled('geolocation'): r += htmltext('<dt><a href="geolocation">%s</a></dt> <dd>%s</dd>') % ( _('Geolocation'), @@ -766,217 +710,6 @@ class SettingsDirectory(QommonSettingsDirectory): get_publisher().write_cfg() return redirect('.') - def themes(self): - request = get_request() - - if 'theme' not in request.form: - current_theme = get_cfg('branding', {}).get('theme', 'default') - - get_response().breadcrumb.append(('themes', _('Themes'))) - html_top('settings', title=_('Themes')) - r = TemplateIO(html=True) - r += htmltext("<h2>%s</h2>") % _('Themes') - - r += get_session().display_message() - - r += htmltext('<a rel="popup" href="install_theme">%s</a>') % _('Install New Theme') - - r += htmltext('<form action="themes" enctype="multipart/form-data" method="post">') - themes = template.get_themes_dict() - r += htmltext('<ul class="biglist themes">') - for theme, theme_dict in sorted(themes.items()): - label = theme_dict.get('label') - if 'version' in theme_dict: - label = '%s (%s)' % (label, theme_dict.get('version')) - if current_theme == theme: - checked = ' checked="checked"' - else: - checked = '' - r += htmltext('<li>') - r += htmltext('<strong class="label"><label>') - r += htmltext(' <input name="theme" value="%s" type="radio"%s>%s</input>') % ( - theme, - checked, - label, - ) - r += htmltext('</label></strong>') - if theme_dict.get('icon'): - r += htmltext('<img src="/themes/%s/icon.png" alt="" class="theme-icon" />') % theme - r += htmltext('<p class="details">%s') % theme_dict.get('desc', '') - r += htmltext(' [<a href="download_theme?theme=%s">%s</a>]') % (theme, _('download')) - r += htmltext(' [<a class="theme-preview" href="theme_preview/%s/">%s</a>]') % ( - theme, - _('preview'), - ) - if theme_dict.get('author'): - r += htmltext('<br/>') - r += htmltext(_('by %s')) % theme_dict.get('author') - r += htmltext('</p>') - r += htmltext('</li>') - r += htmltext('</ul>') - r += htmltext('<div class="buttons">') - r += htmltext('<button>%s</button>') % _('Submit') - r += htmltext('</div>') - r += htmltext('</form>') - return r.getvalue() - else: - themes = template.get_themes() - if str(request.form['theme']) in themes: - branding_cfg = get_cfg('branding', {}) - branding_cfg['theme'] = str(request.form['theme']) - get_publisher().cfg['branding'] = branding_cfg - get_publisher().write_cfg() - return redirect('.') - - def download_theme(self): - theme_id = get_request().form.get('theme') - if not theme_id: - return redirect('themes') - - theme_directory = template.get_theme_directory(theme_id) - if not theme_directory: - return redirect('themes') - - parent_theme_directory = os.path.dirname(theme_directory) - c = io.BytesIO() - with zipfile.ZipFile(c, 'w') as z: - for base, dummy, filenames in os.walk(theme_directory): - basetheme = base[len(parent_theme_directory) + 1 :] - for filename in filenames: - z.write(os.path.join(base, filename), os.path.join(basetheme, filename)) - - response = get_response() - response.set_content_type('application/zip') - response.set_header('content-disposition', 'attachment; filename=%s.zip' % theme_id) - return c.getvalue() - - def install_theme(self): - form = Form(enctype='multipart/form-data') - form.add(FileWidget, 'file', title=_('Theme File'), required=False) - form.add(UrlWidget, 'url', title=_('Theme Address'), required=False, size=50) - form.add_submit('submit', _('Install')) - form.add_submit('cancel', _('Cancel')) - - if form.get_submit() == 'cancel': - return redirect('.') - - if form.is_submitted() and not form.has_errors(): - try: - return self.install_theme_submit(form) - except ValueError: - form.get_widget('file').set_error(_('Invalid Theme')) - - get_response().breadcrumb.append(('install_theme', _('Install Theme'))) - html_top('forms', title=_('Install Theme')) - r = TemplateIO(html=True) - r += htmltext('<h2>%s</h2>') % _('Install Theme') - r += htmltext('<p>%s</p>') % _( - 'You can install a new theme by uploading a file or by pointing to the theme URL.' - ) - r += form.render() - return r.getvalue() - - def install_theme_submit(self, form): - if form.get_widget('url').parse(): - return self.install_theme_from_url(form.get_widget('url').parse()) - if form.get_widget('file').parse(): - return self.install_theme_from_file(form.get_widget('file').parse().fp) - get_session().message = ('error', _('You have to enter a file or a URL.')) - return redirect('themes') - - def install_theme_from_file(self, fp): - try: - with zipfile.ZipFile(fp, 'r') as z: - theme_dir = os.path.join(get_publisher().app_dir, 'themes') - filename_list = [x for x in z.namelist() if x[0] != '/' and x[-1] != '/'] - if len(filename_list) == 0: - get_session().message = ('error', _('Empty theme file.')) - return redirect('themes') - theme_name = filename_list[0].split('/')[0] - if ('%s/desc.xml' % theme_name) not in filename_list: - get_session().message = ('error', _('Theme is missing a desc.xml file.')) - return redirect('themes') - desc_xml = z.read('%s/desc.xml' % theme_name) - theme_dict = template.get_theme_dict(io.StringIO(force_text(desc_xml))) - if theme_dict.get('name') != theme_name: - get_session().message = ('error', _('desc.xml is missing a name attribute.')) - return redirect('themes') - if os.path.exists(os.path.join(theme_dir, theme_name)): - shutil.rmtree(os.path.join(theme_dir, theme_name)) - for f in z.namelist(): - if f[-1] == '/': - continue - path = os.path.join(theme_dir, f) - data = z.read(f) - if not os.path.exists(os.path.dirname(path)): - os.makedirs(os.path.dirname(path)) - with open(path, 'wb') as _f: - _f.write(data) - return redirect('themes') - except Exception as e: - get_session().message = ('error', _('Failed to read theme file. (%s)') % str(e)) - return redirect('themes') - - def install_theme_from_url(self, url): - try: - fp = misc.urlopen(url) - except misc.ConnectionError as e: - get_session().message = ('error', _('Error loading theme (%s).') % str(e)) - return redirect('themes') - - return self.install_theme_from_file(io.StringIO(fp.read())) - - def template(self): - from wcs.qommon.template import get_default_ezt_template - - default_template_ezt = get_default_ezt_template() - branding_cfg = get_cfg('branding', {}) - template = branding_cfg.get('template', default_template_ezt) - form = Form(enctype="multipart/form-data") - form.add(TextWidget, 'template', title=_('Site Template'), value=template, cols=80, rows=25) - form.add_submit('submit', _('Submit')) - form.add_submit('restore-default', _('Restore default template')) - form.add_submit('cancel', _('Cancel')) - if form.get_widget('cancel').parse(): - return redirect('.') - - if form.get_submit() == 'cancel': - return redirect('.') - - if form.get_submit() == 'restore-default': - self.template_submit() - return redirect('.') - - if form.is_submitted() and not form.has_errors(): - self.template_submit(form) - return redirect('.') - - get_response().breadcrumb.append(('template', _('Template'))) - html_top('settings', title=_('Template')) - r = TemplateIO(html=True) - r += htmltext('<h2>%s</h2>') % _('Template') - r += form.render() - return r.getvalue() - - def template_submit(self, form=None): - from wcs.qommon.template import DEFAULT_TEMPLATE_EZT, get_default_ezt_template - - theme_default_template_ezt = get_default_ezt_template() - - get_publisher().reload_cfg() - branding_cfg = get_cfg('branding', {}) - if not form: - template = None - else: - template = form.get_widget('template').parse() - if template in (DEFAULT_TEMPLATE_EZT, theme_default_template_ezt) or not template: - if 'template' in branding_cfg: - del branding_cfg['template'] - else: - branding_cfg['template'] = template - get_publisher().cfg['branding'] = branding_cfg - get_publisher().write_cfg() - def export(self): if get_request().form.get('download'): return self.export_download() diff --git a/wcs/compat.py b/wcs/compat.py index 2ced96fea..3dd646764 100644 --- a/wcs/compat.py +++ b/wcs/compat.py @@ -14,7 +14,6 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, see <http://www.gnu.org/licenses/>. -import os from contextlib import contextmanager from threading import Lock @@ -31,7 +30,7 @@ from quixote.http_request import Upload from .publisher import WcsPublisher from .qommon import force_str, template from .qommon.http_request import HTTPRequest -from .qommon.publisher import get_cfg, set_publisher_class +from .qommon.publisher import set_publisher_class class TemplateWithFallbackView(TemplateView): @@ -65,8 +64,8 @@ class TemplateWithFallbackView(TemplateView): elif request.headers.get('X-Popup') == 'true': response = HttpResponse('<div class="popup-content">%s</div>' % context['body']) elif 'raw' in (getattr(self.quixote_response, 'filter') or {}): - # used for theme preview (generated in /backoffice/ but cannot - # obviously receive the admin template. + # used for raw HTML snippets (for example in the test tool + # results in inspect page). response = HttpResponse(context['body']) else: response = self.render_to_response(context) @@ -145,19 +144,6 @@ class CompatWcsPublisher(WcsPublisher): return output if request.headers.get('X-Popup') == 'true': return '<div class="popup-content">%s</div>' % output - if response.filter and response.filter.get('admin_ezt'): - return self.render_response(output) - - current_theme = get_cfg('branding', {}).get('theme', 'default') - theme_directory = template.get_theme_directory(current_theme) - if not theme_directory: - return self.render_response(output) - - if not os.path.exists(os.path.join(theme_directory, 'templates')): - return self.render_response(output) - - if not os.path.exists(os.path.join(theme_directory, 'templates/wcs/base.html')): - return self.render_response(output) if isinstance(output, template.QommonTemplateResponse): template_response = output diff --git a/wcs/qommon/publisher.py b/wcs/qommon/publisher.py index ed7be5e22..149fca327 100644 --- a/wcs/qommon/publisher.py +++ b/wcs/qommon/publisher.py @@ -116,7 +116,7 @@ class QommonPublisher(Publisher): after_login_url = '' qommon_static_dir = 'static/' qommon_admin_css = 'css/dc2/admin.css' - default_theme = 'default' + default_theme = 'django' site_options = None site_charset = 'utf-8' @@ -346,11 +346,6 @@ class QommonPublisher(Publisher): return error_page - def render_response(self, content): - if isinstance(content, template.QommonTemplateResponse): - content = template.render(content.templates, content.context) - return template.decorate(content, self.get_request().response) - def install_lang(self, request=None): if request: lang = request.language diff --git a/wcs/qommon/template.py b/wcs/qommon/template.py index 8e4f33a6b..5604fbfee 100644 --- a/wcs/qommon/template.py +++ b/wcs/qommon/template.py @@ -14,11 +14,9 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, see <http://www.gnu.org/licenses/>. -import glob import io import os import re -import xml.etree.ElementTree as ET import django.template from django.template import TemplateSyntaxError as DjangoTemplateSyntaxError @@ -27,9 +25,7 @@ from django.template import engines from django.template.loader import render_to_string from django.utils.encoding import force_text, smart_text from quixote import get_publisher, get_request, get_response, get_session -from quixote.directory import Directory from quixote.html import TemplateIO, htmlescape, htmltext -from quixote.util import StaticDirectory, StaticFile from . import ezt, force_str @@ -53,123 +49,6 @@ def get_theme_directory(theme_id): return location -class ThemesDirectory(Directory): - def _q_lookup(self, component): - from . import errors - - if component in ('.', '..'): - raise errors.TraversalError() - - location = get_theme_directory(component) - if location is None: - raise errors.TraversalError() - - if os.path.isdir(location): - return StaticDirectory(location) - else: - return StaticFile(location) - - -def get_themes_dict(): - system_location = os.path.join(get_publisher().data_dir, 'themes') - local_location = os.path.join(get_publisher().app_dir, 'themes') - - themes = {} - for theme_xml in glob.glob(os.path.join(system_location, '*/desc.xml')) + glob.glob( - os.path.join(local_location, '*/desc.xml') - ): - theme_dict = get_theme_dict(theme_xml) - if not theme_dict: - continue - themes[theme_dict.get('name')] = theme_dict - return themes - - -def get_theme_dict(theme_xml): - try: - tree = ET.parse(theme_xml).getroot() - except Exception: # parse error - return None - name = force_str(tree.attrib['name']) - version = force_str(tree.attrib.get('version') or '') - label = force_str(tree.findtext('label') or '') - desc = force_str(tree.findtext('desc') or '') - author = force_str(tree.findtext('author') or '') - icon = None - if isinstance(theme_xml, str): - icon = os.path.join(os.path.dirname(theme_xml), 'icon.png') - if not os.path.exists(icon): - icon = None - theme = {'name': name, 'label': label, 'desc': desc, 'author': author, 'icon': icon, 'version': version} - theme['keywords'] = [] - for keyword in tree.findall('keywords/keyword'): - theme['keywords'].append(keyword.text) - return theme - - -def get_themes(): - # backward compatibility function, it returns a tuple with theme info, - # newer code should use get_themes_dict() - themes = {} - for k, v in get_themes_dict().items(): - themes[k] = (v['label'], v['desc'], v['author'], v['icon']) - return themes - - -def get_current_theme(): - from .publisher import get_cfg - - current_theme = get_cfg('branding', {}).get('theme', 'default') - system_location = os.path.join(get_publisher().data_dir, 'themes', current_theme) - local_location = os.path.join(get_publisher().app_dir, 'themes', current_theme) - for location in (local_location, system_location): - if os.path.exists(location): - return get_theme_dict(os.path.join(location, 'desc.xml')) - default_theme_location = os.path.join(get_publisher().data_dir, 'themes', 'default') - return get_theme_dict(os.path.join(default_theme_location, 'desc.xml')) - - -DEFAULT_TEMPLATE_EZT = """<!DOCTYPE html> -<html lang="[site_lang]"> - <head> - <title>[page_title] - - [script] - - -
-

[if-any title][title][else][site_name][end]

-
- [if-any breadcrumb][end] - [body] -
- -
- -""" - -DEFAULT_IFRAME_EZT = """ - - - [page_title] - - [script] - - -
- [if-any breadcrumb][end] - [body] -
- -""" - -default_template = ezt.Template() -default_template.parse(DEFAULT_TEMPLATE_EZT) - -default_iframe_template = ezt.Template() -default_iframe_template.parse(DEFAULT_IFRAME_EZT) - - def html_top(title=None, default_org=None): if not hasattr(get_response(), 'filter'): get_response().filter = {} @@ -207,38 +86,6 @@ def error_page(error_message, error_title=None, location_hint=None): return htmltext(r.getvalue()) -def get_default_ezt_template(): - from .publisher import get_cfg - - current_theme = get_cfg('branding', {}).get('theme', 'default') - - filename = os.path.join( - get_publisher().app_dir, 'themes', current_theme, 'template.%s.ezt' % get_publisher().APP_NAME - ) - if os.path.exists(filename): - with open(filename) as fd: - return fd.read() - - filename = os.path.join( - get_publisher().data_dir, 'themes', current_theme, 'template.%s.ezt' % get_publisher().APP_NAME - ) - if os.path.exists(filename): - with open(filename) as fd: - return fd.read() - - filename = os.path.join(get_publisher().app_dir, 'themes', current_theme, 'template.ezt') - if os.path.exists(filename): - with open(filename) as fd: - return fd.read() - - filename = os.path.join(get_publisher().data_dir, 'themes', current_theme, 'template.ezt') - if os.path.exists(filename): - with open(filename) as fd: - return fd.read() - - return DEFAULT_TEMPLATE_EZT - - def get_decorate_vars(body, response, generate_breadcrumb=True, **kwargs): from .publisher import get_cfg @@ -303,20 +150,10 @@ def get_decorate_vars(body, response, generate_breadcrumb=True, **kwargs): subtitle = kwargs.get('subtitle') sidebar = kwargs.get('sidebar') css = root_url + get_publisher().qommon_static_dir + get_publisher().qommon_admin_css - - app_dir_filename = os.path.join(get_publisher().app_dir, 'themes', current_theme, 'admin.css') - data_dir_filename = os.path.join(get_publisher().data_dir, 'themes', current_theme, 'admin.css') - for filename in (app_dir_filename, data_dir_filename): - if os.path.exists(filename): - extra_css = root_url + 'themes/%s/admin.css' % current_theme - break extra_head = get_publisher().get_site_option('backoffice_extra_head') app_label = get_publisher().get_site_option('app_label') or 'w.c.s.' else: - if current_theme == 'default': - css = root_url + 'static/css/%s.css' % get_publisher().APP_NAME - else: - css = root_url + 'themes/%s/%s.css' % (current_theme, get_publisher().APP_NAME) + css = root_url + 'themes/%s/%s.css' % (current_theme, get_publisher().APP_NAME) # this variable is kept in locals() as it was once part of the default # template and existing installations may have template changes that @@ -354,53 +191,6 @@ def get_decorate_vars(body, response, generate_breadcrumb=True, **kwargs): return vars -def decorate(body, response): - if get_request().get_header('x-popup') == 'true': - return '''''' % body - - from .publisher import get_cfg - - generate_breadcrumb = True - template_ezt = get_cfg('branding', {}).get('template') - current_theme = get_cfg('branding', {}).get('theme', 'default') - if not template_ezt: - # the theme can provide a default template - possible_filenames = [] - possible_filenames.append('template.%s.ezt' % get_publisher().APP_NAME) - possible_filenames.append('template.ezt') - - possible_dirnames = [ - os.path.join(get_publisher().app_dir, 'themes', current_theme), - os.path.join(get_publisher().data_dir, 'themes', current_theme), - os.path.join(get_publisher().data_dir, 'themes', 'default'), - ] - - for fname in possible_filenames: - for dname in possible_dirnames: - filename = os.path.join(dname, fname) - if os.path.exists(filename): - with open(filename) as fd: - template_ezt = fd.read() - break - else: - continue - break - - if template_ezt: - generate_breadcrumb = '[breadcrumb]' in template_ezt - - template = ezt.Template() - template.parse(template_ezt) - else: - template = default_template - - fd = io.StringIO() - vars = get_decorate_vars(body, response, generate_breadcrumb=generate_breadcrumb) - - template.generate(fd, vars) - return fd.getvalue() - - def render(template_name, context): request = getattr(get_request(), 'django_request', None) result = render_to_string(template_name, context, request=request) diff --git a/wcs/root.py b/wcs/root.py index 35ae5eaa9..94c662fd9 100644 --- a/wcs/root.py +++ b/wcs/root.py @@ -265,7 +265,6 @@ class RootDirectory(Directory): ] api = ApiDirectory() - themes = template.ThemesDirectory() myspace = MyspaceDirectory() pages = PagesDirectory() fargo = portfolio.FargoDirectory() diff --git a/wcs/utils.py b/wcs/utils.py index 8bb0822f0..280e6d429 100644 --- a/wcs/utils.py +++ b/wcs/utils.py @@ -38,7 +38,7 @@ class TemplateLoader(django.template.loaders.filesystem.Loader): template_dirs.append(os.path.join(get_publisher().app_dir, 'templates')) template_dirs.append(os.path.join(get_publisher().app_dir, 'theme', 'templates')) - current_theme = get_cfg('branding', {}).get('theme', 'default') + current_theme = get_cfg('branding', {}).get('theme', get_publisher().default_theme) theme_directory = get_theme_directory(current_theme) if theme_directory: # templates from theme directory