src/pyams_content/shared/common/zmi/__init__.py
changeset 1358 c682811fa1ea
parent 1146 2477f95cf149
child 1394 ed31bfceddda
equal deleted inserted replaced
1357:329116e5f8e3 1358:c682811fa1ea
     7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
     7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
     8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
     9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
    10 # FOR A PARTICULAR PURPOSE.
    10 # FOR A PARTICULAR PURPOSE.
    11 #
    11 #
    12 
       
    13 __docformat__ = 'restructuredtext'
       
    14 
    12 
    15 from datetime import datetime
    13 from datetime import datetime
    16 from uuid import uuid4
    14 from uuid import uuid4
    17 
    15 
    18 from pyramid.location import lineage
    16 from pyramid.location import lineage
    22 from zope.interface import Interface
    20 from zope.interface import Interface
    23 from zope.lifecycleevent import ObjectCreatedEvent
    21 from zope.lifecycleevent import ObjectCreatedEvent
    24 from zope.location import locate
    22 from zope.location import locate
    25 
    23 
    26 from pyams_content.features.review.interfaces import IReviewComments
    24 from pyams_content.features.review.interfaces import IReviewComments
    27 from pyams_content.interfaces import CREATE_CONTENT_PERMISSION, MANAGE_CONTENT_PERMISSION, MANAGE_SITE_ROOT_PERMISSION, \
    25 from pyams_content.interfaces import CREATE_CONTENT_PERMISSION, MANAGE_CONTENT_PERMISSION, \
    28     PUBLISH_CONTENT_PERMISSION
    26     MANAGE_SITE_ROOT_PERMISSION, PUBLISH_CONTENT_PERMISSION
    29 from pyams_content.shared.common.interfaces import IBaseSharedTool, IManagerRestrictions, ISharedContent, \
    27 from pyams_content.shared.common.interfaces import IBaseSharedTool, IContributorRestrictions, \
    30     IWfSharedContent
    28     IManagerRestrictions, ISharedContent, IWfSharedContent
    31 from pyams_form.form import AJAXAddForm, ajax_config
    29 from pyams_form.form import AJAXAddForm, ajax_config
    32 from pyams_form.interfaces.form import IFormContextPermissionChecker, IWidgetsPrefixViewletsManager
    30 from pyams_form.interfaces.form import IFormContextPermissionChecker, IWidgetsPrefixViewletsManager
    33 from pyams_form.schema import CloseButton
    31 from pyams_form.schema import CloseButton
    34 from pyams_i18n.interfaces import II18n, II18nManager, INegotiator
    32 from pyams_i18n.interfaces import II18n, II18nManager, INegotiator
    35 from pyams_i18n.widget import I18nSEOTextLineFieldWidget
    33 from pyams_i18n.widget import I18nSEOTextLineFieldWidget
    42 from pyams_skin.page import DefaultPageHeaderAdapter
    40 from pyams_skin.page import DefaultPageHeaderAdapter
    43 from pyams_skin.table import DefaultElementEditorAdapter
    41 from pyams_skin.table import DefaultElementEditorAdapter
    44 from pyams_skin.viewlet.breadcrumb import BreadcrumbAdminLayerItem
    42 from pyams_skin.viewlet.breadcrumb import BreadcrumbAdminLayerItem
    45 from pyams_skin.viewlet.toolbar import ToolbarMenuDivider, ToolbarMenuItem
    43 from pyams_skin.viewlet.toolbar import ToolbarMenuDivider, ToolbarMenuItem
    46 from pyams_template.template import template_config
    44 from pyams_template.template import template_config
    47 from pyams_utils.adapter import ContextAdapter, ContextRequestAdapter, ContextRequestViewAdapter, adapter_config
    45 from pyams_utils.adapter import ContextAdapter, ContextRequestAdapter, ContextRequestViewAdapter, \
       
    46     adapter_config
    48 from pyams_utils.interfaces import FORBIDDEN_PERMISSION
    47 from pyams_utils.interfaces import FORBIDDEN_PERMISSION
    49 from pyams_utils.registry import get_utility
    48 from pyams_utils.registry import get_utility
    50 from pyams_utils.request import check_request
    49 from pyams_utils.request import check_request
    51 from pyams_utils.traversing import get_parent
    50 from pyams_utils.traversing import get_parent
    52 from pyams_utils.url import absolute_url, generate_url
    51 from pyams_utils.url import absolute_url, generate_url
    53 from pyams_viewlet.viewlet import Viewlet, viewlet_config
    52 from pyams_viewlet.viewlet import Viewlet, viewlet_config
    54 from pyams_workflow.interfaces import IWorkflow, IWorkflowCommentInfo, IWorkflowInfo, IWorkflowPublicationInfo, \
    53 from pyams_workflow.interfaces import IWorkflow, IWorkflowCommentInfo, IWorkflowInfo, \
    55     IWorkflowState, IWorkflowVersions
    54     IWorkflowPublicationInfo, IWorkflowState, IWorkflowVersions
    56 from pyams_workflow.versions import WorkflowHistoryItem
    55 from pyams_workflow.versions import WorkflowHistoryItem
    57 from pyams_zmi.form import AdminDialogAddForm
    56 from pyams_zmi.form import AdminDialogAddForm
    58 from pyams_zmi.interfaces.menu import ISiteManagementMenu
    57 from pyams_zmi.interfaces.menu import ISiteManagementMenu
    59 from pyams_zmi.layer import IAdminLayer
    58 from pyams_zmi.layer import IAdminLayer
       
    59 
       
    60 
       
    61 __docformat__ = 'restructuredtext'
    60 
    62 
    61 from pyams_content import _
    63 from pyams_content import _
    62 
    64 
    63 
    65 
    64 class SharedContentAddForm(AdminDialogAddForm):
    66 class SharedContentAddForm(AdminDialogAddForm):
   106         self.context[uuid] = content
   108         self.context[uuid] = content
   107         IWorkflowVersions(content).add_version(wf_content, None)
   109         IWorkflowVersions(content).add_version(wf_content, None)
   108         IWorkflowInfo(wf_content).fire_transition('init', comment=wf_content.notepad)
   110         IWorkflowInfo(wf_content).fire_transition('init', comment=wf_content.notepad)
   109 
   111 
   110     def nextURL(self):
   112     def nextURL(self):
   111         return absolute_url(self.context, self.request, '{0}/++versions++/1/admin#properties.html'.format(self.__uuid))
   113         return absolute_url(self.context, self.request,
       
   114                             '{0}/++versions++/1/admin#properties.html'.format(self.__uuid))
   112 
   115 
   113 
   116 
   114 class SharedContentAJAXAddForm(AJAXAddForm):
   117 class SharedContentAJAXAddForm(AJAXAddForm):
   115     """Shared event add form, JSON renderer"""
   118     """Shared event add form, JSON renderer"""
   116 
   119 
   119             'status': 'redirect',
   122             'status': 'redirect',
   120             'location': self.nextURL()
   123             'location': self.nextURL()
   121         }
   124         }
   122 
   125 
   123 
   126 
   124 @viewlet_config(name='wf-create-message', context=Interface, layer=IPyAMSLayer, view=SharedContentAddForm,
   127 @viewlet_config(name='wf-create-message', context=Interface, layer=IPyAMSLayer,
       
   128                 view=SharedContentAddForm,
   125                 manager=IWidgetsPrefixViewletsManager, weight=20)
   129                 manager=IWidgetsPrefixViewletsManager, weight=20)
   126 @template_config(template='templates/wf-create-message.pt')
   130 @template_config(template='templates/wf-create-message.pt')
   127 class SharedContentAddFormMessage(Viewlet):
   131 class SharedContentAddFormMessage(Viewlet):
   128     """Shared content add form info message"""
   132     """Shared content add form info message"""
   129 
   133 
   151 
   155 
   152     @property
   156     @property
   153     def edit_permission(self):
   157     def edit_permission(self):
   154         workflow = IWorkflow(self.context)
   158         workflow = IWorkflow(self.context)
   155         state = IWorkflowState(self.context).state
   159         state = IWorkflowState(self.context).state
   156         if state in workflow.readonly_states:  # access forbidden to all for archived contents
   160         if state in workflow.readonly_states:
       
   161             # forbidden access to all for archived contents
   157             return FORBIDDEN_PERMISSION
   162             return FORBIDDEN_PERMISSION
   158         elif state in workflow.protected_states:  # webmaster can update published contents
   163         elif state in workflow.protected_states:
       
   164             # webmaster can update published contents
   159             return MANAGE_SITE_ROOT_PERMISSION
   165             return MANAGE_SITE_ROOT_PERMISSION
   160         else:
   166         else:
   161             request = check_request()
   167             request = check_request()
   162             if request.has_permission(MANAGE_SITE_ROOT_PERMISSION, self.context):  # webmaster access
   168             if request.has_permission(MANAGE_SITE_ROOT_PERMISSION, self.context):
       
   169                 # webmaster access
   163                 return MANAGE_SITE_ROOT_PERMISSION
   170                 return MANAGE_SITE_ROOT_PERMISSION
   164             principal_id = request.principal.id
   171             principal_id = request.principal.id
   165             if state in workflow.manager_states:  # restricted manager access
   172             if state in workflow.manager_states:
       
   173                 # restricted manager access
   166                 if principal_id in self.context.managers:
   174                 if principal_id in self.context.managers:
   167                     return PUBLISH_CONTENT_PERMISSION
   175                     return PUBLISH_CONTENT_PERMISSION
   168                 for parent in lineage(self.context):
   176                 for parent in lineage(self.context):
   169                     manager_restrictions = IManagerRestrictions(parent, None)
   177                     manager_restrictions = IManagerRestrictions(parent, None)
   170                     if manager_restrictions is not None:
   178                     if manager_restrictions is not None:
   175                                                               request=request):
   183                                                               request=request):
   176                                 return PUBLISH_CONTENT_PERMISSION
   184                                 return PUBLISH_CONTENT_PERMISSION
   177                             else:
   185                             else:
   178                                 return FORBIDDEN_PERMISSION
   186                                 return FORBIDDEN_PERMISSION
   179             else:
   187             else:
   180                 if principal_id in self.context.owner | self.context.contributors | self.context.managers:
   188                 # access is granted  to content's owner and designated contributors or managers
       
   189                 if principal_id in self.context.owner | \
       
   190                                    self.context.contributors | \
       
   191                                    self.context.managers:
   181                     return MANAGE_CONTENT_PERMISSION
   192                     return MANAGE_CONTENT_PERMISSION
       
   193                 # check if current principal can manage owner's contents
       
   194                 for parent in lineage(self.context):
       
   195                     contrib_restrictions = IContributorRestrictions(parent, None)
       
   196                     if contrib_restrictions is not None:
       
   197                         user_restrictions = contrib_restrictions.get_restrictions(principal_id)
       
   198                         if user_restrictions:
       
   199                             if user_restrictions.check_access(self.context,
       
   200                                                               permission=MANAGE_CONTENT_PERMISSION,
       
   201                                                               request=request):
       
   202                                 return MANAGE_CONTENT_PERMISSION
       
   203                 restrictions = IContributorRestrictions(self.context).get_restrictions(principal_id)
       
   204                 if restrictions and restrictions.check_access(self.context,
       
   205                                                               permission=MANAGE_CONTENT_PERMISSION,
       
   206                                                               request=request):
       
   207                     return MANAGE_CONTENT_PERMISSION
       
   208                 # check if current principal can manage content's due to manager restrictions
   182                 for parent in lineage(self.context):
   209                 for parent in lineage(self.context):
   183                     manager_restrictions = IManagerRestrictions(parent, None)
   210                     manager_restrictions = IManagerRestrictions(parent, None)
   184                     if manager_restrictions is not None:
   211                     if manager_restrictions is not None:
   185                         user_restrictions = manager_restrictions.get_restrictions(principal_id)
   212                         user_restrictions = manager_restrictions.get_restrictions(principal_id)
   186                         if user_restrictions:
   213                         if user_restrictions:
   187                             if user_restrictions.check_access(self.context,
   214                             if user_restrictions.check_access(self.context,
   188                                                               permission=MANAGE_CONTENT_PERMISSION,
   215                                                               permission=MANAGE_CONTENT_PERMISSION,
   189                                                               request=request):
   216                                                               request=request):
   190                                 return MANAGE_CONTENT_PERMISSION
   217                                 return MANAGE_CONTENT_PERMISSION
   191                             else:
       
   192                                 return FORBIDDEN_PERMISSION
       
   193                 restrictions = IManagerRestrictions(self.context).get_restrictions(principal_id)
   218                 restrictions = IManagerRestrictions(self.context).get_restrictions(principal_id)
   194                 if restrictions and restrictions.check_access(self.context,
   219                 if restrictions and restrictions.check_access(self.context,
   195                                                               permission=MANAGE_CONTENT_PERMISSION,
   220                                                               permission=MANAGE_CONTENT_PERMISSION,
   196                                                               request=request):
   221                                                               request=request):
   197                     return MANAGE_CONTENT_PERMISSION
   222                     return MANAGE_CONTENT_PERMISSION
   247 #
   272 #
   248 # Duplication menus and views
   273 # Duplication menus and views
   249 #
   274 #
   250 
   275 
   251 @viewlet_config(name='duplication.divider', context=IWfSharedContent, layer=IPyAMSLayer,
   276 @viewlet_config(name='duplication.divider', context=IWfSharedContent, layer=IPyAMSLayer,
   252                 view=Interface, manager=IContextActions, permission=CREATE_CONTENT_PERMISSION, weight=49)
   277                 view=Interface, manager=IContextActions, permission=CREATE_CONTENT_PERMISSION,
       
   278                 weight=49)
   253 class WfSharedContentDuplicationMenuDivider(ToolbarMenuDivider):
   279 class WfSharedContentDuplicationMenuDivider(ToolbarMenuDivider):
   254     """Shared content duplication menu divider"""
   280     """Shared content duplication menu divider"""
   255 
   281 
   256 
   282 
   257 @viewlet_config(name='duplication.menu', context=IWfSharedContent, layer=IPyAMSLayer,
   283 @viewlet_config(name='duplication.menu', context=IWfSharedContent, layer=IPyAMSLayer,
   258                 view=Interface, manager=IContextActions, permission=CREATE_CONTENT_PERMISSION, weight=50)
   284                 view=Interface, manager=IContextActions, permission=CREATE_CONTENT_PERMISSION,
       
   285                 weight=50)
   259 class WfSharedContentDuplicateMenu(ToolbarMenuItem):
   286 class WfSharedContentDuplicateMenu(ToolbarMenuItem):
   260     """Shared content duplication menu item"""
   287     """Shared content duplication menu item"""
   261 
   288 
   262     label = _("Duplicate content...")
   289     label = _("Duplicate content...")
   263     label_css_class = 'fa fa-fw fa-files-o'
   290     label_css_class = 'fa fa-fw fa-files-o'
   324         source_state = IWorkflowState(self.context)
   351         source_state = IWorkflowState(self.context)
   325         state = IWorkflowState(new_version)
   352         state = IWorkflowState(new_version)
   326         state.history.clear()
   353         state.history.clear()
   327         history = WorkflowHistoryItem(date=datetime.utcnow(),
   354         history = WorkflowHistoryItem(date=datetime.utcnow(),
   328                                       principal=self.request.principal.id,
   355                                       principal=self.request.principal.id,
   329                                       comment=translate(_("Clone created from version {source} of {oid} "
   356                                       comment=translate(
   330                                                           "(in « {state} » state)")).format(
   357                                           _("Clone created from version {source} of {oid} "
       
   358                                             "(in « {state} » state)")).format(
   331                                           source=source_state.version_id,
   359                                           source=source_state.version_id,
   332                                           oid=ISequentialIdInfo(self.context).get_short_oid(),
   360                                           oid=ISequentialIdInfo(self.context).get_short_oid(),
   333                                           state=translate(IWorkflow(self.context).get_state_label(source_state.state)))
   361                                           state=translate(IWorkflow(self.context).get_state_label(
       
   362                                               source_state.state)))
   334                                       )
   363                                       )
   335         state.history.append(history)
   364         state.history.append(history)
   336         history = WorkflowHistoryItem(date=datetime.utcnow(),
   365         history = WorkflowHistoryItem(date=datetime.utcnow(),
   337                                       target_state=workflow.initial_state,
   366                                       target_state=workflow.initial_state,
   338                                       principal=self.request.principal.id,
   367                                       principal=self.request.principal.id,
   369                 item_dc = IZopeDublinCore(item)
   398                 item_dc = IZopeDublinCore(item)
   370                 if item_dc.modified and (item_dc.modified > IZopeDublinCore(content).created):
   399                 if item_dc.modified and (item_dc.modified > IZopeDublinCore(content).created):
   371                     translate = self.request.localizer.translate
   400                     translate = self.request.localizer.translate
   372                     value += '<i class="fa fa-fw fa-circle txt-color-orange hint align-middle padding-left-5" ' \
   401                     value += '<i class="fa fa-fw fa-circle txt-color-orange hint align-middle padding-left-5" ' \
   373                              'title="{0}" data-ams-hint-gravity="w"></i>'.format(
   402                              'title="{0}" data-ams-hint-gravity="w"></i>'.format(
   374                                 translate(_("Created or modified in this version")))
   403                         translate(_("Created or modified in this version")))
   375         return value
   404         return value