# HG changeset patch # User Damien Correia # Date 1538729072 -7200 # Node ID f50be61c93a6edc3ec6252d41a846cd7be3a12f2 # Parent 8a7ec586dce12d2dfe9e32d622011d3a2d6b2386# Parent a219e2e207797e2542a9d42677c10a969c28b3b6 Merge default diff -r 8a7ec586dce1 -r f50be61c93a6 .hgtags --- a/.hgtags Thu Sep 06 18:10:04 2018 +0200 +++ b/.hgtags Fri Oct 05 10:44:32 2018 +0200 @@ -21,3 +21,8 @@ fc8fe2dede6309db4a8cfc5b53eb894cca2f6970 0.1.15 9cc7207c1399658ef821a1ecdde86df0b5a1298d 0.1.15.1 f687b90488819f2dba88ed44a254d7cba1f8c652 0.1.16 +20c85661ff35eb595a82ab829eede53544455678 0.1.18 +27c643fea2b4149a23f5e424087fa22a84901497 0.1.18.1 +a9bcf47e975416f509bcd7b695b34313b8b28e8c 0.1.18.2 +5e51b05a38facaea6a20bb35fb42996755bbbe46 0.1.19 +33e3a44c50b353b7c6543e8a2594766fc1ca98d2 0.1.19.1 diff -r 8a7ec586dce1 -r f50be61c93a6 buildout.cfg --- a/buildout.cfg Thu Sep 06 18:10:04 2018 +0200 +++ b/buildout.cfg Fri Oct 05 10:44:32 2018 +0200 @@ -86,4 +86,4 @@ eggs = pyams_content [test] [versions] -pyams_content = 0.1.17 +pyams_content = 0.1.20 diff -r 8a7ec586dce1 -r f50be61c93a6 docs/HISTORY.txt --- a/docs/HISTORY.txt Thu Sep 06 18:10:04 2018 +0200 +++ b/docs/HISTORY.txt Fri Oct 05 10:44:32 2018 +0200 @@ -1,6 +1,35 @@ History ======= +0.1.19 +------ + - added "topic" shared content + - added description and notepad attributes to sites, folders and blogs + - added common base interface for all illustrations targets + - added shared content's title portlet + - updated gallery interfaces and properties + +0.1.18.2 +-------- + - check for broken objects while iterating over visible paragraphs + +0.1.18.1 +-------- + - remove broken objects from catalog when reindexing + +0.1.18 +------ + - better PEP 8 conformance + - many many ZMI updates + +0.1.17 +------ + - clear catalog and reindex all objects in "pyams_index" script + - updated forms templates + - updated advanced search engine to search over tags, themes and collections + - added "header" attribute to shared contents (replacing "Header" paragraph), and + added static attribute to disable header on selected shared contents + 0.1.16 ------ - use iterators in all dashboards diff -r 8a7ec586dce1 -r f50be61c93a6 setup.py --- a/setup.py Thu Sep 06 18:10:04 2018 +0200 +++ b/setup.py Fri Oct 05 10:44:32 2018 +0200 @@ -14,7 +14,9 @@ This module contains pyams_content package """ import os -from setuptools import setup, find_packages + +from setuptools import find_packages, setup + DOCS = os.path.join(os.path.dirname(__file__), 'docs') @@ -22,7 +24,7 @@ README = os.path.join(DOCS, 'README.txt') HISTORY = os.path.join(DOCS, 'HISTORY.txt') -version = '0.1.17' +version = '0.1.20' long_description = open(README).read() + '\n\n' + open(HISTORY).read() tests_require = [] diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content.egg-info/PKG-INFO --- a/src/pyams_content.egg-info/PKG-INFO Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content.egg-info/PKG-INFO Fri Oct 05 10:44:32 2018 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: pyams-content -Version: 0.1.16 +Version: 0.1.19.1 Summary: PyAMS base content interfaces and classes Home-page: http://hg.ztfy.org/pyams/pyams_content Author: Thierry Florac @@ -73,6 +73,35 @@ History ======= + 0.1.19 + ------ + - added "topic" shared content + - added description and notepad attributes to sites, folders and blogs + - added common base interface for all illustrations targets + - added shared content's title portlet + - updated gallery interfaces and properties + + 0.1.18.2 + -------- + - check for broken objects while iterating over visible paragraphs + + 0.1.18.1 + -------- + - remove broken objects from catalog when reindexing + + 0.1.18 + ------ + - better PEP 8 conformance + - many many ZMI updates + + 0.1.17 + ------ + - clear catalog and reindex all objects in "pyams_index" script + - updated forms templates + - updated advanced search engine to search over tags, themes and collections + - added "header" attribute to shared contents (replacing "Header" paragraph), and + added static attribute to disable header on selected shared contents + 0.1.16 ------ - use iterators in all dashboards diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content.egg-info/SOURCES.txt --- a/src/pyams_content.egg-info/SOURCES.txt Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content.egg-info/SOURCES.txt Fri Oct 05 10:44:32 2018 +0200 @@ -37,6 +37,7 @@ src/pyams_content/component/gallery/zmi/interfaces.py src/pyams_content/component/gallery/zmi/paragraph.py src/pyams_content/component/gallery/zmi/templates/gallery-media-thumbnail.pt +src/pyams_content/component/gallery/zmi/templates/gallery-media.pt src/pyams_content/component/gallery/zmi/templates/gallery-medias.pt src/pyams_content/component/illustration/__init__.py src/pyams_content/component/illustration/paragraph.py @@ -48,12 +49,14 @@ src/pyams_content/component/illustration/zmi/templates/illustration-thumbnail.pt src/pyams_content/component/illustration/zmi/templates/paragraph-illustration-icon.pt src/pyams_content/component/keynumber/__init__.py +src/pyams_content/component/keynumber/paragraph.py src/pyams_content/component/keynumber/interfaces/__init__.py src/pyams_content/component/keynumber/portlet/__init__.py src/pyams_content/component/keynumber/portlet/interfaces/__init__.py src/pyams_content/component/keynumber/portlet/zmi/__init__.py src/pyams_content/component/keynumber/portlet/zmi/templates/keynumber-preview.pt src/pyams_content/component/keynumber/zmi/__init__.py +src/pyams_content/component/keynumber/zmi/paragraph.py src/pyams_content/component/links/__init__.py src/pyams_content/component/links/interfaces/__init__.py src/pyams_content/component/links/zmi/__init__.py @@ -66,7 +69,6 @@ src/pyams_content/component/paragraph/frame.py src/pyams_content/component/paragraph/header.py src/pyams_content/component/paragraph/html.py -src/pyams_content/component/paragraph/keynumber.py src/pyams_content/component/paragraph/keypoint.py src/pyams_content/component/paragraph/map.py src/pyams_content/component/paragraph/milestone.py @@ -79,13 +81,17 @@ src/pyams_content/component/paragraph/interfaces/frame.py src/pyams_content/component/paragraph/interfaces/header.py src/pyams_content/component/paragraph/interfaces/html.py -src/pyams_content/component/paragraph/interfaces/keynumber.py src/pyams_content/component/paragraph/interfaces/keypoint.py src/pyams_content/component/paragraph/interfaces/map.py src/pyams_content/component/paragraph/interfaces/milestone.py src/pyams_content/component/paragraph/interfaces/pictogram.py src/pyams_content/component/paragraph/interfaces/verbatim.py src/pyams_content/component/paragraph/interfaces/video.py +src/pyams_content/component/paragraph/portlet/__init__.py +src/pyams_content/component/paragraph/portlet/interfaces/__init__.py +src/pyams_content/component/paragraph/portlet/zmi/__init__.py +src/pyams_content/component/paragraph/portlet/zmi/templates/container-preview.pt +src/pyams_content/component/paragraph/portlet/zmi/templates/navigation-preview.pt src/pyams_content/component/paragraph/zmi/__init__.py src/pyams_content/component/paragraph/zmi/audio.py src/pyams_content/component/paragraph/zmi/contact.py @@ -94,7 +100,6 @@ src/pyams_content/component/paragraph/zmi/header.py src/pyams_content/component/paragraph/zmi/html.py src/pyams_content/component/paragraph/zmi/interfaces.py -src/pyams_content/component/paragraph/zmi/keynumber.py src/pyams_content/component/paragraph/zmi/keypoint.py src/pyams_content/component/paragraph/zmi/map.py src/pyams_content/component/paragraph/zmi/milestone.py @@ -240,11 +245,15 @@ src/pyams_content/shared/common/interfaces/types.py src/pyams_content/shared/common/interfaces/zmi.py src/pyams_content/shared/common/portlet/__init__.py -src/pyams_content/shared/common/portlet/content/__init__.py -src/pyams_content/shared/common/portlet/content/interfaces/__init__.py -src/pyams_content/shared/common/portlet/content/skin/__init__.py -src/pyams_content/shared/common/portlet/content/zmi/__init__.py -src/pyams_content/shared/common/portlet/content/zmi/preview.pt +src/pyams_content/shared/common/portlet/head.py +src/pyams_content/shared/common/portlet/title.py +src/pyams_content/shared/common/portlet/interfaces/__init__.py +src/pyams_content/shared/common/portlet/skin/__init__.py +src/pyams_content/shared/common/portlet/zmi/__init__.py +src/pyams_content/shared/common/portlet/zmi/head.py +src/pyams_content/shared/common/portlet/zmi/title.py +src/pyams_content/shared/common/portlet/zmi/templates/head-preview.pt +src/pyams_content/shared/common/portlet/zmi/templates/title-preview.pt src/pyams_content/shared/common/skin/__init__.py src/pyams_content/shared/common/skin/oid.py src/pyams_content/shared/common/skin/opengraph.py @@ -327,6 +336,8 @@ src/pyams_content/shared/site/link.py src/pyams_content/shared/site/manager.py src/pyams_content/shared/site/interfaces/__init__.py +src/pyams_content/shared/site/skin/__init__.py +src/pyams_content/shared/site/skin/breadcrumb.py src/pyams_content/shared/site/zmi/__init__.py src/pyams_content/shared/site/zmi/container.py src/pyams_content/shared/site/zmi/folder.py @@ -335,6 +346,10 @@ src/pyams_content/shared/site/zmi/widget/__init__.py src/pyams_content/shared/site/zmi/widget/interfaces.py src/pyams_content/shared/site/zmi/widget/templates/folders-input.pt +src/pyams_content/shared/topic/__init__.py +src/pyams_content/shared/topic/manager.py +src/pyams_content/shared/topic/interfaces/__init__.py +src/pyams_content/shared/topic/zmi/__init__.py src/pyams_content/shared/view/__init__.py src/pyams_content/shared/view/manager.py src/pyams_content/shared/view/merge.py diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/component/association/zmi/__init__.py --- a/src/pyams_content/component/association/zmi/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/component/association/zmi/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -181,8 +181,10 @@ return switch_element_visibility(request, IAssociationContainer) -@adapter_config(name='pictogram', context=(IAssociationContainerTarget, IPyAMSLayer, AssociationsTable), provides=IColumn) -@adapter_config(name='pictogram', context=(IAssociationContainer, IPyAMSLayer, AssociationsTable), provides=IColumn) +@adapter_config(name='pictogram', context=(IAssociationContainerTarget, IPyAMSLayer, AssociationsTable), + provides=IColumn) +@adapter_config(name='pictogram', context=(IAssociationContainer, IPyAMSLayer, AssociationsTable), + provides=IColumn) class AssociationsTablePictogramColumn(ImageColumn): """Associations table pictogram column""" @@ -197,8 +199,10 @@ return self.request.localizer.translate(item.icon_hint) -@adapter_config(name='name', context=(IAssociationContainerTarget, IPyAMSLayer, AssociationsTable), provides=IColumn) -@adapter_config(name='name', context=(IAssociationContainer, IPyAMSLayer, AssociationsTable), provides=IColumn) +@adapter_config(name='name', context=(IAssociationContainerTarget, IPyAMSLayer, AssociationsTable), + provides=IColumn) +@adapter_config(name='name', context=(IAssociationContainer, IPyAMSLayer, AssociationsTable), + provides=IColumn) class AssociationsTablePublicNameColumn(NameColumn): """Associations table name column""" @@ -215,8 +219,10 @@ return title -@adapter_config(name='inner_name', context=(IAssociationContainerTarget, IPyAMSLayer, AssociationsTable), provides=IColumn) -@adapter_config(name='inner_name', context=(IAssociationContainer, IPyAMSLayer, AssociationsTable), provides=IColumn) +@adapter_config(name='inner_name', context=(IAssociationContainerTarget, IPyAMSLayer, AssociationsTable), + provides=IColumn) +@adapter_config(name='inner_name', context=(IAssociationContainer, IPyAMSLayer, AssociationsTable), + provides=IColumn) class AssociationsTableInnerNameColumn(I18nColumn, GetAttrColumn): """Associations table inner name column""" @@ -231,8 +237,10 @@ return '--' -@adapter_config(name='size', context=(IAssociationContainerTarget, IPyAMSLayer, AssociationsTable), provides=IColumn) -@adapter_config(name='size', context=(IAssociationContainer, IPyAMSLayer, AssociationsTable), provides=IColumn) +@adapter_config(name='size', context=(IAssociationContainerTarget, IPyAMSLayer, AssociationsTable), + provides=IColumn) +@adapter_config(name='size', context=(IAssociationContainer, IPyAMSLayer, AssociationsTable), + provides=IColumn) class AssociationsTableSizeColumn(I18nColumn, GetAttrColumn): """Associations table size column""" @@ -247,8 +255,10 @@ return '--' -@adapter_config(name='trash', context=(IAssociationContainerTarget, IPyAMSLayer, AssociationsTable), provides=IColumn) -@adapter_config(name='trash', context=(IAssociationContainer, IPyAMSLayer, AssociationsTable), provides=IColumn) +@adapter_config(name='trash', context=(IAssociationContainerTarget, IPyAMSLayer, AssociationsTable), + provides=IColumn) +@adapter_config(name='trash', context=(IAssociationContainer, IPyAMSLayer, AssociationsTable), + provides=IColumn) class AssociationsTableTrashColumn(ProtectedFormObjectMixin, TrashColumn): """Associations table trash column""" diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/component/gallery/__init__.py --- a/src/pyams_content/component/gallery/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/component/gallery/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,52 +12,44 @@ __docformat__ = 'restructuredtext' - -# import standard library +from pyramid.events import subscriber +from pyramid.threadlocal import get_current_registry +from zope.interface import implementer +from zope.lifecycleevent import ObjectModifiedEvent +from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectModifiedEvent, IObjectRemovedEvent +from zope.location import locate +from zope.location.interfaces import ISublocations +from zope.schema.fieldproperty import FieldProperty +from zope.traversing.interfaces import ITraversable -# import interfaces -from pyams_content.component.gallery.interfaces import IBaseGallery, IGallery, IGalleryTarget, \ - GALLERY_CONTAINER_KEY, GALLERY_RENDERERS +from pyams_catalog.utils import index_object +from pyams_content import _ +from pyams_content.component.gallery.interfaces import GALLERY_CONTAINER_KEY, GALLERY_RENDERERS, IBaseGallery, IGallery, \ + IGalleryFile, IGalleryTarget from pyams_content.component.paragraph import IBaseParagraph +from pyams_content.features.checker import BaseContentChecker from pyams_content.features.checker.interfaces import IContentChecker +from pyams_content.features.renderer import RenderedContentMixin, RenderersVocabulary from pyams_content.shared.common.interfaces import IWfSharedContent from pyams_form.interfaces.form import IFormContextPermissionChecker from pyams_i18n.interfaces import II18n -from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectModifiedEvent, IObjectRemovedEvent -from zope.location.interfaces import ISublocations -from zope.traversing.interfaces import ITraversable - -# import packages -from pyams_catalog.utils import index_object -from pyams_content.features.checker import BaseContentChecker -from pyams_content.features.renderer import RenderedContentMixin, RenderersVocabulary -from pyams_utils.adapter import adapter_config, ContextAdapter, get_annotation_adapter +from pyams_utils.adapter import ContextAdapter, adapter_config, get_annotation_adapter +from pyams_utils.container import BTreeOrderedContainer from pyams_utils.factory import factory_config -from pyams_utils.container import BTreeOrderedContainer from pyams_utils.traversing import get_parent from pyams_utils.vocabulary import vocabulary_config -from pyramid.events import subscriber -from pyramid.threadlocal import get_current_registry -from zope.interface import implementer -from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent -from zope.location import locate -from zope.schema.fieldproperty import FieldProperty - -from pyams_content import _ # # Galleries container # -@implementer(IGallery) +@implementer(IBaseGallery) @factory_config(provided=IBaseGallery) -class Gallery(RenderedContentMixin, BTreeOrderedContainer): - """Gallery persistent class""" +class BaseGallery(RenderedContentMixin, BTreeOrderedContainer): + """Base gallery persistent class""" - title = FieldProperty(IGallery['title']) - description = FieldProperty(IGallery['description']) - renderer = FieldProperty(IGallery['renderer']) + renderer = FieldProperty(IBaseGallery['renderer']) last_id = 1 @@ -73,7 +65,16 @@ index_object(value) def get_visible_medias(self): - return [media for media in self.values() if media.visible] + yield from filter(lambda x: IGalleryFile(x).visible, self.values()) + + +@implementer(IGallery) +@factory_config(provided=IGallery) +class Gallery(BaseGallery): + """Gallery persistent class""" + + title = FieldProperty(IGallery['title']) + description = FieldProperty(IGallery['description']) @adapter_config(context=IGalleryTarget, provides=IGallery) @@ -161,7 +162,7 @@ for media in IGallery(self.context).values(): if not media.visible: continue - for name, checker in sorted(registry.getAdapters((media, ), IContentChecker), + for name, checker in sorted(registry.getAdapters((media,), IContentChecker), key=lambda x: x[1].weight): output.append('- {0} : '.format(checker.label or II18n(media).query_attribute('title', request=request))) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/component/gallery/file.py --- a/src/pyams_content/component/gallery/file.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/component/gallery/file.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,32 +12,27 @@ __docformat__ = 'restructuredtext' - -# import standard library +from persistent import Persistent +from pyramid.events import subscriber +from pyramid.threadlocal import get_current_registry +from zope.container.contained import Contained +from zope.interface import alsoProvides, implementer +from zope.lifecycleevent import ObjectModifiedEvent +from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectModifiedEvent, IObjectRemovedEvent +from zope.schema.fieldproperty import FieldProperty -# import interfaces from pyams_content.component.gallery.interfaces import IGalleryFile -from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE +from pyams_content.features.checker import BaseContentChecker +from pyams_content.features.checker.interfaces import IContentChecker, MISSING_LANG_VALUE, MISSING_VALUE from pyams_content.shared.common.interfaces import IWfSharedContent -from pyams_file.interfaces import IResponsiveImage, IImage +from pyams_file.interfaces import IImage, IResponsiveImage +from pyams_file.property import FileProperty from pyams_form.interfaces.form import IFormContextPermissionChecker from pyams_i18n.interfaces import II18n, II18nManager, INegotiator -from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectModifiedEvent, IObjectRemovedEvent - -# import packages -from persistent import Persistent -from pyams_content.features.checker import BaseContentChecker -from pyams_file.property import FileProperty -from pyams_utils.adapter import adapter_config, ContextAdapter +from pyams_utils.adapter import ContextAdapter, adapter_config from pyams_utils.registry import get_utility from pyams_utils.request import check_request from pyams_utils.traversing import get_parent -from pyramid.events import subscriber -from pyramid.threadlocal import get_current_registry -from zope.lifecycleevent import ObjectModifiedEvent -from zope.container.contained import Contained -from zope.interface import implementer, alsoProvides -from zope.schema.fieldproperty import FieldProperty # @@ -53,8 +48,6 @@ alt_title = FieldProperty(IGalleryFile['alt_title']) description = FieldProperty(IGalleryFile['description']) author = FieldProperty(IGalleryFile['author']) - author_comments = FieldProperty(IGalleryFile['author_comments']) - pif_number = FieldProperty(IGalleryFile['pif_number']) sound = FileProperty(IGalleryFile['sound']) sound_title = FieldProperty(IGalleryFile['sound_title']) sound_description = FieldProperty(IGalleryFile['sound_description']) @@ -122,7 +115,7 @@ langs = manager.get_languages() else: negotiator = get_utility(INegotiator) - langs = (negotiator.server_language, ) + langs = (negotiator.server_language,) i18n = II18n(self.context) for lang in langs: for attr in ('title', 'alt_title', 'description'): diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/component/gallery/interfaces/__init__.py --- a/src/pyams_content/component/gallery/interfaces/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/component/gallery/interfaces/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,21 +12,16 @@ __docformat__ = 'restructuredtext' +from zope.annotation.interfaces import IAttributeAnnotatable +from zope.container.constraints import containers, contains +from zope.container.interfaces import IOrderedContainer +from zope.interface import Interface +from zope.schema import Bool, Choice, TextLine -# import standard library - -# import interfaces from pyams_content.component.paragraph.interfaces import IBaseParagraph from pyams_content.features.renderer.interfaces import IRenderedContent -from zope.container.interfaces import IOrderedContainer - -# import packages -from pyams_file.schema import MediaField, AudioField -from pyams_i18n.schema import I18nTextLineField, I18nTextField -from zope.annotation.interfaces import IAttributeAnnotatable -from zope.container.constraints import contains, containers -from zope.interface import Interface -from zope.schema import Bool, TextLine, Choice +from pyams_file.schema import AudioField, MediaField +from pyams_i18n.schema import I18nTextField, I18nTextLineField from pyams_content import _ @@ -62,14 +57,6 @@ description=_("Name of document's author"), required=True) - author_comments = I18nTextField(title=_("Author's comments"), - description=_("Comments relatives to author's rights management"), - required=False) - - pif_number = TextLine(title=_("Source ID"), - description=_("Number used to identify media into it's original source"), - required=False) - sound = AudioField(title=_("Audio data"), description=_("Sound file associated with the current media"), required=False) @@ -94,14 +81,6 @@ class IBaseGallery(IOrderedContainer, IAttributeAnnotatable, IRenderedContent): """Base gallery interface""" - title = I18nTextLineField(title=_("Title"), - description=_("Gallery title, as shown in front-office"), - required=False) - - description = I18nTextField(title=_("Description"), - description=_("Gallery description displayed by front-office template"), - required=False) - renderer = Choice(title=_("Gallery template"), description=_("Presentation template used for this gallery"), vocabulary=GALLERY_RENDERERS, @@ -124,6 +103,14 @@ contains(IGalleryItem) + title = I18nTextLineField(title=_("Title"), + description=_("Gallery title, as shown in front-office"), + required=False) + + description = I18nTextField(title=_("Description"), + description=_("Gallery description displayed by front-office template"), + required=False) + class IGalleryTarget(IAttributeAnnotatable): """Gallery container target marker interface""" @@ -133,5 +120,5 @@ GALLERY_PARAGRAPH_NAME = _("Medias gallery") -class IGalleryParagraph(IGallery, IBaseParagraph): +class IGalleryParagraph(IBaseGallery, IBaseParagraph): """Gallery paragraph""" diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/component/gallery/paragraph.py --- a/src/pyams_content/component/gallery/paragraph.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/component/gallery/paragraph.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,22 +12,19 @@ __docformat__ = 'restructuredtext' - -# import standard library +from zope.interface import implementer -# import interfaces -from pyams_content.component.gallery.interfaces import IGalleryParagraph, GALLERY_PARAGRAPH_TYPE, GALLERY_PARAGRAPH_NAME +from pyams_content import _ +from pyams_content.component.gallery import BaseGallery +from pyams_content.component.gallery.interfaces import GALLERY_PARAGRAPH_NAME, GALLERY_PARAGRAPH_TYPE, IGalleryParagraph +from pyams_content.component.paragraph import BaseParagraph, BaseParagraphContentChecker, BaseParagraphFactory from pyams_content.component.paragraph.interfaces import IParagraphFactory -from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE -from pyams_i18n.interfaces import II18n, INegotiator, II18nManager - -# import packages -from pyams_content.component.gallery import Gallery as BaseGallery -from pyams_content.component.paragraph import BaseParagraph, BaseParagraphContentChecker, BaseParagraphFactory +from pyams_content.features.checker.interfaces import IContentChecker, MISSING_LANG_VALUE, MISSING_VALUE +from pyams_i18n.interfaces import II18n, II18nManager, INegotiator from pyams_utils.adapter import adapter_config -from pyams_utils.registry import utility_config, get_utility +from pyams_utils.registry import get_utility, utility_config +from pyams_utils.request import check_request from pyams_utils.traversing import get_parent -from zope.interface import implementer @implementer(IGalleryParagraph) @@ -37,6 +34,18 @@ icon_class = 'fa-picture-o' icon_hint = GALLERY_PARAGRAPH_NAME + @property + def title(self): + request = check_request() + translate = request.localizer.translate + nb_medias = len(self) + if nb_medias > 1: + return translate(_("(gallery contains {0} medias)")).format(nb_medias) + elif nb_medias == 1: + return translate(_("(gallery contains 1 media)")) + else: + return translate(_("(empty gallery)")) + @utility_config(name=GALLERY_PARAGRAPH_TYPE, provides=IParagraphFactory) class GalleryFactory(BaseParagraphFactory): @@ -58,7 +67,7 @@ langs = manager.get_languages() else: negotiator = get_utility(INegotiator) - langs = (negotiator.server_language, ) + langs = (negotiator.server_language,) i18n = II18n(self.context) for lang in langs: value = i18n.get_attribute('title', lang, request) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/component/gallery/zmi/__init__.py --- a/src/pyams_content/component/gallery/zmi/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/component/gallery/zmi/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,41 +12,35 @@ __docformat__ = 'restructuredtext' - -# import standard library import json import zipfile - from io import BytesIO -# import interfaces -from pyams_content.component.gallery.interfaces import IGallery -from pyams_content.component.gallery.zmi.interfaces import IGalleryContentsView -from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION -from pyams_file.interfaces import IFileInfo -from pyams_form.interfaces.form import IWidgetsPrefixViewletsManager -from pyams_i18n.interfaces import II18n -from pyams_skin.layer import IPyAMSLayer -from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION +from pyramid.exceptions import NotFound from pyramid.interfaces import IView - -# import packages -from pyams_content.shared.common.zmi import WfSharedContentPermissionMixin -from pyams_content.features.renderer.zmi.widget import RendererFieldWidget -from pyams_form.form import ajax_config -from pyams_pagelet.pagelet import pagelet_config -from pyams_template.template import template_config -from pyams_utils.url import absolute_url -from pyams_viewlet.viewlet import viewlet_config, Viewlet -from pyams_zmi.form import AdminDialogEditForm, AdminDialogDisplayForm -from pyramid.exceptions import NotFound from pyramid.renderers import render_to_response from pyramid.response import Response from pyramid.view import view_config from z3c.form import field -from zope.interface import implementer, Interface +from zope.interface import Interface, implementer from pyams_content import _ +from pyams_content.component.gallery.interfaces import IBaseGallery, IGallery +from pyams_content.component.gallery.zmi.interfaces import IGalleryContentsView +from pyams_content.features.renderer.zmi.widget import RendererFieldWidget +from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION +from pyams_content.shared.common.zmi import WfSharedContentPermissionMixin +from pyams_file.interfaces import IFileInfo +from pyams_form.form import ajax_config +from pyams_form.interfaces.form import IWidgetsPrefixViewletsManager +from pyams_i18n.interfaces import II18n +from pyams_pagelet.pagelet import pagelet_config +from pyams_skin.layer import IPyAMSLayer +from pyams_template.template import template_config +from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION +from pyams_utils.url import absolute_url +from pyams_viewlet.viewlet import Viewlet, viewlet_config +from pyams_zmi.form import AdminDialogDisplayForm, AdminDialogEditForm # @@ -82,7 +76,7 @@ # Gallery contents # -@pagelet_config(name='contents.html', context=IGallery, layer=IPyAMSLayer, permission=VIEW_SYSTEM_PERMISSION) +@pagelet_config(name='contents.html', context=IBaseGallery, layer=IPyAMSLayer, permission=VIEW_SYSTEM_PERMISSION) @implementer(IGalleryContentsView) class GalleryContentForm(AdminDialogDisplayForm): """Gallery contents form""" @@ -94,7 +88,7 @@ show_widget_title = True -@viewlet_config(name='gallery-medias', context=IGallery, view=IGalleryContentsView, +@viewlet_config(name='gallery-medias', context=IBaseGallery, view=IGalleryContentsView, manager=IWidgetsPrefixViewletsManager) @template_config(template='templates/gallery-medias.pt', layer=IPyAMSLayer) @implementer(IGalleryContentsView) @@ -105,7 +99,7 @@ return II18n(media).query_attribute('title', request=self.request) -@view_config(name='get-gallery-medias.html', context=IGallery, request_type=IPyAMSLayer, +@view_config(name='get-gallery-medias.html', context=IBaseGallery, request_type=IPyAMSLayer, permission=VIEW_SYSTEM_PERMISSION) @implementer(IGalleryContentsView) class GalleryMediasView(WfSharedContentPermissionMixin): @@ -128,7 +122,7 @@ return absolute_url(media, self.request, 'preview.html') -@view_config(name='set-medias-order.json', context=IGallery, request_type=IPyAMSLayer, +@view_config(name='set-medias-order.json', context=IBaseGallery, request_type=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True) def set_medias_order(request): """Set gallery medias order""" @@ -137,11 +131,11 @@ return {'status': 'success'} -@view_config(name='set-media-visibility.json', context=IGallery, request_type=IPyAMSLayer, +@view_config(name='set-media-visibility.json', context=IBaseGallery, request_type=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True) def set_media_visibility(request): """Set gallery media visibility""" - gallery = IGallery(request.context) + gallery = IBaseGallery(request.context) media = gallery.get(str(request.params.get('object_name'))) if media is None: raise NotFound() @@ -153,13 +147,13 @@ # Gallery medias downloader # -@view_config(name='get-medias.zip', context=IGallery, request_type=IPyAMSLayer, +@view_config(name='get-medias.zip', context=IBaseGallery, request_type=IPyAMSLayer, permission=VIEW_SYSTEM_PERMISSION) def get_medias_archive(request): """Get all gallery medias as ZIP file""" zip_data = BytesIO() zip_file = zipfile.ZipFile(zip_data, mode='w') - for media in IGallery(request.context).values(): + for media in IBaseGallery(request.context).values(): zip_file.writestr(IFileInfo(media.data).filename, media.data.data) zip_file.close() zip_data.seek(0) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/component/gallery/zmi/file.py --- a/src/pyams_content/component/gallery/zmi/file.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/component/gallery/zmi/file.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,48 +12,45 @@ __docformat__ = 'restructuredtext' - -# import standard library - -# import interfaces -from pyams_content.component.gallery.interfaces import IGallery, IGalleryFile, IGalleryParagraph, \ - GALLERY_FILE_HIDDEN_FIELDS -from pyams_content.component.gallery.zmi.interfaces import IGalleryMediasAddFields, IGalleryContentsView -from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION -from pyams_file.interfaces.archive import IArchiveExtractor -from pyams_form.interfaces.form import IFormContextPermissionChecker -from pyams_i18n.interfaces import II18n -from pyams_skin.interfaces.viewlet import IWidgetTitleViewletManager, IContextActions -from pyams_skin.layer import IPyAMSLayer -from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION, FORBIDDEN_PERMISSION +from pyramid.renderers import render +from z3c.form import field from z3c.form.interfaces import NOT_CHANGED +from zope.interface import Interface +from zope.lifecycleevent import ObjectCreatedEvent +from zope.location import locate from zope.schema.interfaces import WrongType -# import packages from pyams_content.component.gallery.file import GalleryFile -from pyams_content.shared.common import IWfSharedContent +from pyams_content.component.gallery.interfaces import GALLERY_FILE_HIDDEN_FIELDS, IBaseGallery, IGalleryFile, \ + IGalleryParagraph +from pyams_content.component.gallery.zmi.interfaces import IGalleryContentsView, IGalleryMediasAddFields +from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION +from pyams_content.shared.common.interfaces import IWfSharedContent from pyams_content.shared.common.zmi import WfSharedContentPermissionMixin from pyams_file.file import get_magic_content_type +from pyams_file.interfaces.archive import IArchiveExtractor from pyams_file.zmi.file import FilePropertiesAction from pyams_form.form import AJAXAddForm, ajax_config from pyams_form.group import NamedWidgetsGroup +from pyams_form.interfaces.form import IFormContextPermissionChecker +from pyams_i18n.interfaces import II18n from pyams_pagelet.pagelet import pagelet_config from pyams_skin.event import get_json_refresh_event -from pyams_skin.viewlet.toolbar import ToolbarAction, JsToolbarActionItem +from pyams_skin.interfaces.viewlet import IContextActions, IWidgetTitleViewletManager +from pyams_skin.layer import IPyAMSLayer +from pyams_skin.viewlet.toolbar import JsToolbarActionItem, ToolbarAction +from pyams_utils.interfaces import FORBIDDEN_PERMISSION, VIEW_SYSTEM_PERMISSION from pyams_utils.registry import query_utility from pyams_utils.traversing import get_parent from pyams_utils.url import absolute_url from pyams_viewlet.viewlet import viewlet_config -from pyams_zmi.form import AdminDialogEditForm, AdminDialogAddForm -from pyramid.renderers import render -from z3c.form import field -from zope.lifecycleevent import ObjectCreatedEvent -from zope.location import locate +from pyams_zmi.form import AdminDialogAddForm, AdminDialogEditForm from pyams_content import _ -@viewlet_config(name='add-media.menu', context=IGallery, view=IGalleryContentsView, manager=IWidgetTitleViewletManager) +@viewlet_config(name='add-media.menu', context=IBaseGallery, view=IGalleryContentsView, + manager=IWidgetTitleViewletManager) class GalleryMediaAddMenu(WfSharedContentPermissionMixin, ToolbarAction): """Gallery media add menu""" @@ -64,8 +61,8 @@ stop_propagation = True -@pagelet_config(name='add-media.html', context=IGallery, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION) -@ajax_config(name='add-media.json', context=IGallery, layer=IPyAMSLayer, base=AJAXAddForm) +@pagelet_config(name='add-media.html', context=IBaseGallery, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION) +@ajax_config(name='add-media.json', context=IBaseGallery, layer=IPyAMSLayer, base=AJAXAddForm) class GalleryMediaAddForm(AdminDialogAddForm): """Gallery media add form""" @@ -115,9 +112,8 @@ medias.append(media) for media in medias: media.author = data.get('author') - media.author_comments = data.get('author_comments') self.context.append(media) - return None + return medias def get_ajax_output(self, changes): return { @@ -127,7 +123,7 @@ } -@viewlet_config(name='file.showhide.action', context=IGalleryFile, layer=IPyAMSLayer, view=IGalleryContentsView, +@viewlet_config(name='file.showhide.action', context=IGalleryFile, layer=IPyAMSLayer, view=Interface, manager=IContextActions, permission=VIEW_SYSTEM_PERMISSION, weight=1) class GalleryFileShowHideAction(WfSharedContentPermissionMixin, JsToolbarActionItem): """Gallery file show/hide action""" @@ -163,7 +159,7 @@ return self.url -@viewlet_config(name='file.properties.action', context=IGalleryFile, layer=IPyAMSLayer, view=IGalleryContentsView, +@viewlet_config(name='file.properties.action', context=IGalleryFile, layer=IPyAMSLayer, view=Interface, manager=IContextActions, permission=VIEW_SYSTEM_PERMISSION, weight=5) class GalleryFilePropertiesAction(FilePropertiesAction): """Media properties action""" @@ -188,14 +184,9 @@ @property def title(self): - gallery = get_parent(self.context, IGallery) + gallery = get_parent(self.context, IBaseGallery) return II18n(gallery).query_attribute('title', request=self.request) - def updateWidgets(self, prefix=None): - super(GalleryFilePropertiesEditForm, self).updateWidgets(prefix) - if 'pif_number' in self.widgets: - self.widgets['pif_number'].input_css_class = 'col-md-3' - def updateGroups(self): self.add_group(NamedWidgetsGroup(self, 'audio_file', self.widgets, ('sound', 'sound_title', 'sound_description'), @@ -209,7 +200,7 @@ def get_ajax_output(self, changes): output = super(self.__class__, self).get_ajax_output(changes) if 'title' in changes.get(IGalleryFile, ()): - gallery = get_parent(self.context, IGallery) + gallery = get_parent(self.context, IBaseGallery) if gallery is not None: output.setdefault('events', []).append({ 'event': 'myams.refresh', @@ -228,7 +219,7 @@ return output -@viewlet_config(name='gallery-file-remover.action', context=IGalleryFile, layer=IPyAMSLayer, view=IGalleryContentsView, +@viewlet_config(name='gallery-file-remover.action', context=IGalleryFile, layer=IPyAMSLayer, view=Interface, manager=IContextActions, weight=90) class GalleryFileRemoverAction(WfSharedContentPermissionMixin, JsToolbarActionItem): """Gallery file remover action""" diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/component/gallery/zmi/interfaces.py --- a/src/pyams_content/component/gallery/zmi/interfaces.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/component/gallery/zmi/interfaces.py Fri Oct 05 10:44:32 2018 +0200 @@ -17,13 +17,12 @@ # import interfaces -# import packages -from pyams_file.schema import FileField -from pyams_i18n.schema import I18nTextField from zope.interface import Interface from zope.schema import TextLine from pyams_content import _ +# import packages +from pyams_file.schema import FileField class IGalleryContentsView(Interface): @@ -40,7 +39,3 @@ author = TextLine(title=_("Author"), description=_("Name of document's author"), required=True) - - author_comments = I18nTextField(title=_("Author comments"), - description=_("Comments relatives to author's rights management"), - required=False) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/component/gallery/zmi/paragraph.py --- a/src/pyams_content/component/gallery/zmi/paragraph.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/component/gallery/zmi/paragraph.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,39 +12,42 @@ __docformat__ = 'restructuredtext' - -# import standard library +from pyramid.interfaces import IView +from pyramid.renderers import render +from pyramid.view import view_config +from transaction.interfaces import ITransactionManager +from z3c.form import button, field +from z3c.form.interfaces import INPUT_MODE +from zope.interface import Interface, implementer -# import interfaces -from pyams_content.component.gallery.interfaces import IGalleryParagraph, IBaseGallery, GALLERY_PARAGRAPH_TYPE +from pyams_content.component.gallery.interfaces import GALLERY_PARAGRAPH_TYPE, IGalleryParagraph +from pyams_content.component.gallery.paragraph import Gallery +from pyams_content.component.gallery.zmi.file import GalleryMediaAddForm from pyams_content.component.gallery.zmi.interfaces import IGalleryContentsView -from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, IParagraphContainer, \ - PARAGRAPH_HIDDEN_FIELDS -from pyams_content.component.paragraph.zmi.interfaces import IParagraphInnerEditor, IParagraphContainerView +from pyams_content.component.paragraph.interfaces import IParagraphContainer, IParagraphContainerTarget +from pyams_content.component.paragraph.zmi import BaseParagraphAJAXAddForm, BaseParagraphAJAXEditForm, \ + BaseParagraphAddMenu, BaseParagraphPropertiesEditForm, IParagraphEditFormButtons, ParagraphContainerTable, \ + get_json_paragraph_refresh_event +from pyams_content.component.paragraph.zmi.interfaces import IParagraphContainerView, IParagraphInnerEditor +from pyams_content.features.renderer.zmi.widget import RendererFieldWidget from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION +from pyams_content.shared.common.zmi import WfSharedContentPermissionMixin +from pyams_form.form import AJAXAddForm, ajax_config from pyams_form.interfaces.form import IInnerForm, IInnerSubForm from pyams_i18n.interfaces import II18n +from pyams_pagelet.pagelet import pagelet_config +from pyams_skin.container import delete_container_element from pyams_skin.interfaces.viewlet import IToolbarAddingMenu, IWidgetTitleViewletManager from pyams_skin.layer import IPyAMSLayer -from pyramid.interfaces import IView -from z3c.form.interfaces import INPUT_MODE - -# import packages -from pyams_content.component.gallery.paragraph import Gallery -from pyams_content.component.paragraph.zmi import BaseParagraphAJAXAddForm, BaseParagraphAJAXEditForm, \ - BaseParagraphAddMenu, BaseParagraphPropertiesEditForm, get_json_paragraph_refresh_event, IParagraphEditFormButtons -from pyams_content.features.renderer.zmi.widget import RendererFieldWidget -from pyams_content.shared.common.zmi import WfSharedContentPermissionMixin -from pyams_form.form import ajax_config -from pyams_pagelet.pagelet import pagelet_config +from pyams_skin.table import get_table_id from pyams_skin.viewlet.toolbar import ToolbarAction from pyams_template.template import template_config from pyams_utils.adapter import adapter_config +from pyams_utils.interfaces import ICacheKeyValue +from pyams_utils.traversing import get_parent from pyams_utils.url import absolute_url from pyams_viewlet.viewlet import viewlet_config from pyams_zmi.form import AdminDialogAddForm, InnerAdminDisplayForm -from z3c.form import field, button -from zope.interface import implementer, Interface from pyams_content import _ @@ -70,7 +73,7 @@ legend = _("Add new gallery") icon_css_class = 'fa fa-fw fa-picture-o' - fields = field.Fields(IGalleryParagraph).omit(*PARAGRAPH_HIDDEN_FIELDS) + fields = field.Fields(IGalleryParagraph).select('renderer') edit_permission = MANAGE_CONTENT_PERMISSION def create(self, data): @@ -92,21 +95,11 @@ legend = _("Edit gallery properties") icon_css_class = 'fa fa-fw fa-picture-o' - fields = field.Fields(IGalleryParagraph).omit(*PARAGRAPH_HIDDEN_FIELDS) + fields = field.Fields(IGalleryParagraph).select('renderer') fields['renderer'].widgetFactory = RendererFieldWidget edit_permission = MANAGE_CONTENT_PERMISSION - def get_ajax_output(self, changes): - updated = changes.get(IBaseGallery, ()) - if 'title' in updated: - return { - 'status': 'success', - 'events': [get_json_paragraph_refresh_event(self.context, self.request), ] - } - else: - return super(self.__class__, self).get_ajax_output(changes) - @adapter_config(context=(IGalleryParagraph, IPyAMSLayer), provides=IParagraphInnerEditor) @implementer(IInnerForm) @@ -149,7 +142,7 @@ @viewlet_config(name='add-media.menu', context=IGalleryParagraph, view=GalleryContentsView, manager=IWidgetTitleViewletManager) -class GalleryMediaAddMenu(WfSharedContentPermissionMixin, ToolbarAction): +class GalleryParagraphMediaAddMenu(WfSharedContentPermissionMixin, ToolbarAction): """Gallery media add menu""" label = _("Add media(s)") @@ -157,3 +150,47 @@ url = 'add-media.html' modal_target = True stop_propagation = True + + +@pagelet_config(name='add-media.html', context=IGalleryParagraph, layer=IPyAMSLayer, + permission=MANAGE_CONTENT_PERMISSION) +@ajax_config(name='add-media.json', context=IGalleryParagraph, layer=IPyAMSLayer, base=AJAXAddForm) +class GalleryParagraphMediaAddForm(GalleryMediaAddForm): + """Gallery media add form""" + + def get_ajax_output(self, changes): + ITransactionManager(self.context).commit() + medias = [] + for media in changes: + medias.append(render('templates/gallery-media.pt', + {'media': media}, request=self.request)) + output = { + 'status': 'success', + 'message': self.request.localizer.translate(_("Media(s) successfully added")), + 'events': [ + get_json_paragraph_refresh_event(self.context, self.request) + ], + 'callback': 'PyAMS_content.galleries.addMediaCallback', + 'options': { + 'parent': '{0}::{1}'.format(get_table_id(ParagraphContainerTable, + context=get_parent(self.context, IParagraphContainerTarget)), + ICacheKeyValue(self.context)), + 'medias': medias + } + } + return output + + +@view_config(name='delete-element.json', context=IGalleryParagraph, request_type=IPyAMSLayer, + renderer='json', xhr=True) +def delete_media(request): + """Delete media from container""" + result = delete_container_element(request, IGalleryParagraph) + if result.get('status') == 'success': + result.update({ + 'handle_json': True, + 'events': [ + get_json_paragraph_refresh_event(request.context, request) + ] + }) + return result diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/component/gallery/zmi/templates/gallery-media.pt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/component/gallery/zmi/templates/gallery-media.pt Fri Oct 05 10:44:32 2018 +0200 @@ -0,0 +1,58 @@ +
+ + + + + + + + + + + + + + + + + +
+ +
+ +
diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/component/illustration/__init__.py --- a/src/pyams_content/component/illustration/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/component/illustration/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,39 +12,33 @@ __docformat__ = 'restructuredtext' - -# import standard library - -# import interfaces -from pyams_content.component.illustration.interfaces import IIllustration, IIllustrationTarget, \ - ILLUSTRATION_KEY, ILLUSTRATION_RENDERERS, IBasicIllustration, IBasicIllustrationTarget, BASIC_ILLUSTRATION_KEY, \ - ILinkIllustrationTarget, LINK_ILLUSTRATION_KEY, ILinkIllustration -from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE -from pyams_file.interfaces import IFileInfo, IImage, IResponsiveImage -from pyams_i18n.interfaces import INegotiator, II18n, II18nManager +from persistent import Persistent +from pyramid.events import subscriber +from pyramid.threadlocal import get_current_registry +from zope.container.contained import Contained +from zope.interface import alsoProvides, implementer +from zope.lifecycleevent import ObjectAddedEvent from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectModifiedEvent from zope.location.interfaces import ISublocations +from zope.schema.fieldproperty import FieldProperty from zope.traversing.interfaces import ITraversable -# import packages -from persistent import Persistent +from pyams_content import _ +from pyams_content.component.illustration.interfaces import BASIC_ILLUSTRATION_KEY, IBasicIllustration, \ + IBasicIllustrationTarget, IIllustration, IIllustrationTarget, IIllustrationTargetBase, ILLUSTRATION_KEY, \ + ILLUSTRATION_RENDERERS, ILinkIllustration, ILinkIllustrationTarget, LINK_ILLUSTRATION_KEY from pyams_content.features.checker import BaseContentChecker +from pyams_content.features.checker.interfaces import IContentChecker, MISSING_LANG_VALUE, MISSING_VALUE from pyams_content.features.renderer import RenderedContentMixin, RenderersVocabulary +from pyams_file.interfaces import IFileInfo, IImage, IResponsiveImage +from pyams_i18n.interfaces import II18n, II18nManager, INegotiator from pyams_i18n.property import I18nFileProperty -from pyams_utils.adapter import adapter_config, ContextAdapter, get_annotation_adapter +from pyams_utils.adapter import ContextAdapter, adapter_config, get_annotation_adapter from pyams_utils.factory import factory_config -from pyams_utils.registry import query_utility, get_utility, get_global_registry +from pyams_utils.registry import get_global_registry, get_utility, query_utility from pyams_utils.request import check_request from pyams_utils.traversing import get_parent from pyams_utils.vocabulary import vocabulary_config -from pyramid.events import subscriber -from pyramid.threadlocal import get_current_registry -from zope.container.contained import Contained -from zope.interface import implementer, alsoProvides -from zope.lifecycleevent import ObjectCreatedEvent, ObjectAddedEvent -from zope.schema.fieldproperty import FieldProperty - -from pyams_content import _ @implementer(IBasicIllustration) @@ -77,6 +71,15 @@ return False +@implementer(IIllustration) +@factory_config(provided=IIllustration) +class Illustration(RenderedContentMixin, BasicIllustration): + """Illustration persistent class""" + + description = FieldProperty(IIllustration['description']) + renderer = FieldProperty(IIllustration['renderer']) + + @adapter_config(context=IBasicIllustrationTarget, provides=IIllustration) def basic_illustration_factory(context): """Basic illustration factory""" @@ -89,15 +92,6 @@ callback=illustration_callback) -@implementer(IIllustration) -@factory_config(provided=IIllustration) -class Illustration(RenderedContentMixin, BasicIllustration): - """Illustration persistent class""" - - description = FieldProperty(IIllustration['description']) - renderer = FieldProperty(IIllustration['renderer']) - - @adapter_config(context=IIllustrationTarget, provides=IIllustration) def illustration_factory(context): """Illustration factory""" @@ -151,7 +145,7 @@ update_illustration_properties(illustration) -@adapter_config(name='illustration', context=IBasicIllustrationTarget, provides=ITraversable) +@adapter_config(name='illustration', context=IIllustrationTargetBase, provides=ITraversable) class IllustrationNamespace(ContextAdapter): """++illustration++ namespace adapter""" @@ -160,13 +154,13 @@ return registry.queryAdapter(self.context, IIllustration, name=name) -@adapter_config(name='illustration', context=IBasicIllustrationTarget, provides=ISublocations) +@adapter_config(name='illustration', context=IIllustrationTargetBase, provides=ISublocations) class IllustrationSublocations(ContextAdapter): """Illustration sub-locations adapter""" def sublocations(self): registry = get_global_registry() - for name, adapter in registry.getAdapters((self, ), IBasicIllustration): + for name, adapter in registry.getAdapters((self,), IBasicIllustration): yield adapter @@ -185,7 +179,7 @@ langs = manager.get_languages() else: negotiator = get_utility(INegotiator) - langs = (negotiator.server_language, ) + langs = (negotiator.server_language,) missing_value = translate(MISSING_VALUE) missing_lang_value = translate(MISSING_LANG_VALUE) i18n = II18n(self.context) @@ -204,7 +198,7 @@ output.append(missing_lang_value.format(field=translate(IIllustration[attr].title), lang=lang)) if has_data: - for attr in ('author', ): + for attr in ('author',): value = getattr(self.context, attr) if not value: output.append(missing_value.format(field=translate(IIllustration[attr].title))) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/component/illustration/interfaces/__init__.py --- a/src/pyams_content/component/illustration/interfaces/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/component/illustration/interfaces/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,20 +12,14 @@ __docformat__ = 'restructuredtext' - -# import standard library - -# import interfaces -from pyams_content.component.paragraph.interfaces import IBaseParagraph -from pyams_content.features.renderer.interfaces import IRenderedContent -from pyams_i18n.schema import I18nTextLineField, I18nTextField, I18nThumbnailMediaField from zope.annotation.interfaces import IAttributeAnnotatable - -# import packages from zope.interface import Interface from zope.schema import Choice, TextLine from pyams_content import _ +from pyams_content.component.paragraph.interfaces import IBaseParagraph +from pyams_content.features.renderer.interfaces import IRenderedContent +from pyams_i18n.schema import I18nTextField, I18nTextLineField, I18nThumbnailMediaField # @@ -79,7 +73,11 @@ """Navigation link illustration interface""" -class IBasicIllustrationTarget(IAttributeAnnotatable): +class IIllustrationTargetBase(IAttributeAnnotatable): + """Illustration target base interface""" + + +class IBasicIllustrationTarget(IIllustrationTargetBase): """Basic illustration target marker interface""" @@ -87,7 +85,7 @@ """Illustration target interface""" -class ILinkIllustrationTarget(IBasicIllustrationTarget): +class ILinkIllustrationTarget(IIllustrationTargetBase): """Link illustration target interface""" diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/component/illustration/zmi/__init__.py --- a/src/pyams_content/component/illustration/zmi/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/component/illustration/zmi/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,30 +12,25 @@ __docformat__ = 'restructuredtext' +from transaction.interfaces import ITransactionManager +from z3c.form import field -# import standard library - -# import interfaces +from pyams_content import _ from pyams_content.component.illustration.interfaces import IBasicIllustration, IBasicIllustrationTarget, \ IIllustration, IIllustrationTarget, ILinkIllustrationTarget -from pyams_content.component.paragraph import IBaseParagraph -from pyams_form.interfaces.form import IInnerSubForm, IWidgetsPrefixViewletsManager -from pyams_skin.layer import IPyAMSLayer -from pyams_zmi.interfaces import IPropertiesEditForm -from transaction.interfaces import ITransactionManager - # import packages from pyams_content.component.illustration.zmi.paragraph import ParagraphContainerIllustrationMarker +from pyams_content.component.paragraph import IBaseParagraph from pyams_content.component.paragraph.zmi import get_json_paragraph_markers_refresh_event from pyams_content.features.renderer.zmi.widget import RendererFieldWidget +from pyams_form.interfaces.form import IInnerSubForm, IWidgetsPrefixViewletsManager from pyams_skin.event import get_json_form_refresh_event, get_json_widget_refresh_event +from pyams_skin.layer import IPyAMSLayer from pyams_template.template import template_config from pyams_utils.adapter import adapter_config from pyams_viewlet.viewlet import viewlet_config, Viewlet, EmptyViewlet from pyams_zmi.form import InnerAdminEditForm -from z3c.form import field - -from pyams_content import _ +from pyams_zmi.interfaces import IPropertiesEditForm # diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/component/illustration/zmi/paragraph.py --- a/src/pyams_content/component/illustration/zmi/paragraph.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/component/illustration/zmi/paragraph.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,40 +12,35 @@ __docformat__ = 'restructuredtext' - -# import standard library - -# import interfaces -from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, \ - IParagraphContainer -from pyams_content.component.illustration.interfaces import IIllustrationTarget, IIllustration, \ - IIllustrationParagraph, ILLUSTRATION_PARAGRAPH_TYPE -from pyams_content.component.paragraph.zmi.interfaces import IParagraphInnerEditor, IParagraphContainerView, \ - IParagraphContainerTable, IParagraphTitleToolbar -from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION -from pyams_form.interfaces.form import IInnerForm -from pyams_skin.interfaces.viewlet import IToolbarAddingMenu -from pyams_skin.layer import IPyAMSLayer -from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION from transaction.interfaces import ITransactionManager +from z3c.form import field, button from z3c.form.interfaces import INPUT_MODE - -# import packages -from pyams_content.component.illustration.paragraph import Illustration -from pyams_content.component.paragraph.zmi import BaseParagraphAJAXAddForm, BaseParagraphAJAXEditForm, \ - BaseParagraphAddMenu, BaseParagraphPropertiesEditForm, get_json_paragraph_refresh_event, IParagraphEditFormButtons -from pyams_content.features.renderer.zmi.widget import RendererFieldWidget -from pyams_form.form import ajax_config -from pyams_pagelet.pagelet import pagelet_config -from pyams_skin.event import get_json_form_refresh_event -from pyams_template.template import template_config -from pyams_utils.adapter import adapter_config -from pyams_viewlet.viewlet import viewlet_config, Viewlet -from pyams_zmi.form import AdminDialogAddForm -from z3c.form import field, button from zope.interface import implementer from pyams_content import _ +from pyams_content.component.illustration.interfaces import IIllustrationTarget, IIllustration, \ + IIllustrationParagraph, ILLUSTRATION_PARAGRAPH_TYPE +# import packages +from pyams_content.component.illustration.paragraph import Illustration +from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, \ + IParagraphContainer +from pyams_content.component.paragraph.zmi import BaseParagraphAJAXAddForm, BaseParagraphAJAXEditForm, \ + BaseParagraphAddMenu, BaseParagraphPropertiesEditForm, get_json_paragraph_refresh_event, IParagraphEditFormButtons +from pyams_content.component.paragraph.zmi.interfaces import IParagraphInnerEditor, IParagraphContainerView, \ + IParagraphContainerTable, IParagraphTitleToolbar +from pyams_content.features.renderer.zmi.widget import RendererFieldWidget +from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION +from pyams_form.form import ajax_config +from pyams_form.interfaces.form import IInnerForm +from pyams_pagelet.pagelet import pagelet_config +from pyams_skin.event import get_json_form_refresh_event +from pyams_skin.interfaces.viewlet import IToolbarAddingMenu +from pyams_skin.layer import IPyAMSLayer +from pyams_template.template import template_config +from pyams_utils.adapter import adapter_config +from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION +from pyams_viewlet.viewlet import viewlet_config, Viewlet +from pyams_zmi.form import AdminDialogAddForm # @@ -74,8 +69,8 @@ dialog_class = 'modal-large' icon_css_class = 'fa fa-fw fa-file-image-o' - fields = field.Fields(IIllustrationParagraph).select('data', 'title', 'alt_title', 'description', - 'author', 'renderer') + fields = field.Fields(IIllustrationParagraph).select('data', 'title', 'alt_title', + 'author', 'description', 'renderer') edit_permission = MANAGE_CONTENT_PERMISSION @@ -99,8 +94,8 @@ dialog_class = 'modal-large' icon_css_class = 'fa fa-fw fa-file-image-o' - fields = field.Fields(IIllustrationParagraph).select('data', 'title', 'alt_title', 'description', - 'author', 'renderer') + fields = field.Fields(IIllustrationParagraph).select('data', 'title', 'alt_title', + 'author', 'description', 'renderer') fields['renderer'].widgetFactory = RendererFieldWidget edit_permission = MANAGE_CONTENT_PERMISSION diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/component/keynumber/portlet/zmi/templates/keynumber-preview.pt --- a/src/pyams_content/component/keynumber/portlet/zmi/templates/keynumber-preview.pt Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/component/keynumber/portlet/zmi/templates/keynumber-preview.pt Fri Oct 05 10:44:32 2018 +0200 @@ -23,7 +23,7 @@
- Associated links : + Associated links :
diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/reference/pictograms/zmi/widget.py --- a/src/pyams_content/reference/pictograms/zmi/widget.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/reference/pictograms/zmi/widget.py Fri Oct 05 10:44:32 2018 +0200 @@ -10,31 +10,31 @@ # FOR A PARTICULAR PURPOSE. # - __docformat__ = 'restructuredtext' # import standard library -# import interfaces -from pyams_content.reference.pictograms import IPictogramTable -from pyams_utils.interfaces.data import IObjectData - -# import packages -from pyams_content.reference.pictograms.zmi import get_pictogram_header -from pyams_utils.registry import query_utility -from pyams_utils.url import absolute_url -from z3c.form.browser.select import SelectWidget from z3c.form.widget import FieldWidget from zope.interface import implementer from pyams_content import _ +# import interfaces +from pyams_content.reference.pictograms import IPictogramTable +# import packages +from pyams_content.reference.pictograms.zmi import get_pictogram_header +from pyams_form.widget import Select2Widget +from pyams_utils.interfaces.data import IObjectData +from pyams_utils.registry import query_utility +from pyams_utils.url import absolute_url @implementer(IObjectData) -class PictogramSelectWidget(SelectWidget): +class PictogramSelectWidget(Select2Widget): """Pictogram selection widget""" + noValueMessage = _("No selected pictogram") + pictograms = None label_id = None after_widget_notice = None diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/reference/zmi/__init__.py --- a/src/pyams_content/reference/zmi/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/reference/zmi/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -21,7 +21,6 @@ from pyams_i18n.interfaces import II18n from pyams_skin.interfaces.container import ITableElementName from pyams_skin.interfaces.viewlet import ITopLinksViewletManager, IBreadcrumbItem -from pyams_skin.layer import IPyAMSLayer from pyams_zmi.layer import IAdminLayer # import packages @@ -29,7 +28,7 @@ from pyams_content.reference.zmi.table import ReferenceTableContentsTable from pyams_form.form import AJAXEditForm from pyams_skin.event import get_json_table_row_refresh_event -from pyams_skin.viewlet.breadcrumb import BreadcrumbItem +from pyams_skin.viewlet.breadcrumb import BreadcrumbAdminLayerItem from pyams_skin.viewlet.toplinks import TopLinksViewlet, TopLinksMenu from pyams_utils.adapter import adapter_config, ContextRequestAdapter from pyams_utils.registry import get_local_registry @@ -62,8 +61,8 @@ self.viewlets.append(menu) -@adapter_config(context=(IReferenceManager, IPyAMSLayer), provides=IBreadcrumbItem) -class ReferenceManagerBreadcrumbAdapter(BreadcrumbItem): +@adapter_config(context=(IReferenceManager, IAdminLayer), provides=IBreadcrumbItem) +class ReferenceManagerBreadcrumbAdapter(BreadcrumbAdminLayerItem): """References tables manager breadcrumb adapter""" label = _("References tables") diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/reference/zmi/table.py --- a/src/pyams_content/reference/zmi/table.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/reference/zmi/table.py Fri Oct 05 10:44:32 2018 +0200 @@ -28,12 +28,12 @@ from z3c.table.interfaces import IValues, IColumn # import packages -from pyams_form.form import AJAXEditForm, ajax_config +from pyams_form.form import ajax_config from pyams_pagelet.pagelet import pagelet_config from pyams_skin.container import ContainerView, delete_container_element from pyams_skin.page import DefaultPageHeaderAdapter from pyams_skin.table import BaseTable, TrashColumn -from pyams_skin.viewlet.breadcrumb import BreadcrumbItem +from pyams_skin.viewlet.breadcrumb import BreadcrumbAdminLayerItem from pyams_skin.viewlet.menu import MenuItem from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter, ContextRequestAdapter from pyams_utils.url import absolute_url @@ -52,8 +52,8 @@ # Table properties # -@adapter_config(context=(IReferenceTable, IPyAMSLayer), provides=IBreadcrumbItem) -class ReferenceTableBreadcrumbAdapter(BreadcrumbItem): +@adapter_config(context=(IReferenceTable, IAdminLayer), provides=IBreadcrumbItem) +class ReferenceTableBreadcrumbAdapter(BreadcrumbAdminLayerItem): """References table breadcrumb adapter""" @property diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/root/__init__.py --- a/src/pyams_content/root/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/root/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -14,10 +14,11 @@ __docformat__ = 'restructuredtext' +from persistent import Persistent +from pyramid.events import subscriber +from zope.interface import implementer -# import standard library - -# import interfaces +from pyams_content import _ from pyams_content.component.illustration.interfaces import IIllustrationTarget from pyams_content.component.theme.interfaces import ITagsManagerTarget from pyams_content.features.alert.interfaces import IAlertTarget @@ -25,30 +26,23 @@ from pyams_content.features.header.interfaces import IHeaderTarget from pyams_content.features.preview.interfaces import IPreviewTarget from pyams_content.features.redirect.interfaces import IRedirectionManagerTarget -from pyams_content.interfaces import WEBMASTER_ROLE, OPERATOR_ROLE, MANAGE_SITE_ROOT_PERMISSION -from pyams_content.root.interfaces import ISiteRootRoles, ISiteRootConfiguration, ISiteRoot, \ - ISiteRootToolsConfiguration, ISiteRootBackOfficeConfiguration +from pyams_content.interfaces import MANAGE_SITE_ROOT_PERMISSION, OPERATOR_ROLE, WEBMASTER_ROLE +from pyams_content.root.interfaces import ISiteRoot, ISiteRootBackOfficeConfiguration, ISiteRootConfiguration, \ + ISiteRootRoles, ISiteRootToolsConfiguration from pyams_form.interfaces.form import IFormContextPermissionChecker -from pyams_portal.interfaces import IPortalContext, DESIGNER_ROLE +from pyams_portal.interfaces import DESIGNER_ROLE, IPortalContext from pyams_security.interfaces import IDefaultProtectionPolicy, IGrantedRoleEvent, ISecurityManager, SYSTEM_ADMIN_ROLE -from pyams_skin.interfaces.configuration import IConfiguration, IBackOfficeConfiguration -from pyams_utils.interfaces.site import ISiteRootFactory - -# import packages -from persistent import Persistent from pyams_security.property import RolePrincipalsFieldProperty from pyams_security.security import ProtectedObject -from pyams_skin.configuration import Configuration, BackOfficeConfiguration +from pyams_skin.configuration import BackOfficeConfiguration, Configuration +from pyams_skin.interfaces.configuration import IBackOfficeConfiguration, IConfiguration from pyams_skin.skin import UserSkinnableContent -from pyams_utils.adapter import adapter_config, ContextAdapter, get_annotation_adapter +from pyams_utils.adapter import ContextAdapter, adapter_config, get_annotation_adapter from pyams_utils.factory import factory_config +from pyams_utils.interfaces.site import ISiteRootFactory from pyams_utils.registry import get_utility, utility_config from pyams_utils.site import BaseSiteRoot from pyams_utils.traversing import get_parent -from pyramid.events import subscriber -from zope.interface import implementer - -from pyams_content import _ @implementer(IDefaultProtectionPolicy, ISiteRoot, ISiteRootRoles, IPortalContext, ITagsManagerTarget, @@ -132,7 +126,9 @@ forms_tool_name = None imagemaps_tool_name = None logos_tool_name = None + news_tool_name = None + topics_tool_name = None SITEROOT_TOOLS_CONFIGURATION_KEY = 'pyams_config.tools.configuration' diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/root/interfaces/__init__.py --- a/src/pyams_content/root/interfaces/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/root/interfaces/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,22 +12,16 @@ __docformat__ = 'restructuredtext' - -# import standard library +from zope.interface import Attribute, Interface -# import interfaces -from pyams_content.interfaces import WEBMASTER_ROLE, OPERATOR_ROLE +from pyams_content import _ +from pyams_content.interfaces import OPERATOR_ROLE, WEBMASTER_ROLE from pyams_portal.interfaces import DESIGNER_ROLE from pyams_security.interfaces import SYSTEM_ADMIN_ROLE -from pyams_skin.interfaces.configuration import IConfiguration, IBackOfficeConfiguration +from pyams_security.schema import Principal, PrincipalsSet +from pyams_skin.interfaces.configuration import IBackOfficeConfiguration, IConfiguration from pyams_utils.interfaces.site import ISiteRoot as ISiteRootBase -# import packages -from pyams_security.schema import PrincipalsSet, Principal -from zope.interface import Interface, Attribute - -from pyams_content import _ - class ISiteRoot(ISiteRootBase): """Main site root interface""" @@ -71,7 +65,9 @@ forms_tool_name = Attribute("Forms tool name") imagemaps_tool_name = Attribute("Image maps tool name") logos_tool_name = Attribute("Logos tool name") + news_tool_name = Attribute("News tool name") + topics_tool_name = Attribute("Topics tool name") class ISiteRootBackOfficeConfiguration(IBackOfficeConfiguration): diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/root/zmi/__init__.py --- a/src/pyams_content/root/zmi/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/root/zmi/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -47,7 +47,7 @@ from pyams_skin.container import ContainerView from pyams_skin.page import DefaultPageHeaderAdapter from pyams_skin.table import I18nColumn, DefaultElementEditorAdapter -from pyams_skin.viewlet.breadcrumb import BreadcrumbItem +from pyams_skin.viewlet.breadcrumb import BreadcrumbAdminLayerItem from pyams_skin.viewlet.menu import MenuItem from pyams_template.template import template_config from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter, ContextRequestAdapter @@ -71,8 +71,8 @@ # Site root breadcrumbs # -@adapter_config(context=(ISiteRoot, IPyAMSLayer), provides=IBreadcrumbItem) -class SiteRootBreadcrumbAdapter(BreadcrumbItem): +@adapter_config(context=(ISiteRoot, IAdminLayer), provides=IBreadcrumbItem) +class SiteRootBreadcrumbAdapter(BreadcrumbAdminLayerItem): """Site root breadcrumb adapter""" label = _("Home") @@ -172,8 +172,8 @@ for tool in get_all_utilities_registered_for(IBaseSharedTool): workflow = IWorkflow(tool) query = Eq(catalog['parents'], intids.register(tool)) & \ - Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ - Any(catalog['workflow_state'], workflow.waiting_states) + Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ + Any(catalog['workflow_state'], workflow.waiting_states) params = params | query if params else query yield from filter(self.check_access, unique_iter(map(lambda x: sorted(IWorkflowVersions(x).get_versions(IWorkflowState(x).state), @@ -219,9 +219,9 @@ for tool in get_all_utilities_registered_for(IBaseSharedTool): workflow = IWorkflow(tool) query = Eq(catalog['parents'], intids.register(tool)) & \ - Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ - Any(catalog['workflow_state'], workflow.waiting_states) & \ - Eq(catalog['workflow_principal'], self.request.principal.id) + Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ + Any(catalog['workflow_state'], workflow.waiting_states) & \ + Eq(catalog['workflow_principal'], self.request.principal.id) params = params | query if params else query yield from unique_iter(map(lambda x: sorted(IWorkflowVersions(x).get_versions(IWorkflowState(x).state), key=lambda y: IZopeDublinCore(y).modified, reverse=True)[0], @@ -381,7 +381,7 @@ for tool in get_all_utilities_registered_for(IBaseSharedTool): workflow = IWorkflow(tool) query = And(Eq(catalog['parents'], intids.register(tool)), - Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ + Any(catalog['content_type'], CONTENT_TYPES.keys()) & Or(Eq(catalog['role:owner'], self.request.principal.id), Eq(catalog['role:contributor'], self.request.principal.id)), Eq(catalog['workflow_state'], workflow.initial_state)) @@ -443,7 +443,7 @@ for tool in get_all_utilities_registered_for(IBaseSharedTool): workflow = IWorkflow(tool) query = And(Eq(catalog['parents'], intids.register(tool)), - Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ + Any(catalog['content_type'], CONTENT_TYPES.keys()) & Or(Eq(catalog['role:owner'], self.request.principal.id), Eq(catalog['role:contributor'], self.request.principal.id)), Any(catalog['workflow_state'], workflow.waiting_states)) @@ -505,7 +505,7 @@ for tool in get_all_utilities_registered_for(IBaseSharedTool): workflow = IWorkflow(tool) query = And(Eq(catalog['parents'], intids.register(tool)), - Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ + Any(catalog['content_type'], CONTENT_TYPES.keys()) & Or(Eq(catalog['role:owner'], self.request.principal.id), Eq(catalog['role:contributor'], self.request.principal.id)), Any(catalog['workflow_state'], workflow.published_states)) @@ -567,7 +567,7 @@ for tool in get_all_utilities_registered_for(IBaseSharedTool): workflow = IWorkflow(tool) query = And(Eq(catalog['parents'], intids.register(tool)), - Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ + Any(catalog['content_type'], CONTENT_TYPES.keys()) & Or(Eq(catalog['role:owner'], self.request.principal.id), Eq(catalog['role:contributor'], self.request.principal.id)), Any(catalog['workflow_state'], workflow.retired_states)) @@ -631,7 +631,7 @@ for tool in get_all_utilities_registered_for(IBaseSharedTool): workflow = IWorkflow(tool) query = And(Eq(catalog['parents'], intids.register(tool)), - Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ + Any(catalog['content_type'], CONTENT_TYPES.keys()) & Or(Eq(catalog['role:owner'], principal_id), Eq(catalog['role:contributor'], principal_id)), Any(catalog['workflow_state'], workflow.archived_states)) @@ -721,7 +721,7 @@ for tool in get_all_utilities_registered_for(IBaseSharedTool): workflow = IWorkflow(tool) query = And(Eq(catalog['parents'], intids.register(tool)), - Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ + Any(catalog['content_type'], CONTENT_TYPES.keys()) & Any(catalog['workflow_state'], workflow.published_states)) params = params | query if params else query yield from unique_iter(CatalogResultSet(CatalogQuery(catalog).query(params, diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/root/zmi/search.py --- a/src/pyams_content/root/zmi/search.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/root/zmi/search.py Fri Oct 05 10:44:32 2018 +0200 @@ -116,7 +116,7 @@ intids = get_utility(IIntIds) catalog = get_utility(ICatalog) params = Eq(catalog['parents'], intids.register(self.context)) & \ - Any(catalog['content_type'], CONTENT_TYPES.keys()) + Any(catalog['content_type'], CONTENT_TYPES.keys()) query = self.request.params.get('query') if query: sequence = get_utility(ISequentialIntIds) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/root/zmi/sites.py --- a/src/pyams_content/root/zmi/sites.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/root/zmi/sites.py Fri Oct 05 10:44:32 2018 +0200 @@ -121,9 +121,10 @@ icon_class = 'fa-eye opacity-75' else: icon_class = 'fa-eye-slash text-danger opaque' - return ''.format( - icon_class=icon_class, - title=self.request.localizer.translate(self.icon_hint)) + return ''.format( + icon_class=icon_class, + title=self.request.localizer.translate(self.icon_hint)) @adapter_config(name='oid', context=(ISiteRoot, IPyAMSLayer, SiteTreeTable), provides=IColumn) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/blog/interfaces/__init__.py --- a/src/pyams_content/shared/blog/interfaces/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/blog/interfaces/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,19 +12,16 @@ __docformat__ = 'restructuredtext' +from zope.container.constraints import containers, contains +from zope.container.interfaces import IContainer +from zope.interface import Attribute, Interface +from zope.schema import Text -# import standard library - -# import interfaces from pyams_content.shared.common.interfaces import ISharedSite, IBaseSharedTool, ISharedContent, \ IDeletableElement, IWfSharedContentPortalContext +from pyams_i18n.schema import I18nTextField from pyams_sequence.interfaces import ISequentialIdTarget from pyams_workflow.interfaces import IWorkflowPublicationSupport -from zope.container.interfaces import IContainer - -# import packages -from zope.container.constraints import containers, contains -from zope.interface import Attribute, Interface from pyams_content import _ @@ -68,6 +65,16 @@ topic_content_type = Attribute("Topic content type") topic_content_factory = Attribute("Topic content factory") + description = I18nTextField(title=_("Meta-description"), + description=_("The blog's description is 'hidden' into HTML's page headers; but it " + "can be seen, for example, in some search engines results as content's " + "description; if description is empty, content's header will be used."), + required=False) + + notepad = Text(title=_("Notepad"), + description=_("Internal information to be known about this content"), + required=False) + class IBlogManagerFactory(Interface): """Blog manager factory interface""" diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/blog/manager.py --- a/src/pyams_content/shared/blog/manager.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/blog/manager.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,10 +12,13 @@ __docformat__ = 'restructuredtext' +from pyramid.events import subscriber +from zope.component.interfaces import ISite +from zope.container.folder import Folder +from zope.interface import implementer +from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectRemovedEvent +from zope.schema.fieldproperty import FieldProperty -# import standard library - -# import interfaces from pyams_content.component.illustration import IIllustrationTarget, ILinkIllustrationTarget from pyams_content.component.paragraph.interfaces import IParagraphFactorySettings from pyams_content.component.theme.interfaces import IThemesManagerTarget @@ -24,22 +27,14 @@ from pyams_content.features.preview.interfaces import IPreviewTarget from pyams_content.reference.pictograms.interfaces import IPictogramManagerTarget from pyams_content.root.interfaces import ISiteRoot +from pyams_content.shared.blog import BlogPost from pyams_content.shared.blog.interfaces import IBlogManager, IBlogFolder, IBlogFolderFactory, IBlogManagerFactory from pyams_content.shared.common.interfaces import ISharedContentFactory +from pyams_content.shared.common.manager import BaseSharedTool from pyams_portal.interfaces import IPortalContext -from zope.component.interfaces import ISite -from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectRemovedEvent - -# import packages -from pyams_content.shared.blog import BlogPost -from pyams_content.shared.common.manager import BaseSharedTool from pyams_skin.skin import UserSkinnableContent from pyams_utils.adapter import adapter_config from pyams_utils.traversing import get_parent -from pyramid.events import subscriber -from zope.container.folder import Folder -from zope.interface import implementer -from zope.schema.fieldproperty import FieldProperty @implementer(IBlogFolder) @@ -58,6 +53,9 @@ class BlogManager(Folder, BaseSharedTool, UserSkinnableContent): """Nlog manager class""" + description = FieldProperty(IBlogManager['description']) + notepad = FieldProperty(IBlogManager['notepad']) + allowed_paragraphs = FieldProperty(IParagraphFactorySettings['allowed_paragraphs']) auto_created_paragraphs = FieldProperty(IParagraphFactorySettings['auto_created_paragraphs']) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/blog/zmi/__init__.py --- a/src/pyams_content/shared/blog/zmi/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/blog/zmi/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -16,20 +16,23 @@ # import standard library from datetime import datetime +from pyramid.decorator import reify +from pyramid.path import DottedNameResolver +from pyramid.view import view_config +from zope.interface import Interface +from zope.lifecycleevent import ObjectCreatedEvent + +from pyams_content import _ # import interfaces from pyams_content.interfaces import CREATE_CONTENT_PERMISSION from pyams_content.shared.blog.interfaces import IWfBlogPost, IBlogManager +# import packages +from pyams_content.shared.common.zmi import SharedContentAddForm, SharedContentAJAXAddForm from pyams_i18n.interfaces import II18n, II18nManager, INegotiator +from pyams_pagelet.pagelet import pagelet_config +from pyams_skin.interfaces import IContentTitle from pyams_skin.interfaces.viewlet import IMenuHeader, IWidgetTitleViewletManager from pyams_skin.layer import IPyAMSLayer -from pyams_workflow.interfaces import IWorkflowVersions, IWorkflowInfo -from pyams_zmi.interfaces.menu import IContentManagementMenu -from pyams_zmi.layer import IAdminLayer - -# import packages -from pyams_content.shared.common.zmi import SharedContentAddForm, SharedContentAJAXAddForm -from pyams_pagelet.pagelet import pagelet_config -from pyams_skin.interfaces import IContentTitle from pyams_skin.viewlet.toolbar import ToolbarAction from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter, ContextRequestAdapter from pyams_utils.registry import get_utility @@ -37,13 +40,9 @@ from pyams_utils.unicode import translate_string from pyams_utils.url import absolute_url, generate_url from pyams_viewlet.viewlet import viewlet_config -from pyramid.decorator import reify -from pyramid.path import DottedNameResolver -from pyramid.view import view_config -from zope.interface import Interface -from zope.lifecycleevent import ObjectCreatedEvent - -from pyams_content import _ +from pyams_workflow.interfaces import IWorkflowVersions, IWorkflowInfo +from pyams_zmi.interfaces.menu import IContentManagementMenu +from pyams_zmi.layer import IAdminLayer @adapter_config(context=(IWfBlogPost, IContentManagementMenu), provides=IMenuHeader) @@ -82,6 +81,8 @@ legend = _("Add blog post") content_url = None + __target = None + @reify def content_factory(self): registry = self.request.registry diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/blog/zmi/manager.py --- a/src/pyams_content/shared/blog/zmi/manager.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/blog/zmi/manager.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,28 +12,27 @@ __docformat__ = 'restructuredtext' - -# import standard library from datetime import datetime -# import interfaces -from pyams_content.interfaces import MANAGE_SITE_ROOT_PERMISSION, MANAGE_SITE_PERMISSION +from pyramid.events import subscriber +from pyramid.path import DottedNameResolver +from z3c.form import field +from z3c.form.interfaces import IDataExtractedEvent +from zope.interface import Invalid + +from pyams_content.interfaces import MANAGE_SITE_ROOT_PERMISSION, MANAGE_SITE_PERMISSION, MANAGE_TOOL_PERMISSION from pyams_content.root.interfaces import ISiteRoot from pyams_content.shared.blog.interfaces import IBlogManager, IBlogManagerFactory +from pyams_content.shared.blog.manager import BlogManager +from pyams_content.shared.common import IBaseSharedTool +from pyams_content.shared.common.zmi.manager import SharedToolPropertiesEditForm from pyams_content.skin.zmi.interfaces import ISiteTreeTable, IUserAddingsMenuLabel +from pyams_form.form import AJAXAddForm, ajax_config from pyams_i18n.interfaces import II18n, INegotiator +from pyams_pagelet.pagelet import pagelet_config from pyams_skin.interfaces.container import ITableElementEditor from pyams_skin.interfaces.viewlet import IToolbarAddingMenu, ITableItemColumnActionsMenu, IMenuHeader from pyams_skin.layer import IPyAMSLayer -from pyams_workflow.interfaces import IWorkflowPublicationInfo -from pyams_zmi.interfaces.menu import IPropertiesMenu, ISiteManagementMenu -from pyams_zmi.layer import IAdminLayer -from z3c.form.interfaces import IDataExtractedEvent - -# import packages -from pyams_content.shared.blog.manager import BlogManager -from pyams_form.form import AJAXAddForm, ajax_config -from pyams_pagelet.pagelet import pagelet_config from pyams_skin.table import DefaultElementEditorAdapter from pyams_skin.viewlet.menu import MenuItem from pyams_skin.viewlet.toolbar import ToolbarMenuItem @@ -43,12 +42,10 @@ from pyams_utils.unicode import translate_string from pyams_utils.url import absolute_url from pyams_viewlet.viewlet import viewlet_config +from pyams_workflow.interfaces import IWorkflowPublicationInfo from pyams_zmi.form import AdminDialogAddForm, AdminDialogEditForm -from pyramid.events import subscriber -from pyramid.path import DottedNameResolver -from pyramid.view import view_config -from z3c.form import field -from zope.interface import Invalid +from pyams_zmi.interfaces.menu import IPropertiesMenu, ISiteManagementMenu +from pyams_zmi.layer import IAdminLayer from pyams_content import _ @@ -143,6 +140,17 @@ modal_target = False +@pagelet_config(name='properties.html', context=IBlogManager, layer=IPyAMSLayer, permission=MANAGE_TOOL_PERMISSION) +@ajax_config(name='properties.json', context=IBlogManager, layer=IPyAMSLayer) +class BlogManagerPropertiesEditForm(SharedToolPropertiesEditForm): + """Site folder properties edit form""" + + legend = _("Blog properties") + + fields = field.Fields(IBlogManager).select('title', 'short_name', 'description', 'notepad') + \ + field.Fields(IBaseSharedTool).select('shared_content_workflow') + + # # Blog manager publication views # diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/__init__.py --- a/src/pyams_content/shared/common/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/common/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -17,7 +17,6 @@ # import interfaces from hypatia.interfaces import ICatalog -# import packages from persistent import Persistent from pyramid.events import subscriber from pyramid.interfaces import IWSGIApplicationCreatedEvent @@ -32,6 +31,7 @@ from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm from pyams_content import _ +# import packages from pyams_content.features.checker import BaseContentChecker from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE, ERROR_VALUE from pyams_content.features.review.interfaces import IReviewComments @@ -127,7 +127,9 @@ content_type = None content_name = None + handle_content_url = True handle_header = True + handle_description = True title = FieldProperty(IWfSharedContent['title']) short_name = FieldProperty(IWfSharedContent['short_name']) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/interfaces/__init__.py --- a/src/pyams_content/shared/common/interfaces/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/common/interfaces/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,25 +12,21 @@ __docformat__ = 'restructuredtext' - -# import standard library - from zope.container.constraints import containers, contains from zope.container.interfaces import IContainer from zope.interface import Interface, Attribute from zope.schema import Choice, Bool, Text, TextLine -from pyams_content import _ -# import interfaces from pyams_content.interfaces import IBaseContent, MANAGE_CONTENT_PERMISSION, OWNER_ROLE, MANAGER_ROLE, \ READER_ROLE, GUEST_ROLE, WEBMASTER_ROLE, PILOT_ROLE, CONTRIBUTOR_ROLE -# import packages from pyams_i18n.schema import I18nTextField from pyams_portal.interfaces import IPortalContext, DESIGNER_ROLE from pyams_security.schema import Principal, PrincipalsSet from pyams_utils.schema import TextLineListField from pyams_workflow.interfaces import IWorkflowManagedContent +from pyams_content import _ + class IDeletableElement(Interface): """Deletable element interface""" @@ -126,6 +122,8 @@ "underscores will be automatically replaced by hyphens"), required=True) + handle_content_url = Attribute("Static boolean value to specify if content URL is supported by this content type") + creator = Principal(title=_("Version creator"), description=_("Name of content's version creator. " "The creator of the first version is also it's owner."), @@ -162,6 +160,8 @@ "description; if description is empty, content's header will be used."), required=False) + handle_description = Attribute("Static boolean value to specify if description is supported by this content type") + keywords = TextLineListField(title=_("Keywords"), description=_("They will be included into HTML pages metadata"), required=False) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/manager.py --- a/src/pyams_content/shared/common/manager.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/common/manager.py Fri Oct 05 10:44:32 2018 +0200 @@ -17,8 +17,8 @@ # import interfaces from pyams_content.interfaces import WEBMASTER_ROLE, PILOT_ROLE, MANAGER_ROLE, CONTRIBUTOR_ROLE -from pyams_content.shared.common.interfaces import ISharedToolContainer, IBaseSharedTool, ISharedTool, ISharedToolRoles, \ - ISharedContentFactory +from pyams_content.shared.common.interfaces import ISharedToolContainer, IBaseSharedTool, ISharedTool, \ + ISharedToolRoles, ISharedContentFactory from pyams_portal.interfaces import DESIGNER_ROLE from pyams_security.interfaces import IDefaultProtectionPolicy from pyams_workflow.interfaces import IWorkflow diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/portlet/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/portlet/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -0,0 +1,19 @@ +# +# Copyright (c) 2008-2017 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + +# import standard library + +# import interfaces + +# import packages diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/portlet/head.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/portlet/head.py Fri Oct 05 10:44:32 2018 +0200 @@ -0,0 +1,50 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + +from zope.interface import implementer +from zope.schema.fieldproperty import FieldProperty + +from pyams_content.shared.common.portlet.interfaces import ISharedContentHeaderPortletSettings +from pyams_portal.portlet import PortletSettings, portlet_config, Portlet +from pyams_utils.factory import factory_config +from pyams_utils.interfaces import VIEW_PERMISSION + +from pyams_content import _ + + +SHARED_CONTENT_HEADER_PORTLET_NAME = 'pyams_content.portlet.shared.header' + + +@implementer(ISharedContentHeaderPortletSettings) +@factory_config(provided=ISharedContentHeaderPortletSettings) +class SharedContentHeaderPortletSettings(PortletSettings): + """Shared content header portlet settings""" + + display_breadcrumbs = FieldProperty(ISharedContentHeaderPortletSettings['display_breadcrumbs']) + display_title = FieldProperty(ISharedContentHeaderPortletSettings['display_title']) + display_tags = FieldProperty(ISharedContentHeaderPortletSettings['display_tags']) + display_header = FieldProperty(ISharedContentHeaderPortletSettings['display_header']) + display_specificities = FieldProperty(ISharedContentHeaderPortletSettings['display_specificities']) + + +@portlet_config(permission=VIEW_PERMISSION) +class SharedContentHeaderPortlet(Portlet): + """Shared content header portlet""" + + name = SHARED_CONTENT_HEADER_PORTLET_NAME + label = _("Content header") + + toolbar_css_class = 'fa fa-fw fa-2x fa-header' + + settings_factory = ISharedContentHeaderPortletSettings diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/portlet/interfaces/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/portlet/interfaces/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -0,0 +1,52 @@ +# +# Copyright (c) 2008-2017 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + +from zope.interface import Interface +from zope.schema import Bool + +from pyams_content import _ +from pyams_portal.interfaces import IPortletSettings + + +class ISharedContentHeaderPortletSettings(IPortletSettings): + """Shared content header portlet settings""" + + display_breadcrumbs = Bool(title=_("Display breadcrumbs?"), + required=True, + default=True) + + display_title = Bool(title=_("Display title?"), + required=True, + default=True) + + display_tags = Bool(title=_("Display tags?"), + required=True, + default=True) + + display_header = Bool(title=_("Display header?"), + required=True, + default=True) + + display_specificities = Bool(title=_("Display specificities?"), + description=_("If 'no', specific content's informations won't be displayed..."), + required=True, + default=True) + + +class ISharedContentHeadViewletManager(Interface): + """Shared content head viewlet manager marker interface""" + + +class ISharedContentTitlePortletSettings(IPortletSettings): + """Shared content title portlet settings""" diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/portlet/skin/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/portlet/skin/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -0,0 +1,25 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + +from zope.interface import Interface, implementer + +from pyams_content.shared.common.portlet.interfaces import ISharedContentHeadViewletManager +from pyams_skin.layer import IPyAMSUserLayer +from pyams_viewlet.manager import viewletmanager_config, WeightOrderedViewletManager + + +@viewletmanager_config(name='pyams_content.head', layer=IPyAMSUserLayer, view=Interface) +@implementer(ISharedContentHeadViewletManager) +class SharedContentHeadViewletManager(WeightOrderedViewletManager): + """Shared content head viewlet manager""" diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/portlet/title.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/portlet/title.py Fri Oct 05 10:44:32 2018 +0200 @@ -0,0 +1,42 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + +from zope.interface import implementer + +from pyams_content import _ +from pyams_content.shared.common.portlet.interfaces import ISharedContentTitlePortletSettings +from pyams_portal.portlet import Portlet, PortletSettings, portlet_config +from pyams_utils.factory import factory_config +from pyams_utils.interfaces import VIEW_PERMISSION + + +SHARED_CONTENT_TITLE_PORTLET_NAME = 'pyams_content.portlet.shared.title' + + +@implementer(ISharedContentTitlePortletSettings) +@factory_config(provided=ISharedContentTitlePortletSettings) +class SharedContentTitlePortletSettings(PortletSettings): + """Shared content title portlet settings""" + + +@portlet_config(permission=VIEW_PERMISSION) +class SharedContentTitlePortlet(Portlet): + """Shared content title portlet""" + + name = SHARED_CONTENT_TITLE_PORTLET_NAME + label = _("Content title") + + toolbar_css_class = 'fa fa-fw fa-2x fa-bold' + + settings_factory = ISharedContentTitlePortletSettings diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/portlet/zmi/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/portlet/zmi/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -0,0 +1,20 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces + +# import packages diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/portlet/zmi/head.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/portlet/zmi/head.py Fri Oct 05 10:44:32 2018 +0200 @@ -0,0 +1,55 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + +from zope.interface import Interface + +from pyams_content.shared.common.portlet.interfaces import ISharedContentHeaderPortletSettings +from pyams_form.form import AJAXEditForm +from pyams_form.interfaces.form import IInnerTabForm +from pyams_pagelet.interfaces import IPagelet +from pyams_pagelet.pagelet import pagelet_config +from pyams_portal.interfaces import IPortletPreviewer +from pyams_portal.portlet import PortletPreviewer +from pyams_portal.zmi.portlet import PortletSettingsEditor, PortletSettingsPropertiesEditor +from pyams_skin.layer import IPyAMSLayer +from pyams_template.template import template_config +from pyams_utils.adapter import adapter_config +from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION + + +@pagelet_config(name='properties.html', context=ISharedContentHeaderPortletSettings, layer=IPyAMSLayer, + permission=VIEW_SYSTEM_PERMISSION) +class SharedContentHeaderPortletSettingsEditor(PortletSettingsEditor): + """Shared content header portlet settings editor""" + + settings = ISharedContentHeaderPortletSettings + + +@adapter_config(name='properties', context=(Interface, IPyAMSLayer, SharedContentHeaderPortletSettingsEditor), + provides=IInnerTabForm) +class SharedContentHeaderPortletSettingsPropertiesEditor(PortletSettingsPropertiesEditor): + """Shared content header portlet settings properties editor""" + + +@adapter_config(name='properties.json', context=(ISharedContentHeaderPortletSettings, IPyAMSLayer), + provides=IPagelet) +class SharedContentHeaderPortletAJAXEditor(AJAXEditForm, SharedContentHeaderPortletSettingsEditor): + """Shared content header portlet settings editor, JSON renderer""" + + +@adapter_config(context=(Interface, IPyAMSLayer, Interface, ISharedContentHeaderPortletSettings), + provides=IPortletPreviewer) +@template_config(template='templates/head-preview.pt', layer=IPyAMSLayer) +class SharedContentHeaderPortletPreviewer(PortletPreviewer): + """Shared content header portlet previewer""" diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/portlet/zmi/templates/head-preview.pt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/portlet/zmi/templates/head-preview.pt Fri Oct 05 10:44:32 2018 +0200 @@ -0,0 +1,22 @@ + +
+ + Display breadcrumbs +
+
+ + Display title +
+
+ + Display tags +
+
+ + Display header +
+
+ + Display specificities +
+
\ No newline at end of file diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/portlet/zmi/templates/title-preview.pt diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/portlet/zmi/title.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/common/portlet/zmi/title.py Fri Oct 05 10:44:32 2018 +0200 @@ -0,0 +1,55 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + +from zope.interface import Interface + +from pyams_content.shared.common.portlet.interfaces import ISharedContentTitlePortletSettings +from pyams_form.form import AJAXEditForm +from pyams_form.interfaces.form import IInnerTabForm +from pyams_pagelet.interfaces import IPagelet +from pyams_pagelet.pagelet import pagelet_config +from pyams_portal.interfaces import IPortletPreviewer +from pyams_portal.portlet import PortletPreviewer +from pyams_portal.zmi.portlet import PortletSettingsEditor, PortletSettingsPropertiesEditor +from pyams_skin.layer import IPyAMSLayer +from pyams_template.template import template_config +from pyams_utils.adapter import adapter_config +from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION + + +@pagelet_config(name='properties.html', context=ISharedContentTitlePortletSettings, layer=IPyAMSLayer, + permission=VIEW_SYSTEM_PERMISSION) +class SharedContentTitlePortletSettingsEditor(PortletSettingsEditor): + """Shared content title portlet settings editor""" + + settings = ISharedContentTitlePortletSettings + + +@adapter_config(name='properties', context=(Interface, IPyAMSLayer, SharedContentTitlePortletSettingsEditor), + provides=IInnerTabForm) +class SharedContentTitlePortletSettingsPropertiesEditor(PortletSettingsPropertiesEditor): + """Shared content title portlet settings properties editor""" + + +@adapter_config(name='properties.json', context=(ISharedContentTitlePortletSettings, IPyAMSLayer), + provides=IPagelet) +class SharedContentTitlePortletAJAXEditor(AJAXEditForm, SharedContentTitlePortletSettingsEditor): + """Shared content title portlet settings editor, JSON renderer""" + + +@adapter_config(context=(Interface, IPyAMSLayer, Interface, ISharedContentTitlePortletSettings), + provides=IPortletPreviewer) +@template_config(template='templates/title-preview.pt', layer=IPyAMSLayer) +class SharedContentTitlePortletPreviewer(PortletPreviewer): + """Shared content title portlet previewer""" diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/skin/opengraph.py --- a/src/pyams_content/shared/common/skin/opengraph.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/common/skin/opengraph.py Fri Oct 05 10:44:32 2018 +0200 @@ -90,7 +90,8 @@ image_size = thumbnail.image_size yield PropertyMeta('og:image:width', image_size[0]) yield PropertyMeta('og:image:height', image_size[1]) - yield PropertyMeta('og:image:alt', II18n(illustration).query_attribute('alt_title', lang=lang, request=request)) + yield PropertyMeta('og:image:alt', II18n(illustration).query_attribute('alt_title', lang=lang, + request=request)) # locales properties yield PropertyMeta('of:locale', lang) for lang in II18nManager(context).languages or (): diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/zmi/__init__.py --- a/src/pyams_content/shared/common/zmi/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/common/zmi/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -17,51 +17,51 @@ from datetime import datetime from uuid import uuid4 +from pyramid.location import lineage +from z3c.form import field, button +from zope.copy import copy +from zope.dublincore.interfaces import IZopeDublinCore +from zope.interface import Interface +from zope.lifecycleevent import ObjectCreatedEvent +from zope.location import locate + +from pyams_content import _ +from pyams_content.features.review.interfaces import IReviewComments # import interfaces -from pyams_content.interfaces import MANAGE_SITE_ROOT_PERMISSION, MANAGE_CONTENT_PERMISSION, CREATE_CONTENT_PERMISSION, \ - PUBLISH_CONTENT_PERMISSION -from pyams_content.features.review.interfaces import IReviewComments +from pyams_content.interfaces import MANAGE_SITE_ROOT_PERMISSION, MANAGE_CONTENT_PERMISSION, \ + CREATE_CONTENT_PERMISSION, PUBLISH_CONTENT_PERMISSION from pyams_content.shared.common.interfaces import IWfSharedContent, ISharedContent, IBaseSharedTool, \ IManagerRestrictions +# import packages +from pyams_form.form import AJAXAddForm, ajax_config from pyams_form.interfaces.form import IFormContextPermissionChecker, IWidgetsPrefixViewletsManager +from pyams_form.schema import CloseButton from pyams_i18n.interfaces import II18n, II18nManager, INegotiator +from pyams_i18n.widget import I18nSEOTextLineFieldWidget +from pyams_pagelet.pagelet import pagelet_config from pyams_sequence.interfaces import ISequentialIdInfo from pyams_skin.interfaces import IContentTitle from pyams_skin.interfaces.container import ITable, ITableElementEditor from pyams_skin.interfaces.viewlet import IContextActions, IMenuHeader, IBreadcrumbItem from pyams_skin.layer import IPyAMSLayer -from pyams_utils.interfaces import FORBIDDEN_PERMISSION -from pyams_workflow.interfaces import IWorkflowVersions, IWorkflowInfo, IWorkflowState, IWorkflowCommentInfo, IWorkflow, \ - IWorkflowPublicationInfo -from pyams_zmi.interfaces.menu import ISiteManagementMenu -from zope.dublincore.interfaces import IZopeDublinCore - -# import packages -from pyams_form.form import AJAXAddForm, ajax_config -from pyams_form.schema import CloseButton -from pyams_i18n.widget import I18nSEOTextLineFieldWidget -from pyams_pagelet.pagelet import pagelet_config from pyams_skin.page import DefaultPageHeaderAdapter from pyams_skin.table import DefaultElementEditorAdapter -from pyams_skin.viewlet.breadcrumb import BreadcrumbItem +from pyams_skin.viewlet.breadcrumb import BreadcrumbAdminLayerItem from pyams_skin.viewlet.toolbar import ToolbarMenuItem, ToolbarMenuDivider from pyams_template.template import template_config from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter, ContextAdapter, ContextRequestAdapter +from pyams_utils.interfaces import FORBIDDEN_PERMISSION from pyams_utils.registry import get_utility from pyams_utils.request import check_request from pyams_utils.traversing import get_parent from pyams_utils.url import absolute_url, generate_url from pyams_viewlet.viewlet import viewlet_config, Viewlet +from pyams_workflow.interfaces import IWorkflowVersions, IWorkflowInfo, IWorkflowState, IWorkflowCommentInfo, \ + IWorkflow, IWorkflowPublicationInfo from pyams_workflow.versions import WorkflowHistoryItem from pyams_zmi.form import AdminDialogAddForm -from pyramid.location import lineage -from z3c.form import field, button -from zope.copy import copy -from zope.interface import Interface -from zope.lifecycleevent import ObjectCreatedEvent -from zope.location import locate - -from pyams_content import _ +from pyams_zmi.interfaces.menu import ISiteManagementMenu +from pyams_zmi.layer import IAdminLayer class SharedContentAddForm(AdminDialogAddForm): @@ -78,6 +78,8 @@ ajax_handler = 'add-shared-content.json' edit_permission = CREATE_CONTENT_PERMISSION + __uuid = None + def updateWidgets(self, prefix=None): super(SharedContentAddForm, self).updateWidgets(prefix) if 'title' in self.widgets: @@ -133,8 +135,8 @@ # Shared tools common adapters # -@adapter_config(context=(IWfSharedContent, IPyAMSLayer), provides=IBreadcrumbItem) -class WfSharedContentBreadcrumbAdapter(BreadcrumbItem): +@adapter_config(context=(IWfSharedContent, IAdminLayer), provides=IBreadcrumbItem) +class WfSharedContentBreadcrumbAdapter(BreadcrumbAdminLayerItem): """Shared content breadcrumb adapter""" @property diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/zmi/dashboard.py --- a/src/pyams_content/shared/common/zmi/dashboard.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/common/zmi/dashboard.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,39 +12,33 @@ __docformat__ = 'restructuredtext' - -# import standard library +from hypatia.catalog import CatalogQuery +from hypatia.interfaces import ICatalog +from hypatia.query import And, Or, Eq, Any +from z3c.table.column import GetAttrColumn +from z3c.table.interfaces import IValues, IColumn +from zope.dublincore.interfaces import IZopeDublinCore +from zope.interface import implementer, Interface +from zope.intid.interfaces import IIntIds -# import interfaces -from hypatia.interfaces import ICatalog +from pyams_catalog.query import CatalogResultSet +from pyams_content import _ from pyams_content.interfaces import MANAGE_SITE_ROOT_PERMISSION, PUBLISH_CONTENT_PERMISSION from pyams_content.profile.interfaces import IAdminProfile +from pyams_content.shared.common import CONTENT_TYPES from pyams_content.shared.common.interfaces import IBaseSharedTool, IWfSharedContent, IManagerRestrictions from pyams_content.shared.common.interfaces.zmi import IDashboardTable, ISharedToolDashboardTable, \ IDashboardSearchHeader +from pyams_content.skin import pyams_content from pyams_content.skin.zmi.interfaces import IDashboardMenu, IMyDashboardMenu, IAllContentsMenu from pyams_i18n.interfaces import II18n +from pyams_pagelet.pagelet import pagelet_config from pyams_security.interfaces import ISecurityManager from pyams_sequence.interfaces import ISequentialIdInfo, ISequentialIdTarget, ISequentialIntIds +from pyams_skin.container import ContainerView from pyams_skin.interfaces import IPageHeader from pyams_skin.interfaces.container import ITableElementName from pyams_skin.layer import IPyAMSLayer -from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION -from pyams_workflow.interfaces import IWorkflowState, IWorkflow, IWorkflowVersions, IWorkflowPublicationInfo -from pyams_zmi.interfaces.menu import IContentManagementMenu -from pyams_zmi.layer import IAdminLayer -from z3c.table.interfaces import IValues, IColumn -from zope.dublincore.interfaces import IZopeDublinCore -from zope.intid.interfaces import IIntIds - -# import packages -from hypatia.catalog import CatalogQuery -from hypatia.query import And, Or, Eq, Any -from pyams_catalog.query import CatalogResultSet -from pyams_content.shared.common import CONTENT_TYPES -from pyams_content.skin import pyams_content -from pyams_pagelet.pagelet import pagelet_config -from pyams_skin.container import ContainerView from pyams_skin.page import DefaultPageHeaderAdapter from pyams_skin.table import BaseTable, I18nColumn, NameColumn, JsActionColumn from pyams_skin.viewlet.menu import MenuItem @@ -52,6 +46,7 @@ from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter from pyams_utils.date import format_datetime, SH_DATETIME_FORMAT from pyams_utils.fanstatic import get_resource_path +from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION from pyams_utils.list import unique_iter from pyams_utils.property import cached_property from pyams_utils.registry import get_utility @@ -59,11 +54,10 @@ from pyams_utils.traversing import get_parent from pyams_viewlet.manager import viewletmanager_config from pyams_viewlet.viewlet import viewlet_config +from pyams_workflow.interfaces import IWorkflowState, IWorkflow, IWorkflowVersions, IWorkflowPublicationInfo +from pyams_zmi.interfaces.menu import IContentManagementMenu +from pyams_zmi.layer import IAdminLayer from pyams_zmi.view import InnerAdminView -from z3c.table.column import GetAttrColumn -from zope.interface import implementer, Interface - -from pyams_content import _ # @@ -445,8 +439,8 @@ label = _("My contents") icon_class = 'fa-user' url = '#' - - + + # # My favorites # Dashboard of favorites contents @@ -493,14 +487,14 @@ oid = ISequentialIdInfo(item).hex_oid icon_class = 'fa fa-fw fa-star{0}'.format('' if oid in (self.profile.favorites or ()) else '-o') return ''.format( - path=get_resource_path(pyams_content), - oid=oid, - title=self.request.localizer.translate(self.icon_hint), - icon_class=icon_class) + 'data-ams-plugin-pyams_content-src="{path}" ' \ + 'data-ams-click-handler="PyAMS_content.profile.switchFavorite" data-ams-stop-propagation="true" ' \ + 'data-sequence-oid="{oid}" ' \ + 'class="{icon_class}">
'.format( + path=get_resource_path(pyams_content), + oid=oid, + title=self.request.localizer.translate(self.icon_hint), + icon_class=icon_class) def get_url(self, item): return '' @@ -578,7 +572,7 @@ catalog = get_utility(ICatalog) workflow = get_utility(IWorkflow, name=self.context.shared_content_workflow) params = And(Eq(catalog['parents'], intids.register(self.context)), - Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ + Any(catalog['content_type'], CONTENT_TYPES.keys()) & Or(Eq(catalog['role:owner'], self.request.principal.id), Eq(catalog['role:contributor'], self.request.principal.id)), Eq(catalog['workflow_state'], workflow.initial_state)) @@ -587,7 +581,8 @@ reverse=True))) -@pagelet_config(name='my-preparations.html', context=IBaseSharedTool, layer=IPyAMSLayer, permission=VIEW_SYSTEM_PERMISSION) +@pagelet_config(name='my-preparations.html', context=IBaseSharedTool, layer=IPyAMSLayer, + permission=VIEW_SYSTEM_PERMISSION) class SharedToolPreparationsView(InnerAdminView, ContainerView): """Shared tool preparations view""" @@ -641,7 +636,7 @@ catalog = get_utility(ICatalog) workflow = get_utility(IWorkflow, name=self.context.shared_content_workflow) params = And(Eq(catalog['parents'], intids.register(self.context)), - Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ + Any(catalog['content_type'], CONTENT_TYPES.keys()) & Or(Eq(catalog['role:owner'], self.request.principal.id), Eq(catalog['role:contributor'], self.request.principal.id)), Any(catalog['workflow_state'], workflow.waiting_states)) @@ -650,7 +645,8 @@ reverse=True))) -@pagelet_config(name='my-submissions.html', context=IBaseSharedTool, layer=IPyAMSLayer, permission=VIEW_SYSTEM_PERMISSION) +@pagelet_config(name='my-submissions.html', context=IBaseSharedTool, layer=IPyAMSLayer, + permission=VIEW_SYSTEM_PERMISSION) class SharedToolSubmissionsView(InnerAdminView, ContainerView): """Shared tool submissions view""" @@ -704,7 +700,7 @@ catalog = get_utility(ICatalog) workflow = get_utility(IWorkflow, name=self.context.shared_content_workflow) params = And(Eq(catalog['parents'], intids.register(self.context)), - Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ + Any(catalog['content_type'], CONTENT_TYPES.keys()) & Or(Eq(catalog['role:owner'], self.request.principal.id), Eq(catalog['role:contributor'], self.request.principal.id)), Any(catalog['workflow_state'], workflow.published_states)) @@ -713,7 +709,8 @@ reverse=True))) -@pagelet_config(name='my-publications.html', context=IBaseSharedTool, layer=IPyAMSLayer, permission=VIEW_SYSTEM_PERMISSION) +@pagelet_config(name='my-publications.html', context=IBaseSharedTool, layer=IPyAMSLayer, + permission=VIEW_SYSTEM_PERMISSION) class SharedToolPublicationsView(InnerAdminView, ContainerView): """Shared tool publications view""" @@ -767,7 +764,7 @@ catalog = get_utility(ICatalog) workflow = get_utility(IWorkflow, name=self.context.shared_content_workflow) params = And(Eq(catalog['parents'], intids.register(self.context)), - Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ + Any(catalog['content_type'], CONTENT_TYPES.keys()) & Or(Eq(catalog['role:owner'], self.request.principal.id), Eq(catalog['role:contributor'], self.request.principal.id)), Any(catalog['workflow_state'], workflow.retired_states)) @@ -832,7 +829,7 @@ principal_id = self.request.principal.id workflow = get_utility(IWorkflow, name=self.context.shared_content_workflow) params = And(Eq(catalog['parents'], intids.register(self.context)), - Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ + Any(catalog['content_type'], CONTENT_TYPES.keys()) & Or(Eq(catalog['role:owner'], principal_id), Eq(catalog['role:contributor'], principal_id)), Any(catalog['workflow_state'], workflow.archived_states)) @@ -923,7 +920,7 @@ catalog = get_utility(ICatalog) workflow = get_utility(IWorkflow, name=self.context.shared_content_workflow) params = And(Eq(catalog['parents'], intids.register(self.context)), - Any(catalog['content_type'], CONTENT_TYPES.keys()) & \ + Any(catalog['content_type'], CONTENT_TYPES.keys()) & Any(catalog['workflow_state'], workflow.published_states)) yield from unique_iter(CatalogResultSet(CatalogQuery(catalog).query(params, limit=50, diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/zmi/header.py --- a/src/pyams_content/shared/common/zmi/header.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/common/zmi/header.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,10 +12,10 @@ __docformat__ = 'restructuredtext' +from pyramid.decorator import reify +from zope.interface import Interface -# import standard library - -# import interfaces +from pyams_content import _ from pyams_content.profile.interfaces import IAdminProfile from pyams_content.shared.common.interfaces import IWfSharedContent, IBaseSharedTool from pyams_form.interfaces.form import IInnerTabForm @@ -24,10 +24,6 @@ from pyams_sequence.interfaces import ISequentialIntIds, ISequentialIdInfo from pyams_skin.interfaces import IContextTitlePrefix from pyams_skin.layer import IPyAMSLayer -from pyams_workflow.interfaces import IWorkflowState, IWorkflow, IWorkflowStateLabel, IWorkflowVersions, \ - IWorkflowPublicationInfo - -# import packages from pyams_skin.site import ContextTitlePrefixAdapter from pyams_template.template import template_config from pyams_utils.adapter import adapter_config @@ -36,10 +32,8 @@ from pyams_utils.traversing import get_parent from pyams_utils.url import absolute_url from pyams_viewlet.viewlet import contentprovider_config -from pyramid.decorator import reify -from zope.interface import Interface - -from pyams_content import _ +from pyams_workflow.interfaces import IWorkflowState, IWorkflow, IWorkflowStateLabel, IWorkflowVersions, \ + IWorkflowPublicationInfo @adapter_config(context=(IWfSharedContent, IPyAMSLayer), provides=IContextTitlePrefix) @@ -85,7 +79,8 @@ state_format = translate(_("{state} by {principal}")) if state.state_urgency: state_format = state_format.replace('{state}', - '{state} '); + '{state} ' + '') elif state.state in workflow.published_states: pub_info = IWorkflowPublicationInfo(context, None) if (pub_info is not None) and not pub_info.is_published(): @@ -93,7 +88,8 @@ '{{state}} '.format( - translate(_("Content publication start date is not passed yet")))) + translate(_("Content publication start date is not passed " + "yet")))) state_class = 'text-danger' state_format = state_format.replace('{state}', '{{state}}'.format(state_class)) @@ -190,5 +186,6 @@ def update(self): pass - def render(self): + @staticmethod + def render(): return '' diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/zmi/manager.py --- a/src/pyams_content/shared/common/zmi/manager.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/common/zmi/manager.py Fri Oct 05 10:44:32 2018 +0200 @@ -34,7 +34,7 @@ from pyams_form.help import FormHelp from pyams_pagelet.pagelet import pagelet_config from pyams_skin.page import DefaultPageHeaderAdapter -from pyams_skin.viewlet.breadcrumb import BreadcrumbItem +from pyams_skin.viewlet.breadcrumb import BreadcrumbAdminLayerItem from pyams_skin.viewlet.menu import MenuItem from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter, ContextRequestAdapter from pyams_viewlet.manager import viewletmanager_config @@ -50,8 +50,8 @@ # Shared tools common adapters # -@adapter_config(context=(IBaseSharedTool, IPyAMSLayer), provides=IBreadcrumbItem) -class SharedToolBreadcrumbAdapter(BreadcrumbItem): +@adapter_config(context=(IBaseSharedTool, IAdminLayer), provides=IBreadcrumbItem) +class SharedToolBreadcrumbAdapter(BreadcrumbAdminLayerItem): """Shared tool breadcrumb adapter""" @property diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/zmi/properties.py --- a/src/pyams_content/shared/common/zmi/properties.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/common/zmi/properties.py Fri Oct 05 10:44:32 2018 +0200 @@ -86,8 +86,12 @@ fields = field.Fields(IWfSharedContent).select('title', 'short_name', 'content_url', 'header', 'description', 'notepad') fields['title'].widgetFactory = I18nSEOTextLineFieldWidget + if not self.context.handle_content_url: + fields = fields.omit('content_url') if not self.context.handle_header: fields = fields.omit('header') + if not self.context.handle_description: + fields = fields.omit('description') return fields def updateWidgets(self, prefix=None): @@ -117,7 +121,8 @@ """Automatically set short_name as title""" data = event.data data['short_name'] = data['title'].copy() - data['content_url'] = generate_url(data['content_url']) + if 'content_url' in data: + data['content_url'] = generate_url(data['content_url']) @adapter_config(context=(IWfSharedContent, IAdminLayer, SharedContentPropertiesEditForm), provides=IPageHeader) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/zmi/search.py --- a/src/pyams_content/shared/common/zmi/search.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/common/zmi/search.py Fri Oct 05 10:44:32 2018 +0200 @@ -117,7 +117,7 @@ intids = get_utility(IIntIds) catalog = get_utility(ICatalog) params = Eq(catalog['parents'], intids.register(self.context)) & \ - Any(catalog['content_type'], CONTENT_TYPES.keys()) + Any(catalog['content_type'], CONTENT_TYPES.keys()) query = self.request.params.get('query') if query: sequence = get_utility(ISequentialIntIds) @@ -253,7 +253,7 @@ intids = get_utility(IIntIds) catalog = get_utility(ICatalog) params = Eq(catalog['parents'], intids.register(self.context)) & \ - Any(catalog['content_type'], CONTENT_TYPES.keys()) + Any(catalog['content_type'], CONTENT_TYPES.keys()) query = data.get('query') if query: sequence = get_utility(ISequentialIntIds) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/zmi/security.py --- a/src/pyams_content/shared/common/zmi/security.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/common/zmi/security.py Fri Oct 05 10:44:32 2018 +0200 @@ -164,7 +164,8 @@ @property def legend(self): - return self.request.localizer.translate(_("Edit contributor restrictions for « {0} »")).format(self.principal.title) + return self.request.localizer.translate(_("Edit contributor restrictions for « {0} »")).format( + self.principal.title) @cached_property def interface(self): @@ -252,7 +253,8 @@ modal_target = True -@adapter_config(name='name', context=(IBaseSharedTool, IAdminLayer, SharedToolManagersRestrictionsTable), provides=IColumn) +@adapter_config(name='name', context=(IBaseSharedTool, IAdminLayer, SharedToolManagersRestrictionsTable), + provides=IColumn) class SharedToolManagerRestrictionsNameColumn(I18nColumn, GetAttrColumn): """Shared tool manager restrictions name column""" diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/zmi/summary.py --- a/src/pyams_content/shared/common/zmi/summary.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/common/zmi/summary.py Fri Oct 05 10:44:32 2018 +0200 @@ -9,39 +9,38 @@ # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # -from pyams_content.shared.common.interfaces.types import IWfTypedSharedContent -from pyams_sequence.interfaces import ISequentialIdInfo __docformat__ = 'restructuredtext' # import standard library +from z3c.form import field +from z3c.form.interfaces import DISPLAY_MODE, IDataConverter +from zope.interface import implementer, Interface + +from pyams_content import _ # import interfaces from pyams_content.shared.common.interfaces import IWfSharedContent, IWfSharedContentRoles, IBaseSharedTool +from pyams_content.shared.common.interfaces.types import IWfTypedSharedContent +# import packages +from pyams_content.shared.common.zmi.header import SharedContentHeaderContentProvider from pyams_form.interfaces.form import IWidgetForm, IInnerTabForm, IInnerSubForm +from pyams_pagelet.pagelet import pagelet_config +from pyams_security.utility import get_principal +from pyams_sequence.interfaces import ISequentialIdInfo from pyams_skin.interfaces import IInnerPage from pyams_skin.layer import IPyAMSLayer -from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION -from pyams_workflow.interfaces import IWorkflowState, IWorkflow, IWorkflowPublicationInfo, IWorkflowStateHistoryItem, \ - IWorkflowVersions -from z3c.form.interfaces import DISPLAY_MODE, IDataConverter - -# import packages -from pyams_content.shared.common.zmi.header import SharedContentHeaderContentProvider -from pyams_pagelet.pagelet import pagelet_config -from pyams_security.utility import get_principal from pyams_utils.adapter import adapter_config from pyams_utils.date import format_datetime +from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION from pyams_utils.timezone import tztime from pyams_utils.traversing import get_parent from pyams_utils.url import absolute_url from pyams_viewlet.viewlet import contentprovider_config +from pyams_workflow.interfaces import IWorkflowState, IWorkflow, IWorkflowPublicationInfo, IWorkflowStateHistoryItem, \ + IWorkflowVersions from pyams_zmi.form import AdminDisplayForm, InnerAdminDisplayForm, InnerAdminAddForm -from z3c.form import field -from zope.interface import implementer, Interface - -from pyams_content import _ @pagelet_config(name='summary.html', context=IWfSharedContent, layer=IPyAMSLayer, permission=VIEW_SYSTEM_PERMISSION) @@ -104,7 +103,7 @@ return InnerAdminDisplayForm.__new__(cls) fields = field.Fields(IWorkflowState).select('state', 'state_urgency') + \ - field.Fields(IWorkflowStateHistoryItem).select('comment') + field.Fields(IWorkflowStateHistoryItem).select('comment') def updateWidgets(self, prefix=None): super(SharedContentWorkflowWaitingState, self).updateWidgets(prefix) @@ -155,10 +154,10 @@ weight = 30 fields = field.Fields(IWorkflowState).select('version_id', 'state') + \ - field.Fields(IWfSharedContent).select('creation_label') + \ - field.Fields(IWfSharedContentRoles).select('owner') + \ - field.Fields(IWfSharedContent).select('last_update_label') + \ - field.Fields(IWfSharedContent).select('modifiers') + field.Fields(IWfSharedContent).select('creation_label') + \ + field.Fields(IWfSharedContentRoles).select('owner') + \ + field.Fields(IWfSharedContent).select('last_update_label') + \ + field.Fields(IWfSharedContent).select('modifiers') def updateWidgets(self, prefix=None): super(SharedContentWorkflowVersionSummary, self).updateWidgets(prefix) @@ -184,7 +183,7 @@ legend = _("Content history") fields = field.Fields(IWorkflowPublicationInfo).select('first_publication_date') + \ - field.Fields(IWfSharedContent).select('first_owner') + field.Fields(IWfSharedContent).select('first_owner') weight = 40 diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/zmi/types.py --- a/src/pyams_content/shared/common/zmi/types.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/common/zmi/types.py Fri Oct 05 10:44:32 2018 +0200 @@ -10,10 +10,9 @@ # FOR A PARTICULAR PURPOSE. # + __docformat__ = 'restructuredtext' - -# import standard library import json from pyramid.decorator import reify @@ -22,41 +21,41 @@ from pyramid.view import view_config from z3c.form import field from z3c.form.interfaces import DISPLAY_MODE, IDataExtractedEvent -from z3c.table.interfaces import IValues, IColumn -from zope.interface import Invalid +from z3c.table.interfaces import IColumn, IValues +from zope.interface import Invalid, implementer from pyams_content import _ -# import interfaces -from pyams_content.interfaces import MANAGE_TOOL_PERMISSION, MANAGE_CONTENT_PERMISSION -# import packages +from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION, MANAGE_TOOL_PERMISSION from pyams_content.reference.pictograms.zmi.widget import PictogramSelectFieldWidget -from pyams_content.shared.common.interfaces.types import ITypedSharedTool, ITypedDataManager, \ - IBaseDataType, IDataType, ISubType, IWfTypedSharedContent +from pyams_content.shared.common.interfaces.types import IBaseDataType, IDataType, ISubType, ITypedDataManager, \ + ITypedSharedTool, IWfTypedSharedContent from pyams_content.shared.common.types import DataType, SubType from pyams_content.shared.common.zmi import SharedContentAddForm from pyams_content.shared.common.zmi.properties import SharedContentPropertiesEditForm from pyams_content.skin import pyams_content from pyams_form.form import AJAXAddForm, ajax_config +from pyams_form.interfaces.form import IWidgetForm from pyams_form.security import ProtectedFormObjectMixin from pyams_i18n.interfaces import II18n from pyams_i18n.widget import I18nSEOTextLineFieldWidget from pyams_pagelet.pagelet import pagelet_config from pyams_skin.container import delete_container_element from pyams_skin.event import get_json_table_refresh_event +from pyams_skin.interfaces import IInnerPage from pyams_skin.interfaces.container import ITableElementName from pyams_skin.interfaces.viewlet import IWidgetTitleViewletManager from pyams_skin.layer import IPyAMSLayer -from pyams_skin.table import BaseTable, SorterColumn, TrashColumn, NameColumn, ActionColumn +from pyams_skin.table import ActionColumn, BaseTable, NameColumn, SorterColumn, TrashColumn from pyams_skin.viewlet.menu import MenuItem from pyams_skin.viewlet.toolbar import ToolbarAction -from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter, ContextRequestAdapter +from pyams_utils.adapter import ContextRequestAdapter, ContextRequestViewAdapter, adapter_config from pyams_utils.fanstatic import get_resource_path from pyams_utils.traversing import get_parent from pyams_utils.unicode import translate_string from pyams_utils.url import absolute_url from pyams_viewlet.interfaces import IViewletManager from pyams_viewlet.viewlet import viewlet_config -from pyams_zmi.form import AdminDialogAddForm, AdminDialogEditForm +from pyams_zmi.form import AdminDialogAddForm, AdminDialogEditForm, AdminEditForm from pyams_zmi.interfaces.menu import IPropertiesMenu from pyams_zmi.layer import IAdminLayer from pyams_zmi.view import ContainerAdminView @@ -577,9 +576,43 @@ permission=MANAGE_CONTENT_PERMISSION) @ajax_config(name='properties.json', context=IWfTypedSharedContent, layer=IPyAMSLayer, permission=MANAGE_CONTENT_PERMISSION) -class TypedSharedContentProperteisEditForm(SharedContentPropertiesEditForm): +class TypedSharedContentPropertiesEditForm(SharedContentPropertiesEditForm): """Typed shared content properties edit form""" - fields = field.Fields(IWfTypedSharedContent).select('title', 'short_name', 'content_url', - 'data_type', 'description', 'notepad') - fields['title'].widgetFactory = I18nSEOTextLineFieldWidget + @property + def fields(self): + fields = field.Fields(IWfTypedSharedContent).select('title', 'short_name', 'content_url', + 'data_type', 'header', 'description', 'notepad') + fields['title'].widgetFactory = I18nSEOTextLineFieldWidget + if not self.context.handle_content_url: + fields = fields.omit('content_url') + if not self.context.handle_header: + fields = fields.omit('header') + if not self.context.handle_description: + fields = fields.omit('description') + return fields + + +# +# Typed shared content custom fields edit form +# + +@implementer(IWidgetForm, IInnerPage) +class TypedSharedContentTypeFieldsEditForm(AdminEditForm): + """Typed shared content type fields properties edit form""" + + prefix = 'type_properties.' + + @property + def legend(self): + translate = self.request.localizer.translate + data_type = self.context.get_data_type() + return translate(_("Custom properties for type « {0} »")).format( + II18n(data_type).query_attribute('label', request=self.request)) + + @property + def fields(self): + data_type = self.context.get_data_type() + if data_type is not None: + manager = get_parent(self.context, ITypedSharedTool) + return field.Fields(manager.shared_content_types_fields).select(*data_type.field_names) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/common/zmi/workflow.py --- a/src/pyams_content/shared/common/zmi/workflow.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/common/zmi/workflow.py Fri Oct 05 10:44:32 2018 +0200 @@ -141,9 +141,9 @@ if state.version_id > 1: pub_fields += ('displayed_publication_date', ) return field.Fields(IWorkflowTransitionInfo) + \ - field.Fields(IWorkflowPublicationInfo).select(*pub_fields) + \ - field.Fields(IWorkflowRequestUrgencyInfo) + \ - field.Fields(IWorkflowCommentInfo) + field.Fields(IWorkflowPublicationInfo).select(*pub_fields) + \ + field.Fields(IWorkflowRequestUrgencyInfo) + \ + field.Fields(IWorkflowCommentInfo) buttons = button.Buttons(IPublicationRequestButtons) @@ -322,8 +322,8 @@ if state.version_id > 1: pub_fields += ('displayed_publication_date', ) return field.Fields(IWorkflowTransitionInfo) + \ - field.Fields(IWorkflowPublicationInfo).select(*pub_fields) + \ - field.Fields(IWorkflowCommentInfo) + field.Fields(IWorkflowPublicationInfo).select(*pub_fields) + \ + field.Fields(IWorkflowCommentInfo) buttons = button.Buttons(IPublicationButtons) @@ -402,8 +402,8 @@ """Shared content publication request refuse form""" fields = field.Fields(IWorkflowTransitionInfo) + \ - field.Fields(IWorkflowRequestUrgencyInfo) + \ - field.Fields(IWorkflowCommentInfo) + field.Fields(IWorkflowRequestUrgencyInfo) + \ + field.Fields(IWorkflowCommentInfo) buttons = button.Buttons(IPublicationRetireRequestButtons) def updateWidgets(self, prefix=None): @@ -539,8 +539,8 @@ """Shared content publication request archive form""" fields = field.Fields(IWorkflowTransitionInfo) + \ - field.Fields(IWorkflowRequestUrgencyInfo) + \ - field.Fields(IWorkflowCommentInfo) + field.Fields(IWorkflowRequestUrgencyInfo) + \ + field.Fields(IWorkflowCommentInfo) buttons = button.Buttons(IPublicationArchiveRequestButtons) @@ -715,6 +715,8 @@ buttons = button.Buttons(ISharedContentDeleteButtons) + __target = None + @property def fields(self): fields = super(SharedContentDeleteForm, self).fields diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/form/manager.py --- a/src/pyams_content/shared/form/manager.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/form/manager.py Fri Oct 05 10:44:32 2018 +0200 @@ -18,7 +18,6 @@ # import interfaces from pyams_content.shared.common.interfaces import ISharedContentFactory from pyams_content.shared.form.interfaces import IFormsManager, FORM_CONTENT_TYPE, IFormsManagerFactory -from pyams_portal.interfaces import IPortalContext from zope.component.interfaces import ISite from zope.lifecycleevent.interfaces import IObjectAddedEvent diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/imagemap/__init__.py --- a/src/pyams_content/shared/imagemap/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/imagemap/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,8 +12,6 @@ __docformat__ = 'restructuredtext' - -# import standard library from persistent import Persistent from persistent.mapping import PersistentMapping from pyramid.threadlocal import get_current_registry @@ -27,21 +25,19 @@ from zope.traversing.interfaces import ITraversable from pyams_content import _ -# import interfaces from pyams_content.component.association.interfaces import IAssociationContainer from pyams_content.component.extfile.interfaces import IExtFileContainerTarget from pyams_content.component.links.interfaces import ILinkContainerTarget -from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE, ERROR_VALUE +from pyams_content.features.checker.interfaces import ERROR_VALUE, IContentChecker, MISSING_LANG_VALUE, MISSING_VALUE from pyams_content.features.preview.interfaces import IPreviewTarget from pyams_content.features.review.interfaces import IReviewTarget -# import packages -from pyams_content.shared.common import WfSharedContent, register_content_type, SharedContent, WfSharedContentChecker, \ - IWfSharedContentFactory -from pyams_content.shared.imagemap.interfaces import IMAGEMAP_CONTENT_TYPE, IMAGEMAP_CONTENT_NAME, \ - IWfImageMap, IImageMap, IImageMapArea, IWfImageMapFactory +from pyams_content.shared.common import SharedContent, WfSharedContent, WfSharedContentChecker, register_content_type +from pyams_content.shared.common.interfaces import IWfSharedContentFactory +from pyams_content.shared.imagemap.interfaces import IImageMap, IImageMapArea, IMAGEMAP_CONTENT_NAME, \ + IMAGEMAP_CONTENT_TYPE, IWfImageMap, IWfImageMapFactory from pyams_i18n.interfaces import II18n, II18nManager from pyams_i18n.property import I18nFileProperty -from pyams_utils.adapter import adapter_config, ContextAdapter +from pyams_utils.adapter import ContextAdapter, adapter_config @implementer(IImageMapArea) @@ -61,7 +57,9 @@ content_type = IMAGEMAP_CONTENT_TYPE content_name = IMAGEMAP_CONTENT_NAME + handle_content_url = False handle_header = False + handle_description = False _image = I18nFileProperty(IWfImageMap['image']) areas = FieldProperty(IWfImageMap['areas']) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/logo/__init__.py --- a/src/pyams_content/shared/logo/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/logo/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -20,8 +20,9 @@ from pyams_content import _ # import interfaces +from pyams_content.component.theme.interfaces import IThemesTarget from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE -from pyams_content.features.review import IReviewTarget +from pyams_content.features.review.interfaces import IReviewTarget # import packages from pyams_content.shared.common import WfSharedContent, register_content_type, SharedContent, WfSharedContentChecker, \ IWfSharedContentFactory @@ -30,18 +31,21 @@ from pyams_utils.adapter import adapter_config -@implementer(IWfLogo, IReviewTarget) +@implementer(IWfLogo, IThemesTarget, IReviewTarget) class WfLogo(WfSharedContent): """Logo persistent class""" content_type = LOGO_CONTENT_TYPE content_name = LOGO_CONTENT_NAME + handle_content_url = False handle_header = False + handle_description = False + acronym = FieldProperty(IWfLogo['acronym']) + url = FieldProperty(IWfLogo['url']) image = FileProperty(IWfLogo['image']) monochrome_image = FileProperty(IWfLogo['monochrome_image']) - url = FieldProperty(IWfLogo['url']) register_content_type(WfLogo) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/logo/interfaces/__init__.py --- a/src/pyams_content/shared/logo/interfaces/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/logo/interfaces/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -15,19 +15,18 @@ # import standard library +from zope.interface import Interface +from zope.schema import URI, Choice, TextLine + +from pyams_content import _ # import interfaces from pyams_content.component.paragraph import IBaseParagraph from pyams_content.shared.common.interfaces import ISharedTool, IWfSharedContent, ISharedContent -from pyams_sequence.interfaces import IInternalReferencesList - # import packages from pyams_file.schema import ImageField +from pyams_i18n.schema import I18nTextLineField +from pyams_sequence.interfaces import IInternalReferencesList from pyams_sequence.schema import InternalReferencesListField -from zope.interface import Interface -from zope.schema import URI, Choice - -from pyams_content import _ - LOGO_CONTENT_TYPE = 'logo' LOGO_CONTENT_NAME = _("Logo") @@ -44,6 +43,18 @@ class IWfLogo(IWfSharedContent): """Logo interface""" + title = I18nTextLineField(title=_("Title"), + description=_("Full name of logo organization"), + required=True) + + acronym = TextLine(title=_("Acronym"), + description=_("Matching logo acronym, without spaces or separators"), + required=False) + + url = URI(title=_("Target URL"), + description=_("URL used to access external resource"), + required=False) + image = ImageField(title=_("Image (colored)"), description=_("Image data"), required=True) @@ -53,10 +64,6 @@ "presentation templates"), required=False) - url = URI(title=_("Target URL"), - description=_("URL used to access external resource"), - required=False) - class IWfLogoFactory(Interface): """Logo factory interface""" diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/logo/zmi/properties.py --- a/src/pyams_content/shared/logo/zmi/properties.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/logo/zmi/properties.py Fri Oct 05 10:44:32 2018 +0200 @@ -9,6 +9,9 @@ # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # +from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION +from pyams_form.form import ajax_config +from pyams_pagelet.pagelet import pagelet_config __docformat__ = 'restructuredtext' @@ -17,11 +20,13 @@ # import interfaces from pyams_content.shared.logo import IWfLogo -from pyams_form.interfaces.form import IInnerSubForm +from pyams_form.interfaces.form import IInnerSubForm, IInnerTabForm +from pyams_sequence.interfaces import ISequentialIdInfo from pyams_skin.layer import IPyAMSLayer # import packages from pyams_content.shared.common.zmi.properties import SharedContentPropertiesEditForm +from pyams_content.shared.common.zmi.summary import SharedContentSummaryForm, SharedContentDublinCoreSummary from pyams_utils.adapter import adapter_config from pyams_zmi.form import InnerAdminEditForm from z3c.form import field @@ -29,6 +34,26 @@ from pyams_content import _ +@adapter_config(name='dublincore-summary', + context=(IWfLogo, IPyAMSLayer, SharedContentSummaryForm), + provides=IInnerTabForm) +class LogoDublinCoreSummary(SharedContentDublinCoreSummary): + """Shared content DublinCore summary""" + + fields = field.Fields(IWfLogo).select('title', 'acronym') + \ + field.Fields(ISequentialIdInfo).select('public_oid') + + +@pagelet_config(name='properties.html', context=IWfLogo, layer=IPyAMSLayer, + permission=MANAGE_CONTENT_PERMISSION) +@ajax_config(name='properties.json', context=IWfLogo, layer=IPyAMSLayer, + permission=MANAGE_CONTENT_PERMISSION) +class LogoMainPropertiesEditForm(SharedContentPropertiesEditForm): + """Logo properties edit form""" + + fields = field.Fields(IWfLogo).select('title', 'short_name', 'notepad') + + @adapter_config(name='logo-settings', context=(IWfLogo, IPyAMSLayer, SharedContentPropertiesEditForm), provides=IInnerSubForm) @@ -40,7 +65,7 @@ legend = _("Main logo settings") fieldset_class = 'bordered no-x-margin margin-y-10' - fields = field.Fields(IWfLogo).select('image', 'monochrome_image', 'url') + fields = field.Fields(IWfLogo).select('acronym', 'url', 'image', 'monochrome_image') weight = 1 def get_ajax_output(self, changes): diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/news/__init__.py --- a/src/pyams_content/shared/news/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/news/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -15,20 +15,20 @@ # import standard library +from zope.interface import implementer, provider + # import interfaces -from pyams_content.component.illustration import IIllustrationTarget, ILinkIllustrationTarget +from pyams_content.component.illustration.interfaces import IIllustrationTarget, ILinkIllustrationTarget from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget from pyams_content.component.theme.interfaces import ITagsTarget, IThemesTarget from pyams_content.features.preview.interfaces import IPreviewTarget from pyams_content.features.review.interfaces import IReviewTarget +# import packages +from pyams_content.shared.common import SharedContent, WfSharedContent, register_content_type from pyams_content.shared.common.interfaces import IWfSharedContentFactory from pyams_content.shared.news.interfaces import INewsEvent, IWfNewsEvent, NEWS_CONTENT_TYPE, NEWS_CONTENT_NAME, \ IWfNewsEventFactory - -# import packages -from pyams_content.shared.common import SharedContent, WfSharedContent, register_content_type from pyams_utils.adapter import adapter_config -from zope.interface import implementer, provider @implementer(IWfNewsEvent, IIllustrationTarget, ILinkIllustrationTarget, IParagraphContainerTarget, diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/site/__init__.py --- a/src/pyams_content/shared/site/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/site/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,42 +12,38 @@ __docformat__ = 'restructuredtext' +from zope.interface import implementer, provider -# import standard library - -# import interfaces from pyams_content.component.illustration import IIllustrationTarget, ILinkIllustrationTarget from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget from pyams_content.component.theme.interfaces import ITagsTarget, IThemesTarget from pyams_content.features.preview.interfaces import IPreviewTarget from pyams_content.features.review.interfaces import IReviewTarget -from pyams_content.shared.site.interfaces import ITopic, IWfTopic, TOPIC_CONTENT_NAME, \ - TOPIC_CONTENT_TYPE, IWfTopicFactory -from pyams_workflow.interfaces import IWorkflow, IWorkflowVersions, IWorkflowState - -# import packages -from pyams_content.shared.common import SharedContent, WfSharedContent, register_content_type, IWfSharedContentFactory +from pyams_content.shared.common import IWfSharedContentFactory, SharedContent, WfSharedContent, register_content_type +from pyams_content.shared.site.interfaces import ISiteTopic, IWfSiteTopic, IWfSiteTopicFactory, SITE_TOPIC_CONTENT_NAME, \ + SITE_TOPIC_CONTENT_TYPE from pyams_utils.adapter import adapter_config -from zope.interface import implementer, provider +from pyams_workflow.interfaces import IWorkflow, IWorkflowState, IWorkflowVersions -@implementer(IWfTopic, IIllustrationTarget, ILinkIllustrationTarget, IParagraphContainerTarget, +@implementer(IWfSiteTopic, IIllustrationTarget, ILinkIllustrationTarget, IParagraphContainerTarget, ITagsTarget, IThemesTarget, IPreviewTarget, IReviewTarget) -class WfTopic(WfSharedContent): - """Base topic""" +class WfSiteTopic(WfSharedContent): + """Base site topic""" - content_type = TOPIC_CONTENT_TYPE - content_name = TOPIC_CONTENT_NAME - -register_content_type(WfTopic) + content_type = SITE_TOPIC_CONTENT_TYPE + content_name = SITE_TOPIC_CONTENT_NAME -@provider(IWfTopicFactory) -@implementer(ITopic) -class Topic(SharedContent): - """WOrkflow managed topic class""" +register_content_type(WfSiteTopic) + - content_name = TOPIC_CONTENT_NAME +@provider(IWfSiteTopicFactory) +@implementer(ISiteTopic) +class SiteTopic(SharedContent): + """Workflow managed topic class""" + + content_name = SITE_TOPIC_CONTENT_NAME def is_deletable(self): workflow = IWorkflow(self) @@ -57,6 +53,6 @@ return True -@adapter_config(context=IWfTopicFactory, provides=IWfSharedContentFactory) -def topic_content_factory(context): - return WfTopic +@adapter_config(context=IWfSiteTopicFactory, provides=IWfSharedContentFactory) +def site_topic_content_factory(context): + return WfSiteTopic diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/site/container.py --- a/src/pyams_content/shared/site/container.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/site/container.py Fri Oct 05 10:44:32 2018 +0200 @@ -16,19 +16,19 @@ # import standard library import json +from pyramid.location import lineage +from zope.interface import implementer +from zope.intid.interfaces import IIntIds + # import interfaces from pyams_content.shared.common.interfaces import ISharedContentFactory +# import packages +from pyams_content.shared.site import SiteTopic from pyams_content.shared.site.interfaces import ISiteContainer, ISiteFolder from pyams_i18n.interfaces import II18n -from zope.intid.interfaces import IIntIds - -# import packages -from pyams_content.shared.site import Topic from pyams_utils.adapter import adapter_config from pyams_utils.registry import get_utility from pyams_utils.request import query_request -from pyramid.location import lineage -from zope.interface import implementer @implementer(ISiteContainer) @@ -89,4 +89,4 @@ @adapter_config(context=ISiteContainer, provides=ISharedContentFactory) def site_container_topic_factory(context): - return Topic + return SiteTopic diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/site/folder.py --- a/src/pyams_content/shared/site/folder.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/site/folder.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,35 +12,28 @@ __docformat__ = 'restructuredtext' +from zope.container.ordered import OrderedContainer +from zope.interface import implementer +from zope.intid.interfaces import IIntIds +from zope.schema.fieldproperty import FieldProperty +from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm -# import standard library - -# import interfaces from pyams_content.component.illustration import IIllustrationTarget, ILinkIllustrationTarget from pyams_content.features.preview.interfaces import IPreviewTarget from pyams_content.interfaces import MANAGE_SITE_PERMISSION +from pyams_content.shared.common.manager import BaseSharedTool +from pyams_content.shared.site.container import SiteContainerMixin from pyams_content.shared.site.interfaces import ISiteFolder, ISiteManager, ISiteFolderRoles from pyams_form.interfaces.form import IFormContextPermissionChecker from pyams_i18n.interfaces import II18n from pyams_portal.interfaces import IPortalContext from pyams_security.interfaces import IDefaultProtectionPolicy -from zope.intid.interfaces import IIntIds - -# import packages -from pyams_content.shared.common.manager import BaseSharedTool -from pyams_content.shared.site.container import SiteContainerMixin from pyams_utils.adapter import adapter_config, ContextAdapter from pyams_utils.container import find_objects_providing from pyams_utils.registry import get_local_registry from pyams_utils.request import query_request from pyams_utils.traversing import get_parent from pyams_utils.vocabulary import vocabulary_config -from zope.container.ordered import OrderedContainer -from zope.interface import implementer -from zope.schema.fieldproperty import FieldProperty -from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm - -from pyams_content import _ from pyams_content import _ @@ -53,6 +46,7 @@ roles_interface = ISiteFolderRoles heading = FieldProperty(ISiteFolder['heading']) + description = FieldProperty(ISiteFolder['description']) notepad = FieldProperty(ISiteFolder['notepad']) visible_in_list = FieldProperty(ISiteFolder['visible_in_list']) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/site/interfaces/__init__.py --- a/src/pyams_content/shared/site/interfaces/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/site/interfaces/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,27 +12,23 @@ __docformat__ = 'restructuredtext' - -# import standard library from collections import OrderedDict -# import interfaces -from pyams_content.interfaces import IBaseContent -from pyams_sequence.interfaces import ISequentialIdTarget, IInternalReference -from pyams_workflow.interfaces import IWorkflowPublicationSupport from zope.annotation.interfaces import IAttributeAnnotatable -from zope.container.interfaces import IContainer, IContained - -# import packages -from pyams_content.shared.common.interfaces import ISharedSite, ISharedContent, \ - IBaseContentManagerRoles, IBaseSharedTool, IDeletableElement, IWfSharedContentPortalContext -from pyams_i18n.schema import I18nTextLineField, I18nTextField from zope.container.constraints import containers, contains -from zope.interface import Interface, Attribute -from zope.schema import Text, Bool, Choice -from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm +from zope.container.interfaces import IContained, IContainer +from zope.interface import Attribute, Interface +from zope.schema import Bool, Choice, Text +from zope.schema.vocabulary import SimpleTerm, SimpleVocabulary from pyams_content import _ +from pyams_content.interfaces import IBaseContent +from pyams_content.shared.common.interfaces import IBaseContentManagerRoles, IBaseSharedTool, IDeletableElement, \ + ISharedSite +from pyams_content.shared.topic.interfaces import ITopic, IWfTopic, IWfTopicFactory +from pyams_i18n.schema import I18nTextField, I18nTextLineField +from pyams_sequence.interfaces import IInternalReference, ISequentialIdTarget +from pyams_workflow.interfaces import IWorkflowPublicationSupport FOLDER_REDIRECT_DISPLAY_MODE = 'redirect' @@ -73,6 +69,12 @@ description=_("Heading displayed according to presentation template"), required=False) + description = I18nTextField(title=_("Meta-description"), + description=_("The folder's description is 'hidden' into HTML's page headers; but it " + "can be seen, for example, in some search engines results as content's " + "description; if description is empty, content's header will be used."), + required=False) + notepad = Text(title=_("Notepad"), description=_("Internal information to be known about this content"), required=False) @@ -112,25 +114,35 @@ topic_content_type = Attribute("Topic content type") topic_content_factory = Attribute("Topic content factory") + description = I18nTextField(title=_("Meta-description"), + description=_("The site's description is 'hidden' into HTML's page headers; but it " + "can be seen, for example, in some search engines results as content's " + "description; if description is empty, content's header will be used."), + required=False) + + notepad = Text(title=_("Notepad"), + description=_("Internal information to be known about this content"), + required=False) + class ISiteManagerFactory(Interface): """Site manager factory interface""" -TOPIC_CONTENT_TYPE = 'topic' -TOPIC_CONTENT_NAME = _("Topic") +SITE_TOPIC_CONTENT_TYPE = 'site-topic' +SITE_TOPIC_CONTENT_NAME = _("Site topic") -class IWfTopic(IWfSharedContentPortalContext): - """Topic interface""" +class IWfSiteTopic(IWfTopic): + """Site topic interface""" -class IWfTopicFactory(Interface): +class IWfSiteTopicFactory(IWfTopicFactory): """Topic factory interface""" -class ITopic(ISharedContent, ISiteElement): - """Workflow managed topic interface""" +class ISiteTopic(ITopic, ISiteElement): + """Workflow managed site topic interface""" class IContentLink(ISiteElement, IInternalReference, IAttributeAnnotatable): diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/site/link.py --- a/src/pyams_content/shared/site/link.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/site/link.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,26 +12,20 @@ __docformat__ = 'restructuredtext' - -# import standard library - -# import interfaces -from pyams_content.shared.site.interfaces import IContentLink -from pyams_utils.interfaces.url import IRelativeURL -from pyams_workflow.interfaces import IWorkflow, IWorkflowVersion, IWorkflowVersions, IWorkflowPublicationInfo, \ - IWorkflowState - -# import packages from persistent import Persistent -from pyams_sequence.reference import get_reference_target -from pyams_skin.layer import IPyAMSUserLayer -from pyams_utils.adapter import adapter_config -from pyams_utils.zodb import volatile_property from zope.container.contained import Contained from zope.interface import implementer from zope.schema.fieldproperty import FieldProperty from pyams_content import _ +from pyams_content.shared.site.interfaces import IContentLink +from pyams_sequence.reference import get_reference_target +from pyams_skin.layer import IPyAMSUserLayer +from pyams_utils.adapter import adapter_config +from pyams_utils.interfaces.url import IRelativeURL +from pyams_utils.zodb import volatile_property +from pyams_workflow.interfaces import IWorkflow, IWorkflowVersion, IWorkflowVersions, IWorkflowPublicationInfo, \ + IWorkflowState @implementer(IContentLink) @@ -48,7 +42,8 @@ content_name = _("Content link") - def is_deletable(self): + @staticmethod + def is_deletable(): return True @volatile_property diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/site/manager.py --- a/src/pyams_content/shared/site/manager.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/site/manager.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,10 +12,14 @@ __docformat__ = 'restructuredtext' +from pyramid.events import subscriber +from zope.component.interfaces import ISite +from zope.container.ordered import OrderedContainer +from zope.interface import implementer +from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectRemovedEvent +from zope.schema.fieldproperty import FieldProperty +from zope.schema.vocabulary import SimpleTerm, SimpleVocabulary -# import standard library - -# import interfaces from pyams_content.component.illustration import IIllustrationTarget, ILinkIllustrationTarget from pyams_content.component.paragraph.interfaces import IParagraphFactorySettings from pyams_content.component.theme.interfaces import IThemesManagerTarget @@ -26,29 +30,20 @@ from pyams_content.reference.pictograms.interfaces import IPictogramManagerTarget from pyams_content.root.interfaces import ISiteRoot from pyams_content.shared.common.interfaces import ISharedContentFactory -from pyams_content.shared.site.interfaces import ISiteManager, ISiteManagerFactory, ISiteFolderFactory, ISiteContainer +from pyams_content.shared.common.manager import BaseSharedTool +from pyams_content.shared.site import SiteTopic +from pyams_content.shared.site.container import SiteContainerMixin +from pyams_content.shared.site.folder import SiteFolder +from pyams_content.shared.site.interfaces import ISiteContainer, ISiteFolderFactory, ISiteManager, ISiteManagerFactory from pyams_form.interfaces.form import IFormContextPermissionChecker from pyams_i18n.interfaces import II18n from pyams_portal.interfaces import IPortalContext -from zope.component.interfaces import ISite -from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectRemovedEvent - -# import packages -from pyams_content.shared.common.manager import BaseSharedTool -from pyams_content.shared.site import Topic -from pyams_content.shared.site.container import SiteContainerMixin -from pyams_content.shared.site.folder import SiteFolder from pyams_skin.skin import UserSkinnableContent -from pyams_utils.adapter import adapter_config, ContextAdapter +from pyams_utils.adapter import ContextAdapter, adapter_config from pyams_utils.registry import get_utilities_for from pyams_utils.request import query_request from pyams_utils.traversing import get_parent from pyams_utils.vocabulary import vocabulary_config -from pyramid.events import subscriber -from zope.container.ordered import OrderedContainer -from zope.interface import implementer -from zope.schema.fieldproperty import FieldProperty -from zope.schema.vocabulary import SimpleTerm, SimpleVocabulary from pyams_content import _ @@ -59,6 +54,9 @@ class SiteManager(SiteContainerMixin, OrderedContainer, BaseSharedTool, UserSkinnableContent): """Site manager persistent class""" + description = FieldProperty(ISiteManager['description']) + notepad = FieldProperty(ISiteManager['notepad']) + allowed_paragraphs = FieldProperty(IParagraphFactorySettings['allowed_paragraphs']) auto_created_paragraphs = FieldProperty(IParagraphFactorySettings['auto_created_paragraphs']) @@ -100,7 +98,7 @@ @adapter_config(context=ISiteContainer, provides=ISharedContentFactory) def site_manager_shared_content_factory(context): - return Topic + return SiteTopic @subscriber(IObjectAddedEvent, context_selector=ISiteManager) @@ -138,4 +136,4 @@ request = query_request() super(SiteManagerVocabulary, self).__init__([SimpleTerm(v, title=II18n(t).query_attribute('title', request=request)) - for v, t in get_utilities_for(self.interface)]) + for v, t in get_utilities_for(self.interface)]) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/site/skin/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/site/skin/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -0,0 +1,20 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces + +# import packages diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/site/skin/breadcrumb.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/site/skin/breadcrumb.py Fri Oct 05 10:44:32 2018 +0200 @@ -0,0 +1,35 @@ +# +# Copyright (c) 2008-2018 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + + +# import standard library + +# import interfaces +from pyams_content.shared.site.interfaces import ISiteContainer +from pyams_i18n.interfaces import II18n +from pyams_skin.interfaces.viewlet import IBreadcrumbItem +from pyams_skin.layer import IPyAMSUserLayer + +# import packages +from pyams_skin.viewlet.breadcrumb import BreadcrumbItem +from pyams_utils.adapter import adapter_config + + +@adapter_config(context=(ISiteContainer, IPyAMSUserLayer), provides=IBreadcrumbItem) +class SiteContainerBreadcumbAdapter(BreadcrumbItem): + """Site container breadcrumb adapter""" + + @property + def label(self): + return II18n(self.context).query_attribute('short_name', request=self.request) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/site/zmi/__init__.py --- a/src/pyams_content/shared/site/zmi/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/site/zmi/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -13,46 +13,34 @@ __docformat__ = 'restructuredtext' -# import standard library from uuid import uuid4 -# import interfaces +from pyramid.decorator import reify +from pyramid.path import DottedNameResolver +from z3c.form import field +from zope.interface import Interface +from zope.intid.interfaces import IIntIds +from zope.lifecycleevent import ObjectCreatedEvent +from zope.schema import Int + +from pyams_content import _ from pyams_content.interfaces import CREATE_CONTENT_PERMISSION from pyams_content.shared.common.interfaces import IWfSharedContent -from pyams_content.shared.site.interfaces import ISiteContainer, ISiteManager, IWfTopic -from pyams_i18n.interfaces import II18nManager, INegotiator -from pyams_skin.interfaces.viewlet import IToolbarAddingMenu, IMenuHeader -from pyams_skin.layer import IPyAMSLayer -from pyams_workflow.interfaces import IWorkflowInfo, IWorkflowVersions -from pyams_zmi.interfaces.menu import IContentManagementMenu -from pyams_zmi.layer import IAdminLayer -from zope.intid.interfaces import IIntIds - -# import packages -from pyams_content.shared.common.zmi import SharedContentAddForm, SharedContentAJAXAddForm +from pyams_content.shared.common.zmi import SharedContentAJAXAddForm, SharedContentAddForm +from pyams_content.shared.site.interfaces import ISiteContainer, ISiteManager from pyams_content.shared.site.zmi.widget import SiteManagerFoldersSelectorFieldWidget from pyams_form.form import ajax_config +from pyams_i18n.interfaces import II18nManager, INegotiator from pyams_pagelet.pagelet import pagelet_config +from pyams_skin.interfaces.viewlet import IToolbarAddingMenu +from pyams_skin.layer import IPyAMSLayer from pyams_skin.viewlet.toolbar import ToolbarMenuItem -from pyams_utils.adapter import adapter_config, ContextRequestAdapter from pyams_utils.registry import get_utility from pyams_utils.traversing import get_parent from pyams_utils.url import absolute_url, generate_url from pyams_viewlet.viewlet import viewlet_config -from pyramid.decorator import reify -from pyramid.path import DottedNameResolver -from z3c.form import field -from zope.interface import Interface -from zope.lifecycleevent import ObjectCreatedEvent -from zope.schema import Int -from pyams_content import _ - - -@adapter_config(context=(IWfTopic, IContentManagementMenu), provides=IMenuHeader) -class TopicContentMenuHeader(ContextRequestAdapter): - """Topic content menu header adapter""" - - header = _("This topic") +from pyams_workflow.interfaces import IWorkflowInfo, IWorkflowVersions +from pyams_zmi.layer import IAdminLayer @viewlet_config(name='add-topic.menu', context=ISiteContainer, layer=IAdminLayer, view=Interface, diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/site/zmi/container.py --- a/src/pyams_content/shared/site/zmi/container.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/site/zmi/container.py Fri Oct 05 10:44:32 2018 +0200 @@ -15,67 +15,65 @@ # import standard library import json - from datetime import datetime +from pyramid.exceptions import NotFound +from pyramid.location import lineage +from pyramid.view import view_config +from z3c.form import field +from z3c.table.column import GetAttrColumn +from z3c.table.interfaces import IColumn, IValues +from zope.interface import implementer +from zope.intid.interfaces import IIntIds +from zope.lifecycleevent import ObjectMovedEvent + +from pyams_content import _ # import interfaces -from pyams_content.interfaces import MANAGE_SITE_PERMISSION, MANAGE_CONTENT_PERMISSION +from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION, MANAGE_SITE_PERMISSION from pyams_content.shared.common.interfaces import ISharedContent from pyams_content.shared.common.interfaces.zmi import IDashboardTable -from pyams_content.shared.site.interfaces import ISiteContainer, ISiteManager, IContentLink +from pyams_content.shared.common.zmi.dashboard import SharedToolDashboardOwnerColumn, SharedToolDashboardSequenceColumn, \ + SharedToolDashboardStatusColumn, SharedToolDashboardStatusDateColumn, SharedToolDashboardStatusPrincipalColumn, \ + SharedToolDashboardVersionColumn +# import packages +from pyams_content.shared.site import WfSiteTopic +from pyams_content.shared.site.interfaces import IContentLink, ISiteContainer, ISiteManager +from pyams_content.skin import pyams_content from pyams_content.skin.zmi.interfaces import ISiteTreeMenu, ISiteTreeTable, IUserAddingsMenuLabel +from pyams_form.form import ajax_config from pyams_i18n.interfaces import II18n +from pyams_pagelet.pagelet import pagelet_config +from pyams_skin.container import ContainerView, delete_container_element +from pyams_skin.event import get_json_table_cell_refresh_event from pyams_skin.interfaces import IInnerPage, IPageHeader from pyams_skin.interfaces.container import ITableElementEditor, ITableElementName, ITableWithActions from pyams_skin.interfaces.viewlet import IBreadcrumbItem, ITableItemColumnActionsMenu from pyams_skin.layer import IPyAMSLayer +from pyams_skin.page import DefaultPageHeaderAdapter +from pyams_skin.table import BaseTable, DefaultElementEditorAdapter, I18nColumn, JsActionColumn, NameColumn, \ + SorterColumn, TrashColumn +from pyams_skin.viewlet.breadcrumb import BreadcrumbAdminLayerItem +from pyams_skin.viewlet.menu import MenuItem +from pyams_skin.viewlet.toolbar import ToolbarMenuItem +from pyams_utils.adapter import ContextRequestAdapter, ContextRequestViewAdapter, adapter_config +from pyams_utils.fanstatic import get_resource_path from pyams_utils.interfaces import VIEW_SYSTEM_PERMISSION from pyams_utils.interfaces.traversing import IPathElements -from pyams_workflow.interfaces import IWorkflowVersions, IWorkflowPublicationInfo -from pyams_zmi.interfaces.menu import ISiteManagementMenu, IPropertiesMenu -from pyams_zmi.layer import IAdminLayer -from z3c.table.interfaces import IColumn, IValues -from zope.intid.interfaces import IIntIds - -# import packages -from pyams_content.shared.site import WfTopic -from pyams_content.shared.common.zmi.dashboard import SharedToolDashboardSequenceColumn, \ - SharedToolDashboardStatusColumn, SharedToolDashboardVersionColumn, SharedToolDashboardStatusDateColumn, \ - SharedToolDashboardStatusPrincipalColumn, SharedToolDashboardOwnerColumn -from pyams_content.skin import pyams_content -from pyams_form.form import ajax_config -from pyams_pagelet.pagelet import pagelet_config -from pyams_skin.container import ContainerView, delete_container_element -from pyams_skin.event import get_json_table_cell_refresh_event -from pyams_skin.page import DefaultPageHeaderAdapter -from pyams_skin.table import BaseTable, TrashColumn, DefaultElementEditorAdapter, NameColumn, SorterColumn, \ - JsActionColumn, I18nColumn -from pyams_skin.viewlet.breadcrumb import BreadcrumbItem -from pyams_skin.viewlet.menu import MenuItem -from pyams_skin.viewlet.toolbar import ToolbarMenuItem -from pyams_utils.adapter import adapter_config, ContextRequestViewAdapter, ContextRequestAdapter -from pyams_utils.fanstatic import get_resource_path from pyams_utils.registry import get_utility from pyams_utils.timezone import tztime from pyams_utils.traversing import get_parent from pyams_utils.url import absolute_url from pyams_viewlet.manager import viewletmanager_config from pyams_viewlet.viewlet import viewlet_config +from pyams_workflow.interfaces import IWorkflowPublicationInfo, IWorkflowVersions from pyams_zmi.form import AdminDialogEditForm +from pyams_zmi.interfaces.menu import IPropertiesMenu, ISiteManagementMenu +from pyams_zmi.layer import IAdminLayer from pyams_zmi.view import AdminView -from pyramid.exceptions import NotFound -from pyramid.location import lineage -from pyramid.view import view_config -from z3c.form import field -from z3c.table.column import GetAttrColumn -from zope.interface import implementer, Interface -from zope.lifecycleevent import ObjectMovedEvent - -from pyams_content import _ @adapter_config(context=(ISiteContainer, IAdminLayer), provides=IBreadcrumbItem) -class SiteContainerBreadcrumbAdapter(BreadcrumbItem): +class SiteContainerBreadcrumbAdapter(BreadcrumbAdminLayerItem): """Site container breadcrumb adapter""" @property @@ -90,7 +88,7 @@ @property def label(self): return '{content} ({blog})'.format( - content=self.request.localizer.translate(WfTopic.content_name), + content=self.request.localizer.translate(WfSiteTopic.content_name), blog=II18n(self.context).query_attribute('title', request=self.request)) @@ -332,9 +330,10 @@ icon_class = 'fa-eye opacity-75' else: icon_class = 'fa-eye-slash text-danger opaque' - return ''.format( - icon_class=icon_class, - title=self.request.localizer.translate(self.get_icon_hint(item))) + return ''.format( + icon_class=icon_class, + title=self.request.localizer.translate(self.get_icon_hint(item))) def get_icon_hint(self, item): translate = self.request.localizer.translate @@ -393,12 +392,12 @@ ' ' \ '   {title}' \ ''.format( - padding='' * depth, - hint=self.request.localizer.translate(_("Click to show/hide inner folders")), - switch='fa-{state}-square-o switch'.format( - state=self.table.rows_state or ('minus' if item in lineage(self.context) else 'plus')) - if ISiteContainer.providedBy(item) else '', - title=name or super(SiteContainerTreeNameColumn, self).renderCell(item)) + padding='' * depth, + hint=self.request.localizer.translate(_("Click to show/hide inner folders")), + switch='fa-{state}-square-o switch'.format( + state=self.table.rows_state or ('minus' if item in lineage(self.context) else 'plus')) + if ISiteContainer.providedBy(item) else '', + title=name or super(SiteContainerTreeNameColumn, self).renderCell(item)) @adapter_config(name='content-type', context=(ISiteContainer, IPyAMSLayer, ISiteTreeTable), provides=IColumn) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/site/zmi/folder.py --- a/src/pyams_content/shared/site/zmi/folder.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/site/zmi/folder.py Fri Oct 05 10:44:32 2018 +0200 @@ -9,33 +9,31 @@ # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # -from pyams_form.group import NamedWidgetsGroup -from pyams_form.interfaces.form import IInnerSubForm __docformat__ = 'restructuredtext' +from pyramid.events import subscriber +from pyramid.path import DottedNameResolver +from z3c.form import field +from z3c.form.interfaces import IDataExtractedEvent +from zope.interface import Interface, Invalid +from zope.intid.interfaces import IIntIds +from zope.schema import Text, Int -# import standard library - -# import interfaces from pyams_content.interfaces import MANAGE_SITE_PERMISSION, MANAGE_TOOL_PERMISSION from pyams_content.shared.common.interfaces import IBaseSharedTool +from pyams_content.shared.common.zmi.manager import SharedToolPropertiesEditForm from pyams_content.shared.site.interfaces import ISiteContainer, ISiteManager, ISiteFolder +from pyams_content.shared.site.zmi.widget import SiteManagerFoldersSelectorFieldWidget +from pyams_form.form import AJAXAddForm, ajax_config +from pyams_form.group import NamedWidgetsGroup +from pyams_form.interfaces.form import IInnerSubForm from pyams_i18n.interfaces import INegotiator, II18n +from pyams_i18n.schema import I18nTextLineField +from pyams_pagelet.pagelet import pagelet_config from pyams_skin.interfaces.container import ITableElementName, ITableElementEditor from pyams_skin.interfaces.viewlet import IToolbarAddingMenu, IMenuHeader from pyams_skin.layer import IPyAMSLayer -from pyams_zmi.interfaces.menu import ISiteManagementMenu -from pyams_zmi.layer import IAdminLayer -from z3c.form.interfaces import IDataExtractedEvent -from zope.intid.interfaces import IIntIds - -# import packages -from pyams_content.shared.common.zmi.manager import SharedToolPropertiesEditForm -from pyams_content.shared.site.zmi.widget import SiteManagerFoldersSelectorFieldWidget -from pyams_form.form import AJAXAddForm, ajax_config -from pyams_i18n.schema import I18nTextLineField -from pyams_pagelet.pagelet import pagelet_config from pyams_skin.table import DefaultElementEditorAdapter from pyams_skin.viewlet.toolbar import ToolbarMenuItem from pyams_utils.adapter import adapter_config, ContextRequestAdapter @@ -45,11 +43,8 @@ from pyams_utils.url import absolute_url from pyams_viewlet.viewlet import viewlet_config from pyams_zmi.form import AdminDialogAddForm, InnerAdminEditForm -from pyramid.events import subscriber -from pyramid.path import DottedNameResolver -from z3c.form import field -from zope.interface import Interface, Invalid -from zope.schema import Text, Int +from pyams_zmi.interfaces.menu import ISiteManagementMenu +from pyams_zmi.layer import IAdminLayer from pyams_content import _ @@ -189,8 +184,8 @@ legend = _("Site folder properties") - fields = field.Fields(ISiteFolder).select('title', 'short_name', 'heading', 'notepad') + \ - field.Fields(IBaseSharedTool).select('shared_content_workflow') + fields = field.Fields(ISiteFolder).select('title', 'short_name', 'heading', 'description', 'notepad') + \ + field.Fields(IBaseSharedTool).select('shared_content_workflow') @adapter_config(name='navigation', context=(ISiteFolder, IPyAMSLayer, SiteFolderPropertiesEditForm), @@ -223,5 +218,5 @@ legend=self.main_group_legend, css_class=self.main_group_class, switch=True, - display_mode='auto')) + display_mode='always')) super(SiteFolderNavigationPropertiesEditForm, self).updateGroups() diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/site/zmi/manager.py --- a/src/pyams_content/shared/site/zmi/manager.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/site/zmi/manager.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,42 +12,38 @@ __docformat__ = 'restructuredtext' - -# import standard library +from pyramid.events import subscriber +from pyramid.path import DottedNameResolver +from z3c.form import field +from z3c.form.interfaces import IDataExtractedEvent +from zope.interface import Interface, Invalid -# import interfaces -from pyams_content.interfaces import MANAGE_SITE_ROOT_PERMISSION +from pyams_content import _ +from pyams_content.interfaces import MANAGE_SITE_ROOT_PERMISSION, MANAGE_TOOL_PERMISSION from pyams_content.root.interfaces import ISiteRoot +from pyams_content.shared.common import IBaseSharedTool +from pyams_content.shared.common.zmi.manager import SharedToolPropertiesEditForm +from pyams_content.shared.site import WfSiteTopic from pyams_content.shared.site.interfaces import ISiteManager, ISiteManagerFactory +from pyams_content.shared.site.manager import SiteManager from pyams_content.skin.zmi.interfaces import ISiteTreeTable, IUserAddingsMenuLabel +from pyams_form.form import AJAXAddForm, ajax_config from pyams_i18n.interfaces import II18n, INegotiator +from pyams_pagelet.pagelet import pagelet_config from pyams_skin.interfaces.container import ITableElementEditor, ITableElementName -from pyams_skin.interfaces.viewlet import IToolbarAddingMenu, IBreadcrumbItem, IMenuHeader +from pyams_skin.interfaces.viewlet import IBreadcrumbItem, IMenuHeader, IToolbarAddingMenu from pyams_skin.layer import IPyAMSLayer -from pyams_zmi.interfaces.menu import ISiteManagementMenu -from pyams_zmi.layer import IAdminLayer -from z3c.form.interfaces import IDataExtractedEvent - -# import packages -from pyams_content.shared.site import WfTopic -from pyams_content.shared.site.manager import SiteManager -from pyams_form.form import AJAXAddForm, ajax_config -from pyams_pagelet.pagelet import pagelet_config from pyams_skin.table import DefaultElementEditorAdapter -from pyams_skin.viewlet.breadcrumb import BreadcrumbItem +from pyams_skin.viewlet.breadcrumb import BreadcrumbAdminLayerItem from pyams_skin.viewlet.toolbar import ToolbarMenuItem -from pyams_utils.adapter import adapter_config, ContextRequestAdapter +from pyams_utils.adapter import ContextRequestAdapter, adapter_config from pyams_utils.registry import query_utility from pyams_utils.unicode import translate_string from pyams_utils.url import absolute_url from pyams_viewlet.viewlet import viewlet_config from pyams_zmi.form import AdminDialogAddForm -from pyramid.events import subscriber -from pyramid.path import DottedNameResolver -from z3c.form import field -from zope.interface import Invalid, Interface - -from pyams_content import _ +from pyams_zmi.interfaces.menu import ISiteManagementMenu +from pyams_zmi.layer import IAdminLayer @adapter_config(context=(ISiteManager, ISiteManagementMenu), provides=IMenuHeader) @@ -57,8 +53,8 @@ header = _("Site management") -@adapter_config(context=(ISiteManager, IPyAMSLayer), provides=IBreadcrumbItem) -class SiteManagerBreadcrumbAdapter(BreadcrumbItem): +@adapter_config(context=(ISiteManager, IAdminLayer), provides=IBreadcrumbItem) +class SiteManagerBreadcrumbAdapter(BreadcrumbAdminLayerItem): """Site manager breadcrumb adapter""" @property @@ -100,7 +96,7 @@ @property def label(self): return '{content} ({site})'.format( - content=self.request.localizer.translate(WfTopic.content_name), + content=self.request.localizer.translate(WfSiteTopic.content_name), site=II18n(self.context).query_attribute('title', request=self.request)) @@ -146,6 +142,17 @@ return absolute_url(self.context, self.request, 'site-tree.html') +@pagelet_config(name='properties.html', context=ISiteManager, layer=IPyAMSLayer, permission=MANAGE_TOOL_PERMISSION) +@ajax_config(name='properties.json', context=ISiteManager, layer=IPyAMSLayer) +class SiteManagerPropertiesEditForm(SharedToolPropertiesEditForm): + """Site manager properties edit form""" + + legend = _("Site folder properties") + + fields = field.Fields(ISiteManager).select('title', 'short_name', 'description', 'notepad') + \ + field.Fields(IBaseSharedTool).select('shared_content_workflow') + + @subscriber(IDataExtractedEvent, form_selector=SiteManagerAddForm) def handle_new_site_manager_data_extraction(event): """Handle new site manager data extraction""" diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/topic/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/topic/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -0,0 +1,49 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + +from zope.interface import implementer, provider + +from pyams_content.component.illustration.interfaces import IIllustrationTarget, ILinkIllustrationTarget +from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget +from pyams_content.component.theme.interfaces import ITagsTarget, IThemesTarget +from pyams_content.features.preview.interfaces import IPreviewTarget +from pyams_content.features.review.interfaces import IReviewTarget +from pyams_content.shared.common import SharedContent, WfSharedContent, register_content_type +from pyams_content.shared.common.interfaces import IWfSharedContentFactory +from pyams_content.shared.topic.interfaces import ITopic, IWfTopic, IWfTopicFactory, TOPIC_CONTENT_NAME, \ + TOPIC_CONTENT_TYPE +from pyams_utils.adapter import adapter_config + + +@implementer(IWfTopic, IIllustrationTarget, ILinkIllustrationTarget, IParagraphContainerTarget, + ITagsTarget, IThemesTarget, IPreviewTarget, IReviewTarget) +class WfTopic(WfSharedContent): + """Base topic""" + + content_type = TOPIC_CONTENT_TYPE + content_name = TOPIC_CONTENT_NAME + + +register_content_type(WfTopic) + + +@provider(IWfTopicFactory) +@implementer(ITopic) +class Topic(SharedContent): + """Workflow managed topic class""" + + +@adapter_config(context=IWfTopicFactory, provides=IWfSharedContentFactory) +def topic_content_factory(context): + return WfTopic diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/topic/interfaces/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/topic/interfaces/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -0,0 +1,43 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + +from zope.interface import Interface + +from pyams_content import _ +from pyams_content.shared.common.interfaces import ISharedContent, ISharedToolPortalContext, \ + IWfSharedContentPortalContext + + +TOPIC_CONTENT_TYPE = 'topic' +TOPIC_CONTENT_NAME = _("Topic") + + +class ITopicManager(ISharedToolPortalContext): + """Topic manager interface""" + + +class ITopicManagerFactory(Interface): + """Topic manager factory interface""" + + +class IWfTopic(IWfSharedContentPortalContext): + """Topic interface""" + + +class IWfTopicFactory(Interface): + """Topic parent interface""" + + +class ITopic(ISharedContent): + """Workflow managed topic interface""" diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/topic/manager.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/topic/manager.py Fri Oct 05 10:44:32 2018 +0200 @@ -0,0 +1,62 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + +from pyramid.events import subscriber +from zope.component.interfaces import ISite +from zope.interface import implementer +from zope.lifecycleevent.interfaces import IObjectAddedEvent +from zope.schema.fieldproperty import FieldProperty + +from pyams_content.component.paragraph.interfaces import IParagraphFactorySettings +from pyams_content.component.theme.interfaces import IThemesManagerTarget +from pyams_content.reference.pictograms.interfaces import IPictogramManagerTarget +from pyams_content.shared.common.interfaces import ISharedContentFactory +from pyams_content.shared.common.manager import SharedTool +from pyams_content.shared.topic import Topic +from pyams_content.shared.topic.interfaces import ITopicManager, ITopicManagerFactory, TOPIC_CONTENT_TYPE +from pyams_utils.adapter import adapter_config +from pyams_utils.registry import utility_config +from pyams_utils.traversing import get_parent + + +@implementer(ITopicManager, IParagraphFactorySettings, IThemesManagerTarget, IPictogramManagerTarget) +class TopicManager(SharedTool): + """Topic manager class""" + + shared_content_type = TOPIC_CONTENT_TYPE + + allowed_paragraphs = FieldProperty(IParagraphFactorySettings['allowed_paragraphs']) + auto_created_paragraphs = FieldProperty(IParagraphFactorySettings['auto_created_paragraphs']) + + +@utility_config(provides=ITopicManagerFactory) +class TopicManagerFactory(object): + """Default topic manager factory""" + + def __new__(cls): + return TopicManager + + +@adapter_config(context=ITopicManager, provides=ISharedContentFactory) +def topic_manager_content_factory(context): + return Topic + + +@subscriber(IObjectAddedEvent, context_selector=ITopicManager) +def handle_added_topic_manager(event): + """Register topic manager when added""" + site = get_parent(event.newParent, ISite) + registry = site.getSiteManager() + if registry is not None: + registry.registerUtility(event.object, ITopicManager) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/topic/zmi/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pyams_content/shared/topic/zmi/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -0,0 +1,74 @@ +# +# Copyright (c) 2008-2015 Thierry Florac +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# + +__docformat__ = 'restructuredtext' + +from pyramid.view import view_config +from zope.interface import Interface + +from pyams_content import _ +from pyams_content.interfaces import CREATE_CONTENT_PERMISSION +from pyams_content.shared.common.zmi import SharedContentAJAXAddForm, SharedContentAddForm +from pyams_content.shared.topic.interfaces import ITopicManager, IWfTopic +from pyams_i18n.interfaces import II18n +from pyams_pagelet.pagelet import pagelet_config +from pyams_skin.interfaces import IContentTitle +from pyams_skin.interfaces.viewlet import IMenuHeader, IWidgetTitleViewletManager +from pyams_skin.layer import IPyAMSLayer +from pyams_skin.viewlet.toolbar import ToolbarAction +from pyams_utils.adapter import ContextRequestAdapter, ContextRequestViewAdapter, adapter_config +from pyams_viewlet.viewlet import viewlet_config +from pyams_zmi.interfaces.menu import IContentManagementMenu +from pyams_zmi.layer import IAdminLayer + + +@adapter_config(context=(IWfTopic, IContentManagementMenu), provides=IMenuHeader) +class TopicContentMenuHeader(ContextRequestAdapter): + """Topic content menu header adapter""" + + header = _("This topic") + + +@adapter_config(context=(IWfTopic, IPyAMSLayer, Interface), provides=IContentTitle) +class TopicTitleAdapter(ContextRequestViewAdapter): + """Topic title adapter""" + + @property + def title(self): + translate = self.request.localizer.translate + return translate(_("Topic « {title} »")).format( + title=II18n(self.context).query_attribute('title', request=self.request)) + + +@viewlet_config(name='add-shared-content.action', context=ITopicManager, layer=IAdminLayer, view=Interface, + manager=IWidgetTitleViewletManager, permission=CREATE_CONTENT_PERMISSION, weight=1) +class TopicAddAction(ToolbarAction): + """Topic adding action""" + + label = _("Add topic") + label_css_class = 'fa fa-fw fa-plus' + url = 'add-shared-content.html' + modal_target = True + + +@pagelet_config(name='add-shared-content.html', context=ITopicManager, layer=IPyAMSLayer, + permission=CREATE_CONTENT_PERMISSION) +class TopicAddForm(SharedContentAddForm): + """Topic add form""" + + legend = _("Add topic") + + +@view_config(name='add-shared-content.json', context=ITopicManager, request_type=IPyAMSLayer, + permission=CREATE_CONTENT_PERMISSION, renderer='json', xhr=True) +class TopicAJAXAddForm(SharedContentAJAXAddForm, TopicAddForm): + """Topic add form, JSON renderer""" diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/view/__init__.py --- a/src/pyams_content/shared/view/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/view/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,40 +12,36 @@ __docformat__ = 'restructuredtext' - -# import standard library import logging logger = logging.getLogger("PyAMS (content)") from datetime import datetime from itertools import tee -# import interfaces +from hypatia.catalog import CatalogQuery from hypatia.interfaces import ICatalog +from hypatia.query import Any, Gt, Lt +from pyramid.events import subscriber +from pyramid.threadlocal import get_current_registry +from zope.interface import implementer, provider +from zope.intid.interfaces import IIntIds +from zope.lifecycleevent.interfaces import IObjectModifiedEvent +from zope.schema.fieldproperty import FieldProperty + +from pyams_cache.beaker import get_cache +from pyams_catalog.query import CatalogResultSet, or_ from pyams_content.features.preview.interfaces import IPreviewTarget from pyams_content.features.review.interfaces import IReviewTarget +from pyams_content.shared.common import WfSharedContent, register_content_type, SharedContent, IWfSharedContentFactory from pyams_content.shared.common.interfaces.types import IWfTypedSharedContent from pyams_content.shared.view.interfaces import IView, IWfView, IWfViewFactory, IViewQuery, \ IViewQueryParamsExtension, IViewQueryFilterExtension, VIEW_CONTENT_TYPE, VIEW_CONTENT_NAME, IViewSettings +from pyams_utils.adapter import adapter_config, ContextAdapter from pyams_utils.interfaces import ICacheKeyValue -from zope.intid.interfaces import IIntIds -from zope.lifecycleevent.interfaces import IObjectModifiedEvent - -# import packages -from hypatia.catalog import CatalogQuery -from hypatia.query import Any, Gt, Lt -from pyams_cache.beaker import get_cache -from pyams_catalog.query import CatalogResultSet, or_ -from pyams_content.shared.common import WfSharedContent, register_content_type, SharedContent, IWfSharedContentFactory -from pyams_utils.adapter import adapter_config, ContextAdapter from pyams_utils.list import unique_iter from pyams_utils.registry import get_utility, get_global_registry from pyams_utils.timezone import tztime from pyams_workflow.interfaces import IWorkflow -from pyramid.events import subscriber -from pyramid.threadlocal import get_current_registry -from zope.interface import implementer, provider -from zope.schema.fieldproperty import FieldProperty VIEWS_CACHE_REGION = 'views' @@ -64,7 +60,9 @@ content_type = VIEW_CONTENT_TYPE content_name = VIEW_CONTENT_NAME + handle_content_url = False handle_header = False + handle_description = False select_context_type = FieldProperty(IWfView['select_context_type']) selected_content_types = FieldProperty(IWfView['selected_content_types']) @@ -138,6 +136,7 @@ logger.debug("Retrieving view items from cache key {0}".format(cache_key)) return results + register_content_type(WfView) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/view/interfaces/__init__.py --- a/src/pyams_content/shared/view/interfaces/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/view/interfaces/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -24,7 +24,7 @@ # import packages from pyams_thesaurus.schema import ThesaurusTermsListField from zope.interface import Interface, Attribute -from zope.schema import List, Set, Choice, Bool, Int +from zope.schema import Set, Choice, Bool, Int from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm from pyams_content import _ @@ -41,7 +41,7 @@ VIEW_ORDERS = ( {'id': CREATION_DATE_ORDER, 'title': _("Creation date")}, - {'id': UPDATE_DATE_ORDER,'title': _("Last update date")}, + {'id': UPDATE_DATE_ORDER, 'title': _("Last update date")}, {'id': PUBLICATION_DATE_ORDER, 'title': _("Current publication date")}, {'id': FIRSTPUBLICATION_DATE_ORDER, 'title': _("First publication date")} ) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/view/portlet/__init__.py --- a/src/pyams_content/shared/view/portlet/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/view/portlet/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,27 +12,23 @@ __docformat__ = 'restructuredtext' - -# import standard library from itertools import islice -# import interfaces -from pyams_content.shared.view.interfaces import IViewsMerger, IViewsManager +from zope.interface import implementer +from zope.schema.fieldproperty import FieldProperty + +from pyams_content.shared.view.interfaces import IViewsManager, IViewsMerger from pyams_content.shared.view.portlet.interfaces import IViewItemsPortletSettings, VIEW_DISPLAY_CONTEXT from pyams_portal.interfaces import PREVIEW_MODE +from pyams_portal.portlet import Portlet, PortletSettings, portlet_config +from pyams_sequence.reference import get_sequence_target +from pyams_utils.factory import factory_config from pyams_utils.interfaces import VIEW_PERMISSION from pyams_utils.interfaces.url import DISPLAY_CONTEXT -from pyams_workflow.interfaces import IWorkflow - -# import packages -from pyams_portal.portlet import PortletSettings, portlet_config, Portlet -from pyams_sequence.reference import get_sequence_target -from pyams_utils.factory import factory_config from pyams_utils.list import unique_iter from pyams_utils.registry import get_utility from pyams_utils.request import check_request -from zope.interface import implementer -from zope.schema.fieldproperty import FieldProperty +from pyams_workflow.interfaces import IWorkflow from pyams_content import _ @@ -50,6 +46,7 @@ views_context = FieldProperty(IViewItemsPortletSettings['views_context']) views_merge_mode = FieldProperty(IViewItemsPortletSettings['views_merge_mode']) limit = FieldProperty(IViewItemsPortletSettings['limit']) + start = FieldProperty(IViewItemsPortletSettings['start']) def get_views(self): views_manager = get_utility(IViewsManager) @@ -78,6 +75,7 @@ yield from islice(unique_iter(merger.get_results(self.get_views(), context, ignore_cache=ignore_cache)), + (self.start or 1) - 1, self.limit) diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/view/portlet/interfaces.py --- a/src/pyams_content/shared/view/portlet/interfaces.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/view/portlet/interfaces.py Fri Oct 05 10:44:32 2018 +0200 @@ -92,5 +92,10 @@ description=_("Maximum number of results that the component may extract from merged views"), required=False) + start = Int(title=_("Starting from..."), + description=_("You can skip several results if specifying an integer value here..."), + required=False, + default=1) + def get_items(self): """Get iterator over items returned by selected views, using selected merger""" diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/view/portlet/zmi/templates/view-items-list-preview.pt --- a/src/pyams_content/shared/view/portlet/zmi/templates/view-items-list-preview.pt Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/view/portlet/zmi/templates/view-items-list-preview.pt Fri Oct 05 10:44:32 2018 +0200 @@ -4,14 +4,22 @@ tal:condition="title">
- - - No result found - No selected view - +
+ Selected views: + none + + ${i18n:view.title}, + +
+
+ Extracted contents: + none (no selected view) + +
diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/shared/view/reference.py --- a/src/pyams_content/shared/view/reference.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/shared/view/reference.py Fri Oct 05 10:44:32 2018 +0200 @@ -24,7 +24,7 @@ # import packages from hypatia.catalog import CatalogQuery -from hypatia.query import Any, Not, NotEq +from hypatia.query import Any, NotEq from pyams_catalog.query import CatalogResultSet, and_ from pyams_content.workflow import VISIBLE_STATES from pyams_utils.adapter import adapter_config, ContextAdapter, get_annotation_adapter @@ -87,6 +87,6 @@ if (not items) or (settings.references_mode == ALWAYS_REFERENCE_MODE): catalog = get_utility(ICatalog) params = Any(catalog['oid'], settings.references) & \ - Any(catalog['workflow_state'], VISIBLE_STATES) + Any(catalog['workflow_state'], VISIBLE_STATES) items.prepend(CatalogResultSet(CatalogQuery(catalog).query(params))) return items diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/site.py --- a/src/pyams_content/site.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/site.py Fri Oct 05 10:44:32 2018 +0200 @@ -12,19 +12,15 @@ __docformat__ = 'restructuredtext' - -# import standard library import transaction - -# import interfaces +from ZODB.interfaces import IBroken from hypatia.interfaces import ICatalog +from zope.interface import Interface from zope.intid.interfaces import IIntIds -# import packages from pyams_utils.container import find_objects_providing from pyams_utils.registry import set_local_registry, get_utility from pyams_utils.site import site_factory -from zope.interface import Interface def site_index(request): @@ -38,10 +34,13 @@ transaction.savepoint() intids = get_utility(IIntIds) for index, document in enumerate(find_objects_providing(application, Interface)): - print("Indexing: {0!r}".format(document)) - catalog.reindex_doc(intids.register(document), document) - if not index % 100: - transaction.savepoint() + if IBroken.providedBy(document): + print("Skipping broken object: {0!r}".format(document)) + else: + print("Indexing: {0!r}".format(document)) + catalog.reindex_doc(intids.register(document), document) + if not index % 100: + transaction.savepoint() finally: set_local_registry(None) transaction.commit() diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/skin/resources/js/pyams_content.js --- a/src/pyams_content/skin/resources/js/pyams_content.js Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/skin/resources/js/pyams_content.js Fri Oct 05 10:44:32 2018 +0200 @@ -164,6 +164,21 @@ */ galleries: { + addMediaCallback: function(options) { + var gallery = $('.gallery', $('[id="' + options.parent + '"]')); + var switcher = gallery.siblings('.switcher'); + if (switcher.parents('fieldset:first').hasClass('switched')) { + switcher.click(); + } + for (var i=0; i < options.medias.length; i++) { + gallery.append(options.medias[i]); + } + gallery.sortable({ + helper: 'clone', + stop: PyAMS_content.galleries.setOrder + }) + }, + updateMediaTitle: function(options) { $('img[id="' + options.media_id + '"]').attr('original-title', options.title); }, @@ -215,6 +230,9 @@ {object_name: object_name}, function(result, status) { media.remove(); + if (result.handle_json) { + MyAMS.ajax.handleJSON(result); + } }); } }); diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/skin/resources/js/pyams_content.min.js --- a/src/pyams_content/skin/resources/js/pyams_content.min.js Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/skin/resources/js/pyams_content.min.js Fri Oct 05 10:44:32 2018 +0200 @@ -1,1 +1,1 @@ -!function(t,e){"use strict";var a=e.MyAMS,i={widget:{treeview:{selectFolder:function(e,a){t(e.target).siblings('input[type="hidden"]').val(a.id)},unselectFolder:function(e,a){t(e.target).siblings('input[type="hidden"]').val(null)}}},TinyMCE:{initEditor:function(t){return tinyMCE.addI18n("fr",{"Link list":"Liste de liens","Toggle h3 header":"En-tête H3","Toggle h4 header":"En-tête H4","Insert internal link":"Insérer un lien interne","Link title":"Texte à afficher","Internal number":"N° interne"}),tinymce.PluginManager.add("internal_links",function(t,e){t.addButton("internal_links",{icon:"cloud-check",tooltip:"Insert internal link",image:"/--static--/pyams_content/img/internal-link.png",onclick:function(){t.windowManager.open({title:"Insert internal link",body:[{type:"textbox",name:"oid",label:"Internal number"},{type:"textbox",name:"title",label:"Link title",value:t.selection.getContent()}],onsubmit:function(e){t.insertContent(''+e.data.title+"")}})}})}),tinyMCE.PluginManager.add("headers",function(t,e){["h3","h4"].forEach(function(e){t.addButton("header-"+e,{tooltip:"Toggle "+e+" header",text:e.toUpperCase(),onClick:function(){t.execCommand("mceToggleFormat",!1,e)},onPostRender:function(){var a=this,i=function(){t.formatter.formatChanged(e,function(t){a.active(t)})};t.formatter?i():t.on("init",i)}})})}),t.image_list=i.TinyMCE.getImagesList,t.link_list=i.TinyMCE.getLinksList,t.style_formats=[{title:"Inline",items:[{title:"Bold",icon:"bold",format:"bold"},{title:"Italic",icon:"italic",format:"italic"},{title:"Underline",icon:"underline",format:"underline"},{title:"Strikethrough",icon:"strikethrough",format:"strikethrough"},{title:"Superscript",icon:"superscript",format:"superscript"},{title:"Subscript",icon:"subscript",format:"subscript"},{title:"Code",icon:"code",format:"code"}]},{title:"Blocks",items:[{title:"Paragraph",format:"p"},{title:"Blockquote",format:"blockquote"},{title:"Div",format:"div"},{title:"Pre",format:"pre"}]},{title:"Alignment",items:[{title:"Left",icon:"alignleft",format:"alignleft"},{title:"Center",icon:"aligncenter",format:"aligncenter"},{title:"Right",icon:"alignright",format:"alignright"},{title:"Justify",icon:"alignjustify",format:"alignjustify"}]}],t.plugins+=" internal_links headers",t.toolbar1&&(t.toolbar1="undo redo | header-h3 header-h4 styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent"),t.toolbar2&&(t.toolbar2="forecolor backcolor | charmap internal_links link | fullscreen preview print | code"),t},getImagesList:function(e){var i=t(document.activeElement).parents("form");if(i.exists()){var n=i.attr("data-ams-form-handler")||i.attr("action"),s=n.substr(0,n.lastIndexOf("/")+1);return a.ajax.post(s+"get-images-list.json",{},e)}},getLinksList:function(e){var i=t(document.activeElement).parents("form");if(i.exists()){var n=i.attr("data-ams-form-handler")||i.attr("action"),s=n.substr(0,n.lastIndexOf("/")+1);return a.ajax.post(s+"get-links-list.json",{},e)}}},galleries:{updateMediaTitle:function(e){t('img[id="'+e.media_id+'"]').attr("original-title",e.title)},switchMediaVisibility:function(e){return function(){var e=t(this),i=e.parents(".media"),n=i.parents(".gallery");t("i",e).attr("class","fa fa-fw fa-spinner fa-pulse"),a.ajax.post(n.data("ams-location")+"/set-media-visibility.json",{object_name:i.data("ams-element-name")},function(a,i){a.visible?(t("i",e).attr("class","fa fa-fw fa-eye"),e.parents(".btn-group").siblings("a.fancyimg").removeClass("not-visible")):(t("i",e).attr("class","fa fa-fw fa-eye-slash text-danger"),e.parents(".btn-group").siblings("a.fancyimg").addClass("not-visible"))})}},setOrder:function(e,i){if(!i||!i.item.hasClass("already-dropped")){var n=i.item.parents(".gallery"),s=t(".media",n).listattr("data-ams-element-name");a.ajax.post(n.data("ams-location")+"/set-medias-order.json",{medias:JSON.stringify(s)})}},removeMedia:function(e){return function(){var e=t(this);a.skin.bigBox({title:a.i18n.WARNING,content:'  '+a.i18n.DELETE_WARNING,buttons:a.i18n.BTN_OK_CANCEL},function(t){if(t===a.i18n.BTN_OK){var i=e.parents(".gallery").data("ams-location"),n=e.parents(".media"),s=n.data("ams-element-name");a.ajax.post(i+"/delete-element.json",{object_name:s},function(t,e){n.remove()})}})}},afterFancyboxLoad:function(t,e){t.element.hasClass("not-visible")&&t.inner.prepend('
')}},paragraphs:{preReload:function(){i.paragraphs.switched=t("i.switch.fa-minus-square-o","#paragraphs_list").parents("tr").listattr("id")},postReload:function(){t(i.paragraphs.switched).each(function(){t("i.switch.fa-plus-square-o",'[id="'+this+'"]').parents("div").first().click()}),delete i.paragraphs.switched},refreshParagraph:function(e){var a=t('tr[id="'+e.object_id+'"]');t("span.title",a).html(e.title||" - - - - - - - -")},switchEditor:function(e){var i=t(this),n=t("i.switch",i),s=i.parents("td"),r=t(".editor",s),o=i.parents("tr");if(n.hasClass("fa-plus-square-o")){var l=o.parents("table");r.html('

'),a.ajax.post(l.data("ams-location")+"/get-paragraph-editor.json",{object_name:o.data("ams-element-name")},function(t){r.html(t),t&&(a.initContent(r),n.removeClass("fa-plus-square-o").addClass("fa-minus-square-o"),o.data("ams-disabled-handlers",!0),a.skin.scrollTo(r,{offset:r.height()-o.height()}))})}else a.skin.cleanContainer(r),r.empty(),n.removeClass("fa-minus-square-o").addClass("fa-plus-square-o"),o.removeData("ams-disabled-handlers")},switchLastEditor:function(e){var a=t('table[id="'+e+'"]'),i=t("tr:last",a);t('[data-ams-click-handler="PyAMS_content.paragraphs.switchEditor"]',i).click()},switchAllEditors:function(e){var i=t(this),n=t("i",i),s=i.parents("table");n.hasClass("fa-plus-square-o")?(n.removeClass("fa-plus-square-o").addClass("fa-cog fa-spin"),a.ajax.post(s.data("ams-location")+"/get-paragraphs-editors.json",{},function(e){for(var i in e)if(e.hasOwnProperty(i)){var r=t('tr[data-ams-element-name="'+i+'"]',s),o=t(".editor",r);o.is(":empty")&&o.html(e[i]),t(".fa-plus-square-o",r).removeClass("fa-plus-square-o").addClass("fa-minus-square-o"),r.data("ams-disabled-handlers",!0)}t("i.fa-plus-square-o",t("tbody",s)).exists()||n.removeClass("fa-cog fa-spin").addClass("fa-minus-square-o"),a.initContent(s)})):(t(".editor",s).each(function(){a.skin.cleanContainer(t(this)),t(this).empty()}),t(".fa-minus-square-o",s).removeClass("fa-minus-square-o").addClass("fa-plus-square-o"),t("tr",s).removeData("ams-disabled-handlers"))},updateToolbar:function(e){var i=t('tr[id="'+e.object_id+'"]'),n=t(".title-toolbar",i);n.replaceWith(e.toolbar_tag),n=t(".title-toolbar",i),a.initContent(n)},updateMarkers:function(e){var i=t('tr[id="'+e.object_id+'"]'),n=t(".title-toolbar",i),s=t("DIV.action."+e.marker_type,n);s.exists()?s.replaceWith(e.marker_tag):t(e.marker_tag).appendTo(n),e.marker_tag&&(s=t("DIV.action."+e.marker_type,n),a.initContent(s)),a.helpers.sort(n,"weight")}},pictograms:{initManagerSelection:function(){var e=t(this),a=t('input[type="hidden"]',t(".selected-pictograms",e)).listattr("value");return{selected:JSON.stringify(a)}},switchPictogram:function(){var e=t(this),a=e.parents(".pictograms"),i=a.parents(".pictograms-manager");a.hasClass("available-pictograms")?t(".selected-pictograms",i).append(e):t(".available-pictograms",i).append(e)}},themes:{initExtracts:function(e){var i=t('select[name="manager_themes.widgets.thesaurus_name:list"]',e).val(),n=t('select[name="manager_themes.widgets.extract_name:list"]',e),s=n.val();i&&a.jsonrpc.post("getExtracts",{thesaurus_name:i},{url:"/api/thesaurus/json"},function(e){n.empty(),t(e.result).each(function(){t("").attr("value",this.id).attr("selected",this.id===s).text(this.text).appendTo(n)})})},getExtracts:function(e){var i=t(e.currentTarget).parents("form"),n=t('select[name="manager_themes.widgets.thesaurus_name:list"]',i).val(),s=t('select[name="manager_themes.widgets.extract_name:list"]',i),r=s.data("select2");n&&"--NOVALUE--"!==n?a.jsonrpc.post("getExtracts",{thesaurus_name:n},{url:"/api/thesaurus/json"},function(t){r.results.empty(),r.opts.populateResults.call(r,r.results,t.result,{term:""})}):(s.select2("data",null),r.results.empty(),r.opts.populateResults.call(r,r.results,[],{term:""}))}},fields:{refreshField:function(e){var a=t('table[id="form_fields_list"]'),i=t('tr[data-ams-element-name="'+e.object_name+'"]',a);t("td:nth-child(4)",i).html(e.title)}},imgmap:{init:function(){var e=t(this);a.ajax.check(t.fn.canvasAreaDraw,"/--static--/pyams_content/js/jquery-canvasAreaDraw"+a.devext+".js",function(){e.canvasAreaDraw({imageUrl:e.data("ams-image-url")})})},initPreview:function(){var e=t(this);a.ajax.check(t.fn.mapster,"/--static--/pyams_content/js/jquery-imagemapster-1.2.10"+a.devext+".js",function(){e.mapster({fillColor:"ff0000",fillOpacity:.35,selected:!0,highlight:!0,staticState:!0})})}},site:{switchVisibility:function(){return function(){var e=t(this),i=e.parents("tr").first();a.ajax.post(i.data("ams-location")+"/switch-content-visibility.json",{object_name:i.data("ams-element-name")},function(a,i){var n="fa-eye";a.visible||(n+="-slash"),a.published||(n+=" text-danger"),t("i",e).attr("class","fa fa-fw "+n)})}}},review:{timer:null,timer_duration:{general:3e4,chat:5e3},initComments:function(e){var n=t(".chat-body",e);n.animate({scrollTop:n[0].scrollHeight},1e3),clearInterval(i.review.timer),i.review.timer=setInterval(i.review.updateComments,i.review.timer_duration.chat),a.skin.registerCleanCallback(i.review.cleanCommentsCallback)},cleanCommentsCallback:function(){clearInterval(i.review.timer),i.review.timer=setInterval(i.review.updateComments,i.review.timer_duration.general)},updateComments:function(){var e,i=t(".badge",'nav a[href="#review-comments.html"]'),n=t(".chat-body",".widget-body");e=n.exists()?t(".message",n).length:parseInt(i.text()),a.ajax.post("get-last-review-comments.json",{count:e},function(a){n.exists()&&i.removeClass("bg-color-danger").addClass("bg-color-info"),e!==a.count&&(i.text(a.count).removeClass("hidden"),n.exists()&&(t(".messages",n).append(a.content),n.animate({scrollTop:n[0].scrollHeight},1e3)),n.exists()||i.removeClass("bg-color-info").addClass("bg-color-danger").animate({padding:"3px 12px 2px","margin-right":"9px"},"slow",function(){t(this).animate({padding:"3px 6px 2px","margin-right":"15px"},"slow")}))})},initCommentData:function(e){var a=t(".chat-body",".widget-body");return{count:t(".message",a).length}},addCommentAction:function(){return function(){t('textarea[name="comment"]').focus()}},addCommentCallback:function(e){var a=t(this),i=a.parents(".widget-body");t(".messages",i).append(e.content),t('textarea[name="comment"]',a).val("");var n=t(".chat-body",i);n.animate({scrollTop:n[0].scrollHeight},1e3),t(".badge",'nav a[href="#review-comments.html"]').text(e.count).removeClass("hidden")}},header:{submitEditForm:function(){var e=t(this).parents("form").first();a.form.submit(e,{form_data:{autosubmit:!0}})}},footer:{submitEditForm:function(){var e=t(this).parents("form").first();a.form.submit(e,{form_data:{autosubmit:!0}})}},profile:{switchFavorite:function(){var e=t(this),i=e.data("sequence-oid");a.ajax.post("switch-user-favorite.json",{oid:i},function(t,a){t.favorite?e.removeClass("fa-star-o").addClass("fa-star"):e.removeClass("fa-star").addClass("fa-star-o")})}}};t(".badge",'nav a[href="#review-comments.html"]').exists()&&(i.review.timer=setInterval(i.review.updateComments,i.review.timer_duration.general)),e.PyAMS_content=i}(jQuery,this); +!function(t,e){"use strict";var a=e.MyAMS,i={widget:{treeview:{selectFolder:function(e,a){t(e.target).siblings('input[type="hidden"]').val(a.id)},unselectFolder:function(e,a){t(e.target).siblings('input[type="hidden"]').val(null)}}},TinyMCE:{initEditor:function(t){return tinyMCE.addI18n("fr",{"Link list":"Liste de liens","Toggle h3 header":"En-tête H3","Toggle h4 header":"En-tête H4","Insert internal link":"Insérer un lien interne","Link title":"Texte à afficher","Internal number":"N° interne"}),tinymce.PluginManager.add("internal_links",function(t,e){t.addButton("internal_links",{icon:"cloud-check",tooltip:"Insert internal link",image:"/--static--/pyams_content/img/internal-link.png",onclick:function(){t.windowManager.open({title:"Insert internal link",body:[{type:"textbox",name:"oid",label:"Internal number"},{type:"textbox",name:"title",label:"Link title",value:t.selection.getContent()}],onsubmit:function(e){t.insertContent(''+e.data.title+"")}})}})}),tinyMCE.PluginManager.add("headers",function(t,e){["h3","h4"].forEach(function(e){t.addButton("header-"+e,{tooltip:"Toggle "+e+" header",text:e.toUpperCase(),onClick:function(){t.execCommand("mceToggleFormat",!1,e)},onPostRender:function(){var a=this,i=function(){t.formatter.formatChanged(e,function(t){a.active(t)})};t.formatter?i():t.on("init",i)}})})}),t.image_list=i.TinyMCE.getImagesList,t.link_list=i.TinyMCE.getLinksList,t.style_formats=[{title:"Inline",items:[{title:"Bold",icon:"bold",format:"bold"},{title:"Italic",icon:"italic",format:"italic"},{title:"Underline",icon:"underline",format:"underline"},{title:"Strikethrough",icon:"strikethrough",format:"strikethrough"},{title:"Superscript",icon:"superscript",format:"superscript"},{title:"Subscript",icon:"subscript",format:"subscript"},{title:"Code",icon:"code",format:"code"}]},{title:"Blocks",items:[{title:"Paragraph",format:"p"},{title:"Blockquote",format:"blockquote"},{title:"Div",format:"div"},{title:"Pre",format:"pre"}]},{title:"Alignment",items:[{title:"Left",icon:"alignleft",format:"alignleft"},{title:"Center",icon:"aligncenter",format:"aligncenter"},{title:"Right",icon:"alignright",format:"alignright"},{title:"Justify",icon:"alignjustify",format:"alignjustify"}]}],t.plugins+=" internal_links headers",t.toolbar1&&(t.toolbar1="undo redo | header-h3 header-h4 styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent"),t.toolbar2&&(t.toolbar2="forecolor backcolor | charmap internal_links link | fullscreen preview print | code"),t},getImagesList:function(e){var i=t(document.activeElement).parents("form");if(i.exists()){var n=i.attr("data-ams-form-handler")||i.attr("action"),s=n.substr(0,n.lastIndexOf("/")+1);return a.ajax.post(s+"get-images-list.json",{},e)}},getLinksList:function(e){var i=t(document.activeElement).parents("form");if(i.exists()){var n=i.attr("data-ams-form-handler")||i.attr("action"),s=n.substr(0,n.lastIndexOf("/")+1);return a.ajax.post(s+"get-links-list.json",{},e)}}},galleries:{addMediaCallback:function(e){var a=t(".gallery",t('[id="'+e.parent+'"]')),n=a.siblings(".switcher");n.parents("fieldset:first").hasClass("switched")&&n.click();for(var s=0;s  '+a.i18n.DELETE_WARNING,buttons:a.i18n.BTN_OK_CANCEL},function(t){if(t===a.i18n.BTN_OK){var i=e.parents(".gallery").data("ams-location"),n=e.parents(".media"),s=n.data("ams-element-name");a.ajax.post(i+"/delete-element.json",{object_name:s},function(t,e){n.remove(),t.handle_json&&a.ajax.handleJSON(t)})}})}},afterFancyboxLoad:function(t,e){t.element.hasClass("not-visible")&&t.inner.prepend('
')}},paragraphs:{preReload:function(){i.paragraphs.switched=t("i.switch.fa-minus-square-o","#paragraphs_list").parents("tr").listattr("id")},postReload:function(){t(i.paragraphs.switched).each(function(){t("i.switch.fa-plus-square-o",'[id="'+this+'"]').parents("div").first().click()}),delete i.paragraphs.switched},refreshParagraph:function(e){var a=t('tr[id="'+e.object_id+'"]');t("span.title",a).html(e.title||" - - - - - - - -")},switchEditor:function(e){var i=t(this),n=t("i.switch",i),s=i.parents("td"),r=t(".editor",s),o=i.parents("tr");if(n.hasClass("fa-plus-square-o")){var l=o.parents("table");r.html('

'),a.ajax.post(l.data("ams-location")+"/get-paragraph-editor.json",{object_name:o.data("ams-element-name")},function(t){r.html(t),t&&(a.initContent(r),n.removeClass("fa-plus-square-o").addClass("fa-minus-square-o"),o.data("ams-disabled-handlers",!0),a.skin.scrollTo(r,{offset:r.height()-o.height()}))})}else a.skin.cleanContainer(r),r.empty(),n.removeClass("fa-minus-square-o").addClass("fa-plus-square-o"),o.removeData("ams-disabled-handlers")},switchLastEditor:function(e){var a=t('table[id="'+e+'"]'),i=t("tr:last",a);t('[data-ams-click-handler="PyAMS_content.paragraphs.switchEditor"]',i).click()},switchAllEditors:function(e){var i=t(this),n=t("i",i),s=i.parents("table");n.hasClass("fa-plus-square-o")?(n.removeClass("fa-plus-square-o").addClass("fa-cog fa-spin"),a.ajax.post(s.data("ams-location")+"/get-paragraphs-editors.json",{},function(e){for(var i in e)if(e.hasOwnProperty(i)){var r=t('tr[data-ams-element-name="'+i+'"]',s),o=t(".editor",r);o.is(":empty")&&o.html(e[i]),t(".fa-plus-square-o",r).removeClass("fa-plus-square-o").addClass("fa-minus-square-o"),r.data("ams-disabled-handlers",!0)}t("i.fa-plus-square-o",t("tbody",s)).exists()||n.removeClass("fa-cog fa-spin").addClass("fa-minus-square-o"),a.initContent(s)})):(t(".editor",s).each(function(){a.skin.cleanContainer(t(this)),t(this).empty()}),t(".fa-minus-square-o",s).removeClass("fa-minus-square-o").addClass("fa-plus-square-o"),t("tr",s).removeData("ams-disabled-handlers"))},updateToolbar:function(e){var i=t('tr[id="'+e.object_id+'"]'),n=t(".title-toolbar",i);n.replaceWith(e.toolbar_tag),n=t(".title-toolbar",i),a.initContent(n)},updateMarkers:function(e){var i=t('tr[id="'+e.object_id+'"]'),n=t(".title-toolbar",i),s=t("DIV.action."+e.marker_type,n);s.exists()?s.replaceWith(e.marker_tag):t(e.marker_tag).appendTo(n),e.marker_tag&&(s=t("DIV.action."+e.marker_type,n),a.initContent(s)),a.helpers.sort(n,"weight")}},pictograms:{initManagerSelection:function(){var e=t(this),a=t('input[type="hidden"]',t(".selected-pictograms",e)).listattr("value");return{selected:JSON.stringify(a)}},switchPictogram:function(){var e=t(this),a=e.parents(".pictograms"),i=a.parents(".pictograms-manager");a.hasClass("available-pictograms")?t(".selected-pictograms",i).append(e):t(".available-pictograms",i).append(e)}},themes:{initExtracts:function(e){var i=t('select[name="manager_themes.widgets.thesaurus_name:list"]',e).val(),n=t('select[name="manager_themes.widgets.extract_name:list"]',e),s=n.val();i&&a.jsonrpc.post("getExtracts",{thesaurus_name:i},{url:"/api/thesaurus/json"},function(e){n.empty(),t(e.result).each(function(){t("").attr("value",this.id).attr("selected",this.id===s).text(this.text).appendTo(n)})})},getExtracts:function(e){var i=t(e.currentTarget).parents("form"),n=t('select[name="manager_themes.widgets.thesaurus_name:list"]',i).val(),s=t('select[name="manager_themes.widgets.extract_name:list"]',i),r=s.data("select2");n&&"--NOVALUE--"!==n?a.jsonrpc.post("getExtracts",{thesaurus_name:n},{url:"/api/thesaurus/json"},function(t){r.results.empty(),r.opts.populateResults.call(r,r.results,t.result,{term:""})}):(s.select2("data",null),r.results.empty(),r.opts.populateResults.call(r,r.results,[],{term:""}))}},fields:{refreshField:function(e){var a=t('table[id="form_fields_list"]'),i=t('tr[data-ams-element-name="'+e.object_name+'"]',a);t("td:nth-child(4)",i).html(e.title)}},imgmap:{init:function(){var e=t(this);a.ajax.check(t.fn.canvasAreaDraw,"/--static--/pyams_content/js/jquery-canvasAreaDraw"+a.devext+".js",function(){e.canvasAreaDraw({imageUrl:e.data("ams-image-url")})})},initPreview:function(){var e=t(this);a.ajax.check(t.fn.mapster,"/--static--/pyams_content/js/jquery-imagemapster-1.2.10"+a.devext+".js",function(){e.mapster({fillColor:"ff0000",fillOpacity:.35,selected:!0,highlight:!0,staticState:!0})})}},site:{switchVisibility:function(){return function(){var e=t(this),i=e.parents("tr").first();a.ajax.post(i.data("ams-location")+"/switch-content-visibility.json",{object_name:i.data("ams-element-name")},function(a,i){var n="fa-eye";a.visible||(n+="-slash"),a.published||(n+=" text-danger"),t("i",e).attr("class","fa fa-fw "+n)})}}},review:{timer:null,timer_duration:{general:3e4,chat:5e3},initComments:function(e){var n=t(".chat-body",e);n.animate({scrollTop:n[0].scrollHeight},1e3),clearInterval(i.review.timer),i.review.timer=setInterval(i.review.updateComments,i.review.timer_duration.chat),a.skin.registerCleanCallback(i.review.cleanCommentsCallback)},cleanCommentsCallback:function(){clearInterval(i.review.timer),i.review.timer=setInterval(i.review.updateComments,i.review.timer_duration.general)},updateComments:function(){var e,i=t(".badge",'nav a[href="#review-comments.html"]'),n=t(".chat-body",".widget-body");e=n.exists()?t(".message",n).length:parseInt(i.text()),a.ajax.post("get-last-review-comments.json",{count:e},function(a){n.exists()&&i.removeClass("bg-color-danger").addClass("bg-color-info"),e!==a.count&&(i.text(a.count).removeClass("hidden"),n.exists()&&(t(".messages",n).append(a.content),n.animate({scrollTop:n[0].scrollHeight},1e3)),n.exists()||i.removeClass("bg-color-info").addClass("bg-color-danger").animate({padding:"3px 12px 2px","margin-right":"9px"},"slow",function(){t(this).animate({padding:"3px 6px 2px","margin-right":"15px"},"slow")}))})},initCommentData:function(e){var a=t(".chat-body",".widget-body");return{count:t(".message",a).length}},addCommentAction:function(){return function(){t('textarea[name="comment"]').focus()}},addCommentCallback:function(e){var a=t(this),i=a.parents(".widget-body");t(".messages",i).append(e.content),t('textarea[name="comment"]',a).val("");var n=t(".chat-body",i);n.animate({scrollTop:n[0].scrollHeight},1e3),t(".badge",'nav a[href="#review-comments.html"]').text(e.count).removeClass("hidden")}},header:{submitEditForm:function(){var e=t(this).parents("form").first();a.form.submit(e,{form_data:{autosubmit:!0}})}},footer:{submitEditForm:function(){var e=t(this).parents("form").first();a.form.submit(e,{form_data:{autosubmit:!0}})}},profile:{switchFavorite:function(){var e=t(this),i=e.data("sequence-oid");a.ajax.post("switch-user-favorite.json",{oid:i},function(t,a){t.favorite?e.removeClass("fa-star-o").addClass("fa-star"):e.removeClass("fa-star").addClass("fa-star-o")})}}};t(".badge",'nav a[href="#review-comments.html"]').exists()&&(i.review.timer=setInterval(i.review.updateComments,i.review.timer_duration.general)),e.PyAMS_content=i}(jQuery,this); diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/skin/zmi/viewlet/toplinks/__init__.py --- a/src/pyams_content/skin/zmi/viewlet/toplinks/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/skin/zmi/viewlet/toplinks/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -9,32 +9,29 @@ # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # +import locale + __docformat__ = 'restructuredtext' -# import standard library +from hypatia.catalog import CatalogQuery +from hypatia.interfaces import ICatalog +from hypatia.query import And, Any, NotEq, Or -# import interfaces -from hypatia.interfaces import ICatalog +from pyams_catalog.query import CatalogResultSet +from pyams_content import _ from pyams_content.shared.common.interfaces import IBaseSharedTool, ISharedSite from pyams_content.skin.zmi.interfaces import IUserAddingsMenuLabel from pyams_i18n.interfaces import II18n from pyams_skin.interfaces.viewlet import ITopLinksViewletManager -from pyams_zmi.layer import IAdminLayer - -# import packages -from hypatia.catalog import CatalogQuery -from hypatia.query import Any, And, Or, NotEq -from pyams_catalog.query import CatalogResultSet -from pyams_skin.viewlet.toplinks import TopLinksViewlet, TopLinksMenu +from pyams_skin.viewlet.toplinks import TopLinksMenu, TopLinksViewlet from pyams_template.template import template_config from pyams_utils.list import unique -from pyams_utils.registry import get_utility, get_all_utilities_registered_for +from pyams_utils.registry import get_all_utilities_registered_for, get_utility from pyams_utils.url import absolute_url from pyams_viewlet.viewlet import viewlet_config - -from pyams_content import _ +from pyams_zmi.layer import IAdminLayer @viewlet_config(name='shared-sites.menu', layer=IAdminLayer, manager=ITopLinksViewletManager, weight=20) @@ -51,7 +48,7 @@ request = self.request parent = self.__parent__ for site in sorted(get_all_utilities_registered_for(ISharedSite), - key=lambda x: II18n(x).query_attribute('title', request=request) or ''): + key=lambda x: locale.strxfrm(II18n(x).query_attribute('title', request=request) or '')): menu = TopLinksMenu(context, request, parent, self) menu.label = II18n(site).query_attribute('title', request=request) or site.__name__ menu.url = absolute_url(site, request, 'admin#dashboard.html') @@ -72,7 +69,7 @@ request = self.request parent = self.__parent__ for tool in sorted(get_all_utilities_registered_for(IBaseSharedTool), - key=lambda x: II18n(x).query_attribute('title', request=request) or ''): + key=lambda x: locale.strxfrm(II18n(x).query_attribute('title', request=request) or '')): if ISharedSite.providedBy(tool) or (not tool.shared_content_menu): continue menu = TopLinksMenu(context, request, parent, self) @@ -95,7 +92,7 @@ request = self.request parent = self.__parent__ for tool in sorted(get_all_utilities_registered_for(IBaseSharedTool), - key=lambda x: II18n(x).query_attribute('title', request=request) or ''): + key=lambda x: locale.strxfrm(II18n(x).query_attribute('title', request=request) or '')): if ISharedSite.providedBy(tool) or tool.shared_content_menu: continue menu = TopLinksMenu(context, request, parent, self) @@ -123,7 +120,7 @@ Any(catalog['role:pilot'], {request.principal.id})), NotEq(catalog['content_type'], None)) for tool in sorted(unique(CatalogResultSet(CatalogQuery(catalog).query(params))), - key=lambda x: II18n(x).query_attribute('title', request=request) or ''): + key=lambda x: locale.strxfrm(II18n(x).query_attribute('title', request=request) or '')): menu = TopLinksMenu(context, request, parent, self) menu.label = II18n(tool).query_attribute('title', request=request) or tool.__name__ menu.url = absolute_url(tool, request, 'admin#dashboard.html') @@ -149,7 +146,7 @@ params = And(Any(catalog['role:contributor'], {request.principal.id}), NotEq(catalog['content_type'], None)) for tool in sorted(unique(CatalogResultSet(CatalogQuery(catalog).query(params))), - key=lambda x: II18n(x).query_attribute('title', request=request) or ''): + key=lambda x: locale.strxfrm(II18n(x).query_attribute('title', request=request) or '')): content_class = tool.shared_content_factory.content_class if content_class is None: continue diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/tests/test_utilsdocs.py --- a/src/pyams_content/tests/test_utilsdocs.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/tests/test_utilsdocs.py Fri Oct 05 10:44:32 2018 +0200 @@ -23,6 +23,7 @@ current_dir = os.path.dirname(__file__) + def doc_suite(test_dir, setUp=None, tearDown=None, globs=None): """Returns a test suite, based on doctests found in /doctest.""" suite = [] @@ -50,10 +51,12 @@ return unittest.TestSuite(suite) + def test_suite(): """returns the test suite""" return doc_suite(current_dir) + if __name__ == '__main__': unittest.main(defaultTest='test_suite') diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/tests/test_utilsdocstrings.py --- a/src/pyams_content/tests/test_utilsdocstrings.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/tests/test_utilsdocstrings.py Fri Oct 05 10:44:32 2018 +0200 @@ -23,6 +23,7 @@ current_dir = os.path.abspath(os.path.dirname(__file__)) + def doc_suite(test_dir, globs=None): """Returns a test suite, based on doc tests strings found in /*.py""" suite = [] @@ -54,9 +55,11 @@ return unittest.TestSuite(suite) + def test_suite(): """returns the test suite""" return doc_suite(current_dir) + if __name__ == '__main__': unittest.main(defaultTest='test_suite') diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/workflow/__init__.py --- a/src/pyams_content/workflow/__init__.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/workflow/__init__.py Fri Oct 05 10:44:32 2018 +0200 @@ -152,9 +152,9 @@ # can't create new version when previous draft already exists versions = IWorkflowVersions(context) if (versions.has_version(DRAFT) or - versions.has_version(PROPOSED) or - versions.has_version(CANCELED) or - versions.has_version(REFUSED)): + versions.has_version(PROPOSED) or + versions.has_version(CANCELED) or + versions.has_version(REFUSED)): return False request = check_request() # grant access to webmaster @@ -246,7 +246,8 @@ for version in IWorkflowVersions(context).get_versions((PUBLISHED, RETIRING, RETIRED, ARCHIVING)): if version is not context: IWorkflowInfo(version).fire_transition_toward(ARCHIVED, - comment=translate(_("Published version {0}")).format(version_id)) + comment=translate(_("Published version {0}")).format( + version_id)) def archive_action(wf, context): diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/workflow/basic.py --- a/src/pyams_content/workflow/basic.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/workflow/basic.py Fri Oct 05 10:44:32 2018 +0200 @@ -157,7 +157,8 @@ for version in IWorkflowVersions(context).get_versions((PUBLISHED, )): if version is not context: IWorkflowInfo(version).fire_transition_toward(ARCHIVED, - comment=translate(_("Published version {0}")).format(version_id)) + comment=translate(_("Published version {0}")).format( + version_id)) def archive_action(wf, context): diff -r 8a7ec586dce1 -r f50be61c93a6 src/pyams_content/workflow/task.py --- a/src/pyams_content/workflow/task.py Thu Sep 06 18:10:04 2018 +0200 +++ b/src/pyams_content/workflow/task.py Fri Oct 05 10:44:32 2018 +0200 @@ -55,8 +55,8 @@ for tool in get_all_utilities_registered_for(IBaseSharedTool): workflow = IWorkflow(tool) params = Eq(catalog['parents'], intids.register(tool)) & \ - Any(catalog['workflow_state'], workflow.published_states) & \ - Lt(catalog['expiration_date'], now) + Any(catalog['workflow_state'], workflow.published_states) & \ + Lt(catalog['expiration_date'], now) for content in CatalogResultSet(CatalogQuery(catalog).query(params)): if not has_retired: report.write(translate(_("Automatic contents withdrawal:\n")))