diff --git a/fas/fas/auth.py b/fas/fas/auth.py index 990a0ef..f1e56de 100644 --- a/fas/fas/auth.py +++ b/fas/fas/auth.py @@ -53,11 +53,93 @@ def isApproved(userName, groupName, g=None): except: return False -def canEditUser(userName, editUserName): +def canEditUser(userName, editUserName, g=None): + if not g: + g = Groups.byUserName(userName) if userName == editUserName: return True - elif isAdmin(userName): + elif isAdmin(userName, g): return True else: return False +def canCreateGroup(userName, groupName, g=None): + if not g: + g = Groups.byUserName(userName) + if isAdmin(userName, g): + return True + else: + return False + +def canEditGroup(userName, groupName, g=None): + if not g: + g = Groups.byUserName(userName) + if canAdminGroup(userName, groupName): + return True + else: + return False + +def canApplyGroup(userName, groupName, applyUserName, g=None): + # This is where we could make groups depend on other ones. + if not g: + g = Groups.byUserName(userName) + # A user can apply themselves, and FAS admins can apply other people. + if (userName == applyUserName) or \ + isAdmin(userName, g): + return True + else: + return False + +def canSponsorUser(userName, groupName, sponsorUserName, g=None): + if not g: + g = Groups.byUserName(userName) + # This is just here in case we want to add more complex checks in the future + if canSponsorGroup(userName, groupName, g): + return True + else: + return False + +def canRemoveUser(userName, groupName, removeUserName, g=None): + if not g: + g = Groups.byUserName(userName) + group = Groups.groups(groupName)[groupName] + # Only administrators can remove administrators. + if canAdminGroup(removeUserName, groupName) and \ + not canAdminGroup(userName, groupName, g): + return False + # A user can remove themself from a group if fedoraGroupUserCanRemove is TRUE + # Otherwise, a sponsor can remove sponsors/users. + elif ((userName == removeUserName) and (group.fedoraGroupUserCanRemove.lower() == 'TRUE')) or \ + canSponsorGroup(userName, groupName, g): + return True + else: + return False + +def canUpgradeUser(userName, groupName, sponsorUserName, g=None): + if not g: + g = Groups.byUserName(userName) + # Group admins can upgrade anybody (fasLDAP.py has the checks to prevent + # upgrading admins, etc. + if canAdminGroup(userName, groupName, g): + return True + # Sponsors can only upgrade non-sponsors (i.e. normal users) fasLDAP.py + # ensures that sponsorUserName is at least an approved user. + elif canSponsorGroup(userName, groupName, g) and \ + not canSponsorGroup(sponsorUserName, groupName): + return True + else: + return False + +def canDowngradeUser(userName, groupName, sponsorUserName, g=None): + if not g: + g = Groups.byUserName(userName) + # Group admins can downgrade anybody. + if canAdminGroup(userName, groupName, g): + return True + # Sponsors can only downgrade sponsors. (fasLDAP.py won't let you + # downgrade a normal user already) + elif canSponsorGroup(userName, groupName, g) and \ + not canAdminGroup(sponsorUserName, groupName): + return True + else: + return False diff --git a/fas/fas/group.py b/fas/fas/group.py index 6b20a02..fb4c910 100644 --- a/fas/fas/group.py +++ b/fas/fas/group.py @@ -10,7 +10,7 @@ from fas.fasLDAP import Person from fas.fasLDAP import Groups from fas.fasLDAP import UserGroup -from fas.auth import isAdmin, canAdminGroup, canSponsorGroup, canEditUser +from fas.auth import * from fas.user import knownUser, userNameExists @@ -102,7 +102,7 @@ class Group(controllers.Controller): def new(self): '''Display create group form''' userName = turbogears.identity.current.user_name - if not isAdmin(userName): + if not canCreateGroup(userName): turbogears.flash(_('Only FAS adminstrators can create groups.')) turbogears.redirect('/') return dict() @@ -114,7 +114,7 @@ class Group(controllers.Controller): def create(self, groupName, fedoraGroupDesc, fedoraGroupOwner, fedoraGroupNeedsSponsor="FALSE", fedoraGroupUserCanRemove="FALSE", fedoraGroupJoinMsg=""): '''Create a group''' userName = turbogears.identity.current.user_name - if not isAdmin(userName): + if not canCreateGroup(userName): turbogears.flash(_('Only FAS adminstrators can create groups.')) turbogears.redirect('/') try: @@ -168,24 +168,24 @@ class Group(controllers.Controller): def save(self, groupName, fedoraGroupDesc, fedoraGroupOwner, fedoraGroupType=1, fedoraGroupNeedsSponsor="FALSE", fedoraGroupUserCanRemove="FALSE", fedoraGroupJoinMsg=""): '''Edit a group''' userName = turbogears.identity.current.user_name - if not canAdminGroup(userName, groupName): + if not canEditGroup(userName, groupName): turbogears.flash(_("You cannot edit '%s'.") % groupName) turbogears.redirect('/group/view/%s' % groupName) # TODO: This is kind of an ugly hack. - base = 'cn=%s,ou=FedoraGroups,dc=fedoraproject,dc=org' % groupName - try: - fas.fasLDAP.modify(base, 'fedoraGroupDesc', fedoraGroupDesc.encode('utf8')) - fas.fasLDAP.modify(base, 'fedoraGroupOwner', fedoraGroupOwner.encode('utf8')) - fas.fasLDAP.modify(base, 'fedoraGroupType', str(fedoraGroupType).encode('utf8')) - fas.fasLDAP.modify(base, 'fedoraGroupNeedsSponsor', fedoraGroupNeedsSponsor.encode('utf8')) - fas.fasLDAP.modify(base, 'fedoraGroupUserCanRemove', fedoraGroupUserCanRemove.encode('utf8')) - fas.fasLDAP.modify(base, 'fedoraGroupJoinMsg', fedoraGroupJoinMsg.encode('utf8')) - except: - turbogears.flash(_('The group details could not be saved.')) - return dict() else: - turbogears.flash(_('The group details have been saved.')) - turbogears.redirect('/group/view/%s' % groupName) + base = 'cn=%s,ou=FedoraGroups,dc=fedoraproject,dc=org' % groupName + try: + fas.fasLDAP.modify(base, 'fedoraGroupDesc', fedoraGroupDesc.encode('utf8')) + fas.fasLDAP.modify(base, 'fedoraGroupOwner', fedoraGroupOwner.encode('utf8')) + fas.fasLDAP.modify(base, 'fedoraGroupType', str(fedoraGroupType).encode('utf8')) + fas.fasLDAP.modify(base, 'fedoraGroupNeedsSponsor', fedoraGroupNeedsSponsor.encode('utf8')) + fas.fasLDAP.modify(base, 'fedoraGroupUserCanRemove', fedoraGroupUserCanRemove.encode('utf8')) + fas.fasLDAP.modify(base, 'fedoraGroupJoinMsg', fedoraGroupJoinMsg.encode('utf8')) + except: + turbogears.flash(_('The group details could not be saved.')) + else: + turbogears.flash(_('The group details have been saved.')) + turbogears.redirect('/group/view/%s' % groupName) return dict() @expose(template="fas.templates.group.list") @@ -205,16 +205,27 @@ class Group(controllers.Controller): @error_handler(error) @expose(template='fas.templates.group.view') @identity.require(turbogears.identity.not_anonymous()) - def apply(self, groupName, userName): + def apply(self, groupName, userName=None): '''Apply to a group''' - try: - Groups.apply(groupName, userName) - except ldap.ALREADY_EXISTS: - turbogears.flash(_('%(user)s is already in %(group)s!') % {'user': userName, 'group': groupName}) + applicant = turbogears.identity.current.user_name + if not userName: + userName = applicant + if not canApplyGroup(applicant, groupName, userName): + turbogears.flash(_('You cannot apply %(user)s for %(group)s!') % \ + {'user': userName, 'group': groupName}) turbogears.redirect('/group/view/%s' % groupName) + return dict() else: - turbogears.flash(_('%(user)s has applied to %(group)s!') % {'user': userName, 'group': groupName}) - turbogears.redirect('/group/view/%s' % groupName) + try: + Groups.apply(groupName, userName) + except ldap.ALREADY_EXISTS: + turbogears.flash(_('%(user)s has already applied to %(group)s!') % \ + {'user': userName, 'group': groupName}) + else: + turbogears.flash(_('%(user)s has applied to %(group)s!') % \ + {'user': userName, 'group': groupName}) + turbogears.redirect('/group/view/%s' % groupName) + return dict() @validate(validators=userNameGroupNameExists()) @error_handler(error) @@ -223,21 +234,24 @@ class Group(controllers.Controller): def sponsor(self, groupName, userName): '''Sponsor user''' sponsor = turbogears.identity.current.user_name - if not canSponsorGroup(sponsor, groupName): - turbogears.flash(_("You are not a sponsor for '%s'") % groupName) + if not canSponsorUser(sponsor, groupName, userName): + turbogears.flash(_("You cannot sponsor '%s'") % userName) turbogears.redirect('/group/view/%s' % groupName) - try: - group = Groups.groups(groupName)[groupName] - except KeyError: - turbogears.flash(_('Group Error: %s does not exist.') % groupName) - # The following line is kind of pointless- any suggestions? - turbogears.redirect('/group/view/%s' % groupName) - p = Person.byUserName(userName) - g = Groups.byGroupName(groupName, includeUnapproved=True) - # TODO: Check if the person actually applied to the group. - p.sponsor(groupName, sponsor) - turbogears.flash(_('%s has been sponsored!') % p.cn) - turbogears.redirect('/group/view/%s' % groupName) + return dict() + else: + p = Person.byUserName(userName) + # TODO: Check if the person actually applied to the group. + # (or should this be done in auth.py or fasLDAP.py?) + # this will probably give a 500 now if the user didn't apply + try: + p.sponsor(groupName, sponsor) + except: + turbogears.flash(_("'%s' could not be sponsored!") % p.cn) + turbogears.redirect('/group/view/%s' % groupName) + else: + turbogears.flash(_("'%s' has been sponsored!") % p.cn) + turbogears.redirect('/group/view/%s' % groupName) + return dict() @validate(validators=userNameGroupNameExists()) @error_handler(error) @@ -247,23 +261,22 @@ class Group(controllers.Controller): '''Remove user from group''' # TODO: Add confirmation? sponsor = turbogears.identity.current.user_name - if not canSponsorGroup(sponsor, groupName) \ - and sponsor != userName: # Users can remove themselves - turbogears.flash(_("You are not a sponsor for '%s'") % groupName) - turbogears.redirect('/group/view/%s' % groupName) - if canAdminGroup(userName, groupName) \ - and (not canAdminGroup(sponsor, groupName)): - turbogears.flash(_('Sponsors cannot remove administrators.') % userName) - turbogears.redirect('/group/view/%s' % groupName) - try: - Groups.remove(groupName, userName) - except TypeError: - turbogears.flash(_('%(name)s could not be removed from %(group)s!') % {'name': userName, 'group': groupName}) + if not canRemoveUser(sponsor, groupName, userName): + turbogears.flash(_("You cannot remove '%s'.") % userName) turbogears.redirect('/group/view/%s' % groupName) + return dict() else: - turbogears.flash(_('%(name)s has been removed from %(group)s!') % {'name': userName, 'group': groupName}) - turbogears.redirect('/group/view/%s' % groupName) - return dict() + try: + Groups.remove(groupName, userName) + except: + turbogears.flash(_('%(name)s could not be removed from %(group)s!') % \ + {'name': userName, 'group': groupName}) + turbogears.redirect('/group/view/%s' % groupName) + else: + turbogears.flash(_('%(name)s has been removed from %(group)s!') % \ + {'name': userName, 'group': groupName}) + turbogears.redirect('/group/view/%s' % groupName) + return dict() @validate(validators=userNameGroupNameExists()) @error_handler(error) @@ -272,25 +285,21 @@ class Group(controllers.Controller): def upgrade(self, groupName, userName): '''Upgrade user in group''' sponsor = turbogears.identity.current.user_name - if not canSponsorGroup(sponsor, groupName): - turbogears.flash(_("You are not a sponsor for '%s'") % groupName) + if not canUpgradeUser(sponsor, groupName, userName): + turbogears.flash(_("You cannot upgrade '%s'") % userName) turbogears.redirect('/group/view/%s' % groupName) - # This is already checked in fasLDAP.py - #if canAdminGroup(userName, groupName): - # turbogears.flash(_('Group administators cannot be upgraded any further.')) - # turbogears.redirect('/group/view/%s' % groupName) - elif canSponsorGroup(userName, groupName) \ - and (not canAdminGroup(sponsor, groupName)): - turbogears.flash(_('Sponsors cannot upgrade other sponsors.') % userName) - turbogears.redirect('/group/view/%s' % groupName) - p = Person.byUserName(userName) - try: - p.upgrade(groupName) - except: - turbogears.flash(_('%(name)s could not be upgraded!') % userName) - turbogears.redirect('/group/view/%s' % groupName) - turbogears.flash(_('%s has been upgraded!') % userName) - turbogears.redirect('/group/view/%s' % groupName) + return dict() + else: + p = Person.byUserName(userName) + try: + p.upgrade(groupName) + except: + turbogears.flash(_('%(name)s could not be upgraded!') % userName) + turbogears.redirect('/group/view/%s' % groupName) + else: + turbogears.flash(_('%s has been upgraded!') % userName) + turbogears.redirect('/group/view/%s' % groupName) + return dict() @validate(validators=userNameGroupNameExists()) @error_handler(error) @@ -299,21 +308,21 @@ class Group(controllers.Controller): def downgrade(self, groupName, userName): '''Upgrade user in group''' sponsor = turbogears.identity.current.user_name - if not canSponsorGroup(sponsor, groupName): - turbogears.flash(_("You are not a sponsor for '%s'") % groupName) + if not canDowngradeUser(sponsor, groupName, userName): + turbogears.flash(_("You cannot downgrade '%s'") % userName) turbogears.redirect('/group/view/%s' % groupName) - if canAdminGroup(userName, groupName) \ - and (not canAdminGroup(sponsor, groupName)): - turbogears.flash(_('Sponsors cannot downgrade group administrators.') % userName) - turbogears.redirect('/group/view/%s' % groupName) - p = Person.byUserName(userName) - try: - p.upgrade(groupName) - except: - turbogears.flash(_('%(name)s could not be downgraded!') % userName) - turbogears.redirect('/group/view/%s' % groupName) - turbogears.flash(_('%s has been downgraded!') % p.cn) - turbogears.redirect('/group/view/%s' % groupName) + return dict() + else: + p = Person.byUserName(userName) + try: + p.upgrade(groupName) + except: + turbogears.flash(_('%(name)s could not be downgraded!') % userName) + turbogears.redirect('/group/view/%s' % groupName) + else: + turbogears.flash(_('%s has been downgraded!') % p.cn) + turbogears.redirect('/group/view/%s' % groupName) + return dict() @validate(validators=groupNameExists()) @error_handler(error) diff --git a/fas/fas/templates/group/view.html b/fas/fas/templates/group/view.html index ccaf549..f9dad6e 100644 --- a/fas/fas/templates/group/view.html +++ b/fas/fas/templates/group/view.html @@ -70,13 +70,21 @@ diff --git a/fas/fas/templates/user/view.html b/fas/fas/templates/user/view.html index 6cd65a1..bb3dcc7 100644 --- a/fas/fas/templates/user/view.html +++ b/fas/fas/templates/user/view.html @@ -51,7 +51,7 @@
  • Invite a New Member...
  • View All Pending Group Membership Requests...
  • Manage Group Membership...
  • -
  • Manage Group Details...
  • +
  • Manage Group Details...
  • diff --git a/fas/fas/user.py b/fas/fas/user.py index 1a318fb..8a489df 100644 --- a/fas/fas/user.py +++ b/fas/fas/user.py @@ -10,7 +10,7 @@ from fas.fasLDAP import Person from fas.fasLDAP import Groups from fas.fasLDAP import UserGroup -from fas.auth import isAdmin, canAdminGroup, canSponsorGroup, canEditUser +from fas.auth import * class knownUser(validators.FancyValidator): '''Make sure that a user already exists'''