Add club representative support

The only difference between a club representative account and a member account
is how they are registered for terms.  If you are already a representative for
the current term, you need only go through the membership renewal process to
become a full fledged member.
This commit is contained in:
Michael Spang 2007-12-20 16:43:33 -05:00
parent e28b159cdc
commit 34b2aa1028
5 changed files with 126 additions and 17 deletions

View File

@ -426,6 +426,41 @@ def register(userid, term_list):
ld.modify_s(user_dn, mlist)
def register_nonmember(userid, term_list):
"""Registers a non-member for one or more terms."""
user_dn = 'uid=%s,%s' % (ldapi.escape(userid), cfg['users_base'])
if type(term_list) in (str, unicode):
term_list = [ term_list ]
ldap_member = get(userid)
if not ldap_member:
raise NoSuchMember(userid)
if 'term' not in ldap_member:
ldap_member['term'] = []
if 'nonMemberTerm' not in ldap_member:
ldap_member['nonMemberTerm'] = []
new_member = ldap_member.copy()
new_member['nonMemberTerm'] = new_member['nonMemberTerm'][:]
for term in term_list:
# check term syntax
if not re.match('^[wsf][0-9]{4}$', term):
raise InvalidTerm(term)
# add the term to the entry
if not term in ldap_member['nonMemberTerm'] \
and not term in ldap_member['term']:
new_member['nonMemberTerm'].append(term)
mlist = ldapi.make_modlist(ldap_member, new_member)
ld.modify_s(user_dn, mlist)
def registered(userid, term):
"""
Determines whether a member is registered

View File

@ -55,8 +55,10 @@ syscom_data = {
def main_menu():
menu = [
("New Member", new_member, None),
("New Club Rep", new_club_user, None),
("Renew Membership", renew_member, None),
("Create Club Account", new_club, None),
("Renew Club Rep", renew_club_user, None),
("New Club", new_club, None),
("Display Member", display_member, None),
("Change Shell", change_shell, None),
("Search", search_members, None),
@ -86,6 +88,15 @@ def new_club(*args, **kwargs):
(newmember.EndPage, "club"),
], (60, 15))
def new_club_user(*args, **kwargs):
push_wizard("New Club Rep Account", [
newmember.ClubUserIntroPage,
newmember.InfoPage,
newmember.SignPage,
newmember.PassPage,
(newmember.EndPage, "clubuser"),
], (60, 15))
def manage_group(*args, **kwargs):
push_wizard("Manage Club or Group Members", [
groups.IntroPage,
@ -101,6 +112,14 @@ def renew_member(*args, **kwargs):
renew.EndPage,
])
def renew_club_user(*args, **kwargs):
push_wizard("Renew Club Rep Account", [
renew.ClubUserIntroPage,
renew.UserPage,
(renew.TermPage, "clubuser"),
(renew.EndPage, "clubuser"),
], (60, 15))
def display_member(data):
push_wizard("Display Member", [
renew.UserPage,

View File

@ -17,19 +17,32 @@ class IntroPage(WizardPanel):
class ClubIntroPage(WizardPanel):
def init_widgets(self):
self.widgets = [
urwid.Text( "Club Services" ),
urwid.Text( "Club Accounts" ),
urwid.Divider(),
urwid.Text( "We provide other UW clubs accounts for email and "
"web hosting, free of charge. Like members, clubs "
"get web hosting at %s. We can also arrange for "
"uwaterloo.ca subdomains; please instruct the club "
"representative to contact the systems committee "
"for more information."
"\n\nNote: This is not complete. Authorizing members "
"to access the club account still requires manual "
"intervention."
% "http://csclub.uwaterloo.ca/~clubid/"
)
"for more information. Club accounts do not have "
"passwords, and exist primarily to own club data. "
% "http://csclub.uwaterloo.ca/~clubid/" ),
]
def focusable(self):
return False
class ClubUserIntroPage(WizardPanel):
def init_widgets(self):
self.widgets = [
urwid.Text( "Club Rep Account" ),
urwid.Divider(),
urwid.Text( "This is for people who need access to a club account, "
"but are not currently interested in full CSC membership. "
"Registering a user in this way grants one term of free "
"access to our machines, without any other membership "
"privileges (they can't vote, hold office, etc). If such "
"a user later decides to join, use the Renew Membership "
"option." ),
]
def focusable(self):
return False
@ -150,6 +163,9 @@ class EndPage(WizardPanel):
if self.utype == 'member':
members.create_member( self.state['userid'], self.state['password'], self.state['name'], self.state['program'] )
members.register( self.state['userid'], terms.current() )
elif self.utype == 'clubuser':
members.create_member( self.state['userid'], self.state['password'], self.state['name'], self.state['program'] )
members.register_nonmember( self.state['userid'], terms.current() )
elif self.utype == 'club':
members.create_club( self.state['userid'], self.state['name'] )
else:

View File

@ -14,6 +14,21 @@ class IntroPage(WizardPanel):
def focusable(self):
return False
class ClubUserIntroPage(IntroPage):
def init_widgets(self):
self.widgets = [
urwid.Text( "Renewing Club User Account" ),
urwid.Divider(),
urwid.Text( "In order for clubs to maintain websites hosted by "
"the Computer Science Club, they need access to our "
"machines. We grant accounts to club users at no charge "
"in order to provide this access. Registering a user "
"in this way grants one term of free access to our "
"machines, without any other membership privileges "
"(they can't vote, hold office, etc). If such a user "
"decides to join, use the Renew Membership option." )
]
class UserPage(WizardPanel):
def init_widgets(self):
self.userid = LdapWordEdit(csclub_uri, csclub_base, 'uid',
@ -35,6 +50,9 @@ class UserPage(WizardPanel):
return True
class TermPage(WizardPanel):
def __init__(self, state, utype='member'):
self.utype = utype
WizardPanel.__init__(self, state)
def init_widgets(self):
self.start = SingleEdit("Start: ")
self.count = SingleIntEdit("Count: ")
@ -47,10 +65,14 @@ class TermPage(WizardPanel):
]
def activate(self):
if not self.start.get_edit_text():
old_terms = []
if 'term' in self.state['member']:
old_terms = self.state['member']['term']
self.start.set_edit_text( terms.next_unregistered( old_terms ) )
self.terms = self.state['member'].get('term', [])
self.nmterms = self.state['member'].get('nonMemberTerm', [])
if self.utype == 'member':
self.start.set_edit_text( terms.next_unregistered( self.terms ) )
else:
self.start.set_edit_text( terms.next_unregistered( self.terms + self.nmterms ) )
self.count.set_edit_text( "1" )
def check(self):
try:
@ -60,7 +82,12 @@ class TermPage(WizardPanel):
set_status( "Invalid start term" )
return True
for term in self.state['terms']:
if members.registered( self.state['userid'], term):
if self.utype == 'member':
already = term in self.terms
else:
already = term in self.terms or term in self.nmterms
if already:
self.focus_widget( self.start )
set_status( "Already registered for " + term )
return True
@ -91,6 +118,9 @@ class PayPage(WizardPanel):
"continuing. " % ( len(regterms), plural, len(regterms * 2)))
class EndPage(WizardPanel):
def __init__(self, state, utype='member'):
self.utype = utype
WizardPanel.__init__(self, state)
def init_widgets(self):
self.headtext = urwid.Text("")
self.midtext = urwid.Text("")
@ -105,10 +135,15 @@ class EndPage(WizardPanel):
def activate(self):
problem = None
try:
members.register( self.state['userid'], self.state['terms'] )
self.headtext.set_text("Registration Succeeded")
if self.utype == 'member':
members.register( self.state['userid'], self.state['terms'] )
self.midtext.set_text("The member has been registered for the following "
"terms: " + ", ".join(self.state['terms']) + ".")
else:
members.register_nonmember( self.state['userid'], self.state['terms'] )
self.midtext.set_text("The club user has been registered for the following "
"terms: " + ", ".join(self.state['terms']) + ".")
except ldap.LDAPError, e:
problem = ldapi.format_ldaperror(e)
except members.MemberException, e:

View File

@ -16,10 +16,14 @@ attributetype ( 1.3.6.1.4.1.27934.1.1.4 NAME 'position'
EQUALITY caseIgnoreIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} )
attributetype ( 1.3.6.1.4.1.27934.1.1.5 NAME 'nonMemberTerm'
EQUALITY caseIgnoreIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{5} )
objectclass ( 1.3.6.1.4.1.27934.1.2.1 NAME 'member'
SUP top AUXILIARY
MUST ( cn $ uid )
MAY ( studentid $ program $ term $ description $ position ) )
MAY ( studentid $ program $ term $ nonMemberTerm $ description $ position ) )
objectclass ( 1.3.6.1.4.1.27934.1.2.2 NAME 'club'
SUP top AUXILIARY