From f15b43c34bad2fe13adabd3246d78d283f3b7170 Mon Sep 17 00:00:00 2001 From: Michael McGrath Date: Tue, 26 Feb 2008 13:48:43 -0600 Subject: [PATCH 1/8] added an explicit flush so sponsorship and upgrades work properly --- fas/fas/group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fas/fas/group.py b/fas/fas/group.py index 545c2a4..f29874a 100644 --- a/fas/fas/group.py +++ b/fas/fas/group.py @@ -174,8 +174,8 @@ class Group(controllers.Controller): return dict() else: try: - session.flush() owner.apply(group, person) # Apply... + session.flush() owner.sponsor(group, person) owner.upgrade(group, person) owner.upgrade(group, person) From 931fe79760a3355dc43ef0e04e2bc7379a9ba007 Mon Sep 17 00:00:00 2001 From: Michael McGrath Date: Tue, 26 Feb 2008 14:44:14 -0600 Subject: [PATCH 2/8] Added userlist and create group to the side menu via method provided by toshio --- fas/fas/templates/master.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fas/fas/templates/master.html b/fas/fas/templates/master.html index af4db79..9c634d5 100644 --- a/fas/fas/templates/master.html +++ b/fas/fas/templates/master.html @@ -50,11 +50,11 @@ From 9984ff5aeedf08c3ccaa6da085cb7df23fcb0b22 Mon Sep 17 00:00:00 2001 From: Michael McGrath Date: Tue, 26 Feb 2008 15:43:27 -0600 Subject: [PATCH 4/8] user listing working again for admins --- fas/fas/templates/user/list.html | 8 ++++---- fas/fas/user.py | 24 ++++++++++++++++-------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/fas/fas/templates/user/list.html b/fas/fas/templates/user/list.html index c21f7ff..1b46b8c 100644 --- a/fas/fas/templates/user/list.html +++ b/fas/fas/templates/user/list.html @@ -28,11 +28,11 @@ - - ${user} + + ${person.username} - ${_('CLA Done')} - ${_('CLA Not Done')} + ${_('CLA Done')} + ${_('CLA Not Done')} diff --git a/fas/fas/user.py b/fas/fas/user.py index bac12a9..fcebf9b 100644 --- a/fas/fas/user.py +++ b/fas/fas/user.py @@ -1,6 +1,7 @@ import turbogears from turbogears import controllers, expose, paginate, identity, redirect, widgets, validate, validators, error_handler from turbogears.database import session +import cherrypy import ldap @@ -135,6 +136,11 @@ class User(controllers.Controller): ''' turbogears.redirect('/user/view/%s' % turbogears.identity.current.user_name) + def jsonRequest(self): + return 'tg_format' in cherrypy.request.params and \ + cherrypy.request.params['tg_format'] == 'json' + + @expose(template="fas.templates.error") def error(self, tg_errors=None): '''Show a friendly error message''' @@ -222,17 +228,19 @@ class User(controllers.Controller): return dict(target=target) @identity.require(turbogears.identity.in_group("accounts")) #TODO: Use auth.py - @expose(template="fas.templates.user.list") + @expose(template="fas.templates.user.list", allow_json=True) def list(self, search="a*"): '''List users ''' - people = People.query.filter(People.username.like('%%%s%%' % username)) - try: - people[0] - except: - turbogears.flash(_("No users found matching '%s'") % search) - people = [] - return dict(users=users, search=search) + re_search = re.sub(r'\*', r'%', search).lower() + people = People.query.filter(People.username.like(re_search)).order_by('username') + if people.count() < 0: + turbogears.flash(_("No Users found matching '%s'") % search) + if self.jsonRequest(): + return ({'users': users}) + cla_done_group = Groups.by_name('cla_done') + + return dict(people=people, search=search, cla_done_group=cla_done_group) @expose(template='fas.templates.user.new') def new(self): From 06568942cd517c4bfbe524569dee3099551aa761 Mon Sep 17 00:00:00 2001 From: Michael McGrath Date: Tue, 26 Feb 2008 15:43:43 -0600 Subject: [PATCH 5/8] Self application to groups works again. We're getting real close now --- fas/fas/auth.py | 14 +++++++++++--- fas/fas/group.py | 14 ++++++++------ fas/fas/templates/group/list.html | 2 +- fas/fas/templates/group/view.html | 4 +++- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/fas/fas/auth.py b/fas/fas/auth.py index 5710fdb..40b2fe4 100644 --- a/fas/fas/auth.py +++ b/fas/fas/auth.py @@ -37,10 +37,12 @@ def canAdminGroup(person, group): return True else: try: - role = PersonRoles.query.filter_by(group_id=g.id, person_id=p.id).one() + role = PersonRoles.query.filter_by(group_id=group.id, person_id=person.id).one() except IndexError: ''' Not in the group ''' return False + except InvalidRequestError: + return False if r.role_status == 'approved' and r.role_type == 'administrator': return True return False @@ -165,16 +167,22 @@ def canApplyGroup(person, group, applicant): # owner of the group (when they initially make it). prerequisite = group.prerequisite # TODO: Make this return more useful info. - if prequisite: + + if prerequisite: + if prerequisite in person.approved_memberships: pass else: + print "GOT HERE %s" % prerequisite + turbogears.flash(_('%s membership required before application to this group is allowed' % prerequisite.name)) return False # A user can apply themselves, and FAS admins can apply other people. - if (username == applicant) or \ + + if (person == applicant) or \ canAdminGroup(person, group): return True else: + turbogears.flash(_('%s membership required before application to this group is allowed' % prerequisite.name)) return False def canSponsorUser(person, group, target): diff --git a/fas/fas/group.py b/fas/fas/group.py index f29874a..33e02d2 100644 --- a/fas/fas/group.py +++ b/fas/fas/group.py @@ -58,7 +58,7 @@ class editGroup(validators.Schema): class usernameGroupnameExists(validators.Schema): groupname = validators.All(knownGroup(not_empty=True, max=10), validators.String(max=32, min=3)) - username = validators.All(knownUser(not_empty=True, max=10), validators.String(max=32, min=3)) + targetname = validators.All(knownUser(not_empty=True, max=10), validators.String(max=32, min=3)) class groupnameExists(validators.Schema): groupname = validators.All(knownGroup(not_empty=True, max=10), validators.String(max=32, min=3)) @@ -265,8 +265,8 @@ class Group(controllers.Controller): group = Groups.by_name(groupname) if not canApplyGroup(person, group, target): - turbogears.flash(_('%(user)s could not apply to %(group)s.') % \ - {'user': target.username, 'group': group.name }) + # turbogears.flash(_('%(user)s could not apply to %(group)s.') % \ + # {'user': target.username, 'group': group.name }) turbogears.redirect('/group/view/%s' % group.name) return dict() else: @@ -277,16 +277,18 @@ class Group(controllers.Controller): {'user': target.username, 'group': group.name}) else: import turbomail + # TODO: CC to right place, put a bit more thought into how to most elegantly do this message = turbomail.Message(config.get('accounts_mail'), '%s-sponsors@fedoraproject.org' % group.name, \ "Fedora '%(group)s' sponsor needed for %(user)s" % {'user': target.username, 'group': group.name}) - url = config.get('base_url') + turbogears.url('/group/edit/%s' % groupname) + url = config.get('base_url_filter.base_url') + turbogears.url('/group/edit/%s' % groupname) + message.plain = dedent(''' Fedora user %(user)s, aka %(name)s <%(email)s> has requested - membership for %(applicant) (%(applicant_name)) in the %(group) group and needs a sponsor. + membership for %(applicant)s (%(applicant_name)s) in the %(group)s group and needs a sponsor. Please go to %(url)s to take action. - ''') % {'user': person.username, 'name': person.human_name, 'applicant': target.username, 'applicant_name': target.human_name, 'email': person.emails['primary'].email, 'url': url} + ''' % {'user': person.username, 'name': person.human_name, 'applicant': target.username, 'applicant_name': target.human_name, 'email': person.emails['primary'].email, 'url': url, 'group': group.name} ) turbomail.enqueue(message) turbogears.flash(_('%(user)s has applied to %(group)s!') % \ {'user': target.username, 'group': group.name}) diff --git a/fas/fas/templates/group/list.html b/fas/fas/templates/group/list.html index 3d6aaeb..f16efa6 100644 --- a/fas/fas/templates/group/list.html +++ b/fas/fas/templates/group/list.html @@ -43,7 +43,7 @@ - ${_('Apply')} + ${_('Apply')} diff --git a/fas/fas/templates/group/view.html b/fas/fas/templates/group/view.html index b0abb8f..84c25a8 100644 --- a/fas/fas/templates/group/view.html +++ b/fas/fas/templates/group/view.html @@ -38,7 +38,9 @@ ${_('No')}  
${_('Join Message:')}
${group.joinmsg} 
-
${_('Prerequisite:')}
${group.prerequisite.name} 
+
${_('Prerequisite:')}
+
${group.prerequisite.name} 
+
 
${_('Created:')}
${group.creation} 
From 2a8e369daa3db77769d00ff2270566a02e9759a5 Mon Sep 17 00:00:00 2001 From: Michael McGrath Date: Tue, 26 Feb 2008 16:14:01 -0600 Subject: [PATCH 6/8] This might break bugzilla syncs, not sure. Right now though it does allow us to delete members --- fas/fas2.sql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fas/fas2.sql b/fas/fas2.sql index 3a4edae..ced9430 100644 --- a/fas/fas2.sql +++ b/fas/fas2.sql @@ -276,6 +276,8 @@ create or replace function bugzilla_sync() returns trigger as $bz_sync$ row = TD['new'] # If this is not a fedorabugs role, no change needed + if not row: + return None if row['group_id'] != result[0]['id']: return None From a858cf4b231e0e4ff6d8e864ae2de7c4e51542cc Mon Sep 17 00:00:00 2001 From: Michael McGrath Date: Tue, 26 Feb 2008 16:43:43 -0600 Subject: [PATCH 7/8] self removal now working --- fas/fas/auth.py | 6 ++++-- fas/fas/group.py | 14 +++++++------- fas/fas/model.py | 24 +++++++++++++----------- fas/fas/templates/group/list.html | 8 ++++---- fas/fas/templates/group/view.html | 6 +++--- 5 files changed, 31 insertions(+), 27 deletions(-) diff --git a/fas/fas/auth.py b/fas/fas/auth.py index 40b2fe4..886535c 100644 --- a/fas/fas/auth.py +++ b/fas/fas/auth.py @@ -43,7 +43,7 @@ def canAdminGroup(person, group): return False except InvalidRequestError: return False - if r.role_status == 'approved' and r.role_type == 'administrator': + if role.role_status == 'approved' and role.role_type == 'administrator': return True return False @@ -205,10 +205,12 @@ def canRemoveUser(person, group, target): return False # A user can remove themself from a group if user_can_remove is 1 # Otherwise, a sponsor can remove sponsors/users. - elif ((person == target) and (group.user_can_remove == 1)) or \ + elif ((person == target) and (group.user_can_remove == True)) or \ canSponsorGroup(person, group): + print "GOT HERE TRUE" return True else: + print "GOT HERE FALSE" return False def canUpgradeUser(person, group, target): diff --git a/fas/fas/group.py b/fas/fas/group.py index 33e02d2..a6d87c5 100644 --- a/fas/fas/group.py +++ b/fas/fas/group.py @@ -340,23 +340,23 @@ class Group(controllers.Controller): # TODO: Add confirmation? username = turbogears.identity.current.user_name person = People.by_username(username) - target = People.by_username(targetname) + requester = People.by_username(targetname) group = Groups.by_name(groupname) - if not canRemoveUser(person, group, target): + if not canRemoveUser(person, group, requester): turbogears.flash(_("You cannot remove '%s'.") % target.username) turbogears.redirect('/group/view/%s' % group.name) return dict() else: try: - group.remove_person(person, target) - except: + person.remove(group, requester) + except KeyError: turbogears.flash(_('%(name)s could not be removed from %(group)s!') % \ - {'name': target.username, 'group': group.name}) + {'name': requester.username, 'group': group.name}) turbogears.redirect('/group/view/%s' % group.name) else: import turbomail - message = turbomail.Message(config.get('accounts_mail'), target.emails['primary'].email, "Your Fedora '%s' membership has been removed" % group.name) + message = turbomail.Message(config.get('accounts_mail'), requester.emails['primary'].email, "Your Fedora '%s' membership has been removed" % group.name) message.plain = dedent(''' %(name)s <%(email)s> has removed you from the '%(group)s' group of the Fedora Accounts System This change is effective @@ -365,7 +365,7 @@ class Group(controllers.Controller): ''') % {'group': group.name, 'name': person.human_name, 'email': person.emails['primary'].email} turbomail.enqueue(message) turbogears.flash(_('%(name)s has been removed from %(group)s!') % \ - {'name': target.username, 'group': group.name}) + {'name': requester.username, 'group': group.name}) turbogears.redirect('/group/view/%s' % group.name) return dict() diff --git a/fas/fas/model.py b/fas/fas/model.py index 3503642..ad78e34 100644 --- a/fas/fas/model.py +++ b/fas/fas/model.py @@ -37,6 +37,8 @@ from sqlalchemy.orm.collections import column_mapped_collection from sqlalchemy.ext.associationproxy import association_proxy from sqlalchemy import select, and_ +from turbogears.database import session + from turbogears import identity from fas.json import SABase @@ -112,7 +114,7 @@ class People(SABase): by_username = classmethod(by_username) # If we're going to do logging here, we'll have to pass the person that did the applying. - def apply(cls, group, requestor): + def apply(cls, group, requester): ''' Apply a person to a group ''' @@ -122,9 +124,9 @@ class People(SABase): role.member = cls role.group = group - def approve(cls, group, requestor): + def approve(cls, group, requester): ''' - Approve a person in a group - requestor for logging purposes + Approve a person in a group - requester for logging purposes ''' if group in cls.approved_memberships: raise '%s is already approved in %s' % (cls.username, group.name) @@ -132,9 +134,9 @@ class People(SABase): role = PersonRoles.query.filter_by(person_id=cls.id, group_id=group.id).first() role.role_status = 'approved' - def upgrade(cls, group, requestor): + def upgrade(cls, group, requester): ''' - Upgrade a user in a group - requestor for logging purposes + Upgrade a user in a group - requester for logging purposes ''' if not group in cls.memberships: raise '%s not a member of %s' % (group.name, cls.memberships) @@ -147,9 +149,9 @@ class People(SABase): elif role.role_type == 'user': role.role_type = 'sponsor' - def downgrade(cls, group, requestor): + def downgrade(cls, group, requester): ''' - Downgrade a user in a group - requestor for logging purposes + Downgrade a user in a group - requester for logging purposes ''' if not group in cls.memberships: raise '%s not a member of %s' % (group.name, cls.memberships) @@ -162,20 +164,20 @@ class People(SABase): elif role.role_type == 'administrator': role.role_type = 'sponsor' - def sponsor(cls, group, requestor): + def sponsor(cls, group, requester): # If we want to do logging, this might be the place. # TODO: Find out how to log timestamp if not group in cls.memberships: raise '%s not a member of %s' % (group.name, cls.memberships) role = PersonRoles.query.filter_by(person_id=cls.id, group_id=group.id).first() role.role_status = 'approved' - role.sponsor_id = requestor.id + role.sponsor_id = requester.id - def remove(cls, group, requestor): + def remove(cls, group, requester): role = PersonRoles.query.filter_by(person_id=cls.id, group_id=group.id).first() try: session.delete(role) - except: + except TypeError: pass # Handle somehow. diff --git a/fas/fas/templates/group/list.html b/fas/fas/templates/group/list.html index f16efa6..332338e 100644 --- a/fas/fas/templates/group/list.html +++ b/fas/fas/templates/group/list.html @@ -39,11 +39,11 @@ ${group.name} ${ group.display_name } - - + + ${_('Approved')} + ${_('Unapproved')} - ${_('Apply')} + ${_('Apply')} diff --git a/fas/fas/templates/group/view.html b/fas/fas/templates/group/view.html index 84c25a8..7295850 100644 --- a/fas/fas/templates/group/view.html +++ b/fas/fas/templates/group/view.html @@ -11,8 +11,8 @@

${group.display_name} (${group.name})

${_('My Status:')} - ${_('Approved')} - ${_('Unapproved')} + ${_('Approved')} + ${_('Unapproved')} ${_('Not a Member')}

@@ -22,7 +22,7 @@
${_('Remove me')} -

Group Details ${_('(edit)')}

+

Group Details ${_('(edit)')}

${_('Name:')}
${group.name} 
From 84d6a4b27b26a415463e588de4bfbfe35a51ace0 Mon Sep 17 00:00:00 2001 From: Michael McGrath Date: Tue, 26 Feb 2008 17:01:41 -0600 Subject: [PATCH 8/8] Got initial sponsor button to show up, have to run --- fas/fas/templates/group/view.html | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/fas/fas/templates/group/view.html b/fas/fas/templates/group/view.html index 7295850..a912f5a 100644 --- a/fas/fas/templates/group/view.html +++ b/fas/fas/templates/group/view.html @@ -70,20 +70,20 @@ from datetime import datetime from pytz import timezone ?> - + ${role.member.creation} ${role.member.creation} - + ${role.member.timezone} ${role.role_status} ${role.role_type}
    - - --> +