def transformIterable(self, result, encoding): """ Apply our customize transform that attempts to provide b/w compatibility with diazo if user still tries to use a diazo powered theme. """ if self.request.response.getHeader('X-Theme-Applied'): return if not isinstance(result, XMLSerializer): return # Obtain settings. Do nothing if not found policy = theming_policy(self.request) settings = policy.getSettings() if settings is None: return None if not policy.isThemeEnabled(): return None try: if isPloneTheme(settings): # XXX old style theme # manual render tiles, then do theme transform result.tree = tiles.renderTiles(self.request, result.tree) result = self._old_transformIterable(result, encoding) return result except AttributeError: pass DevelopmentMode = Globals.DevelopmentMode try: # if we are here, it means we are rendering the the # classic way and we need to do replacements. # check for #visual-portal-wrapper to make sure we need # transform this response # XXX WARNING: THIS IS NECESSARY wrapper = wrapper_xpath(result.tree) if len(wrapper) == 0: return None context = get_context_from_request(self.request) transform = getTransform(context, self.request) if transform is None: return None transformed = transform(self.request, result, context=context) if transformed is None: return None result = transformed if settings.doctype: result.doctype = settings.doctype if not result.doctype.endswith('\n'): result.doctype += '\n' return result except etree.LxmlError: if not (DevelopmentMode): raise return result
def test_hostname_switching(self): """Switch theme based on hostname""" request = self.request request['HTTP_HOST'] = 'cms.localhost:8080' policy = theming_policy(request) themename = policy.getCurrentTheme() self.assertEqual(themename, u'barceloneta')
def test_hostname_switching(self): """Switch theme based on hostname""" request = self.request request['HTTP_HOST'] = 'cms.localhost:8080' policy = theming_policy(request) themename = policy.getCurrentTheme() self.assertEqual(themename, u'barceloneta')
def getTransform(context, request): DevelopmentMode = Globals.DevelopmentMode policy = theming_policy(request) # Obtain settings. Do nothing if not found settings = policy.getSettings() if settings is None: return None try: if not policy.isThemeEnabled(): return None except: pass cache = policy.getCache() # Apply theme transform = None if not DevelopmentMode and cache.transform: transform = cache.transform if transform is None: name = policy.getCurrentTheme() transform = _Transform(name) if not DevelopmentMode: cache.updateTransform(transform) return transform
def test_hostname_bundle_filtering(self): request = self.request request['HTTP_HOST'] = 'cms.localhost:8080' self.bust_request_caches() policy = theming_policy(request) policy.filter_request() self.assertTrue('themeAbundle' in request.disabled_bundles)
def test_hostname_bundle_filtering(self): request = self.request request['HTTP_HOST'] = 'cms.localhost:8080' self.bust_request_caches() policy = theming_policy(request) policy.filter_request() self.assertTrue('themeAbundle' in request.disabled_bundles)
def test_hostname_layer_filtering(self): request = self.request request['HTTP_HOST'] = 'cms.localhost:8080' self.bust_request_caches() policy = theming_policy(request) policy.filter_request() active = [x for x in directlyProvidedBy(request)] self.assertFalse(IThemeASpecific in active)
def test_hostname_layer_filtering(self): request = self.request request['HTTP_HOST'] = 'cms.localhost:8080' self.bust_request_caches() policy = theming_policy(request) policy.filter_request() active = [x for x in directlyProvidedBy(request)] self.assertFalse(IThemeASpecific in active)
def test_isThemeEnabled_blacklist(self): request = self.layer['request'] request.set('BASE1', 'http://nohost/path/to/site') policy = theming_policy(request) settings = policy.getSettings() # Should pay no attention to BASE1 and only use SERVER_URL settings.hostnameBlacklist.append('nohost') self.assertFalse(policy.isThemeEnabled())
def test_isThemeEnabled_blacklist(self): request = self.layer['request'] request.set('BASE1', 'http://nohost/path/to/site') policy = theming_policy(request) settings = policy.getSettings() # Should pay no attention to BASE1 and only use SERVER_URL settings.hostnameBlacklist.append('nohost') self.assertFalse(policy.isThemeEnabled())
def test_getSettings(self): request = self.layer['request'] policy = theming_policy(request) settings = policy.getSettings() self.assertEqual(settings.currentTheme, u'barceloneta') self.assertEqual(settings.rules, u'/++theme++barceloneta/rules.xml')
def test_settings(self): """Switch theme based on hostname""" request = self.request request['HTTP_HOST'] = 'cms.localhost:8080' policy = theming_policy(request) settings = policy.getSettings() self.assertTrue('SwitchableRecordsProxy' in repr(settings)) self.assertEqual(settings.currentTheme, u'barceloneta') self.assertEqual(settings.rules, u'/++theme++barceloneta/rules.xml')
def test_getCacheStorage(self): request = self.layer['request'] policy = theming_policy(request) self.assertEqual(policy.getCacheStorage().keys(), ['mtime']) cache = policy.getCache() storage = policy.getCacheStorage() self.assertEqual( [(k, v) for (k, v) in storage.items() if k != 'mtime'], [(u'http://nohost/plone::barceloneta', cache)])
def test_settings(self): """Switch theme based on hostname""" request = self.request request['HTTP_HOST'] = 'cms.localhost:8080' policy = theming_policy(request) settings = policy.getSettings() self.assertTrue('SwitchableRecordsProxy' in repr(settings)) self.assertEqual(settings.currentTheme, u'barceloneta') self.assertEqual(settings.rules, u'/++theme++barceloneta/rules.xml')
def test_getCacheStorage(self): request = self.layer['request'] policy = theming_policy(request) self.assertEqual(policy.getCacheStorage().keys(), ['mtime']) cache = policy.getCache() storage = policy.getCacheStorage() self.assertEqual([(k, v) for (k, v) in storage.items() if k != 'mtime'], [(u'http://nohost/plone::barceloneta', cache)])
def test_hostname_switching_registry(self): request = self.request policy = theming_policy(request) themename = policy.getCurrentTheme() self.assertEqual(themename, u'ploneintranet.themeswitcher.testthemeA') switchersettings = policy.getSwitcherSettings() switchersettings.hostname_switchlist.append(u"nohost") self.bust_request_caches() themename = policy.getCurrentTheme() self.assertEqual(themename, u'barceloneta')
def is_castle_theme(self): policy = theming_policy(self.request) settings = policy.getSettings() if settings is None: return False if not policy.isThemeEnabled(): return False if not isPloneTheme(settings): return True return False
def test_hostname_switching_registry(self): request = self.request policy = theming_policy(request) themename = policy.getCurrentTheme() self.assertEqual(themename, u'ploneintranet.themeswitcher.testthemeA') switchersettings = policy.getSwitcherSettings() switchersettings.hostname_switchlist.append(u"nohost") self.bust_request_caches() themename = policy.getCurrentTheme() self.assertEqual(themename, u'barceloneta')
def test_invalidateCache_locally(self): """Poor man's IPC - verify within same thread""" request = self.layer['request'] policy = theming_policy(request) cache = policy.getCache() storage = policy.getCacheStorage() self.assertEqual( [(k, v) for (k, v) in storage.items() if k != 'mtime'], [(u'http://nohost/plone::barceloneta', cache)]) shared_mtime_1 = policy._get_shared_invalidation() policy.invalidateCache() shared_mtime_2 = policy._get_shared_invalidation() self.assertTrue(shared_mtime_2 > shared_mtime_1)
def test_invalidateCache_locally(self): """Poor man's IPC - verify within same thread""" request = self.layer['request'] policy = theming_policy(request) cache = policy.getCache() storage = policy.getCacheStorage() self.assertEqual([(k, v) for (k, v) in storage.items() if k != 'mtime'], [(u'http://nohost/plone::barceloneta', cache)]) shared_mtime_1 = policy._get_shared_invalidation() policy.invalidateCache() shared_mtime_2 = policy._get_shared_invalidation() self.assertTrue(shared_mtime_2 > shared_mtime_1)
def test_registry(self): """Verify that registry.xml was loaded instead of the interfaces.py default values """ policy = theming_policy() switch_settings = policy.getSwitcherSettings() self.assertTrue(switch_settings.enabled) self.assertEqual(switch_settings.fallback_theme, u'barceloneta') self.assertEqual(switch_settings.hostname_switchlist, [u'cms.localhost']) self.assertEqual( switch_settings.browserlayer_filterlist, [u'ploneintranet.themeswitcher.interfaces.IThemeASpecific'])
def get(self, context, request, name): policy = theming_policy() theme_directory = self.get_directory(policy) template_path = "%s/%s.pt" % (FRAGMENTS_DIRECTORY, name) template = self.get_from_cache(policy, theme_directory, name, template_path) # Now disable the theme so we don't double-transform request.response.setHeader('X-Theme-Disabled', '1') return FragmentView(context, request, name, 'View', template)
def test_registry(self): """Verify that registry.xml was loaded instead of the interfaces.py default values """ policy = theming_policy() switch_settings = policy.getSwitcherSettings() self.assertTrue(switch_settings.enabled) self.assertEqual(switch_settings.fallback_theme, u'barceloneta') self.assertEqual(switch_settings.hostname_switchlist, [u'cms.localhost']) self.assertEqual( switch_settings.browserlayer_filterlist, [u'ploneintranet.themeswitcher.interfaces.IThemeASpecific'])
def get_directory(self, policy=None): if policy is None: policy = theming_policy() current_theme = policy.getCurrentTheme() if current_theme is None: raise KeyError() theme_directory = queryResourceDirectory( THEME_RESOURCE_NAME, current_theme) if theme_directory is None: raise KeyError() return theme_directory
def __call__(self): """Redirect between default and fallback hosts. Note that this is not protocol aware, so you'll have to run either both on http or both on https.""" policy = theming_policy(self.request) if ISwitchableThemingPolicy.providedBy(self.request): log.error("@@switch_theme invoked but no switchable policy") return "@@switch_theme invoked but no switchable policy" switcher = policy.getSwitcherSettings() current = self.context.absolute_url() default_host = switcher.hostname_default or u'localhost' fallback_host = switcher.hostname_switchlist[0] if policy.isFallbackActive(): target = current.replace(fallback_host, default_host) else: target = current.replace(default_host, fallback_host) self.request.response.redirect(target)
def update(self): self.portal_state = getMultiAdapter((self.context, self.request), name=u"plone_portal_state") self.site_url = self.portal_state.portal_url() self.registry = getUtility(IRegistry) self.production_path = get_production_resource_directory() theme = None policy = theming_policy(self.request) if policy.isThemeEnabled(): # Check if Diazo is enabled theme = policy.get_theme() or None self.diazo_production_css = getattr(theme, "production_css", None) self.diazo_development_css = getattr(theme, "development_css", None) self.diazo_production_js = getattr(theme, "production_js", None) self.diazo_development_js = getattr(theme, "development_js", None) self.theme_enabled_bundles = getattr(theme, "enabled_bundles", []) self.theme_disabled_bundles = getattr(theme, "disabled_bundles", [])
def test_caching(self): """roundtrip""" request = self.layer['request'] policy = theming_policy(request) theme = policy.get_theme() cache = policy.getCache() storage = policy.getCacheStorage() self.assertEqual([(k, v) for (k, v) in storage.items() if k != 'mtime'], [(u'http://nohost/plone::barceloneta', cache)]) self.assertEqual(cache.themeObj, theme) policy.set_theme(u'barceloneta', 'faketheme') self.assertEqual(policy.get_theme(), 'faketheme') policy.invalidateCache() self.assertEqual(policy.getCacheStorage().keys(), ['mtime']) theme2 = policy.get_theme() # different objects but both are barceloneta self.assertEqual(theme.title, theme2.title)
def test_caching(self): """roundtrip""" request = self.layer['request'] policy = theming_policy(request) theme = policy.get_theme() cache = policy.getCache() storage = policy.getCacheStorage() self.assertEqual( [(k, v) for (k, v) in storage.items() if k != 'mtime'], [(u'http://nohost/plone::barceloneta', cache)]) self.assertEqual(cache.themeObj, theme) policy.set_theme(u'barceloneta', 'faketheme') self.assertEqual(policy.get_theme(), 'faketheme') policy.invalidateCache() self.assertEqual(policy.getCacheStorage().keys(), ['mtime']) theme2 = policy.get_theme() # different objects but both are barceloneta self.assertEqual(theme.title, theme2.title)
def __call__(self, context, request): if request.get("ploneintranet.layout.app.enabled"): return # manipulate the same request only once, and only for one app request.set("ploneintranet.layout.app.enabled", True) app_layers = list(context.app_layers) # do not undo themeswitching policy = theming_policy(request) if ISwitchableThemingPolicy.providedBy(policy) and policy.isFallbackActive(): # only applies to Barceloneta switcher = policy.getSwitcherSettings() # respect themeswitching blacklist remove_layers = [resolveDottedName(x) for x in switcher.browserlayer_filterlist] # enable only non-blacklisted IAppLayers app_layers = [x for x in app_layers if x not in remove_layers] active_layers = app_layers + get_layers(request) directlyProvides(request, *active_layers)
def __call__(self): """Redirect between default and fallback hosts. Note that this is not protocol aware, so you'll have to run either both on http or both on https.""" policy = theming_policy(self.request) if ISwitchableThemingPolicy.providedBy(self.request): log.error("@@switch_theme invoked but no switchable policy") return "@@switch_theme invoked but no switchable policy" switcher = policy.getSwitcherSettings() current = self.context.absolute_url() default_host = switcher.hostname_default or u'localhost' fallback_host = switcher.hostname_switchlist[0] if policy.isFallbackActive(): target = current.replace(fallback_host, default_host) else: target = current.replace(default_host, fallback_host) if self.url_append: target = "/".join((target, self.url_append)) self.request.response.redirect(target)
def update(self): self.portal_state = getMultiAdapter((self.context, self.request), name=u'plone_portal_state') self.site_url = self.portal_state.portal_url() self.registry = getUtility(IRegistry) self.production_path = get_production_resource_directory() theme = None policy = theming_policy(self.request) if policy.isThemeEnabled(): # Check if Diazo is enabled theme = policy.get_theme() or None self.diazo_production_css = getattr(theme, 'production_css', None) self.diazo_development_css = getattr(theme, 'development_css', None) self.diazo_production_js = getattr(theme, 'production_js', None) self.diazo_development_js = getattr(theme, 'development_js', None) self.theme_enabled_bundles = getattr(theme, 'enabled_bundles', []) self.theme_disabled_bundles = getattr(theme, 'disabled_bundles', [])
def setupTransform(self, runtrace=False): debug_mode = self.develop_theme() policy = theming_policy(self.request) # Obtain settings. Do nothing if not found settings = policy.getSettings() if settings is None: return None if not settings.rules: return None if not policy.isThemeEnabled(): return None cache = policy.getCache() # Apply theme transform = None if not debug_mode: transform = cache.transform if transform is None: rules = settings.rules absolutePrefix = settings.absolutePrefix or None readNetwork = settings.readNetwork parameterExpressions = settings.parameterExpressions transform = compileThemeTransform(rules, absolutePrefix, readNetwork, parameterExpressions, runtrace=runtrace) if transform is None: return None if not debug_mode: cache.updateTransform(transform) return transform
def setupTransform(self, runtrace=False): DevelopmentMode = self.develop_theme() policy = theming_policy(self.request) # Obtain settings. Do nothing if not found settings = policy.getSettings() if settings is None: return None if not policy.isThemeEnabled(): return None cache = policy.getCache() # Apply theme transform = None if not DevelopmentMode: transform = cache.transform if transform is None: rules = settings.rules absolutePrefix = settings.absolutePrefix or None readNetwork = settings.readNetwork parameterExpressions = settings.parameterExpressions transform = compileThemeTransform( rules, absolutePrefix, readNetwork, parameterExpressions, runtrace=runtrace ) if transform is None: return None if not DevelopmentMode: cache.updateTransform(transform) return transform
def setup(self): self.request.response.setHeader('X-Theme-Disabled', '1') processInputs(self.request) self.resourceDirectory = self.context self.theme = getThemeFromResourceDirectory(self.context) self.name = self.resourceDirectory.__name__ self.title = self.theme.title self.portalUrl = getToolByName(self.context, 'portal_url')() self.themeBasePath = "++{0:s}++{1:s}".format( THEME_RESOURCE_NAME, self.name ) self.themeBasePathEncoded = urllib.quote_plus(self.themeBasePath) self.themeBaseUrl = '/'.join([self.portalUrl, self.themeBasePath]) try: registry = getUtility(IRegistry) self.lessUrl = registry['plone.resources.lessc'] self.lessVariables = self.portalUrl + '/' + registry['plone.resources.less-variables'] except: self.lessUrl = None self.lessVariables = None self.editable = IWritableResourceDirectory.providedBy( self.resourceDirectory ) if self.editable: self.resourceUrl = self.resourceDirectory.context.absolute_url() else: self.resourceUrl = None policy = theming_policy(self.request) settings = policy.getSettings() self.active = (settings.enabled and self.name == policy.getCurrentTheme()) self.rulesFileName = RULE_FILENAME
def setup(self): self.request.response.setHeader('X-Theme-Disabled', '1') processInputs(self.request) self.resourceDirectory = self.context self.theme = getThemeFromResourceDirectory(self.context) self.name = self.resourceDirectory.__name__ self.title = self.theme.title self.portalUrl = getToolByName(self.context, 'portal_url')() self.themeBasePath = "++{0:s}++{1:s}".format( THEME_RESOURCE_NAME, self.name ) self.themeBasePathEncoded = urllib.parse.quote_plus(self.themeBasePath) self.themeBaseUrl = '/'.join([self.portalUrl, self.themeBasePath]) try: registry = getUtility(IRegistry) self.lessUrl = registry['plone.resources.lessc'] self.lessVariables = self.portalUrl + '/' + registry['plone.resources.less-variables'] except: self.lessUrl = None self.lessVariables = None self.editable = IWritableResourceDirectory.providedBy( self.resourceDirectory ) if self.editable: self.resourceUrl = self.resourceDirectory.context.absolute_url() else: self.resourceUrl = None policy = theming_policy(self.request) settings = policy.getSettings() self.active = (settings.enabled and self.name == policy.getCurrentTheme()) self.rulesFileName = RULE_FILENAME
def __call__(self, context, request): if request.get('ploneintranet.layout.app.enabled'): return # manipulate the same request only once, and only for one app request.set('ploneintranet.layout.app.enabled', True) app_layers = list(context.app_layers) # do not undo themeswitching policy = theming_policy(request) if ISwitchableThemingPolicy.providedBy(policy) \ and policy.isFallbackActive(): # only applies to Barceloneta switcher = policy.getSwitcherSettings() # respect themeswitching blacklist remove_layers = [ resolveDottedName(x) for x in switcher.browserlayer_filterlist ] # enable only non-blacklisted IAppLayers app_layers = [x for x in app_layers if x not in remove_layers] active_layers = app_layers + get_layers(request) directlyProvides(request, *active_layers)
def test_invalidateCache_threaded(self): """Poor man's IPC - verify in other thread""" request = self.layer['request'] policy = theming_policy(request) cache = policy.getCache() storage = policy.getCacheStorage() self.assertEqual( [(k, v) for (k, v) in storage.items() if k != 'mtime'], [(u'http://nohost/plone::barceloneta', cache)]) shared_mtime_1 = policy._get_shared_invalidation() def invalidate(registry): setattr(registry, '_theme_cache_mtime', time.time()) registry._p_modified = True transaction.commit() registry = queryUtility(IRegistry) t = threading.Thread(target=invalidate, args=(registry, )) t.start() t.join(5.0) shared_mtime_2 = policy._get_shared_invalidation() self.assertTrue(shared_mtime_2 > shared_mtime_1)
def test_invalidateCache_threaded(self): """Poor man's IPC - verify in other thread""" request = self.layer['request'] policy = theming_policy(request) cache = policy.getCache() storage = policy.getCacheStorage() self.assertEqual([(k, v) for (k, v) in storage.items() if k != 'mtime'], [(u'http://nohost/plone::barceloneta', cache)]) shared_mtime_1 = policy._get_shared_invalidation() def invalidate(registry): setattr(registry, '_theme_cache_mtime', time.time()) registry._p_modified = True transaction.commit() registry = queryUtility(IRegistry) t = threading.Thread(target=invalidate, args=(registry, )) t.start() t.join(5.0) shared_mtime_2 = policy._get_shared_invalidation() self.assertTrue(shared_mtime_2 > shared_mtime_1)
def onRequest(object, event): """Call onRequest() on each plugin for the eanbled theme on each request """ request = event.request policy = theming_policy(request) if not policy.isThemeEnabled(): return theme = policy.getCurrentTheme() if theme is None: return themeDirectory = queryResourceDirectory(THEME_RESOURCE_NAME, theme) if themeDirectory is None: return plugins = getPlugins() pluginSettings = getPluginSettings(themeDirectory, plugins) for name, plugin in plugins: plugin.onRequest(request, theme, pluginSettings[name], pluginSettings)
def onRequest(object, event): """Call onRequest() on each plugin for the eanbled theme on each request """ request = event.request policy = theming_policy(request) if not policy.isThemeEnabled(): return theme = policy.getCurrentTheme() if theme is None: return themeDirectory = queryResourceDirectory(THEME_RESOURCE_NAME, theme) if themeDirectory is None: return plugins = getPlugins() pluginSettings = getPluginSettings(themeDirectory, plugins) for name, plugin in plugins: plugin.onRequest(request, theme, pluginSettings[name], pluginSettings)
def update(self): self.portal_state = getMultiAdapter((self.context, self.request), name=u'plone_portal_state') self.site_url = self.portal_state.portal_url() self.registry = getUtility(IRegistry) self.production_path = get_production_resource_directory() self.diazo_production_css = None self.diazo_development_css = None self.diazo_development_js = None self.diazo_production_js = None self.themeObj = None # Check if its Diazo enabled policy = theming_policy(self.request) if policy.isThemeEnabled(): self.themeObj = policy.get_theme() if self.themeObj: if hasattr(self.themeObj, 'production_css'): self.diazo_production_css = self.themeObj.production_css self.diazo_development_css = self.themeObj.development_css self.diazo_development_js = self.themeObj.development_js self.diazo_production_js = self.themeObj.production_js
def update(self): self.portal_state = getMultiAdapter((self.context, self.request), name=u'plone_portal_state') self.site_url = self.portal_state.portal_url() self.registry = getUtility(IRegistry) self.production_path = get_production_resource_directory() self.diazo_production_css = None self.diazo_development_css = None self.diazo_development_js = None self.diazo_production_js = None self.themeObj = None # Check if its Diazo enabled policy = theming_policy(self.request) if policy.isThemeEnabled(): self.themeObj = policy.get_theme() if self.themeObj: if hasattr(self.themeObj, 'production_css'): self.diazo_production_css = self.themeObj.production_css self.diazo_development_css = self.themeObj.development_css self.diazo_development_js = self.themeObj.development_js self.diazo_production_js = self.themeObj.production_js
def test_default_theme(self): """Verify normal theme loading""" policy = theming_policy(self.request) themename = policy.getCurrentTheme() self.assertEqual(themename, u'ploneintranet.themeswitcher.testthemeA')
def tearDown(self): Globals.DevelopmentMode = False policy = theming_policy(self.request) # static class attribute is cached across test runs policy.invalidateCache()
def test_custom_policy(self): """Verify that our custom adapter is loaded""" from ploneintranet.themeswitcher.policy import SwitchableThemingPolicy policy = theming_policy() self.assertEqual(policy.__class__, SwitchableThemingPolicy)
def tearDown(self): policy = theming_policy(self.request) # static class attribute is cached across test runs policy.invalidateCache()
def test_getCache(self): request = self.layer['request'] policy = theming_policy(request) cache = policy.getCache() self.assertEqual(cache.themeObj, None)
def update(self): # XXX: complexity too high: refactoring needed processInputs(self.request) self._setup() self.errors = {} form = self.request.form if 'form.button.Cancel' in form: IStatusMessage(self.request).add(_(u"Changes cancelled")) portalUrl = getToolByName(self.context, 'portal_url')() self.redirect("{0:s}/@@overview-controlpanel".format(portalUrl)) return False if 'form.button.Enable' in form: self.authorize() themeSelection = form.get('themeName', None) if themeSelection: themeData = self.getThemeData(self.availableThemes, themeSelection) applyTheme(themeData) self.theme_settings.enabled = True IStatusMessage(self.request).add( _(u"Theme enabled. Note that this control panel page is " u"never themed.")) self._setup() return True if 'form.button.InvalidateCache' in form: self.authorize() policy = theming_policy() policy.invalidateCache() return True if 'form.button.Disable' in form: self.authorize() applyTheme(None) self.theme_settings.enabled = False IStatusMessage(self.request).add(_(u"Theme disabled.")) self._setup() return True if 'form.button.AdvancedSave' in form: self.authorize() self.theme_settings.readNetwork = form.get('readNetwork', False) themeEnabled = form.get('themeEnabled', False) rules = form.get('rules', None) prefix = form.get('absolutePrefix', None) doctype = str(form.get('doctype', "")) hostnameBlacklist = form.get('hostnameBlacklist', []) parameterExpressions = {} parameterExpressionsList = form.get('parameterExpressions', []) for line in parameterExpressionsList: try: name, expression = line.split('=', 1) name = str(name.strip()) expression = str(expression.strip()) parameterExpressions[name] = expression except ValueError: message = _( 'error_invalid_parameter_expressions', default=u"Please ensure you enter one expression per " u"line, in the format <name> = <expression>.") self.errors['parameterExpressions'] = message themeBase = form.get('themeBase', None) markSpecialLinks = form.get('markSpecialLinks', None) extLinksOpenInNewWindow = form.get('extLinksOpenInNewWindow', None) if not self.errors: # Trigger onDisabled() on plugins if theme was active # previously and rules were changed if self.theme_settings.rules != rules: applyTheme(None) self.theme_settings.enabled = themeEnabled self.theme_settings.rules = rules self.theme_settings.absolutePrefix = prefix self.theme_settings.parameterExpressions = parameterExpressions self.theme_settings.hostnameBlacklist = hostnameBlacklist self.theme_settings.doctype = doctype # Theme base settings if themeBase is not None: self.pskin.default_skin = themeBase.encode('utf-8') if markSpecialLinks is not None: self.mark_special_links = markSpecialLinks if extLinksOpenInNewWindow is not None: self.ext_links_open_new_window = extLinksOpenInNewWindow IStatusMessage(self.request).add(_(u"Changes saved")) self._setup() return True else: IStatusMessage(self.request).add(_(u"There were errors"), 'error') self.redirectToFieldset('advanced') return False if 'form.button.Import' in form: self.authorize() enableNewTheme = form.get('enableNewTheme', False) replaceExisting = form.get('replaceExisting', False) themeArchive = form.get('themeArchive', None) themeZip = None performImport = False try: themeZip = zipfile.ZipFile(themeArchive) except ( zipfile.BadZipfile, zipfile.LargeZipFile, ): logger.exception("Could not read zip file") self.errors['themeArchive'] = _( 'error_invalid_zip', default=u"The uploaded file is not a valid Zip archive") if themeZip: try: themeData = extractThemeInfo(themeZip, checkRules=False) except ( ValueError, KeyError, ), e: logger.warn(str(e)) self.errors['themeArchive'] = _( 'error_no_rules_file', u"The uploaded file does not contain a valid theme " u"archive.") else: themeContainer = getOrCreatePersistentResourceDirectory() themeExists = themeData.__name__ in themeContainer if themeExists: if not replaceExisting: self.errors['themeArchive'] = _( 'error_already_installed', u"This theme is already installed. Select " u"'Replace existing theme' and re-upload to " u"replace it.") else: del themeContainer[themeData.__name__] performImport = True else: performImport = True if performImport: themeContainer.importZip(themeZip) themeDirectory = queryResourceDirectory( THEME_RESOURCE_NAME, themeData.__name__) if themeDirectory is not None: # If we don't have a rules file, use the template if themeData.rules == u"/++{0:s}++{1:s}/{2:s}".format( THEME_RESOURCE_NAME, themeData.__name__, RULE_FILENAME, ) and not themeDirectory.isFile(RULE_FILENAME): templateThemeDirectory = queryResourceDirectory( THEME_RESOURCE_NAME, TEMPLATE_THEME) themeDirectory.writeFile( RULE_FILENAME, templateThemeDirectory.readFile(RULE_FILENAME)) if not themeDirectory.isFile(DEFAULT_THEME_FILENAME): IStatusMessage(self.request).add( _(u"A boilerplate rules.xml was added to " u"your theme, but no index.html file " u"found. Update rules.xml to reference " u"the current theme file."), 'warning', ) plugins = getPlugins() pluginSettings = getPluginSettings(themeDirectory, plugins) if pluginSettings is not None: for name, plugin in plugins: plugin.onCreated(themeData.__name__, pluginSettings[name], pluginSettings) if enableNewTheme: applyTheme(themeData) self.theme_settings.enabled = True if not self.errors: portalUrl = getToolByName(self.context, 'portal_url')() self.redirect( "{0}/++theme++{1}/@@theming-controlpanel-mapper".format( portalUrl, themeData.__name__)) return False else: IStatusMessage(self.request).add(_(u"There were errors"), "error") self.renderOverlay('upload') return True
def get_theme(self): return theming_policy().get_theme()
def setUp(self): request = self.layer['request'] policy = theming_policy(request) # avoid cache pollution from other tests policy.invalidateCache()
def update(self): # XXX: complexity too high: refactoring needed processInputs(self.request) self._setup() self.errors = {} form = self.request.form if 'form.button.Cancel' in form: IStatusMessage(self.request).add(_(u"Changes cancelled")) self.redirect("{0}/@@overview-controlpanel".format(self.site_url)) return False if 'form.button.Enable' in form: self.authorize() themeSelection = form.get('themeName', None) if themeSelection: themeData = self.getThemeData( self.availableThemes, themeSelection ) applyTheme(themeData) self.theme_settings.enabled = True IStatusMessage( self.request ).add( _( u"Theme enabled. Note that this control panel page is " u"never themed." ) ) self._setup() return True if 'form.button.InvalidateCache' in form: self.authorize() policy = theming_policy() policy.invalidateCache() return True if 'form.button.Disable' in form: self.authorize() applyTheme(None) self.theme_settings.enabled = False IStatusMessage(self.request).add(_(u"Theme disabled.")) self._setup() return True if 'form.button.AdvancedSave' in form: self.authorize() self.theme_settings.readNetwork = form.get('readNetwork', False) themeEnabled = form.get('themeEnabled', False) rules = form.get('rules', None) prefix = form.get('absolutePrefix', None) doctype = str(form.get('doctype', "")) hostnameBlacklist = form.get('hostnameBlacklist', []) parameterExpressions = {} parameterExpressionsList = form.get('parameterExpressions', []) for line in parameterExpressionsList: try: name, expression = line.split('=', 1) name = str(name.strip()) expression = str(expression.strip()) parameterExpressions[name] = expression except ValueError: message = _( 'error_invalid_parameter_expressions', default=u"Please ensure you enter one expression per " u"line, in the format <name> = <expression>." ) self.errors['parameterExpressions'] = message themeBase = form.get('themeBase', None) markSpecialLinks = form.get('markSpecialLinks', None) extLinksOpenInNewWindow = form.get('extLinksOpenInNewWindow', None) if not self.errors: # Trigger onDisabled() on plugins if theme was active # previously and rules were changed if self.theme_settings.rules != rules: applyTheme(None) self.theme_settings.enabled = themeEnabled self.theme_settings.rules = rules self.theme_settings.absolutePrefix = prefix self.theme_settings.parameterExpressions = parameterExpressions self.theme_settings.hostnameBlacklist = hostnameBlacklist self.theme_settings.doctype = doctype # Theme base settings if themeBase is not None: if six.PY2: themeBase = themeBase.encode('utf-8') self.pskin.default_skin = themeBase if markSpecialLinks is not None: self.mark_special_links = markSpecialLinks if extLinksOpenInNewWindow is not None: self.ext_links_open_new_window = extLinksOpenInNewWindow IStatusMessage(self.request).add(_(u"Changes saved")) self._setup() return True else: IStatusMessage(self.request).add( _(u"There were errors"), 'error' ) self.redirectToFieldset('advanced') return False if 'form.button.Import' in form: self.authorize() enableNewTheme = form.get('enableNewTheme', False) replaceExisting = form.get('replaceExisting', False) themeArchive = form.get('themeArchive', None) themeZip = None performImport = False try: themeZip = zipfile.ZipFile(themeArchive) except (zipfile.BadZipfile, zipfile.LargeZipFile): logger.exception("Could not read zip file") self.errors['themeArchive'] = _( 'error_invalid_zip', default=u"The uploaded file is not a valid Zip archive" ) if themeZip: try: themeData = extractThemeInfo(themeZip, checkRules=False) except (ValueError, KeyError) as e: logger.warn(str(e)) self.errors['themeArchive'] = _( 'error_no_rules_file', u"The uploaded file does not contain a valid theme " u"archive." ) else: themeContainer = getOrCreatePersistentResourceDirectory() themeExists = themeData.__name__ in themeContainer if themeExists: if not replaceExisting: self.errors['themeArchive'] = _( 'error_already_installed', u"This theme is already installed. Select " u"'Replace existing theme' and re-upload to " u"replace it." ) else: del themeContainer[themeData.__name__] performImport = True else: performImport = True if performImport: themeContainer.importZip(themeZip) themeDirectory = queryResourceDirectory( THEME_RESOURCE_NAME, themeData.__name__ ) if themeDirectory is not None: # If we don't have a rules file, use the template if themeData.rules == u"/++{0:s}++{1:s}/{2:s}".format( THEME_RESOURCE_NAME, themeData.__name__, RULE_FILENAME, ) and not themeDirectory.isFile(RULE_FILENAME): templateThemeDirectory = queryResourceDirectory( THEME_RESOURCE_NAME, TEMPLATE_THEME ) themeDirectory.writeFile( RULE_FILENAME, templateThemeDirectory.readFile(RULE_FILENAME) ) if not themeDirectory.isFile(DEFAULT_THEME_FILENAME): IStatusMessage(self.request).add( _( u"A boilerplate rules.xml was added to " u"your theme, but no index.html file " u"found. Update rules.xml to reference " u"the current theme file." ), 'warning', ) plugins = getPlugins() pluginSettings = getPluginSettings(themeDirectory, plugins) if pluginSettings is not None: for name, plugin in plugins: plugin.onCreated( themeData.__name__, pluginSettings[name], pluginSettings ) if enableNewTheme: applyTheme(themeData) self.theme_settings.enabled = True if not self.errors: self.redirect( "{0}/++theme++{1}/@@theming-controlpanel-mapper".format( self.site_url, themeData.__name__ ) ) return False else: IStatusMessage(self.request).add( _(u"There were errors"), "error" ) self.renderOverlay('upload') return True if 'form.button.CreateTheme' in form: self.authorize() title = form.get('title') description = form.get('description') or '' baseOn = form.get('baseOn', TEMPLATE_THEME) enableImmediately = form.get('enableImmediately', True) if not title: self.errors['title'] = _(u"Title is required") IStatusMessage(self.request).add( _(u"There were errors"), 'error' ) self.renderOverlay('new-theme') return True else: if any(x.__name__ == title for x in getZODBThemes()): self.errors['title'] = _(u"Duplicate title") IStatusMessage(self.request).add( _(u"This title is already in use"), 'error' ) return True name = createThemeFromTemplate(title, description, baseOn) self._setup() if enableImmediately: themeData = self.getThemeData(self.availableThemes, name) applyTheme(themeData) self.theme_settings.enabled = True self.redirect( "{0}/++theme++{1}/@@theming-controlpanel-mapper".format( self.site_url, name ) ) return False if 'form.button.DeleteSelected' in form: self.authorize() toDelete = form.get('themes', []) themeDirectory = getOrCreatePersistentResourceDirectory() for theme in toDelete: del themeDirectory[theme] IStatusMessage(self.request).add(_(u"Theme deleted"), 'info') self._setup() return True return True
def get_theme(self): return theming_policy().get_theme()
def tearDown(self): request = self.layer['request'] policy = theming_policy(request) # clear local thread caches policy.invalidateCache()
def transformIterable(self, result, encoding): """Apply the transform if required """ # Obtain settings. Do nothing if not found policy = theming_policy(self.request) settings = policy.getSettings() if settings is None: return None if not policy.isThemeEnabled(): return None result = self.parseTree(result) if result is None: return None DevelopmentMode = Globals.DevelopmentMode runtrace = self.debug_theme() try: etree.clear_error_log() if settings.doctype: result.doctype = settings.doctype if not result.doctype.endswith('\n'): result.doctype += '\n' transform = self.setupTransform(runtrace=runtrace) if transform is None: return None cache = None if not DevelopmentMode: cache = policy.getCache() parameterExpressions = settings.parameterExpressions or {} params = prepareThemeParameters( findContext(self.request), self.request, parameterExpressions, cache ) transformed = transform(result.tree, **params) error_log = transform.error_log if transformed is not None: # Transformed worked, swap content with result result.tree = transformed except etree.LxmlError as e: if not(DevelopmentMode): raise error_log = e.error_log runtrace = True if runtrace: from diazo.runtrace import generate_debug_html # Add debug information to end of body body = result.tree.xpath('/html/body')[0] debug_url = findContext( self.request ).portal_url() + '/++resource++diazo-debug' body.insert( -1, generate_debug_html( debug_url, rules=settings.rules, rules_parser=getParser('rules', settings.readNetwork), error_log=error_log, ) ) return result
def get_cooked_bundles(self): """ Get the cooked bundles """ cache = component.queryUtility(ram.IRAMCache) bundles = self.get_bundles() policy = theming_policy(self.request) # Check if its Diazo enabled if policy.isThemeEnabled(): themeObj = policy.get_theme() enabled_diazo_bundles = themeObj.enabled_bundles disabled_diazo_bundles = themeObj.disabled_bundles if hasattr(themeObj, 'production_css'): self.diazo_production_css = themeObj.production_css self.diazo_development_css = themeObj.development_css self.diazo_development_js = themeObj.development_js self.diazo_production_js = themeObj.production_js else: self.diazo_production_css = None self.diazo_development_css = None self.diazo_development_js = None self.diazo_production_js = None else: enabled_diazo_bundles = [] disabled_diazo_bundles = [] self.diazo_production_css = None self.diazo_development_css = None self.diazo_development_js = None self.diazo_production_js = None # Request set bundles enabled_request_bundles = [] disabled_request_bundles = [] if hasattr(self.request, 'enabled_bundles'): enabled_request_bundles.extend(self.request.enabled_bundles) if hasattr(self.request, 'disabled_bundles'): disabled_request_bundles.extend(self.request.disabled_bundles) for key, bundle in bundles.items(): # The diazo manifest and request bundles are more important than # the disabled bundle on registry. # We can access the site with diazo.off=1 without diazo bundles if (bundle.enabled or key in enabled_request_bundles or key in enabled_diazo_bundles) and\ (key not in disabled_diazo_bundles and key not in disabled_request_bundles): # check expression if bundle.expression: cooked_expression = None if cache is not None: cooked_expression = cache.query( 'plone.bundles.cooked_expressions', key=dict(prefix=bundle.__prefix__), default=None) if (cooked_expression is None or cooked_expression.text != bundle.expression): cooked_expression = Expression(bundle.expression) if cache is not None: cache.set(cooked_expression, 'plone.bundles.cooked_expressions', key=dict(prefix=bundle.__prefix__)) if not self.evaluateExpression(cooked_expression, self.context): continue yield key, bundle
def test_isThemeEnabled(self): request = self.layer['request'] policy = theming_policy(request) self.assertTrue(policy.isThemeEnabled())
def getSettings(self): return theming_policy(self.request).getSettings()
def get_cooked_bundles(self): """ Get the cooked bundles """ cache = component.queryUtility(ram.IRAMCache) bundles = self.get_bundles() policy = theming_policy(self.request) enabled_diazo_bundles = [] disabled_diazo_bundles = [] self.diazo_production_css = None self.diazo_development_css = None self.diazo_development_js = None self.diazo_production_js = None # Check if its Diazo enabled if policy.isThemeEnabled(): themeObj = policy.get_theme() if themeObj: enabled_diazo_bundles = themeObj.enabled_bundles disabled_diazo_bundles = themeObj.disabled_bundles if hasattr(themeObj, 'production_css'): self.diazo_production_css = themeObj.production_css self.diazo_development_css = themeObj.development_css self.diazo_development_js = themeObj.development_js self.diazo_production_js = themeObj.production_js # Request set bundles enabled_request_bundles = [] disabled_request_bundles = [] if hasattr(self.request, 'enabled_bundles'): enabled_request_bundles.extend(self.request.enabled_bundles) if hasattr(self.request, 'disabled_bundles'): disabled_request_bundles.extend(self.request.disabled_bundles) for key, bundle in bundles.items(): # The diazo manifest and request bundles are more important than # the disabled bundle on registry. # We can access the site with diazo.off=1 without diazo bundles if (bundle.enabled or key in enabled_request_bundles or key in enabled_diazo_bundles) and\ (key not in disabled_diazo_bundles and key not in disabled_request_bundles): # check expression if bundle.expression: cooked_expression = None if cache is not None: cooked_expression = cache.query( 'plone.bundles.cooked_expressions', key=dict(prefix=bundle.__prefix__), default=None) if ( cooked_expression is None or cooked_expression.text != bundle.expression): cooked_expression = Expression(bundle.expression) if cache is not None: cache.set( cooked_expression, 'plone.bundles.cooked_expressions', key=dict(prefix=bundle.__prefix__)) if not self.evaluateExpression( cooked_expression, self.context): continue yield key, bundle
def test_getCurrentTheme(self): request = self.layer['request'] policy = theming_policy(request) self.assertEqual(policy.getCurrentTheme(), u'barceloneta')
def test_getCacheKey(self): request = self.layer['request'] policy = theming_policy(request) self.assertEqual(policy.getCacheKey(), u'http://nohost/plone::barceloneta')