# HG changeset patch # User Thierry Florac # Date 1444233220 -7200 # Node ID 0dd5876f9d70b26aa94b6b72b87d6ed2b6a9a8b1 # Parent 25cf058f7e1dd93c17db525ed38e5ef5a35808ef Added back-office configuration interface and classes diff -r 25cf058f7e1d -r 0dd5876f9d70 src/pyams_skin/configuration.py --- a/src/pyams_skin/configuration.py Wed Oct 07 17:52:40 2015 +0200 +++ b/src/pyams_skin/configuration.py Wed Oct 07 17:53:40 2015 +0200 @@ -18,8 +18,9 @@ # import interfaces from pyams_skin.interfaces.configuration import IStaticConfiguration, IConfiguration, \ - SKIN_CONFIGURATION_KEY -from pyams_utils.interfaces.site import IStaticConfigurationManager, IConfigurationManager, IConfigurationFactory + SKIN_CONFIGURATION_KEY, IBackOfficeConfiguration, SKIN_BACK_CONFIGURATION_KEY +from pyams_utils.interfaces.site import IStaticConfigurationManager, IConfigurationManager, IConfigurationFactory, \ + IBackOfficeConfigurationFactory from pyams_utils.interfaces.tales import ITALESExtension from zope.annotation.interfaces import IAnnotations from zope.traversing.interfaces import ITraversable @@ -41,6 +42,10 @@ from pyams_skin import _ +# +# Static configuration +# + @adapter_config(context=(IStaticConfigurationManager, Interface, Interface), provides=IStaticConfiguration) class StaticConfiguration(object): """Default static configuration""" @@ -89,6 +94,11 @@ return registry.queryMultiAdapter((target, self.request, self.view), IStaticConfiguration) +# +# Dynamic front-office configuration +# May be overriden by custom applications +# + @implementer(IConfiguration) class Configuration(Persistent, Contained): """Manageable configuration""" @@ -107,10 +117,9 @@ configuration = annotations.get(SKIN_CONFIGURATION_KEY) if configuration is None: registry = check_request().registry - factory = registry.queryAdapter(context, IConfigurationFactory) - if factory is not None: - configuration = annotations[SKIN_CONFIGURATION_KEY] = factory() - locate(configuration, context, '++configuration++') + factory = registry.queryAdapter(context, IConfigurationFactory, default=Configuration) + configuration = annotations[SKIN_CONFIGURATION_KEY] = factory() + locate(configuration, context, '++configuration++') return configuration @@ -142,3 +151,63 @@ request.context = configuration.icon return MediaFileView(request) return HTTPNotFound() + + +# +# Dynamic back-office configuration +# May be overriden by custom applications +# + +@implementer(IBackOfficeConfiguration) +class BackOfficeConfiguration(Persistent, Contained): + """Back-office manageable configuration""" + + title = FieldProperty(IBackOfficeConfiguration['title']) + login_header = FieldProperty(IBackOfficeConfiguration['login_header']) + login_footer = FieldProperty(IBackOfficeConfiguration['login_footer']) + icon = FileProperty(IBackOfficeConfiguration['icon']) + logo = FileProperty(IBackOfficeConfiguration['logo']) + display_content_icon = FieldProperty(IBackOfficeConfiguration['display_content_icon']) + + +@adapter_config(context=IConfigurationManager, provides=IBackOfficeConfiguration) +def BackOfficeConfigurationFactory(context): + """Back-office configuration factory""" + annotations = IAnnotations(context) + configuration = annotations.get(SKIN_BACK_CONFIGURATION_KEY) + if configuration is None: + registry = check_request().registry + factory = registry.queryAdapter(context, IBackOfficeConfigurationFactory, default=BackOfficeConfiguration) + configuration = annotations[SKIN_BACK_CONFIGURATION_KEY] = factory() + locate(configuration, context, '++back-configuration++') + return configuration + + +@adapter_config(name='back_configuration', context=(Interface, Interface, Interface), provides=ITALESExtension) +class BackOfficeConfigurationTalesExtension(ContextRequestViewAdapter): + """extension:back_configuration TALES expression""" + + def render(self, context=None): + if context is None: + context = self.context + manager = get_parent(context, IConfigurationManager) + if manager is not None: + return IBackOfficeConfiguration(manager) + + +@adapter_config(name='back-configuration', context=IConfigurationManager, provides=ITraversable) +class BackOfficeConfigurationTraverser(ContextAdapter): + """++back-configuration++ namespace traverser""" + + def traverse(self, name, furtherpath=None): + return IBackOfficeConfiguration(self.context) + + +@view_config(name='back-favicon.ico', context=IConfigurationManager) +def back_office_site_icon(request): + configuration = IBackOfficeConfiguration(request.context) + if configuration.icon is not None: + request = request.copy() + request.context = configuration.icon + return MediaFileView(request) + return HTTPNotFound() diff -r 25cf058f7e1d -r 0dd5876f9d70 src/pyams_skin/interfaces/configuration.py --- a/src/pyams_skin/interfaces/configuration.py Wed Oct 07 17:52:40 2015 +0200 +++ b/src/pyams_skin/interfaces/configuration.py Wed Oct 07 17:53:40 2015 +0200 @@ -21,7 +21,7 @@ # import packages from pyams_file.schema import ImageField from zope.interface import Interface, Attribute -from zope.schema import TextLine, Choice, Bool +from zope.schema import TextLine, Text, Choice, Bool from pyams_skin import _ @@ -133,10 +133,42 @@ description=_("Public author name"), required=False) - icon = ImageField(title="Icon", + icon = ImageField(title=_("Icon"), description=_("Browser favourite icon"), required=False) logo = ImageField(title=_("Logo"), description=_("Image containing application logo"), required=False) + + +SKIN_BACK_CONFIGURATION_KEY = 'pyams_skin.back-office.configuration' + + +class IBackOfficeConfiguration(IContained): + """Back-office configuration""" + + title = TextLine(title=_("Title"), + description=_("Application title visible in back-office"), + required=False) + + login_header = Text(title=_("Login header"), + description=_("This reStructuredText text will be displayed in login page header"), + required=False) + + login_footer = Text(title=_("Login footer"), + description=_("This reStructuredText text will be displayed in login page footer"), + required=False) + + icon = ImageField(title=_("Icon"), + description=_("Browser favourite icon"), + required=False) + + logo = ImageField(title=_("Logo"), + description=_("Image containing application logo"), + required=False) + + display_content_icon = Bool(title=_("Display title icon?"), + description=_("Should icons be displayed into content's title area ?"), + required=True, + default=True)