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