diff --git a/fields/__init__.py b/fields/__init__.py index 3b250d1..d9125c4 100644 --- a/fields/__init__.py +++ b/fields/__init__.py @@ -246,14 +246,14 @@ class Field: elif rp and isinstance(rp, basestring): self.readPermission = rp else: - self.readPermission = 'View' + self.readPermission = 'read' wp = self.specificWritePermission if wp and not isinstance(wp, basestring): self.writePermission = '%s: Write %s %s' % (appName, prefix, name) elif wp and isinstance(wp, basestring): self.writePermission = wp else: - self.writePermission = 'Modify portal content' + self.writePermission = 'write' if (self.type == 'Ref') and not self.isBack: # We must initialise the corresponding back reference self.back.klass = klass diff --git a/fields/ref.py b/fields/ref.py index 8d09387..0654d1b 100644 --- a/fields/ref.py +++ b/fields/ref.py @@ -140,7 +140,7 @@ class Ref(Field): folder=zobj.getCreateFolder(); tiedClassName=ztool.getPortalType(field.klass); canWrite=not field.isBack and zobj.allows(field.writePermission); - showPlusIcon=zobj.mayAddReference(field.name); + showPlusIcon=field.mayAdd(zobj); atMostOneRef=(field.multiplicity[1] == 1) and \ (len(zobjects)<=1); addConfirmMsg=field.addConfirm and \ @@ -592,12 +592,8 @@ class Ref(Field): # May the user edit this Ref field? if not obj.allows(self.writePermission): return gutils.No('no_write_perm') - # Have the user the correct add permission? - tool = obj.getTool() - addPermission = '%s: Add %s' % (tool.getAppName(), - tool.getPortalType(self.klass)) - folder = obj.getCreateFolder() - if not tool.getUser().has_permission(addPermission, folder): + # May the user create instances of the referred class? + if not obj.getTool().userMayCreate(self.klass): return gutils.No('no_add_perm') return True diff --git a/fields/search.py b/fields/search.py index f61b8a6..d5571fe 100644 --- a/fields/search.py +++ b/fields/search.py @@ -147,7 +147,7 @@ class UiSearch: pxView = Px('''
''') diff --git a/gen/__init__.py b/gen/__init__.py index 6459369..fa4e184 100644 --- a/gen/__init__.py +++ b/gen/__init__.py @@ -59,12 +59,6 @@ class Import: self.sort = sort # Workflow-specific types and default workflows -------------------------------- -appyToZopePermissions = { - 'read': ('View', 'Access contents information'), - 'write': 'Modify portal content', - 'delete': 'Delete objects', -} - class Role: '''Represents a role.''' zopeRoles = ('Manager', 'Owner', 'Anonymous', 'Authenticated') @@ -108,7 +102,7 @@ class State: name of a role, this method returns self.usedRoles[role] if it exists, or creates a Role instance, puts it in self.usedRoles and returns it else. If it is a Role instance, the method stores it in - self.usedRoles if it not in it yet and returns it.''' + self.usedRoles if it is not in it yet and returns it.''' if isinstance(role, basestring): if role in self.usedRoles: return self.usedRoles[role] @@ -135,61 +129,6 @@ class State: def getUsedRoles(self): return self.usedRoles.values() - def getPermissions(self): - '''If you get the permissions mapping through self.permissions, dict - values may be of different types (a list of roles, a single role or - None). Iy you call this method, you will always get a list which - may be empty.''' - res = {} - for permission, roleValue in self.permissions.iteritems(): - if roleValue == None: - res[permission] = [] - elif isinstance(roleValue, basestring): - res[permission] = [roleValue] - else: - res[permission] = roleValue - return res - - def updatePermission(self, obj, zopePermission, roleNames): - '''Updates, on p_obj, list of p_roleNames which are granted a given - p_zopePermission. This method returns True if the list has been - effectively updated.''' - attr = Permission.getZopeAttrName(zopePermission) - if not hasattr(obj.aq_base, attr) or \ - (getattr(obj.aq_base, attr) != roleNames): - setattr(obj, attr, roleNames) - return True - return False - - def updatePermissions(self, wf, obj): - '''Zope requires permission-to-roles mappings to be stored as attributes - on the object itself. This method does this job, duplicating the info - from this state definition on p_obj. p_res is True if at least one - change has been effectively performed.''' - res = False - for permission, roles in self.getPermissions().iteritems(): - roleNames = tuple([role.name for role in roles]) - # Compute Zope permission(s) related to this permission. - if appyToZopePermissions.has_key(permission): - # It is a standard permission (r, w, d) - zopePerm = appyToZopePermissions[permission] - elif isinstance(permission, basestring): - # It is a user-defined permission - zopePerm = permission - else: - # It is a Permission instance - appName = obj.getProductConfig().PROJECTNAME - zopePerm = permission.getName(wf, appName) - # zopePerm contains a single permission or a tuple of permissions - if isinstance(zopePerm, basestring): - changed = self.updatePermission(obj, zopePerm, roleNames) - res = res or changed - else: - for zPerm in zopePerm: - changed = self.updatePermission(obj, zPerm, roleNames) - res = res or changed - return res - class Transition: def __init__(self, states, condition=True, action=None, notify=None, show=True, confirm=False): @@ -345,8 +284,6 @@ class Transition: if not doHistory: comment = '_invisible_' obj.addHistoryEvent(action, review_state=targetStateName, comments=comment) - # Update permissions-to-roles attributes - targetState.updatePermissions(wf, obj) # Reindex the object if required. Not only security-related indexes # (Allowed, State) need to be updated here. if not obj.isTemporary(): obj.reindex() @@ -384,8 +321,7 @@ class Permission: self.fieldDescriptor = fieldDescriptor def getName(self, wf, appName): - '''Returns the name of the Zope permission that corresponds to this - permission.''' + '''Returns the name of this permission.''' className, fieldName = self.fieldDescriptor.rsplit('.', 1) if className.find('.') == -1: # The related class resides in the same module as the workflow @@ -398,16 +334,6 @@ class Permission: else: access = 'Write' return '%s: %s %s %s' % (appName, access, fullClassName, fieldName) - @staticmethod - def getZopeAttrName(zopePermission): - '''Gets the name of the attribute where Zope stores, on every object, - the tuple of roles who are granted a given p_zopePermission.''' - res = '' - for c in zopePermission: - if c in Permission.allowedChars: res += c - else: res += '_' - return '_%s_Permission' % res - class ReadPermission(Permission): pass class WritePermission(Permission): pass @@ -475,7 +401,7 @@ class Config: languageSelector = False # People having one of these roles will be able to create instances # of classes defined in your application. - defaultCreators = ['Manager', 'Owner'] + defaultCreators = ['Manager'] # Number of translations for every page on a Translation object translationsPerPage = 30 # Language that will be used as a basis for translating to other diff --git a/gen/generator.py b/gen/generator.py index af3b9c5..c34606a 100644 --- a/gen/generator.py +++ b/gen/generator.py @@ -557,12 +557,6 @@ class ZopeGenerator(Generator): if theImport not in imports: imports.append(theImport) repls['imports'] = '\n'.join(imports) - # Compute list of add permissions - addPermissions = '' - for classDescr in classesAll: - addPermissions += ' "%s":"%s: Add %s",\n' % (classDescr.name, - self.applicationName, classDescr.name) - repls['addPermissions'] = addPermissions # Compute root classes repls['rootClasses'] = ','.join(["'%s'" % c.name \ for c in classesButTool if c.isRoot()]) diff --git a/gen/installer.py b/gen/installer.py index d97dcf2..b29147c 100644 --- a/gen/installer.py +++ b/gen/installer.py @@ -63,7 +63,6 @@ class ZopeInstaller: self.productName = config.PROJECTNAME self.languages = config.appConfig.languages self.logger = config.logger - self.addContentPermissions = config.ADD_CONTENT_PERMISSIONS def installUi(self): '''Installs the user interface.''' @@ -157,14 +156,9 @@ class ZopeInstaller: catalog.reindexIndex('SearchableText', self.app.REQUEST) self.logger.info('Done.') - def getAddPermission(self, className): - '''What is the name of the permission allowing to create instances of - class whose name is p_className?''' - return self.productName + ': Add ' + className - def installBaseObjects(self): - '''Creates the tool and the root data folder if they do not exist.''' - # Create or update the base folder for storing data + '''Creates the tool and the base data folder if they do not exist.''' + # Create the tool. zopeContent = self.app.objectIds() from OFS.Folder import manage_addFolder @@ -172,29 +166,8 @@ class ZopeInstaller: toolName = '%sTool' % self.productName gutils.createObject(self.app, 'config', toolName, self.productName, wf=False, noSecurity=True) - - if 'data' not in zopeContent: - manage_addFolder(self.app, 'data') - data = self.app.data - tool = self.app.config - # Manager has been granted Add permissions for all root classes. - # This may not be desired, so remove this. - for className in self.config.rootClasses: - permission = self.getAddPermission(className) - data.manage_permission(permission, (), acquire=0) - # All roles defined as creators should be able to create the - # corresponding root classes in this folder. - i = -1 - for klass in self.config.appClasses: - i += 1 - if not klass.__dict__.has_key('root') or \ - not klass.__dict__['root']: - continue # It is not a root class - className = self.config.appClassNames[i] - wrapperClass = tool.getAppyClass(className, wrapper=True) - creators = wrapperClass.getCreators(self.config) - permission = self.getAddPermission(className) - gutils.updateRolesForPermission(permission,tuple(creators),data) + # Create the base data folder. + if 'data' not in zopeContent: manage_addFolder(self.app, 'data') # Remove some default objects created by Zope but not useful to Appy for name in ('standard_html_footer', 'standard_html_header',\ @@ -206,14 +179,13 @@ class ZopeInstaller: inner objects (users, groups, translations, documents).''' tool = self.app.config tool.createOrUpdate(True, None) - tool.refreshSecurity() appyTool = tool.appy() appyTool.log('Appy version is "%s".' % appy.version.short) # Create the default users if they do not exist. for login, roles in self.defaultUsers.iteritems(): if not appyTool.count('User', noSecurity=True, login=login): - appyTool.create('users', noSecurity=True, login=login, + appyTool.create('users', noSecurity=True, id=login, login=login, password1=login, password2=login, email='%s@appyframework.org'%login, roles=roles) appyTool.log('User "%s" created.' % login) @@ -332,8 +304,7 @@ class ZopeInstaller: wrapper = klass.wrapperClass exec 'from %s import manage_add%s as ctor' % (module, name) self.zopeContext.registerClass(meta_type=name, - constructors = (ctor,), - permission = self.addContentPermissions[name]) + constructors = (ctor,), permission = None) # Create workflow prototypical instances in __instance__ attributes wf = wrapper.getWorkflow() if not hasattr(wf, '__instance__'): wf.__instance__ = wf() diff --git a/gen/mixins/ToolMixin.py b/gen/mixins/ToolMixin.py index ee79b5e..0a11e04 100644 --- a/gen/mixins/ToolMixin.py +++ b/gen/mixins/ToolMixin.py @@ -199,7 +199,8 @@ class ToolMixin(BaseMixin): def getRootClasses(self): '''Returns the list of root classes for this application.''' - return self.getProductConfig().rootClasses + cfg = self.getProductConfig() + return [self.getAppyClass(k) for k in cfg.rootClasses] def _appy_getAllFields(self, className): '''Returns the (translated) names of fields of p_className.''' @@ -265,8 +266,8 @@ class ToolMixin(BaseMixin): p_className.''' appyClass = self.getAppyClass(className) importParams = self.getCreateMeans(appyClass)['import'] - onElement = importParams['onElement'].__get__('') - sortMethod = importParams['sort'] + onElement = importParams.onElement.__get__('') + sortMethod = importParams.sort if sortMethod: sortMethod = sortMethod.__get__('') elems = [] importType = self.getAppyType('importPathFor%s' % className) @@ -280,7 +281,7 @@ class ToolMixin(BaseMixin): elems.append(elemInfo) if sortMethod: elems = sortMethod(elems) - return [importParams['headers'], elems] + return [importParams.headers, elems] def showPortlet(self, context, layoutType): '''When must the portlet be shown?''' @@ -489,17 +490,13 @@ class ToolMixin(BaseMixin): if wrapper: return zopeClass.wrapperClass else: return zopeClass.wrapperClass.__bases__[-1] - def getCreateMeans(self, contentTypeOrAppyClass): - '''Gets the different ways objects of p_contentTypeOrAppyClass (which - can be a Zope content type or a Appy class) can be created - (via a web form, by importing external data, etc). Result is a - dict whose keys are strings (ie "form", "import"...) and whose - values are additional data about the particular mean.''' - pythonClass = contentTypeOrAppyClass - if isinstance(contentTypeOrAppyClass, basestring): - pythonClass = self.getAppyClass(pythonClass) + def getCreateMeans(self, klass): + '''Gets the different ways objects of p_klass can be created (via a web + form, by importing external data, etc). Result is a dict whose keys + are strings (ie "form", "import"...) and whose values are additional + data about the particular mean.''' res = {} - if not pythonClass.__dict__.has_key('create'): + if not klass.__dict__.has_key('create'): res['form'] = None # No additional data for this means, which is the default one. else: @@ -511,23 +508,28 @@ class ToolMixin(BaseMixin): if isinstance(mean, basestring): res[mean] = None else: - res[mean.id] = mean.__dict__ + res[mean.id] = mean else: - res[means.id] = means.__dict__ + res[means.id] = means return res def userMaySearch(self, rootClass): - '''This method checks if the currently logged user can trigger searches - on a given p_rootClass. This is done by calling method "maySearch" - on the class. If no such method exists, we return True.''' - # When editign a form, one should avoid annoying the user with this. + '''May the logged user search among instances of p_rootClass ?''' + # When editing a form, one should avoid annoying the user with this. url = self.REQUEST['ACTUAL_URL'] if url.endswith('/edit') or url.endswith('/do'): return - pythonClass = self.getAppyClass(rootClass) - if 'maySearch' in pythonClass.__dict__: - return pythonClass.maySearch(self.appy()) + if 'maySearch' in rootClass.__dict__: + return pythonClass.rootClass(self.appy()) return True + def userMayCreate(self, klass): + '''May the logged user create instances of p_klass ?''' + allowedRoles = getattr(klass, 'creators', None) or \ + self.getProductConfig().appConfig.defaultCreators + for role in self.getUser().getRoles(): + if role in allowedRoles: + return True + def onImportObjects(self): '''This method is called when the user wants to create objects from external data.''' @@ -737,23 +739,22 @@ class ToolMixin(BaseMixin): obj = self.getObject(objectUid) return obj, fieldName - def getGroupedSearches(self, className): + def getGroupedSearches(self, klass): '''Returns an object with 2 attributes: - * "searches" stores the searches that are defined for p_className; + * "searches" stores the searches that are defined for p_klass; * "default" stores the search defined as the default one. Every item representing a search is a dict containing info about a search or about a group of searches. ''' - appyClass = self.getAppyClass(className) res = [] default = None # Also retrieve the default one here. groups = {} # The already encountered groups page = Page('main') # A dummy page required by class UiGroup # Get the searches statically defined on the class - searches = ClassDescriptor.getSearches(appyClass, tool=self.appy()) + searches = ClassDescriptor.getSearches(klass, tool=self.appy()) # Get the dynamically computed searches - if hasattr(appyClass, 'getDynamicSearches'): - searches += appyClass.getDynamicSearches(self.appy()) + if hasattr(klass, 'getDynamicSearches'): + searches += klass.getDynamicSearches(self.appy()) for search in searches: # Create the search descriptor uiSearch = UiSearch(search, className, self) @@ -792,9 +793,8 @@ class ToolMixin(BaseMixin): if ui: res = UiSearch(res, className, self) return res - def advancedSearchEnabledFor(self, className): + def advancedSearchEnabledFor(self, klass): '''Is advanced search visible for p_klass ?''' - klass = self.getAppyClass(className) # By default, advanced search is enabled. if not hasattr(klass, 'searchAdvanced'): return True # Evaluate attribute "show" on this Search instance representing the @@ -1103,29 +1103,26 @@ class ToolMixin(BaseMixin): login = (rq.__class__.__name__ == 'Object') and 'system' or 'anon' # Get the User object from a query in the catalog. user = tool.search1('User', noSecurity=True, login=login) + # It is possible that we find no user here: it happens before users + # "anon" and "system" are created, at first Zope startup. + if not user: return rq.user = user - # Precompute some values or this usser for performance reasons + # Precompute some values or this user for performance reasons. rq.userRoles = user.getRoles() + rq.userLogins = user.getLogins() rq.zopeUser = user.getZopeUser() return user - #from AccessControl import getSecurityManager - #user = getSecurityManager().getUser() - #if not user: - # from AccessControl.User import nobody - # return nobody - #return user def getUserLine(self): '''Returns a info about the currently logged user as a 2-tuple: first elem is the one-line user info as shown on every page; second line is the URL to edit user info.''' user = self.getUser() - userRoles = self.appy().request.userRoles info = [user.title] - rolesToShow = [r for r in userRoles if r != 'Authenticated'] - if rolesToShow: + showable = [r for r in user.getRoles() if r != 'Authenticated'] + if showable: info.append(', '.join([self.translate('role_%s' % r) \ - for r in rolesToShow])) + for r in showable])) # Edit URL for the user. url = None if user.o.mayEdit(): @@ -1134,17 +1131,17 @@ class ToolMixin(BaseMixin): def getUserName(self, login=None, normalized=False): '''Gets the user name corresponding to p_login (or the currently logged - login if None), or the p_login itself if the user does not exist + user if None), or the p_login itself if the user does not exist anymore. If p_normalized is True, special chars in the first and last names are normalized.''' tool = self.appy() if not login: login = tool.user.login # Manage the special case of an anonymous user. - if login == 'Anonymous User': + if login == 'anon': name = self.translate('anonymous') if normalized: name = sutils.normalizeString(name) return name - # Manage the case of a "real" user. + # Manage the case of any other user. user = tool.search1('User', noSecurity=True, login=login) if not user: return login firstName = user.firstName diff --git a/gen/mixins/__init__.py b/gen/mixins/__init__.py index 7ed2073..2e2fbff 100644 --- a/gen/mixins/__init__.py +++ b/gen/mixins/__init__.py @@ -93,9 +93,6 @@ class BaseMixin: # Manage potential link with an initiator object if created and initiator: initiator.appy().link(initiatorField.name,obj) - # Manage "add" permissions and reindex the object - obj._appy_managePermissions() - # Call the custom "onEdit" if available msg = None # The message to display to the user. It can be set by onEdit if obj.wrapperClass: @@ -410,7 +407,7 @@ class BaseMixin: return self.goto(tool.getSiteUrl(), msg) # If the user can't access the object anymore, redirect him to the # main site page. - if not obj.allows('View'): + if not obj.allows('read'): return self.goto(tool.getSiteUrl(), msg) if (buttonClicked == 'save') or saveConfirmed: obj.say(msg) @@ -484,7 +481,7 @@ class BaseMixin: corresponding Appy wrapper and returns, as XML, the its result.''' self.REQUEST.RESPONSE.setHeader('Content-Type','text/xml;charset=utf-8') # Check if the user is allowed to consult this object - if not self.allows('View'): + if not self.allows('read'): return XmlMarshaller().marshall('Unauthorized') if not action: marshaller = XmlMarshaller(rootTag=self.getClass().__name__, @@ -670,11 +667,6 @@ class BaseMixin: if not allValues: return '' return getattr(allValues[rowIndex], name, '') - def mayAddReference(self, name): - '''May the user add references via Ref field named p_name in - p_folder?''' - return self.getAppyType(name).mayAdd(self) - def isDebug(self): '''Are we in debug mode ?''' for arg in sys.argv: @@ -937,30 +929,6 @@ class BaseMixin: stateName = stateName or self.State() return '%s_%s' % (self.getWorkflow(name=True), stateName) - def refreshSecurity(self): - '''Refresh security info on this object. Returns True if the info has - effectively been updated.''' - wf = self.getWorkflow() - try: - # Get the state definition of the object's current state. - state = getattr(wf, self.State()) - except AttributeError: - # The workflow information for this object does not correspond to - # its current workflow attribution. Add a new fake event - # representing passage of this object to the initial state of his - # currently attributed workflow. - stateName = self.State(name=True, initial=True) - self.addHistoryEvent(None, review_state=stateName) - state = self.State(name=False, initial=True) - self.log('Wrong workflow info for a "%s"; is now in state "%s".' % \ - (self.meta_type, stateName)) - # Update permission attributes on the object if required - updated = state.updatePermissions(wf, self) - if updated: - # Reindex the object because security-related info is indexed. - self.reindex() - return updated - def applyUserIdChange(self, oldId, newId): '''A user whose ID was p_oldId has now p_newId. If the old ID was mentioned in self's local roles, update it to the new ID. This @@ -1105,14 +1073,14 @@ class BaseMixin: def mayDelete(self): '''May the currently logged user delete this object?''' - res = self.allows('Delete objects') + res = self.allows('delete') if not res: return # An additional, user-defined condition, may refine the base permission. appyObj = self.appy() if hasattr(appyObj, 'mayDelete'): return appyObj.mayDelete() return True - def mayEdit(self, permission='Modify portal content'): + def mayEdit(self, permission='write'): '''May the currently logged user edit this object? p_perm can be a field-specific permission.''' res = self.allows(permission) @@ -1195,6 +1163,12 @@ class BaseMixin: self.reindex() return self.goto(self.getUrl(rq['HTTP_REFERER'])) + def getRolesFor(self, permission): + '''Gets, according to the workflow, the roles that are currently granted + p_permission on this object.''' + state = self.State(name=False) + return [role.name for role in state.permissions[permission]] + def appy(self): '''Returns a wrapper object allowing to manipulate p_self the Appy way.''' @@ -1284,18 +1258,17 @@ class BaseMixin: '''Returns the list of roles and users that are allowed to view this object. This index value will be used within catalog queries for filtering objects the user is allowed to see.''' - res = set() - # Get, from the workflow, roles having permission 'View'. - for role in self.getProductConfig().rolesForPermissionOn('View', self): - res.add(role) - # Add users having, locally, this role on this object. - localRoles = getattr(self, '__ac_local_roles__', None) - if not localRoles: return list(res) + # Get, from the workflow, roles having permission 'read'. + res = self.getRolesFor('read') + # Add users or groups having, locally, this role on this object. + localRoles = getattr(self.aq_base, '__ac_local_roles__', None) + if not localRoles: return res for id, roles in localRoles.iteritems(): for role in roles: if role in res: - res.add('user:%s' % id) - return list(res) + usr = 'user:%s' % id + if usr not in res: res.append(usr) + return res def showState(self): '''Must I show self's current state ?''' @@ -1326,39 +1299,6 @@ class BaseMixin: res.append((elem, self.translate(self.getWorkflowLabel(elem)))) return res - def _appy_managePermissions(self): - '''When an object is created or updated, we must update "add" - permissions accordingly: if the object is a folder, we must set on - it permissions that will allow to create, inside it, objects through - Ref fields; if it is not a folder, we must update permissions on its - parent folder instead.''' - # Determine on which folder we need to set "add" permissions - folder = self.getCreateFolder() - # On this folder, set "add" permissions for every content type that will - # be created through reference fields - allCreators = {} # One key for every add permission - addPermissions = self.getProductConfig().ADD_CONTENT_PERMISSIONS - for appyType in self.getAllAppyTypes(): - if appyType.type != 'Ref': continue - if appyType.isBack or appyType.link: continue - # Indeed, no possibility to create objects with such Refs - tool = self.getTool() - refType = tool.getPortalType(appyType.klass) - if refType not in addPermissions: continue - # Get roles that may add this content type - appyWrapper = tool.getAppyClass(refType, wrapper=True) - creators = appyWrapper.getCreators(self.getProductConfig()) - # Add those creators to the list of creators for this meta_type - addPermission = addPermissions[refType] - if addPermission in allCreators: - allCreators[addPermission] = allCreators[\ - addPermission].union(creators) - else: - allCreators[addPermission] = set(creators) - # Update the permissions - for permission, creators in allCreators.iteritems(): - updateRolesForPermission(permission, tuple(creators), folder) - getUrlDefaults = {'page':True, 'nav':True} def getUrl(self, base=None, mode='view', **kwargs): '''Returns an URL for this object. diff --git a/gen/templates/config.pyt b/gen/templates/config.pyt index 0db1f63..795c346 100644 --- a/gen/templates/config.pyt +++ b/gen/templates/config.pyt @@ -13,7 +13,6 @@ from ZPublisher.HTTPRequest import BaseRequest from OFS.Image import File from ZPublisher.HTTPRequest import FileUpload from AccessControl import getSecurityManager -from AccessControl.PermissionRole import rolesForPermissionOn from DateTime import DateTime from Products.ExternalMethod.ExternalMethod import ExternalMethod from Products.Transience.Transience import TransientObjectContainer @@ -24,8 +23,6 @@ logger = logging.getLogger('') # Some global variables -------------------------------------------------------- PROJECTNAME = '' diskFolder = os.path.dirname(.__file__) -ADD_CONTENT_PERMISSIONS = { -} # Applications classes, in various formats rootClasses = [] @@ -34,7 +31,7 @@ appClassNames = [] allClassNames = [] # In the following dict, we store, for every Appy class, the ordered list of -# appy types (included inherited ones). +# fields. attributes = {} # Application roles diff --git a/gen/utils.py b/gen/utils.py index e6ca05d..f3476c6 100644 --- a/gen/utils.py +++ b/gen/utils.py @@ -17,17 +17,11 @@ def createObject(folder, id, className, appName, wf=True, noSecurity=False): user = tool.getUser() if not noSecurity: # Check that the user can create objects of className. - userRoles = user.getRoles() - allowedRoles=ZopeClass.wrapperClass.getCreators(tool.getProductConfig()) - allowed = False - for role in userRoles: - if role in allowedRoles: - allowed = True - break - if not allowed: + klass = ZopeClass.wrapperClass.__bases__[-1] + if not tool.userMayCreate(klass): from AccessControl import Unauthorized raise Unauthorized("User can't create instances of %s" % \ - ZopeClass.__name__) + klass.__name__) obj = ZopeClass(id) folder._objects = folder._objects + ({'id':id, 'meta_type':className},) folder._setOb(id, obj) @@ -137,21 +131,6 @@ def getClassName(klass, appName=None): res = klass.__module__.replace('.', '_') + '_' + klass.__name__ return res -# ------------------------------------------------------------------------------ -def updateRolesForPermission(permission, roles, obj): - '''Adds roles from list p_roles to the list of roles that are granted - p_permission on p_obj.''' - from AccessControl.Permission import Permission - # Find existing roles that were granted p_permission on p_obj - existingRoles = () - for p in obj.ac_inherited_permissions(1): - name, value = p[:2] - if name == permission: - perm = Permission(name, value, obj) - existingRoles = perm.getRoles() - allRoles = set(existingRoles).union(roles) - obj.manage_permission(permission, tuple(allRoles), acquire=0) - # ------------------------------------------------------------------------------ def callMethod(obj, method, klass=None, cache=True): '''This function is used to call a p_method on some Appy p_obj. m_method diff --git a/gen/wrappers/GroupWrapper.py b/gen/wrappers/GroupWrapper.py index 5c5ca95..01a8995 100644 --- a/gen/wrappers/GroupWrapper.py +++ b/gen/wrappers/GroupWrapper.py @@ -30,55 +30,18 @@ class GroupWrapper(AbstractWrapper): '''Inter-field validation.''' return self._callCustom('validate', new, errors) - def confirm(self, new): - '''Use this method for remembering the previous list of users for this - group.''' - obj = self.o - if hasattr(obj.aq_base, '_oldUsers'): del obj.aq_base._oldUsers - obj._oldUsers = self.users - def addUser(self, user): '''Adds a p_user to this group.''' # Update the Ref field. self.link('users', user) - # Update the group-related info on the Zope user. - zopeUser = user.getZopeUser() - zopeUser.groups[self.login] = self.roles def removeUser(self, user): '''Removes a p_user from this group.''' self.unlink('users', user) - # Update the group-related info on the Zope user. - zopeUser = user.getZopeUser() - del zopeUser.groups[self.login] def onEdit(self, created): - # Create or update, on every Zope user of this group, group-related - # information. - # 1. Remove reference to this group for users that were removed from it - newUsers = self.users - # The list of previously existing users does not exist when editing a - # group from Python. For updating self.users, it is recommended to use - # methods m_addUser and m_removeUser above. - oldUsers = getattr(self.o.aq_base, '_oldUsers', ()) - for user in oldUsers: - if user not in newUsers: - del user.getZopeUser().groups[self.login] - self.log('User "%s" removed from group "%s".' % \ - (user.login, self.login)) - # 2. Add reference to this group for users that were added to it - for user in newUsers: - zopeUser = user.getZopeUser() - # We refresh group-related info on the Zope user even if the user - # was already in the group. - zopeUser.groups[self.login] = self.roles - if user not in oldUsers: - self.log('User "%s" added to group "%s".' % \ - (user.login, self.login)) - if hasattr(self.o.aq_base, '_oldUsers'): del self.o._oldUsers - # If the group was created by an Anonymous, Anonymous can't stay Owner - # of the object. - if None in self.o.__ac_local_roles__: - del self.o.__ac_local_roles__[None] + # If the group was created by anon, anon can't stay its Owner. + if 'anon' in self.o.__ac_local_roles__: + del self.o.__ac_local_roles__['anon'] return self._callCustom('onEdit', created) # ------------------------------------------------------------------------------ diff --git a/gen/wrappers/ToolWrapper.py b/gen/wrappers/ToolWrapper.py index 14635e3..4be1719 100644 --- a/gen/wrappers/ToolWrapper.py +++ b/gen/wrappers/ToolWrapper.py @@ -174,8 +174,8 @@ class ToolWrapper(AbstractWrapper): -