# HG changeset patch # User Thierry Florac # Date 1510310879 -3600 # Node ID 50452584f7ae04d41912a4ba97fdea89e7368040 # Parent 0eca05146080ea58b07c9726f18ae8854f7b375b Added paragraphs content checkers diff -r 0eca05146080 -r 50452584f7ae src/pyams_content/component/paragraph/__init__.py --- a/src/pyams_content/component/paragraph/__init__.py Fri Nov 10 11:47:23 2017 +0100 +++ b/src/pyams_content/component/paragraph/__init__.py Fri Nov 10 11:47:59 2017 +0100 @@ -20,11 +20,13 @@ IParagraphContainer, IParagraphFactorySettings from pyams_content.shared.common.interfaces import IWfSharedContent from pyams_form.interfaces.form import IFormContextPermissionChecker +from pyams_i18n.interfaces import II18n from pyams_workflow.interfaces import IWorkflowState from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectModifiedEvent, IObjectRemovedEvent # import packages from persistent import Persistent +from pyams_content.features.checker import BaseContentChecker from pyams_utils.adapter import adapter_config, ContextAdapter from pyams_utils.registry import query_utility from pyams_utils.request import check_request @@ -76,6 +78,17 @@ title = FieldProperty(IBaseParagraph['title']) +class BaseParagraphContentChecker(BaseContentChecker): + """Base paragraph content checker mixin""" + + @property + def label(self): + request = check_request() + translate = request.localizer.translate + return II18n(self.context).query_attribute('title', request) or \ + '({0})'.format(translate(self.context.icon_hint).lower()) + + @vocabulary_config(name='PyAMS paragraph factories') class ParagraphFactoriesVocabulary(SimpleVocabulary): """Paragraph factories vocabulary""" @@ -96,14 +109,14 @@ @property def edit_permission(self): - content = get_parent(self.context, IWfSharedContent) + content = get_parent(self.context, IParagraphContainerTarget) return IFormContextPermissionChecker(content).edit_permission @subscriber(IObjectAddedEvent, context_selector=IBaseParagraph) def handle_added_paragraph(event): """Handle added paragraph""" - content = get_parent(event.object, IWfSharedContent) + content = get_parent(event.object, IParagraphContainerTarget) if content is not None: get_current_registry().notify(ObjectModifiedEvent(content)) @@ -111,7 +124,7 @@ @subscriber(IObjectModifiedEvent, context_selector=IBaseParagraph) def handle_modified_paragraph(event): """Handle modified paragraph""" - content = get_parent(event.object, IWfSharedContent) + content = get_parent(event.object, IParagraphContainerTarget) if content is not None: get_current_registry().notify(ObjectModifiedEvent(content)) @@ -119,6 +132,6 @@ @subscriber(IObjectRemovedEvent, context_selector=IBaseParagraph) def handle_removed_paragraph(event): """Handle removed paragraph""" - content = get_parent(event.object, IWfSharedContent) + content = get_parent(event.object, IParagraphContainerTarget) if content is not None: get_current_registry().notify(ObjectModifiedEvent(content)) diff -r 0eca05146080 -r 50452584f7ae src/pyams_content/component/paragraph/container.py --- a/src/pyams_content/component/paragraph/container.py Fri Nov 10 11:47:23 2017 +0100 +++ b/src/pyams_content/component/paragraph/container.py Fri Nov 10 11:47:59 2017 +0100 @@ -18,11 +18,13 @@ # import interfaces from pyams_content.component.paragraph.interfaces import IParagraphContainer, IParagraphContainerTarget, \ PARAGRAPH_CONTAINER_KEY +from pyams_content.features.checker.interfaces import IContentChecker from zope.annotation.interfaces import IAnnotations from zope.location.interfaces import ISublocations from zope.traversing.interfaces import ITraversable # import packages +from pyams_content.features.checker import BaseContentChecker from pyams_utils.adapter import adapter_config, ContextAdapter from pyams_utils.container import BTreeOrderedContainer from pyramid.threadlocal import get_current_registry @@ -30,6 +32,8 @@ from zope.lifecycleevent import ObjectCreatedEvent from zope.location import locate +from pyams_content import _ + @implementer(IParagraphContainer) class ParagraphContainer(BTreeOrderedContainer): @@ -69,3 +73,33 @@ def sublocations(self): return IParagraphContainer(self.context).values() + + +@adapter_config(name='paras', context=IParagraphContainerTarget, provides=IContentChecker) +class ParagraphContainerChecker(BaseContentChecker): + """Paragraphs container checker""" + + label = _("Paragraphs") + sep = '\n' + weight = 10 + + def inner_check(self, request): + output = [] + registry = request.registry + translate = request.localizer.translate + visible = False + for paragraph in IParagraphContainer(self.context).values(): + if not paragraph.visible: + continue + visible = True + for name, checker in sorted(registry.getAdapters((paragraph, ), IContentChecker), + key=lambda x: x[1].weight): + if name: + output.append('
') + output.append('- {0} :'.format(translate(checker.label))) + output.append(checker.get_check_output(request)) + if name: + output.append('
') + if not visible: + output.append('{0}'.format(translate(_("no visible paragraph")))) + return output diff -r 0eca05146080 -r 50452584f7ae src/pyams_content/component/paragraph/header.py --- a/src/pyams_content/component/paragraph/header.py Fri Nov 10 11:47:23 2017 +0100 +++ b/src/pyams_content/component/paragraph/header.py Fri Nov 10 11:47:59 2017 +0100 @@ -18,12 +18,15 @@ # import interfaces from pyams_content.component.paragraph.interfaces import IParagraphFactory from pyams_content.component.paragraph.interfaces.header import IHeaderParagraph -from pyams_i18n.interfaces import II18n +from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE +from pyams_i18n.interfaces import II18n, II18nManager, INegotiator # import packages -from pyams_content.component.paragraph import BaseParagraph -from pyams_utils.registry import utility_config +from pyams_content.component.paragraph import BaseParagraph, BaseParagraphContentChecker +from pyams_utils.adapter import adapter_config +from pyams_utils.registry import utility_config, get_utility from pyams_utils.text import get_text_start +from pyams_utils.traversing import get_parent from zope.interface import implementer from zope.schema.fieldproperty import FieldProperty @@ -51,3 +54,28 @@ name = _("Header paragraph") content_type = HeaderParagraph + + +@adapter_config(context=IHeaderParagraph, provides=IContentChecker) +class HeaderParagraphContentChecker(BaseParagraphContentChecker): + """Header paragraph content checker""" + + def inner_check(self, request): + output = [] + translate = request.localizer.translate + manager = get_parent(self.context, II18nManager) + if manager is not None: + langs = manager.get_languages() + else: + negotiator = get_utility(INegotiator) + langs = (negotiator.server_language, ) + i18n = II18n(self.context) + for lang in langs: + value = i18n.get_attribute('header', lang, request) + if not value: + field_title = translate(IHeaderParagraph['header'].title) + if len(langs) == 1: + output.append(translate(MISSING_VALUE).format(field=field_title)) + else: + output.append(translate(MISSING_LANG_VALUE).format(field=field_title, lang=lang)) + return output diff -r 0eca05146080 -r 50452584f7ae src/pyams_content/component/paragraph/html.py --- a/src/pyams_content/component/paragraph/html.py Fri Nov 10 11:47:23 2017 +0100 +++ b/src/pyams_content/component/paragraph/html.py Fri Nov 10 11:47:59 2017 +0100 @@ -23,14 +23,17 @@ from pyams_content.component.links.interfaces import ILinkContainerTarget, IInternalLink, IExternalLink, IMailtoLink from pyams_content.component.paragraph.interfaces import IParagraphFactory from pyams_content.component.paragraph.interfaces.html import IHTMLParagraph -from pyams_i18n.interfaces import II18n +from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE +from pyams_i18n.interfaces import II18n, II18nManager, INegotiator from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectModifiedEvent # import packages from pyams_content.component.links import InternalLink, ExternalLink, MailtoLink -from pyams_content.component.paragraph import BaseParagraph -from pyams_utils.registry import utility_config +from pyams_content.component.paragraph import BaseParagraph, BaseParagraphContentChecker +from pyams_utils.adapter import adapter_config +from pyams_utils.registry import utility_config, get_utility from pyams_utils.request import check_request +from pyams_utils.traversing import get_parent from pyams_utils.url import absolute_url from pyquery import PyQuery from pyramid.events import subscriber @@ -145,3 +148,28 @@ paragraph = event.object for lang, body in (paragraph.body or {}).items(): check_associations(paragraph, body, lang, notify=False) + + +@adapter_config(context=IHTMLParagraph, provides=IContentChecker) +class HTMLParagraphContentChecker(BaseParagraphContentChecker): + """HTML paragraph content checker""" + + def inner_check(self, request): + output = [] + translate = request.localizer.translate + manager = get_parent(self.context, II18nManager) + if manager is not None: + langs = manager.get_languages() + else: + negotiator = get_utility(INegotiator) + langs = (negotiator.server_language, ) + i18n = II18n(self.context) + for lang in langs: + value = i18n.get_attribute('body', lang, request) + if not value: + field_title = translate(IHTMLParagraph['body'].title) + if len(langs) == 1: + output.append(translate(MISSING_VALUE).format(field=field_title)) + else: + output.append(translate(MISSING_LANG_VALUE).format(field=field_title, lang=lang)) + return output diff -r 0eca05146080 -r 50452584f7ae src/pyams_content/component/paragraph/video.py --- a/src/pyams_content/component/paragraph/video.py Fri Nov 10 11:47:23 2017 +0100 +++ b/src/pyams_content/component/paragraph/video.py Fri Nov 10 11:47:59 2017 +0100 @@ -9,10 +9,6 @@ # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # -from pyramid.events import subscriber -from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectModifiedEvent - -from pyams_content.component.paragraph.html import check_associations __docformat__ = 'restructuredtext' @@ -24,11 +20,18 @@ from pyams_content.component.links.interfaces import ILinkContainerTarget from pyams_content.component.paragraph.interfaces import IParagraphFactory from pyams_content.component.paragraph.interfaces.video import IVideoParagraph +from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE +from pyams_i18n.interfaces import II18nManager, INegotiator, II18n +from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectModifiedEvent # import packages -from pyams_content.component.paragraph import BaseParagraph +from pyams_content.component.paragraph import BaseParagraph, BaseParagraphContentChecker +from pyams_content.component.paragraph.html import check_associations from pyams_file.property import FileProperty -from pyams_utils.registry import utility_config +from pyams_utils.adapter import adapter_config +from pyams_utils.registry import utility_config, get_utility +from pyams_utils.traversing import get_parent +from pyramid.events import subscriber from zope.interface import implementer from zope.schema.fieldproperty import FieldProperty @@ -70,3 +73,32 @@ paragraph = event.object for lang, body in (paragraph.body or {}).items(): check_associations(paragraph, body, lang, notify=False) + + +@adapter_config(context=IVideoParagraph, provides=IContentChecker) +class VideoParagraphContentChecker(BaseParagraphContentChecker): + """Video paragraph content checker""" + + def inner_check(self, request): + output = [] + translate = request.localizer.translate + manager = get_parent(self.context, II18nManager) + if manager is not None: + langs = manager.get_languages() + else: + negotiator = get_utility(INegotiator) + langs = (negotiator.server_language, ) + i18n = II18n(self.context) + for lang in langs: + value = i18n.get_attribute('title', lang, request) + if not value: + field_title = translate(IVideoParagraph['title'].title) + if len(langs) == 1: + output.append(translate(MISSING_VALUE).format(field=field_title)) + else: + output.append(translate(MISSING_LANG_VALUE).format(field=field_title, lang=lang)) + for attr in ('author', 'data'): + value = getattr(self.context, attr) + if not value: + output.append(translate(MISSING_VALUE).format(field=translate(IVideoParagraph[attr].title))) + return output