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:
Michael Spang 2007-07-16 07:52:21 -04:00
parent 396779cee2
commit 89276f899b
4 changed files with 237 additions and 407 deletions

View File

@ -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':

View File

@ -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']

View File

@ -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)

View File

@ -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 ),
]