eggification
[GroupUserFolder.git] / Products / GroupUserFolder / interfaces / IUserFolder.py
diff --git a/Products/GroupUserFolder/interfaces/IUserFolder.py b/Products/GroupUserFolder/interfaces/IUserFolder.py
new file mode 100644 (file)
index 0000000..026a612
--- /dev/null
@@ -0,0 +1,608 @@
+# -*- coding: utf-8 -*-
+## GroupUserFolder
+## Copyright (C)2006 Ingeniweb
+
+## 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
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+
+## You should have received a copy of the GNU General Public License
+## along with this program; see the file COPYING. If not, write to the
+## Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+VOCABULARY:
+
+  - [Pure] User: A user is a user atom who can log itself on, and
+    have additional properties such as domains and password.
+
+  - Group: A group is a user atom other atoms can belong to.
+
+  - User atom: Abstract representation of either a User or
+    a Group.
+
+  - Member (of a group): User atom inside a group.
+
+  - Name (of an atom): For a user, the name can be set by
+    the underlying user folder but usually id == name.
+    For a group, its id is prefixed, but its name is NOT prefixed by 'group_'.
+    For method taking a name instead of an id (eg. getUserByName()),
+    if a user and a group have the same name,
+    the USER will have precedence over the group.
+"""
+__version__ = "$Revision:  $"
+# $Source:  $
+# $Id: IUserFolder.py 30098 2006-09-08 12:35:01Z encolpe $
+__docformat__ = 'restructuredtext'
+
+from zope.interface import Interface, Attribute
+
+
+class IUserFolder(Interface):
+
+    #                                                   #
+    #           Regular Zope UserFolder API             #
+    #                                                   #
+
+    # User atom access
+    
+    def getUserNames():
+        """
+        Return a list of all possible user atom names in the system.
+        Groups will be returned WITHOUT their prefix by this method.
+        So, there might be a collision between a user name and a group name.
+        [NOTA: This method is time-expensive !]
+        """
+
+    def getUserIds():
+        """
+        Return a list of all possible user atom ids in the system.
+        WARNING: Please see the id Vs. name consideration at the
+        top of this document. So, groups will be returned
+        WITH their prefix by this method
+        [NOTA: This method is time-expensive !]
+        """
+        
+    def getUser(name):
+        """Return the named user atom object or None
+        NOTA: If no user can be found, we try to append a group prefix
+        and fetch the user again before returning 'None'. This will ensure
+        backward compatibility. So in fact, both group id and group name can be
+        specified to this method.
+        """
+
+    def getUsers():
+        """Return a list of user atom objects in the users cache.
+        In case of some UF implementations, the returned object may only be a subset
+        of all possible users.
+        In other words, you CANNOT assert that len(getUsers()) equals len(getUserNames()).
+        With cache-support UserFolders, such as LDAPUserFolder, the getUser() method will
+        return only cached user objects instead of fetching all possible users.
+        So this method won't be very time-expensive, but won't be accurate !
+        """
+
+    def getUserById(id, default):
+        """Return the user atom corresponding to the given id.
+        If default is provided, return default if no user found, else return None.
+        """
+
+    def getUserByName(name, default):
+        """Same as getUserById() but works with a name instead of an id.
+        If default is provided, return default if no user found, else return None.
+        [NOTA: Theorically, the id is a handle, while the name is the actual login name.
+        But difference between a user id and a user name is unsignificant in
+        all current User Folder implementations... except for GROUPS.]        
+        """
+
+    def hasUsers():
+        """
+        From Zope 2.7's User.py:
+        This is not a formal API method: it is used only to provide
+        a way for the quickstart page to determine if the default user
+        folder contains any users to provide instructions on how to
+        add a user for newbies.  Using getUserNames or getUsers would have
+        posed a denial of service risk.
+        In GRUF, this method always return 1."""
+    
+
+    # Search interface for users; they won't return groups in any case.
+
+    def searchUsersByName(search_term):
+        """Return user ids which match the specified search_term.
+        If search_term is an empty string, behaviour depends on the underlying user folder:
+        it may return all users, return only cached users (for LDAPUF) or return no users.
+        """
+
+    def searchUsersById(search_term):
+        """Return users whose id match the specified search_term.
+        If search_term is an empty string, behaviour depends on the underlying user folder:
+        it may return all users, return only cached users (for LDAPUF) or return no users.
+        """
+        
+    def searchUsersByAttribute(attribute, search_term):
+        """Return user ids whose 'attribute' match the specified search_term.
+        If search_term is an empty string, behaviour depends on the underlying user folder:
+        it may return all users, return only cached users (for LDAPUF) or return no users.
+        This will return all users whose name contains search_term (whaterver its case).
+        THIS METHOD MAY BE VERY EXPENSIVE ON USER FOLDER KINDS WHICH DO NOT PROVIDE A
+        SEARCHING METHOD (ie. every UF kind except LDAPUF).
+        'attribute' can be 'id' or 'name' for all UF kinds, or anything else for LDAPUF.
+        [NOTA: This method is time-expensive !]
+        """
+
+    # Search interface for groups;
+
+    def searchGroupsByName(search_term):
+        """Return group ids which match the specified search_term.
+        If search_term is an empty string, behaviour depends on the underlying group folder:
+        it may return all groups, return only cached groups (for LDAPUF) or return no groups.
+        """
+
+    def searchGroupsById(search_term):
+        """Return groups whose id match the specified search_term.
+        If search_term is an empty string, behaviour depends on the underlying group folder:
+        it may return all groups, return only cached groups (for LDAPUF) or return no groups.
+        """
+        
+    def searchGroupsByAttribute(attribute, search_term):
+        """Return group ids whose 'attribute' match the specified search_term.
+        If search_term is an empty string, behaviour depends on the underlying group folder:
+        it may return all groups, return only cached groups (for LDAPUF) or return no groups.
+        This will return all groups whose name contains search_term (whaterver its case).
+        THIS METHOD MAY BE VERY EXPENSIVE ON GROUP FOLDER KINDS WHICH DO NOT PROVIDE A
+        SEARCHING METHOD (ie. every UF kind except LDAPUF).
+        'attribute' can be 'id' or 'name' for all UF kinds, or anything else for LDAPUF.
+        [NOTA: This method is time-expensive !]
+        """
+
+
+    # User access
+
+    def getPureUserNames():
+        """Same as getUserNames() but without groups
+        """
+
+    def getPureUserIds():
+        """Same as getUserIds() but without groups
+        """
+
+    def getPureUsers():
+        """Same as getUsers() but without groups.
+        """
+
+    def getPureUser(id):
+        """Same as getUser() but forces returning a user and not a group
+        """
+        
+    # Group access
+
+    def getGroupNames():
+        """Same as getUserNames() but without pure users.
+        """
+
+    def getGroupIds():
+        """Same as getUserIds() but without pure users.
+        """
+
+    def getGroups():
+        """Same as getUsers() but without pure users.
+        In case of some UF implementations, the returned object may only be a subset
+        of all possible users.
+        In other words, you CANNOT assert that len(getUsers()) equals len(getUserNames()).
+        With cache-support UserFolders, such as LDAPUserFolder, the getUser() method will
+        return only cached user objects instead of fetching all possible users.
+        So this method won't be very time-expensive, but won't be accurate !
+        """
+
+    def getGroup(name):
+        """Return the named group object or None. As usual, 'id' is prefixed.
+        """
+
+    def getGroupById(id):
+        """Same as getUserById(id) but forces returning a group.
+        """
+
+    def getGroupByName(name):
+        """Same as getUserByName(name) but forces returning a group.
+        The specified name MUST NOT be prefixed !
+        """
+    
+
+    # Mutators
+
+    def userFolderAddUser(name, password, roles, domains, groups, **kw):
+        """API method for creating a new user object. Note that not all
+        user folder implementations support dynamic creation of user
+        objects.
+        Groups can be specified by name or by id (preferabily by name)."""
+
+    def userFolderEditUser(name, password, roles, domains, groups, **kw):
+        """API method for changing user object attributes. Note that not
+        all user folder implementations support changing of user object
+        attributes.
+        Groups can be specified by name or by id (preferabily by name)."""
+
+    def userFolderUpdateUser(name, password, roles, domains, groups, **kw):
+        """Same as userFolderEditUser, but with all arguments except name
+        being optional.
+        """
+
+    def userFolderDelUsers(names):
+        """API method for deleting one or more user atom objects. Note that not
+        all user folder implementations support deletion of user objects."""
+
+    def userFolderAddGroup(name, roles, groups, **kw):
+        """API method for creating a new group.
+        """
+        
+    def userFolderEditGroup(name, roles, groups, **kw):
+        """API method for changing group object attributes.
+        """
+
+    def userFolderUpdateGroup(name, roles, groups, **kw):
+        """Same as userFolderEditGroup but with all arguments (except name) being
+        optinal.
+        """
+
+    def userFolderDelGroups(names):
+        """API method for deleting one or more group objects.
+        Implem. note : All ids must be prefixed with 'group_',
+        so this method ends up beeing only a filter of non-prefixed ids
+        before calling userFolderDelUsers().
+        """
+
+    # User mutation
+
+    
+    # XXX do we have to allow a user to be renamed ?
+##    def setUserId(id, newId):
+##        """Change id of a user atom. The user name might be changed as well by this operation.
+##        """
+
+##    def setUserName(id, newName):
+##        """Change the name of a user atom. The user id might be changed as well by this operation.
+##        """
+
+    def userSetRoles(id, roles):
+        """Change the roles of a user atom
+        """
+
+    def userAddRole(id, role):
+        """Append a role for a user atom
+        """
+
+    def userRemoveRole(id, role):
+        """Remove the role of a user atom.
+        This will not, of course, affect implicitly-acquired roles from the user groups.
+        """
+
+    def userSetPassword(id, newPassword):
+        """Set the password of a user
+        """
+
+    def userSetDomains(id, domains):
+        """Set domains for a user
+        """
+
+    def userGetDomains(id, ):
+        """Get domains for a user
+        """
+
+    def userAddDomain(id, domain):
+        """Append a domain to a user
+        """
+
+    def userRemoveDomain(id, domain):
+        """Remove a domain from a user
+        """
+
+    def userSetGroups(userid, groupnames):
+        """Set the groups of a user. Groupnames are, as usual, not prefixed.
+        However, a groupid can be given as a fallback
+        """
+
+    def userAddGroup(id, groupname):
+        """add a group to a user atom. Groupnames are, as usual, not prefixed.
+        However, a groupid can be given as a fallback
+        """
+
+    def userRemoveGroup(id, groupname):
+        """remove a group from a user atom. Groupnames are, as usual, not prefixed.
+        However, a groupid can be given as a fallback
+        """
+
+
+    # Security management
+
+    def setRolesOnUsers(roles, userids):
+        """Set a common set of roles for a bunch of user atoms.
+        """
+
+##    def setUsersOfRole(usernames, role):
+##        """Sets the users of a role.
+##        XXX THIS METHOD SEEMS TO BE SEAMLESS.
+##        """
+
+    def getUsersOfRole(role, object = None):
+        """Gets the user (and group) ids having the specified role...
+        ...on the specified Zope object if it's not None
+        ...on their own information if the object is None.
+        NOTA: THIS METHOD IS VERY EXPENSIVE.
+        """
+
+    def getRolesOfUser(userid):
+        """Alias for user.getRoles()
+        """
+
+    def userFolderAddRole(role):
+        """Add a new role. The role will be appended, in fact, in GRUF's surrounding folder.
+        """
+
+    def userFolderDelRoles(roles):
+        """Delete roles.
+        The removed roles will be removed from the UserFolder's users and groups as well,
+        so this method can be very time consuming with a large number of users.
+        """
+
+    def userFolderGetRoles():
+        """List the roles defined at the top of GRUF's folder.
+        """
+
+
+    # Groups support
+    def setMembers(groupid, userids):
+        """Set the members of the group
+        """
+
+    def addMember(groupid, id):
+        """Add a member to a group
+        """
+
+    def removeMember(groupid, id):
+        """Remove a member from a group
+        """
+
+    def hasMember(groupid, id):
+        """Return true if the specified atom id is in the group.
+        This is the contrary of IUserAtom.isInGroup(groupid).
+        THIS CAN BE VERY EXPENSIVE"""
+
+    def getMemberIds(groupid):
+        """Return the list of member ids (groups and users) in this group.
+        It will unmangle nested groups as well.
+        THIS METHOD CAN BE VERY EXPENSIVE AS IT NEEDS TO FETCH ALL USERS.
+        """
+
+    def getUserMemberIds(groupid):
+        """Same as listMemberIds but only return user ids
+        THIS METHOD CAN BE VERY EXPENSIVE AS IT NEEDS TO FETCH ALL USERS.
+        """
+
+    def getGroupMemberIds(groupid):
+        """Same as listMemberUserIds but only return group ids.
+        THIS METHOD CAN BE VERY EXPENSIVE AS IT NEEDS TO FETCH ALL USERS.
+        """
+
+
+    # Local roles acquisition blocking support
+    def acquireLocalRoles(folder, status):
+        """Enable or disable local role acquisition on the specified folder.
+        If status is true, it will enable, else it will disable.
+        """
+
+    def isLocalRoleAcquired(folder):
+        """Return true if the specified folder allows local role acquisition.
+        """
+
+    # Audit & security checking methods
+
+    def getAllLocalRoles(object):
+        """getAllLocalRoles(self, object): return a dictionnary {user: roles} of local
+        roles defined AND herited at a certain point. This will handle lr-blocking
+        as well.
+        """
+        
+
+class IUserAtom(Interface):
+    """
+    This interface is an abstract representation of what both a User and a Group can do.
+    """
+    # Accessors
+    
+    def getId(unprefixed = 0):
+        """Get the ID of the user. The ID can be used, at least from
+        Python, to get the user from the user's UserDatabase.
+        If unprefixed, remove all prefixes in any case."""
+
+    def getUserName():
+        """Alias for getName()
+        """
+
+    def getName():
+        """Get user's or group's name.
+        For a user, the name can be set by the underlying user folder but usually id == name.
+        For a group, the ID is prefixed, but the NAME is NOT prefixed by 'group_'.
+        """
+
+    def getRoles():
+        """Return the list of roles assigned to a user atom.
+        This will never return gruf-related roles.
+        """
+
+    # Properties are defined depending on the underlying user folder: some support
+    # properties mutation (such as LDAPUserFolder), some do not (such as regular UF).
+
+    def getProperty(name):
+        """Get a property's value.
+        Will raise if not available.
+        """
+
+    def hasProperty(name):
+        """Return true if the underlying user object has a value for the property.
+        """
+
+    # Mutators
+
+    def setProperty(name, value):
+        """Set a property's value.
+        As some user folders cannot set properties, this method is not guaranteed to work
+        and will raise a NotImplementedError if the underlying user folder cannot store
+        properties (or _this_ particular property) for a user.
+        """
+        
+    # XXX We do not allow user name / id changes
+##    def setId(newId):
+##        """Set the id of the user or group. This might change its name as well.
+##        """
+
+##    def setName(newName):
+##        """Set the name of the user or group. Depending on the UserFolder implementation,
+##        this might change the id as well.
+##        """
+
+    def setRoles(roles):
+        """Change user's roles
+        """
+
+    def addRole(role):
+        """Append a role to the user
+        """
+
+    def removeRole(role):
+        """Remove a role from the user's ones
+        """
+
+    # Security-related methods
+
+    def getRolesInContext(object):
+        """Return the list of roles assigned to the user,
+           including local roles assigned in context of
+           the passed in object."""
+
+    def has_permission(permission, object):
+        """Check to see if a user has a given permission on an object."""
+
+    def allowed(object, object_roles=None):
+        """Check whether the user has access to object. The user must
+           have one of the roles in object_roles to allow access."""
+
+    def has_role(roles, object=None):
+        """Check to see if a user has a given role or roles."""
+
+
+
+    # Group management
+
+    # XXX TODO: CLARIFY ID VS. NAME
+
+    def isGroup():
+        """Return true if this atom is a group.
+        """
+
+    def getGroupNames():
+        """Return the names of the groups that the user or group is directly a member of.
+        Return an empty list if the user or group doesn't belong to any group.
+        Doesn't include transitive groups."""
+
+    def getGroupIds():
+        """Return the names of the groups that the user or group is a member of.
+        Return an empty list if the user or group doesn't belong to any group.
+        Doesn't include transitive groups."""
+
+    def getGroups():
+        """getAllGroupIds() alias.
+        Return the IDS (not names) of the groups that the user or group is a member of.
+        Return an empty list if the user or group doesn't belong to any group.
+        THIS WILL INCLUDE TRANSITIVE GROUPS AS WELL."""
+
+    def getAllGroupIds():
+        """Return the names of the groups that the user or group is a member of.
+        Return an empty list if the user or group doesn't belong to any group.
+        Include transitive groups."""
+
+    def getAllGroupNames():
+        """Return the names of the groups that the user or group is directly a member of.
+        Return an empty list if the user or group doesn't belong to any group.
+        Include transitive groups."""
+
+    def isInGroup(groupid):
+        """Return true if the user is member of the specified group id
+        (including transitive groups)"""
+
+    def setGroups(groupids):
+        """Set 'groupids' groups for the user or group.
+        """
+
+    def addGroup(groupid):
+        """Append a group to the current object's groups.
+        """
+
+    def removeGroup(groupid):
+        """Remove a group from the object's groups
+        """
+
+    def getRealId():
+        """Return group id WITHOUT group prefix.
+        For a user, return regular user id.
+        This method is essentially internal.
+        """
+
+
+class IUser(IUserAtom):
+    """
+    A user is a user atom who can log itself on, and
+    have additional properties such as domains and password.
+    """
+    
+    # Accessors
+
+    def getDomains():
+        """Return the list of domain restrictions for a user"""
+
+    # Mutators
+    
+    def setPassword(newPassword):
+        """Set user's password
+        """
+
+    def setDomains(domains):
+        """Replace domains for the user
+        """
+
+    def addDomain(domain):
+        """Append a domain for the user
+        """
+
+    def removeDomain(domain):
+        """Remove a domain for the user
+        """
+
+
+class IGroup(Interface):
+    """
+    A group is a user atom other atoms can belong to.
+    """
+    def getMemberIds(transitive = 1, ):
+        """Return the member ids (users and groups) of the atoms of this group.
+        This method can be very expensive !"""
+
+    def getUserMemberIds(transitive = 1, ):
+        """Return the member ids (users only) of the users of this group"""
+
+    def getGroupMemberIds(transitive = 1, ):
+        """Return the members ids (groups only) of the groups of this group"""
+
+    def hasMember(id):
+        """Return true if the specified atom id is in the group.
+        This is the contrary of IUserAtom.isInGroup(groupid)"""
+
+    def addMember(userid):
+         """Add a user the the current group"""
+         
+    def removeMember(userid):
+         """Remove a user from the current group"""