--- 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))
--- 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('<div class="padding-left-20">')
+ output.append('- {0} :'.format(translate(checker.label)))
+ output.append(checker.get_check_output(request))
+ if name:
+ output.append('</div>')
+ if not visible:
+ output.append('<span class="text-danger">{0}</span>'.format(translate(_("no visible paragraph"))))
+ return output
--- 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
--- 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
--- 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