allow better control of create actions by checking 'AssignAsParent': check action permissions + related fixes
This commit is contained in:
parent
d9a0f39f06
commit
344a1d81e5
12 changed files with 56 additions and 30 deletions
|
@ -2,8 +2,6 @@
|
|||
loops - Linked Objects for Organization and Processing Services
|
||||
===============================================================
|
||||
|
||||
($Id$)
|
||||
|
||||
The loops platform consists up of three basic types of objects:
|
||||
|
||||
(1) concepts: simple interconnected objects usually representing
|
||||
|
@ -612,7 +610,7 @@ Actions
|
|||
>>> view.controller = Controller(view, request)
|
||||
>>> #view.setupController()
|
||||
|
||||
>>> actions = view.getActions('portlet')
|
||||
>>> actions = view.getAllowedActions('portlet')
|
||||
>>> len(actions)
|
||||
2
|
||||
|
||||
|
@ -849,7 +847,7 @@ In order to provide suitable links for viewing or editing a target you may
|
|||
ask a view which view and edit actions it supports. We directly use the
|
||||
target object's view here:
|
||||
|
||||
>>> actions = view.virtualTarget.getActions('object', page=view)
|
||||
>>> actions = view.virtualTarget.getAllowedActions('object', page=view)
|
||||
>>> #actions[0].url
|
||||
|
||||
'http://127.0.0.1/loops/views/m1/m11/m111/.target23'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2012 Helmut Merz helmutm@cy55.de
|
||||
# Copyright (c) 2013 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -129,6 +129,7 @@ actions.register('edit_object', 'portlet', DialogAction,
|
|||
viewName='edit_object.html',
|
||||
dialogName='edit',
|
||||
prerequisites=['registerDojoEditor'],
|
||||
permission='zope.ManageContent',
|
||||
)
|
||||
|
||||
actions.register('edit_concept', 'portlet', DialogAction,
|
||||
|
@ -137,6 +138,7 @@ actions.register('edit_concept', 'portlet', DialogAction,
|
|||
viewName='edit_concept.html',
|
||||
dialogName='edit',
|
||||
prerequisites=['registerDojoEditor'],
|
||||
permission='zope.ManageContent',
|
||||
)
|
||||
|
||||
actions.register('create_concept', 'portlet', DialogAction,
|
||||
|
@ -146,6 +148,7 @@ actions.register('create_concept', 'portlet', DialogAction,
|
|||
dialogName='createConcept',
|
||||
qualifier='create_concept',
|
||||
innerForm='inner_concept_form.html',
|
||||
permission='loops.AssignAsParent',
|
||||
)
|
||||
|
||||
actions.register('create_subtype', 'portlet', DialogAction,
|
||||
|
@ -155,4 +158,5 @@ actions.register('create_subtype', 'portlet', DialogAction,
|
|||
dialogName='createConcept',
|
||||
qualifier='subtype',
|
||||
innerForm='inner_concept_form.html',
|
||||
permission='loops.AssignAsParent',
|
||||
)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2012 Helmut Merz helmutm@cy55.de
|
||||
# Copyright (c) 2013 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -45,7 +45,7 @@ from zope.publisher.browser import applySkin
|
|||
from zope.publisher.interfaces.browser import IBrowserSkinType, IBrowserView
|
||||
from zope import schema
|
||||
from zope.schema.vocabulary import SimpleTerm
|
||||
from zope.security import canAccess, checkPermission
|
||||
from zope.security import canAccess
|
||||
from zope.security.interfaces import ForbiddenAttribute, Unauthorized
|
||||
from zope.security.proxy import removeSecurityProxy
|
||||
from zope.traversing.browser import absoluteURL
|
||||
|
@ -67,6 +67,7 @@ from loops.i18n.browser import I18NView
|
|||
from loops.interfaces import IResource, IView, INode, ITypeConcept
|
||||
from loops.organize.tracking import access
|
||||
from loops.resource import Resource
|
||||
from loops.security.common import checkPermission
|
||||
from loops.security.common import canAccessObject, canListObject, canWriteObject
|
||||
from loops.type import ITypeConcept
|
||||
from loops import util
|
||||
|
@ -706,6 +707,16 @@ class BaseView(GenericView, I18NView):
|
|||
"""
|
||||
return []
|
||||
|
||||
def getAllowedActions(self, category='object', page=None, target=None):
|
||||
result = []
|
||||
for act in self.getActions(category, page=page, target=target):
|
||||
if act.permission is not None:
|
||||
ctx = (target is not None and target.context) or self.context
|
||||
if not checkPermission(act.permission, ctx):
|
||||
continue
|
||||
result.append(act)
|
||||
return result
|
||||
|
||||
@Lazy
|
||||
def showObjectActions(self):
|
||||
return not IUnauthenticatedPrincipal.providedBy(self.request.principal)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2012 Helmut Merz helmutm@cy55.de
|
||||
# Copyright (c) 2013 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -51,17 +51,18 @@ from cybertools.typology.interfaces import IType, ITypeManager
|
|||
from cybertools.util.jeep import Jeep
|
||||
from cybertools.xedit.browser import ExternalEditorView
|
||||
from loops.browser.action import actions, DialogAction
|
||||
from loops.browser.common import BaseView
|
||||
from loops.browser.concept import ConceptView
|
||||
from loops.common import adapted, AdapterBase, baseObject
|
||||
from loops.i18n.browser import i18n_macros, LanguageInfo
|
||||
from loops.interfaces import IConcept, IResource, IDocument, IMediaAsset, INode
|
||||
from loops.interfaces import IViewConfiguratorSchema
|
||||
from loops.resource import MediaAsset
|
||||
from loops import util
|
||||
from loops.util import _
|
||||
from loops.browser.common import BaseView
|
||||
from loops.browser.concept import ConceptView
|
||||
from loops.organize.interfaces import IPresence
|
||||
from loops.organize.tracking import access
|
||||
from loops.resource import MediaAsset
|
||||
from loops.security.common import canWriteObject
|
||||
from loops import util
|
||||
from loops.util import _
|
||||
from loops.versioning.util import getVersion
|
||||
|
||||
|
||||
|
@ -149,13 +150,15 @@ class NodeView(BaseView):
|
|||
priority=20)
|
||||
cm.register('portlet_left', 'navigation', title='Navigation',
|
||||
subMacro=node_macros.macros['menu'])
|
||||
if canWrite(self.context, 'title') or (
|
||||
if canWriteObject(self.context) or (
|
||||
# TODO: is this useful in any case?
|
||||
self.virtualTargetObject is not None and
|
||||
canWrite(self.virtualTargetObject, 'title')):
|
||||
canWriteObject(self.virtualTargetObject)):
|
||||
# check if there are any available actions;
|
||||
# store list of actions in macro object (evaluate only once)
|
||||
actions = [act for act in self.getActions('portlet') if act.condition]
|
||||
actions = [act for act in self.getAllowedActions('portlet',
|
||||
target=self.virtualTarget)
|
||||
if act.condition]
|
||||
if actions:
|
||||
cm.register('portlet_right', 'actions', title=_(u'Actions'),
|
||||
subMacro=node_macros.macros['actions'],
|
||||
|
@ -534,7 +537,7 @@ class NodeView(BaseView):
|
|||
return self.makeTargetUrl(self.url, util.getUidForObject(target),
|
||||
target.title)
|
||||
|
||||
def getActions(self, category='object', target=None):
|
||||
def getActions(self, category='object', page=None, target=None):
|
||||
actions = []
|
||||
#self.registerDojo()
|
||||
self.registerDojoFormAll()
|
||||
|
@ -557,9 +560,11 @@ class NodeView(BaseView):
|
|||
description='Open concept map editor in new window',
|
||||
url=cmeUrl, target=target))
|
||||
if self.checkAction('create_resource', 'portlet', target):
|
||||
actions.append(DialogAction(self, title='Create Resource...',
|
||||
actions.append(DialogAction(self, name='create_resource',
|
||||
title='Create Resource...',
|
||||
description='Create a new resource object.',
|
||||
page=self, target=target))
|
||||
page=self, target=target,
|
||||
permission='zope.ManageContent'))
|
||||
return actions
|
||||
|
||||
actions = dict(portlet=getPortletActions)
|
||||
|
|
|
@ -293,7 +293,8 @@
|
|||
<metal:actions define-macro="object_actions">
|
||||
<div id="object-actions" class="object-actions"
|
||||
tal:define="target nocall:target|nothing;">
|
||||
<tal:actions repeat="action python:view.getActions('object', target=target)">
|
||||
<tal:actions repeat="action python:
|
||||
view.getAllowedActions('object', target=target)">
|
||||
<metal:action use-macro="action/macro" />
|
||||
</tal:actions>
|
||||
</div>
|
||||
|
@ -322,7 +323,7 @@
|
|||
<div><a href="logout.html?nextURL=login.html"
|
||||
tal:attributes="href string:logout.html?nextURL=${view/menu/url}"
|
||||
i18n:translate="">Log out</a></div>
|
||||
<tal:actions repeat="action python:view.getActions('personal')">
|
||||
<tal:actions repeat="action python:view.getAllowedActions('personal')">
|
||||
<metal:action use-macro="action/macro" />
|
||||
</tal:actions>
|
||||
</metal:actions>
|
||||
|
|
|
@ -52,6 +52,7 @@ actions.register('createBlogPost', 'portlet', DialogAction,
|
|||
fixedType=True,
|
||||
innerForm='inner_concept_form.html',
|
||||
prerequisites=['registerDojoDateWidget'], # +'registerDojoTextWidget'?
|
||||
permission='loops.AssignAsParent',
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@ actions.register('createTopic', 'portlet', DialogAction,
|
|||
typeToken='.loops/concepts/topic',
|
||||
fixedType=True,
|
||||
innerForm='inner_concept_form.html',
|
||||
permission='loops.AssignAsParent',
|
||||
)
|
||||
|
||||
actions.register('editTopic', 'portlet', DialogAction,
|
||||
|
@ -57,6 +58,7 @@ actions.register('editTopic', 'portlet', DialogAction,
|
|||
description=_(u'Modify topic.'),
|
||||
viewName='edit_concept.html',
|
||||
dialogName='editTopic',
|
||||
permission='zope.ManageContent',
|
||||
)
|
||||
|
||||
actions.register('createQualification', 'portlet', DialogAction,
|
||||
|
@ -66,6 +68,7 @@ actions.register('createQualification', 'portlet', DialogAction,
|
|||
dialogName='createQualification',
|
||||
prerequisites=['registerDojoDateWidget', 'registerDojoNumberWidget',
|
||||
'registerDojoTextarea'],
|
||||
permission='loops.AssignAsParent',
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ actions.register('createEvent', 'portlet', DialogAction,
|
|||
typeToken='.loops/concepts/event',
|
||||
fixedType=True,
|
||||
prerequisites=['registerDojoDateWidget'],
|
||||
permission='loops.AssignAsParent',
|
||||
)
|
||||
|
||||
actions.register('editEvent', 'portlet', DialogAction,
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
<zope:adapter
|
||||
factory="loops.organize.stateful.base.SimplePublishable"
|
||||
name="simple_publishing" trusted="True" />
|
||||
name="simple_publishing" />
|
||||
<zope:class class="loops.organize.stateful.base.SimplePublishable">
|
||||
<require permission="zope.View"
|
||||
interface="cybertools.stateful.interfaces.IStateful" />
|
||||
|
@ -41,7 +41,7 @@
|
|||
|
||||
<zope:adapter
|
||||
factory="loops.organize.stateful.task.StatefulTask"
|
||||
name="task_states" trusted="True" />
|
||||
name="task_states" />
|
||||
<zope:class class="loops.organize.stateful.task.StatefulTask">
|
||||
<require permission="zope.View"
|
||||
interface="cybertools.stateful.interfaces.IStateful" />
|
||||
|
@ -55,7 +55,7 @@
|
|||
|
||||
<zope:adapter
|
||||
factory="loops.organize.stateful.task.PublishableTask"
|
||||
name="publishable_task" trusted="True" />
|
||||
name="publishable_task" />
|
||||
<zope:class class="loops.organize.stateful.task.PublishableTask">
|
||||
<require permission="zope.View"
|
||||
interface="cybertools.stateful.interfaces.IStateful" />
|
||||
|
@ -69,7 +69,7 @@
|
|||
|
||||
<zope:adapter
|
||||
factory="loops.organize.stateful.quality.ClassificationQualityCheckable"
|
||||
name="classification_quality" trusted="True" />
|
||||
name="classification_quality" />
|
||||
<zope:class class="loops.organize.stateful.quality.ClassificationQualityCheckable">
|
||||
<require permission="zope.View"
|
||||
interface="cybertools.stateful.interfaces.IStateful" />
|
||||
|
|
|
@ -75,7 +75,7 @@ def canListObject(obj, noCheck=False):
|
|||
return canAccess(obj, 'title')
|
||||
|
||||
def canWriteObject(obj):
|
||||
return canWrite(obj, 'title')
|
||||
return canWrite(obj, 'title') or canAssignAsParent(obj)
|
||||
|
||||
def canEditRestricted(obj):
|
||||
return checkPermission('loops.EditRestricted', obj)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# Copyright (c) 2009 Helmut Merz helmutm@cy55.de
|
||||
# Copyright (c) 2013 Helmut Merz helmutm@cy55.de
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -18,8 +18,6 @@
|
|||
|
||||
"""
|
||||
Interfaces for loops security management.
|
||||
|
||||
$Id$
|
||||
"""
|
||||
|
||||
from zope.interface import Interface, Attribute
|
||||
|
@ -35,6 +33,10 @@ class ISecuritySetter(Interface):
|
|||
context object.
|
||||
"""
|
||||
|
||||
def setStateSecurity():
|
||||
""" Set the security according to the state(s) of the object.
|
||||
"""
|
||||
|
||||
def setDefaultRolePermissions():
|
||||
""" Set some default role permission assignments (grants) on the
|
||||
context object.
|
||||
|
|
|
@ -123,7 +123,6 @@ class LoopsObjectSecuritySetter(BaseSecuritySetter):
|
|||
rpm = self.rolePermissionManager
|
||||
for p, r, s in rpm.getRolesAndPermissions():
|
||||
setRolePermission(rpm, p, r, Unset)
|
||||
self.setStateSecurity()
|
||||
|
||||
def setStateSecurity(self):
|
||||
statesDefs = (self.globalOptions('organize.stateful.concept', []) +
|
||||
|
@ -151,6 +150,7 @@ class LoopsObjectSecuritySetter(BaseSecuritySetter):
|
|||
settings[(p, r)] = s
|
||||
self.setDefaultRolePermissions()
|
||||
self.setRolePermissions(settings)
|
||||
self.setStateSecurity()
|
||||
|
||||
def setRolePermissions(self, settings):
|
||||
for (p, r), s in settings.items():
|
||||
|
|
Loading…
Add table
Reference in a new issue