diff --git a/README.txt b/README.txt
index 8140683..6ec6fc2 100755
--- a/README.txt
+++ b/README.txt
@@ -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'
diff --git a/browser/action.py b/browser/action.py
index 68176d9..06600c5 100644
--- a/browser/action.py
+++ b/browser/action.py
@@ -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',
)
diff --git a/browser/common.py b/browser/common.py
index 5c51a59..897ff96 100644
--- a/browser/common.py
+++ b/browser/common.py
@@ -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)
diff --git a/browser/node.py b/browser/node.py
index 5a9a238..2763ada 100644
--- a/browser/node.py
+++ b/browser/node.py
@@ -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)
diff --git a/browser/node_macros.pt b/browser/node_macros.pt
index 7f65b19..b67f1fb 100644
--- a/browser/node_macros.pt
+++ b/browser/node_macros.pt
@@ -293,7 +293,8 @@
-
+
@@ -322,7 +323,7 @@
-
+
diff --git a/compound/blog/browser.py b/compound/blog/browser.py
index 032b99a..dcc3b88 100755
--- a/compound/blog/browser.py
+++ b/compound/blog/browser.py
@@ -52,6 +52,7 @@ actions.register('createBlogPost', 'portlet', DialogAction,
fixedType=True,
innerForm='inner_concept_form.html',
prerequisites=['registerDojoDateWidget'], # +'registerDojoTextWidget'?
+ permission='loops.AssignAsParent',
)
diff --git a/knowledge/browser.py b/knowledge/browser.py
index fd9a8ed..c749f23 100644
--- a/knowledge/browser.py
+++ b/knowledge/browser.py
@@ -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',
)
diff --git a/organize/browser/event.py b/organize/browser/event.py
index ee9bbdc..8f43548 100644
--- a/organize/browser/event.py
+++ b/organize/browser/event.py
@@ -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,
diff --git a/organize/stateful/configure.zcml b/organize/stateful/configure.zcml
index 74c7663..7833208 100644
--- a/organize/stateful/configure.zcml
+++ b/organize/stateful/configure.zcml
@@ -27,7 +27,7 @@
+ name="simple_publishing" />
@@ -41,7 +41,7 @@
+ name="task_states" />
@@ -55,7 +55,7 @@
+ name="publishable_task" />
@@ -69,7 +69,7 @@
+ name="classification_quality" />
diff --git a/security/common.py b/security/common.py
index f3b1b07..bb8c874 100644
--- a/security/common.py
+++ b/security/common.py
@@ -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)
diff --git a/security/interfaces.py b/security/interfaces.py
index ef4876e..283db83 100644
--- a/security/interfaces.py
+++ b/security/interfaces.py
@@ -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.
diff --git a/security/setter.py b/security/setter.py
index e9248df..135db0e 100644
--- a/security/setter.py
+++ b/security/setter.py
@@ -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():