# usermanager.py """ UserManager is a collection of User objects. It can create new users, load users from a repository, and save users to the repository. To avoid risking corruption of the repository, there should be only one UserManager instance for the entire application. 20010619 JJD Created. 20021115 JJD Remove group-related features. Use shelve as repository. 20021119 JJD Just assume that the repository is some kind of mapping, and make its opening and closing external. Add exception classes. """ from user import User class UserManagerError(Exception): pass class UserLimitExceededError(UserManagerError): pass class AuthenticationFailedError(UserManagerError): pass class DuplicateUsernameError(UserManagerError): pass class UserManager: def __init__(self, usermapping=None, userclass=None, maxusers=0): if userclass is not None: self._userclass = userclass else: self._userclass = User if usermapping is not None: self._users = usermapping else: # Dict is useful for testing self._users = {} self._maxusers = maxusers def authenticate(self, username, password): """If username and password match one of the users, return that user. Otherwise, return None.""" user = None if len(self._users) > self._maxusers > 0: raise UserLimitExceededError try: user = self.user(username) except KeyError: raise if not user.validatePassword(password): raise AuthenticationFailedError return user def addUser(self, user): """This should be the only way to add a user to the collection.""" if 1+len(self._users) > self._maxusers > 0: raise UserLimitExceededError if not isinstance(user, self._userclass): raise TypeError username = user.username() if self._users.has_key(username): raise DuplicateUsernameError(username) self._users[username] = user def user(self, username): try: user = self._users[username] except KeyError: raise return user def updateUser(self, username, user): """Allow an edited user to be re-entered in the collection.""" if not isinstance(user, self._userclass): raise TypeError assert username == user.username() if self._users.has_key(username): self._users[username] = user else: raise KeyError(username) def removeUser(self, username): """Note: Raises KeyError if username not found.""" del self._users[username] ## Partial dict interface for convenience ## def keys(self): return self._users.keys() def has_key(self, username): return self._users.has_key(username) def get(self, username, default=None): return self._users.get(username, default) __getitem__ = user __delitem__ = removeUser def __len__(self): return len(self._users) def __repr__ (self): return "<%s at %x: %s>" % (self.__class__.__name__, id(self), type(self._users)) if __name__ == '__main__': class SuperDuperUser(User): pass print "\nTesting UserManager and User classes\n" um = UserManager() print repr(um) clem = SuperDuperUser('clem', 'idiot', securitylevel=1, new=1) um.addUser(clem) print "Add user:", repr(um['clem']) print "Try to add same user:", try: um.addUser(clem) except Exception, why: print "Duplicate username:", str(why) freddy = User('freddy', 'freeloader', securitylevel=1, new=1) um.addUser(freddy) print "Add user:", repr(um.user('freddy')) print "Number of users:", len(um) print "Get rid of freddy. " del um['freddy'] print "Number of users:", len(um) print "Try to get freddy." try: print um.user('freddy') except KeyError, why: print "Not found:", str(why) print "Authenticate 'clem', 'idiot':", um.authenticate('clem', 'idiot') print "But not 'clem', 'genius':", try: print um.authenticate('clem', 'genius') except Exception, why: print "Failed.", str(why) print "Dump of clem:\n", um['clem'].dump()