PgSQL to LDAP transition - Complete
With this commit, the PostgreSQL database is no longer used by CEO. All term and member information are now retrieved and saved to the LDAP directory.
This commit is contained in:
parent
396779cee2
commit
89276f899b
20
bin/ceoquery
20
bin/ceoquery
|
@ -15,9 +15,9 @@ for key in os.environ.keys():
|
|||
|
||||
os.environ['PATH'] = '/usr/sbin:/usr/bin:/sbin:/bin'
|
||||
|
||||
for pathent in sys.path[:]:
|
||||
if not pathent.find('/usr') == 0:
|
||||
sys.path.remove(pathent)
|
||||
#for pathent in sys.path[:]:
|
||||
# if not pathent.find('/usr') == 0:
|
||||
# sys.path.remove(pathent)
|
||||
|
||||
euid = os.geteuid()
|
||||
egid = os.getegid()
|
||||
|
@ -37,7 +37,7 @@ except Exception, e:
|
|||
sys.exit(1)
|
||||
|
||||
def usage():
|
||||
print "Usage: ceoquery memberlist|booklist|allmembers|allusers|termusers"
|
||||
print "Usage: ceoquery memberlist|booklist|allusers|termusers"
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
usage()
|
||||
|
@ -46,14 +46,16 @@ elif sys.argv[1] == 'memberlist':
|
|||
|
||||
current_term = terms.current()
|
||||
members = members.list_term(current_term)
|
||||
for member in members:
|
||||
print "%(memberid)s|%(name)s|%(program)s|%(userid)s" % member
|
||||
for member in members.values():
|
||||
if 'program' in member:
|
||||
program = member['program'][0]
|
||||
else:
|
||||
program = ''
|
||||
print "%s|%s|%s" % (member['cn'][0], program, member['uid'][0])
|
||||
|
||||
elif sys.argv[1] == 'allmembers':
|
||||
|
||||
members = members.list_all()
|
||||
for member in members:
|
||||
print "%(memberid)s|%(name)s|%(program)s|%(userid)s" % member
|
||||
pass
|
||||
|
||||
elif sys.argv[1] == 'booklist':
|
||||
|
||||
|
|
|
@ -655,18 +655,14 @@ def remove_member(username, groupname):
|
|||
|
||||
### Account Types ###
|
||||
|
||||
def create_member(username, password, name, memberid):
|
||||
def create_member(username, password, name):
|
||||
"""
|
||||
Creates a UNIX user account with options tailored to CSC members.
|
||||
|
||||
Note: The 'other' section of the GECOS field is filled with the CSC
|
||||
memberid. This section cannot be changed by the user via chfn(1).
|
||||
|
||||
Parameters:
|
||||
username - the desired UNIX username
|
||||
password - the desired UNIX password
|
||||
name - the member's real name
|
||||
memberid - the CSC member id number
|
||||
|
||||
Exceptions:
|
||||
InvalidArgument - on bad account attributes provided
|
||||
|
@ -692,24 +688,20 @@ def create_member(username, password, name, memberid):
|
|||
maximum_id = cfg['member_max_id']
|
||||
home = cfg['member_home'] + '/' + username
|
||||
description = cfg['member_desc']
|
||||
gecos_field = build_gecos(name, other=memberid)
|
||||
gecos_field = build_gecos(name)
|
||||
shell = cfg['member_shell']
|
||||
group = cfg['member_group']
|
||||
|
||||
return create(username, name, minimum_id, maximum_id, home, password, description, gecos_field, shell, group)
|
||||
|
||||
|
||||
def create_club(username, name, memberid):
|
||||
def create_club(username, name):
|
||||
"""
|
||||
Creates a UNIX user account with options tailored to CSC-hosted clubs.
|
||||
|
||||
Note: The 'other' section of the GECOS field is filled with the CSC
|
||||
memberid. This section cannot be changed by the user via chfn(1).
|
||||
|
||||
Parameters:
|
||||
username - the desired UNIX username
|
||||
name - the club name
|
||||
memberid - the CSC member id number
|
||||
|
||||
Exceptions:
|
||||
InvalidArgument - on bad account attributes provided
|
||||
|
@ -732,7 +724,7 @@ def create_club(username, name, memberid):
|
|||
maximum_id = cfg['club_max_id']
|
||||
home = cfg['club_home'] + '/' + username
|
||||
description = cfg['club_desc']
|
||||
gecos_field = build_gecos(name, other=memberid)
|
||||
gecos_field = build_gecos(name)
|
||||
shell = cfg['club_shell']
|
||||
group = cfg['club_group']
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ must also be moved into this module.
|
|||
"""
|
||||
import re
|
||||
from csc.adm import terms
|
||||
from csc.backends import db, ldapi
|
||||
from csc.backends import ldapi
|
||||
from csc.common import conf
|
||||
from csc.common.excep import InvalidArgument
|
||||
|
||||
|
@ -42,7 +42,6 @@ def load_configuration():
|
|||
|
||||
### Exceptions ###
|
||||
|
||||
DBException = db.DBException
|
||||
ConfigurationException = conf.ConfigurationException
|
||||
|
||||
class MemberException(Exception):
|
||||
|
@ -87,9 +86,6 @@ class NoSuchMember(MemberException):
|
|||
|
||||
### Connection Management ###
|
||||
|
||||
# global database connection
|
||||
db_connection = db.DBConnection()
|
||||
|
||||
# global directory connection
|
||||
ldap_connection = ldapi.LDAPConnection()
|
||||
|
||||
|
@ -97,27 +93,25 @@ def connect():
|
|||
"""Connect to PostgreSQL."""
|
||||
|
||||
load_configuration()
|
||||
db_connection.connect(cfg['server'], cfg['database'])
|
||||
ldap_connection.connect(cfg['server_url'], cfg['admin_bind_dn'], cfg['admin_bind_pw'], cfg['users_base'], cfg['groups_base'])
|
||||
|
||||
|
||||
def disconnect():
|
||||
"""Disconnect from PostgreSQL."""
|
||||
|
||||
db_connection.disconnect()
|
||||
ldap_connection.disconnect()
|
||||
|
||||
|
||||
def connected():
|
||||
"""Determine whether the db_connection has been established."""
|
||||
"""Determine whether the connection has been established."""
|
||||
|
||||
return db_connection.connected() and ldap_connection.connected()
|
||||
return ldap_connection.connected()
|
||||
|
||||
|
||||
|
||||
### Member Table ###
|
||||
|
||||
def new(uid, realname, studentid=None, program=None, mtype='user'):
|
||||
def new(uid, realname, studentid=None, program=None):
|
||||
"""
|
||||
Registers a new CSC member. The member is added to the members table
|
||||
and registered for the current term.
|
||||
|
@ -127,23 +121,21 @@ def new(uid, realname, studentid=None, program=None, mtype='user'):
|
|||
realname - the full real name of the member
|
||||
studentid - the student id number of the member
|
||||
program - the program of study of the member
|
||||
mtype - a string describing the type of member ('user', 'club')
|
||||
|
||||
Returns: the memberid of the new member
|
||||
Returns: the username of the new member
|
||||
|
||||
Exceptions:
|
||||
DuplicateStudentID - if the student id already exists in the database
|
||||
InvalidStudentID - if the student id is malformed
|
||||
InvalidRealName - if the real name is malformed
|
||||
|
||||
Example: new("Michael Spang", program="CS") -> 3349
|
||||
Example: new("Michael Spang", program="CS") -> "mspang"
|
||||
"""
|
||||
|
||||
# blank attributes should be NULL
|
||||
if studentid == '': studentid = None
|
||||
if program == '': program = None
|
||||
if uid == '': uid = None
|
||||
if mtype == '': mtype = None
|
||||
|
||||
# check the student id format
|
||||
if studentid is not None and not re.match(cfg['studentid_regex'], str(studentid)):
|
||||
|
@ -154,92 +146,61 @@ def new(uid, realname, studentid=None, program=None, mtype='user'):
|
|||
raise InvalidRealName(realname)
|
||||
|
||||
# check for duplicate student id
|
||||
member = db_connection.select_member_by_studentid(studentid) or \
|
||||
ldap_connection.member_search_studentid(studentid)
|
||||
member = ldap_connection.member_search_studentid(studentid)
|
||||
if member:
|
||||
raise DuplicateStudentID(studentid)
|
||||
|
||||
# check for duplicate userid
|
||||
member = db_connection.select_member_by_userid(uid) or \
|
||||
ldap_connection.user_lookup(uid)
|
||||
member = ldap_connection.user_lookup(uid)
|
||||
if member:
|
||||
raise InvalidArgument("uid", uid, "duplicate uid")
|
||||
|
||||
# add the member to the database
|
||||
memberid = db_connection.insert_member(realname, studentid, program, userid=uid)
|
||||
|
||||
# add the member to the directory
|
||||
ldap_connection.member_add(uid, realname, studentid, program)
|
||||
|
||||
# register them for this term in the database
|
||||
db_connection.insert_term(memberid, terms.current())
|
||||
|
||||
# register them for this term in the directory
|
||||
member = ldap_connection.member_lookup(uid)
|
||||
member['term'] = [ terms.current() ]
|
||||
ldap_connection.user_modify(uid, member)
|
||||
|
||||
# commit the database transaction
|
||||
db_connection.commit()
|
||||
|
||||
return memberid
|
||||
return uid
|
||||
|
||||
|
||||
def get(memberid):
|
||||
"""
|
||||
Look up attributes of a member by memberid.
|
||||
|
||||
Returns: a dictionary of attributes
|
||||
|
||||
Example: get(3349) -> {
|
||||
'memberid': 3349,
|
||||
'name': 'Michael Spang',
|
||||
'program': 'Computer Science',
|
||||
...
|
||||
}
|
||||
"""
|
||||
|
||||
return db_connection.select_member_by_id(memberid)
|
||||
|
||||
|
||||
def get_userid(userid):
|
||||
def get(userid):
|
||||
"""
|
||||
Look up attributes of a member by userid.
|
||||
|
||||
Parameters:
|
||||
userid - the UNIX user id
|
||||
|
||||
Returns: a dictionary of attributes
|
||||
|
||||
Example: get('mspang') -> {
|
||||
'memberid': 3349,
|
||||
'name': 'Michael Spang',
|
||||
'program': 'Computer Science',
|
||||
'cn': [ 'Michael Spang' ],
|
||||
'program': [ 'Computer Science' ],
|
||||
...
|
||||
}
|
||||
"""
|
||||
|
||||
return db_connection.select_member_by_userid(userid)
|
||||
return ldap_connection.user_lookup(userid)
|
||||
|
||||
|
||||
def get_studentid(studentid):
|
||||
"""
|
||||
Look up attributes of a member by studnetid.
|
||||
Look up attributes of a member by studentid.
|
||||
|
||||
Parameters:
|
||||
studentid - the student ID number
|
||||
|
||||
Returns: a dictionary of attributes
|
||||
Returns: a dict of members
|
||||
|
||||
Example: get(...) -> {
|
||||
'memberid': 3349,
|
||||
'name': 'Michael Spang',
|
||||
'program': 'Computer Science',
|
||||
'mspang': {
|
||||
'name': [ 'Michael Spang' ],
|
||||
'program': [ 'Computer Science' ],
|
||||
}
|
||||
...
|
||||
}
|
||||
"""
|
||||
|
||||
return db_connection.select_member_by_studentid(studentid)
|
||||
return ldap_connection.member_search_studentid(studentid)
|
||||
|
||||
|
||||
def list_term(term):
|
||||
|
@ -249,19 +210,16 @@ def list_term(term):
|
|||
Parameters:
|
||||
term - the term to match members against
|
||||
|
||||
Returns: a list of member dictionaries
|
||||
Returns: a list of members
|
||||
|
||||
Example: list_term('f2006'): -> [
|
||||
{ 'memberid': 3349, ... },
|
||||
{ 'memberid': ... }.
|
||||
Example: list_term('f2006'): -> {
|
||||
'mspang': { 'cn': 'Michael Spang', ... },
|
||||
'ctdalek': { 'cn': 'Calum T. Dalek', ... },
|
||||
...
|
||||
]
|
||||
}
|
||||
"""
|
||||
|
||||
# retrieve a list of memberids in term
|
||||
memberlist = db_connection.select_members_by_term(term)
|
||||
|
||||
return memberlist.values()
|
||||
return ldap_connection.member_search_term(term)
|
||||
|
||||
|
||||
def list_name(name):
|
||||
|
@ -273,123 +231,52 @@ def list_name(name):
|
|||
|
||||
Returns: a list of member dictionaries
|
||||
|
||||
Example: list_name('Spang'): -> [
|
||||
{ 'memberid': 3349, ... },
|
||||
{ 'memberid': ... },
|
||||
Example: list_name('Spang'): -> {
|
||||
'mspang': { 'cn': 'Michael Spang', ... },
|
||||
...
|
||||
]
|
||||
"""
|
||||
|
||||
# retrieve a list of memberids matching name
|
||||
memberlist = db_connection.select_members_by_name(name)
|
||||
|
||||
return memberlist.values()
|
||||
return ldap_connection.member_search_name(name)
|
||||
|
||||
|
||||
def list_all():
|
||||
"""
|
||||
Builds a list of all members.
|
||||
|
||||
Returns: a list of member dictionaries
|
||||
"""
|
||||
|
||||
# retrieve a list of members
|
||||
memberlist = db_connection.select_all_members()
|
||||
|
||||
return memberlist.values()
|
||||
|
||||
|
||||
def delete(memberid):
|
||||
def delete(userid):
|
||||
"""
|
||||
Erase all records of a member.
|
||||
|
||||
Note: real members are never removed from the database
|
||||
|
||||
Returns: attributes and terms of the member in a tuple
|
||||
Returns: ldap entry of the member
|
||||
|
||||
Exceptions:
|
||||
NoSuchMember - if the member id does not exist
|
||||
NoSuchMember - if the user id does not exist
|
||||
|
||||
Example: delete(0) -> ({ 'memberid': 0, name: 'Calum T. Dalek' ...}, ['s1993'])
|
||||
Example: delete('ctdalek') -> { 'cn': [ 'Calum T. Dalek' ], 'term': ['s1993'], ... }
|
||||
"""
|
||||
|
||||
# save member data
|
||||
member = db_connection.select_member_by_id(memberid)
|
||||
member = ldap_connection.user_lookup(userid)
|
||||
|
||||
# bail if not found
|
||||
if not member:
|
||||
raise NoSuchMember(memberid)
|
||||
|
||||
term_list = db_connection.select_terms(memberid)
|
||||
|
||||
# remove data from the db
|
||||
db_connection.delete_term_all(memberid)
|
||||
db_connection.delete_member(memberid)
|
||||
db_connection.commit()
|
||||
raise NoSuchMember(userid)
|
||||
|
||||
# remove data from the directory
|
||||
if member and member['userid']:
|
||||
uid = member['userid']
|
||||
ldap_connection.user_delete(uid)
|
||||
uid = member['uid'][0]
|
||||
ldap_connection.user_delete(uid)
|
||||
|
||||
return (member, term_list)
|
||||
|
||||
|
||||
def update(member):
|
||||
"""
|
||||
Update CSC member attributes.
|
||||
|
||||
Parameters:
|
||||
member - a dictionary with member attributes as returned by get,
|
||||
possibly omitting some attributes. member['memberid']
|
||||
must exist and be valid. None is NULL.
|
||||
|
||||
Exceptions:
|
||||
NoSuchMember - if the member id does not exist
|
||||
InvalidStudentID - if the student id number is malformed
|
||||
DuplicateStudentID - if the student id number exists
|
||||
|
||||
Example: update( {'memberid': 3349, userid: 'mspang'} )
|
||||
"""
|
||||
|
||||
if member.has_key('studentid') and member['studentid'] is not None:
|
||||
|
||||
studentid = member['studentid']
|
||||
|
||||
# check the student id format
|
||||
if studentid is not None and not re.match(cfg['studentid_regex'], str(studentid)):
|
||||
raise InvalidStudentID(studentid)
|
||||
|
||||
# check for duplicate student id
|
||||
dupmember = db_connection.select_member_by_studentid(studentid)
|
||||
if dupmember:
|
||||
raise DuplicateStudentID(studentid)
|
||||
|
||||
# not specifying memberid is a bug
|
||||
if not member.has_key('memberid'):
|
||||
raise Exception("no member specified in call to update")
|
||||
memberid = member['memberid']
|
||||
|
||||
# see if member exists
|
||||
if not get(memberid):
|
||||
raise NoSuchMember(memberid)
|
||||
|
||||
# do the update
|
||||
db_connection.update_member(member)
|
||||
|
||||
# commit the transaction
|
||||
db_connection.commit()
|
||||
return member
|
||||
|
||||
|
||||
|
||||
### Term Table ###
|
||||
|
||||
def register(memberid, term_list):
|
||||
def register(userid, term_list):
|
||||
"""
|
||||
Registers a member for one or more terms.
|
||||
|
||||
Parameters:
|
||||
memberid - the member id number
|
||||
userid - the member's username
|
||||
term_list - the term to register for, or a list of terms
|
||||
|
||||
Exceptions:
|
||||
|
@ -403,13 +290,12 @@ def register(memberid, term_list):
|
|||
if type(term_list) in (str, unicode):
|
||||
term_list = [ term_list ]
|
||||
|
||||
ldap_member = None
|
||||
db_member = get(memberid)
|
||||
if db_member['userid']:
|
||||
uid = db_member['userid']
|
||||
ldap_member = ldap_connection.member_lookup(uid)
|
||||
if ldap_member and 'term' not in ldap_member:
|
||||
ldap_member['term'] = []
|
||||
ldap_member = ldap_connection.member_lookup(userid)
|
||||
if ldap_member and 'term' not in ldap_member:
|
||||
ldap_member['term'] = []
|
||||
|
||||
if not ldap_member:
|
||||
raise NoSuchMember(userid)
|
||||
|
||||
for term in term_list:
|
||||
|
||||
|
@ -417,52 +303,48 @@ def register(memberid, term_list):
|
|||
if not re.match('^[wsf][0-9]{4}$', term):
|
||||
raise InvalidTerm(term)
|
||||
|
||||
# add term to database
|
||||
db_connection.insert_term(memberid, term)
|
||||
|
||||
# add the term to the directory
|
||||
if ldap_member:
|
||||
ldap_member['term'].append(term)
|
||||
ldap_member['term'].append(term)
|
||||
|
||||
if ldap_member:
|
||||
ldap_connection.user_modify(uid, ldap_member)
|
||||
|
||||
db_connection.commit()
|
||||
ldap_connection.user_modify(userid, ldap_member)
|
||||
|
||||
|
||||
def registered(memberid, term):
|
||||
def registered(userid, term):
|
||||
"""
|
||||
Determines whether a member is registered
|
||||
for a term.
|
||||
|
||||
Parameters:
|
||||
memberid - the member id number
|
||||
userid - the member's username
|
||||
term - the term to check
|
||||
|
||||
Returns: whether the member is registered
|
||||
|
||||
Example: registered(3349, "f2006") -> True
|
||||
Example: registered("mspang", "f2006") -> True
|
||||
"""
|
||||
|
||||
return db_connection.select_term(memberid, term) is not None
|
||||
member = ldap_connection.member_lookup(userid)
|
||||
return 'term' in member and term in member['term']
|
||||
|
||||
|
||||
def member_terms(memberid):
|
||||
def member_terms(userid):
|
||||
"""
|
||||
Retrieves a list of terms a member is
|
||||
registered for.
|
||||
|
||||
Parameters:
|
||||
memberid - the member id number
|
||||
userid - the member's username
|
||||
|
||||
Returns: list of term strings
|
||||
|
||||
Example: registered(0) -> 's1993'
|
||||
Example: registered('ctdalek') -> 's1993'
|
||||
"""
|
||||
|
||||
terms_list = db_connection.select_terms(memberid)
|
||||
terms_list.sort(terms.compare)
|
||||
return terms_list
|
||||
member = ldap_connection.member_lookup(userid)
|
||||
if not 'term' in member:
|
||||
return []
|
||||
else:
|
||||
return member['term']
|
||||
|
||||
|
||||
|
||||
|
@ -484,9 +366,9 @@ if __name__ == '__main__':
|
|||
tm2usid = '00000002'
|
||||
tm2uprogram = 'Pseudoscience'
|
||||
|
||||
tmdict = {'name': tmname, 'userid': tmuid, 'program': tmprogram, 'type': 'user', 'studentid': tmsid }
|
||||
tm2dict = {'name': tm2name, 'userid': tm2uid, 'program': None, 'type': 'user', 'studentid': tm2sid }
|
||||
tm2udict = {'name': tm2uname, 'userid': tm2uid, 'program': tm2uprogram, 'type': 'user', 'studentid': tm2usid }
|
||||
tmdict = {'cn': [tmname], 'uid': [tmuid], 'program': [tmprogram], 'studentid': [tmsid] }
|
||||
tm2dict = {'cn': [tm2name], 'uid': [tm2uid], 'studentid': [tm2sid] }
|
||||
tm2udict = {'cn': [tm2uname], 'uid': [tm2uid], 'program': [tm2uprogram], 'studentid': [tm2usid] }
|
||||
|
||||
thisterm = terms.current()
|
||||
nextterm = terms.next(thisterm)
|
||||
|
@ -500,21 +382,17 @@ if __name__ == '__main__':
|
|||
success()
|
||||
|
||||
dmid = get_studentid(tmsid)
|
||||
if dmid: delete(dmid['memberid'])
|
||||
if tmuid in dmid: delete(dmid[tmuid]['uid'][0])
|
||||
dmid = get_studentid(tm2sid)
|
||||
if dmid: delete(dmid['memberid'])
|
||||
if tm2uid in dmid: delete(dmid[tm2uid]['uid'][0])
|
||||
dmid = get_studentid(tm2usid)
|
||||
if dmid: delete(dmid['memberid'])
|
||||
if tm2uid in dmid: delete(dmid[tm2uid]['uid'][0])
|
||||
|
||||
test(new)
|
||||
tmid = new(tmuid, tmname, tmsid, tmprogram)
|
||||
tm2id = new(tm2uid, tm2name, tm2sid)
|
||||
success()
|
||||
|
||||
tmdict['memberid'] = tmid
|
||||
tm2dict['memberid'] = tm2id
|
||||
tm2udict['memberid'] = tm2id
|
||||
|
||||
test(registered)
|
||||
assert_equal(True, registered(tmid, thisterm))
|
||||
assert_equal(True, registered(tm2id, thisterm))
|
||||
|
@ -522,19 +400,19 @@ if __name__ == '__main__':
|
|||
success()
|
||||
|
||||
test(get)
|
||||
assert_equal(tmdict, get(tmid))
|
||||
assert_equal(tm2dict, get(tm2id))
|
||||
tmp = get(tmid)
|
||||
del tmp['objectClass']
|
||||
del tmp['term']
|
||||
assert_equal(tmdict, tmp)
|
||||
tmp = get(tm2id)
|
||||
del tmp['objectClass']
|
||||
del tmp['term']
|
||||
assert_equal(tm2dict, tmp)
|
||||
success()
|
||||
|
||||
test(list_name)
|
||||
assert_equal(True, tmid in [ x['memberid'] for x in list_name(tmname) ])
|
||||
assert_equal(True, tm2id in [ x['memberid'] for x in list_name(tm2name) ])
|
||||
success()
|
||||
|
||||
test(list_all)
|
||||
allmembers = list_all()
|
||||
assert_equal(True, tmid in [ x['memberid'] for x in allmembers ])
|
||||
assert_equal(True, tm2id in [ x['memberid'] for x in allmembers ])
|
||||
assert_equal(True, tmid in list_name(tmname).keys())
|
||||
assert_equal(True, tm2id in list_name(tm2name).keys())
|
||||
success()
|
||||
|
||||
test(register)
|
||||
|
@ -548,24 +426,28 @@ if __name__ == '__main__':
|
|||
success()
|
||||
|
||||
test(list_term)
|
||||
assert_equal(True, tmid in [ x['memberid'] for x in list_term(thisterm) ])
|
||||
assert_equal(True, tmid in [ x['memberid'] for x in list_term(nextterm) ])
|
||||
assert_equal(True, tm2id in [ x['memberid'] for x in list_term(thisterm) ])
|
||||
assert_equal(False, tm2id in [ x['memberid'] for x in list_term(nextterm) ])
|
||||
assert_equal(True, tmid in list_term(thisterm).keys())
|
||||
assert_equal(True, tmid in list_term(nextterm).keys())
|
||||
assert_equal(True, tm2id in list_term(thisterm).keys())
|
||||
assert_equal(False, tm2id in list_term(nextterm).keys())
|
||||
success()
|
||||
|
||||
test(update)
|
||||
update(tm2udict)
|
||||
assert_equal(tm2udict, get(tm2id))
|
||||
success()
|
||||
|
||||
test(get_userid)
|
||||
assert_equal(tm2udict, get_userid(tm2uid))
|
||||
test(get)
|
||||
tmp = get(tm2id)
|
||||
del tmp['objectClass']
|
||||
del tmp['term']
|
||||
assert_equal(tm2dict, tmp)
|
||||
success()
|
||||
|
||||
test(get_studentid)
|
||||
assert_equal(tm2udict, get_studentid(tm2usid))
|
||||
assert_equal(tmdict, get_studentid(tmsid))
|
||||
tmp = get_studentid(tm2sid)[tm2uid]
|
||||
del tmp['objectClass']
|
||||
del tmp['term']
|
||||
assert_equal(tm2dict, tmp)
|
||||
tmp = get_studentid(tmsid)[tmuid]
|
||||
del tmp['objectClass']
|
||||
del tmp['term']
|
||||
assert_equal(tmdict, tmp)
|
||||
success()
|
||||
|
||||
test(delete)
|
||||
|
|
|
@ -18,21 +18,56 @@ from csc.common.excep import InvalidArgument
|
|||
BORDER_COLOR = curses.COLOR_RED
|
||||
|
||||
|
||||
def read_uid(wnd):
|
||||
"""Read a username."""
|
||||
|
||||
prompt = 'Username:'
|
||||
return inputbox(wnd, prompt, 36)
|
||||
|
||||
def read_member(wnd):
|
||||
"""Looks up a member."""
|
||||
|
||||
# connect the members module to its backend if necessary
|
||||
if not members.connected(): members.connect()
|
||||
|
||||
uid = read_uid(wnd)
|
||||
if not uid or uid.lower() == 'exit':
|
||||
return
|
||||
|
||||
member = members.get(uid)
|
||||
if not member:
|
||||
msgbox(wnd, "Invalid username: %s" % uid)
|
||||
return
|
||||
|
||||
# display user
|
||||
display_member_details(wnd, member)
|
||||
|
||||
return member
|
||||
|
||||
|
||||
def action_library(wnd):
|
||||
"""Display a link to the library."""
|
||||
msgbox(wnd, "Please visit library.csclub.uwaterloo.ca")
|
||||
|
||||
def action_new_member(wnd):
|
||||
"""Interactively add a new member."""
|
||||
|
||||
userid, studentid, program = '', None, ''
|
||||
|
||||
msgbox(wnd, "Membership is $2.00 CDN. Please ensure\n"
|
||||
"the money is desposited in the safe\n"
|
||||
"before continuing.")
|
||||
|
||||
# read the name
|
||||
prompt = " Name: "
|
||||
prompt = "New member's full name: "
|
||||
realname = inputbox(wnd, prompt, 18)
|
||||
|
||||
# abort if no username is entered
|
||||
# abort if no name is entered
|
||||
if not realname or realname.lower() == 'exit':
|
||||
return False
|
||||
|
||||
# read the student id
|
||||
prompt = "Student id:"
|
||||
prompt = "New member's student ID:"
|
||||
while studentid is None or (re.search("[^0-9]", studentid) and not studentid.lower() == 'exit'):
|
||||
studentid = inputbox(wnd, prompt, 18)
|
||||
|
||||
|
@ -44,7 +79,7 @@ def action_new_member(wnd):
|
|||
studentid = None
|
||||
|
||||
# read the program of study
|
||||
prompt = " Program:"
|
||||
prompt = "New member's program of study:"
|
||||
program = inputbox(wnd, prompt, 18)
|
||||
|
||||
# abort if exit is entered
|
||||
|
@ -52,7 +87,7 @@ def action_new_member(wnd):
|
|||
return False
|
||||
|
||||
# read user id
|
||||
prompt = "Userid:"
|
||||
prompt = "New member's UWdir username:"
|
||||
while userid == '':
|
||||
userid = inputbox(wnd, prompt, 18)
|
||||
|
||||
|
@ -65,10 +100,10 @@ def action_new_member(wnd):
|
|||
|
||||
# attempt to create the member
|
||||
try:
|
||||
memberid = members.new(userid, realname, studentid, program)
|
||||
members.new(userid, realname, studentid, program)
|
||||
|
||||
msgbox(wnd, "Success! Your memberid is %s. You are now registered\n"
|
||||
% memberid + "for the " + terms.current() + " term.")
|
||||
msgbox(wnd, "Success! Your username is %s. You are now registered\n"
|
||||
% userid + "for the " + terms.current() + " term.")
|
||||
|
||||
except members.InvalidStudentID:
|
||||
msgbox(wnd, "Invalid student ID: %s" % studentid)
|
||||
|
@ -90,26 +125,25 @@ def action_new_member(wnd):
|
|||
def action_term_register(wnd):
|
||||
"""Interactively register a member for a term."""
|
||||
|
||||
memberid, term = '', ''
|
||||
term = ''
|
||||
|
||||
# read the member id
|
||||
prompt = 'Enter memberid ("exit" to cancel):'
|
||||
memberuserid = inputbox(wnd, prompt, 36)
|
||||
member = read_member(wnd)
|
||||
if not member:
|
||||
return False
|
||||
uid = member['uid'][0]
|
||||
|
||||
if not memberuserid or memberuserid.lower() == 'exit':
|
||||
# verify member
|
||||
prompt = "Is this the correct member?"
|
||||
answer = None
|
||||
while answer != "yes" and answer != "y" and answer != "n" and answer != "no" and answer != "exit":
|
||||
answer = inputbox(wnd, prompt, 28)
|
||||
|
||||
# user abort
|
||||
if answer == "exit":
|
||||
return False
|
||||
|
||||
member = get_member_memberid_userid(wnd, memberuserid)
|
||||
if not member: return False
|
||||
|
||||
memberid = member['memberid']
|
||||
term_list = members.member_terms(memberid)
|
||||
|
||||
# display user
|
||||
display_member_details(wnd, member, term_list)
|
||||
|
||||
# read the term
|
||||
prompt = "Which term to register for ([fws]20nn):"
|
||||
prompt = "Which term to register for ([wsf]20nn):"
|
||||
while not re.match('^[wsf][0-9]{4}$', term) and not term == 'exit':
|
||||
term = inputbox(wnd, prompt, 41)
|
||||
|
||||
|
@ -118,17 +152,17 @@ def action_term_register(wnd):
|
|||
return False
|
||||
|
||||
# already registered?
|
||||
if members.registered(memberid, term):
|
||||
if members.registered(uid, term):
|
||||
msgbox(wnd, "You are already registered for term " + term)
|
||||
return False
|
||||
|
||||
try:
|
||||
|
||||
# attempt to register
|
||||
members.register(memberid, term)
|
||||
members.register(uid, term)
|
||||
|
||||
# display success message [sic]
|
||||
msgbox(wnd, "Your are now registered for term " + term)
|
||||
# display success message
|
||||
msgbox(wnd, "You are now registered for term " + term)
|
||||
|
||||
except members.InvalidTerm:
|
||||
msgbox(wnd, "Term is not valid: %s" % term)
|
||||
|
@ -139,23 +173,22 @@ def action_term_register(wnd):
|
|||
def action_term_register_multiple(wnd):
|
||||
"""Interactively register a member for multiple terms."""
|
||||
|
||||
memberid, base, num = '', '', None
|
||||
base, num = '', None
|
||||
|
||||
# read the member id
|
||||
prompt = 'Enter memberid ("exit" to cancel):'
|
||||
memberuserid = inputbox(wnd, prompt, 36)
|
||||
|
||||
if not memberuserid or memberuserid.lower() == 'exit':
|
||||
member = read_member(wnd)
|
||||
if not member:
|
||||
return False
|
||||
uid = member['uid'][0]
|
||||
|
||||
member = get_member_memberid_userid(wnd, memberuserid)
|
||||
if not member: return False
|
||||
# verify member
|
||||
prompt = "Is this the correct member?"
|
||||
answer = None
|
||||
while answer != "yes" and answer != "y" and answer != "n" and answer != "no" and answer != "exit":
|
||||
answer = inputbox(wnd, prompt, 28)
|
||||
|
||||
memberid = member['memberid']
|
||||
term_list = members.member_terms(memberid)
|
||||
|
||||
# display user
|
||||
display_member_details(wnd, member, term_list)
|
||||
# user abort
|
||||
if answer == "exit":
|
||||
return False
|
||||
|
||||
# read the base
|
||||
prompt = "Which term to start registering ([fws]20nn):"
|
||||
|
@ -182,14 +215,14 @@ def action_term_register_multiple(wnd):
|
|||
|
||||
# already registered?
|
||||
for term in term_list:
|
||||
if members.registered(memberid, term):
|
||||
if members.registered(uid, term):
|
||||
msgbox(wnd, "You are already registered for term " + term)
|
||||
return False
|
||||
|
||||
try:
|
||||
|
||||
# attempt to register all terms
|
||||
members.register(memberid, term_list)
|
||||
members.register(uid, term_list)
|
||||
|
||||
# display success message [sic]
|
||||
msgbox(wnd, "Your are now registered for terms: " + ", ".join(term_list))
|
||||
|
@ -200,30 +233,6 @@ def action_term_register_multiple(wnd):
|
|||
return False
|
||||
|
||||
|
||||
def repair_account(wnd, memberid, userid):
|
||||
"""Attemps to repair an account."""
|
||||
|
||||
if not accounts.connected(): accounts.connect()
|
||||
|
||||
member = members.get(memberid)
|
||||
exists, haspw = accounts.status(userid)
|
||||
|
||||
if not exists:
|
||||
password = input_password(wnd)
|
||||
accounts.create_member(userid, password, member['name'], memberid)
|
||||
msgbox(wnd, "Account created (where the hell did it go, anyway?)\n"
|
||||
"If your homedir still exists, it will not be inaccessible to you,\n"
|
||||
"please contact systems-committee@csclub.uwaterloo.ca to get this resolved.\n")
|
||||
|
||||
elif not haspw:
|
||||
password = input_password(wnd)
|
||||
accounts.add_password(userid, password)
|
||||
msgbox(wnd, "Password added to account.")
|
||||
|
||||
else:
|
||||
msgbox(wnd, "No problems to repair.")
|
||||
|
||||
|
||||
def input_password(wnd):
|
||||
|
||||
# password input loop
|
||||
|
@ -249,24 +258,16 @@ def input_password(wnd):
|
|||
def action_create_account(wnd):
|
||||
"""Interactively create an account for a member."""
|
||||
|
||||
memberid, userid = '', ''
|
||||
|
||||
# read the member id
|
||||
prompt = 'Enter member ID (exit to cancel):'
|
||||
memberid = inputbox(wnd, prompt, 35)
|
||||
|
||||
if not memberid or memberid.lower() == 'exit':
|
||||
member = read_member(wnd)
|
||||
if not member:
|
||||
return False
|
||||
|
||||
member = get_member_memberid_userid(wnd, memberid)
|
||||
if not member: return False
|
||||
# member already has an account?
|
||||
if not accounts.connected(): accounts.connect()
|
||||
if 'posixAccount' in member['objectClass']:
|
||||
msgbox(wnd, "Account already exists.")
|
||||
return False
|
||||
|
||||
memberid = member['memberid']
|
||||
term_list = members.member_terms(memberid)
|
||||
|
||||
# display the member
|
||||
display_member_details(wnd, member, term_list)
|
||||
|
||||
# verify member
|
||||
prompt = "Is this the correct member?"
|
||||
answer = None
|
||||
|
@ -282,30 +283,9 @@ def action_create_account(wnd):
|
|||
msgbox(wnd, "I suggest searching for the member by userid or name from the main menu.")
|
||||
return False
|
||||
|
||||
# member already has an account?
|
||||
if not accounts.connected(): accounts.connect()
|
||||
if member['userid'] and accounts.status(member['userid'])[0]:
|
||||
|
||||
userid = member['userid']
|
||||
msgbox(wnd, "Member " + str(memberid) + " already has an account: " + member['userid'] + "\n"
|
||||
"Attempting to repair it. Contact the sysadmin if there are still problems." )
|
||||
|
||||
repair_account(wnd, memberid, userid)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
if member['userid']:
|
||||
userid = member['userid']
|
||||
|
||||
# read user id
|
||||
prompt = "Userid:"
|
||||
while userid == '':
|
||||
userid = inputbox(wnd, prompt, 18)
|
||||
|
||||
# user abort
|
||||
if userid is None or userid.lower() == 'exit':
|
||||
return False
|
||||
msgbox(wnd, "Ensure the member has signed the machine\n"
|
||||
"usage policy. Accounts of users who have\n"
|
||||
"not signed will be suspended if discovered.")
|
||||
|
||||
# read password
|
||||
password = input_password(wnd)
|
||||
|
@ -313,7 +293,7 @@ def action_create_account(wnd):
|
|||
# create the UNIX account
|
||||
try:
|
||||
if not accounts.connected(): accounts.connect()
|
||||
accounts.create_member(userid, password, member['name'], memberid)
|
||||
accounts.create_member(member['uid'][0], password, member['cn'][0])
|
||||
except accounts.NameConflict, e:
|
||||
msgbox(wnd, str(e))
|
||||
return False
|
||||
|
@ -329,86 +309,53 @@ def action_create_account(wnd):
|
|||
except accounts.KrbException, e:
|
||||
msgbox(wnd, "Error creating Kerberos principal - Contact the Systems Administrator: %s" % e)
|
||||
return False
|
||||
|
||||
# now update the CEO database with the username
|
||||
members.update( {'memberid': memberid, 'userid': userid} )
|
||||
|
||||
# success
|
||||
msgbox(wnd, "Please run 'addhomedir " + userid + "'.")
|
||||
msgbox(wnd, "Please run 'addhomedir " + member['uid'][0] + "'.")
|
||||
msgbox(wnd, "Success! Your account has been added")
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def display_member_details(wnd, member, term_list):
|
||||
def display_member_details(wnd, member):
|
||||
"""Display member attributes in a message box."""
|
||||
|
||||
# clone and sort term_list
|
||||
term_list = list(term_list)
|
||||
if 'term' in member:
|
||||
term_list = list(member['term'])
|
||||
else:
|
||||
term_list = []
|
||||
term_list.sort( terms.compare )
|
||||
|
||||
# labels for data
|
||||
id_label, studentid_label, name_label = "ID:", "StudentID:", "Name:"
|
||||
program_label, userid_label, terms_label = "Program:", "User ID:", "Terms:"
|
||||
program_label, terms_label = "Program:", "Terms:"
|
||||
|
||||
if 'program' in member:
|
||||
program = member['program'][0]
|
||||
else:
|
||||
program = None
|
||||
|
||||
if 'studentid' in member:
|
||||
studentid = member['studentid'][0]
|
||||
else:
|
||||
studentid = None
|
||||
|
||||
# format it all into a massive string
|
||||
message = "%8s %-20s %10s %-10s (user)\n" % (name_label, member['name'], id_label, member['memberid']) + \
|
||||
"%8s %-20s %10s %-10s\n" % (program_label, member['program'], studentid_label, member['studentid'])
|
||||
|
||||
if member['userid']:
|
||||
message += "%8s %s\n" % (userid_label, member['userid'])
|
||||
else:
|
||||
message += 'No user ID.\n'
|
||||
message = "%8s %-20s %10s %-10s\n" % (name_label, member['cn'][0], id_label, member['uid'][0]) + \
|
||||
"%8s %-20s %10s %-10s\n" % (program_label, program, studentid_label, studentid)
|
||||
|
||||
message += "%s %s" % (terms_label, " ".join(term_list))
|
||||
|
||||
# display the string in a message box
|
||||
msgbox(wnd, message)
|
||||
|
||||
|
||||
def get_member_memberid_userid(wnd, memberuserid):
|
||||
"""Retrieve member attributes by member of user id."""
|
||||
|
||||
# connect the members module to its backends
|
||||
if not members.connected(): members.connect()
|
||||
|
||||
# retrieve member data
|
||||
|
||||
if re.match('^[0-9]*$', memberuserid):
|
||||
|
||||
# numeric memberid, look it up
|
||||
memberid = int(memberuserid)
|
||||
member = members.get( memberid )
|
||||
if not member:
|
||||
msgbox(wnd, '%s is an invalid memberid' % memberuserid)
|
||||
|
||||
else:
|
||||
|
||||
# non-numeric memberid: try userids
|
||||
member = members.get_userid( memberuserid )
|
||||
if not member:
|
||||
msgbox(wnd, "%s is an invalid account userid" % memberuserid)
|
||||
|
||||
return member
|
||||
|
||||
|
||||
def action_display_member(wnd):
|
||||
"""Interactively display a member."""
|
||||
|
||||
# read the member id
|
||||
prompt = 'Memberid: '
|
||||
memberid = inputbox(wnd, prompt, 36)
|
||||
|
||||
if not memberid or memberid.lower() == 'exit':
|
||||
return False
|
||||
|
||||
member = get_member_memberid_userid(wnd, memberid)
|
||||
if not member: return False
|
||||
term_list = members.member_terms( member['memberid'] )
|
||||
|
||||
# display the details in a window
|
||||
display_member_details(wnd, member, term_list)
|
||||
|
||||
if not members.connected(): members.connect()
|
||||
member = read_member(wnd)
|
||||
return False
|
||||
|
||||
|
||||
|
@ -430,14 +377,26 @@ def format_members(member_list):
|
|||
|
||||
# clone and sort member_list
|
||||
member_list = list(member_list)
|
||||
member_list.sort( lambda x, y: x['memberid']-y['memberid'] )
|
||||
member_list.sort( lambda x, y: cmp(x['uid'], y['uid']) )
|
||||
|
||||
buf = ''
|
||||
|
||||
for member in member_list:
|
||||
attrs = ( member['memberid'], member['name'], member['studentid'],
|
||||
member['type'], member['program'], member['userid'] )
|
||||
buf += "%4d %50s %10s %10s \n%55s %10s\n\n" % attrs
|
||||
if 'uid' in member:
|
||||
uid = member['uid'][0]
|
||||
else:
|
||||
uid = None
|
||||
if 'program' in member:
|
||||
program = member['program'][0]
|
||||
else:
|
||||
program = None
|
||||
if 'studentid' in member:
|
||||
studentid = member['studentid'][0]
|
||||
else:
|
||||
studentid = None
|
||||
attrs = ( uid, member['cn'][0],
|
||||
studentid, program )
|
||||
buf += "%10s %30s %10s\n%41s\n\n" % attrs
|
||||
|
||||
return buf
|
||||
|
||||
|
@ -463,7 +422,7 @@ def action_list_term(wnd):
|
|||
member_list = members.list_term(term)
|
||||
|
||||
# format the data into a mess of text
|
||||
buf = format_members(member_list)
|
||||
buf = format_members(member_list.values())
|
||||
|
||||
# display the mass of text with a pager
|
||||
page( buf )
|
||||
|
@ -491,7 +450,7 @@ def action_list_name(wnd):
|
|||
member_list = members.list_name(name)
|
||||
|
||||
# format the data into a mess of text
|
||||
buf = format_members(member_list)
|
||||
buf = format_members(member_list.values())
|
||||
|
||||
# display the mass of text with a pager
|
||||
page( buf )
|
||||
|
@ -516,14 +475,10 @@ def action_list_studentid(wnd):
|
|||
if not members.connected(): members.connect()
|
||||
|
||||
# retrieve a list of members for term
|
||||
member = members.get_studentid(studentid)
|
||||
if member != None:
|
||||
member_list = [ members.get_studentid(studentid) ]
|
||||
else:
|
||||
member_list = []
|
||||
member_list = members.get_studentid(studentid)
|
||||
|
||||
# format the data into a mess of text
|
||||
buf = format_members(member_list)
|
||||
buf = format_members(member_list.values())
|
||||
|
||||
# display the mass of text with a pager
|
||||
page( buf )
|
||||
|
@ -551,8 +506,7 @@ top_menu = [
|
|||
( "Search for a member by name", action_list_name ),
|
||||
( "Search for a member by student id", action_list_studentid ),
|
||||
( "Create an account", action_create_account ),
|
||||
( "Re Create an account", action_create_account ),
|
||||
( "Library functions", null_callback ),
|
||||
( "Library functions", action_library ),
|
||||
( "Exit", exit_callback ),
|
||||
]
|
||||
|
||||
|
|
Loading…
Reference in New Issue