Remove remnants of SQL interface
This commit is contained in:
parent
f1702130d7
commit
31c05d869f
|
@ -7,7 +7,7 @@ Standards-Version: 3.7.2
|
|||
|
||||
Package: ceo
|
||||
Architecture: any
|
||||
Depends: python2.4, python-ldap, python-pygresql, python-urwid, krb5-user, less, python-pam, ${shlibs:Depends}
|
||||
Depends: python2.4, python-ldap, python-urwid, krb5-user, less, python-pam, ${shlibs:Depends}
|
||||
Recommends: quota
|
||||
Description: Computer Science Club Administrative Utilities
|
||||
This package contains the CSC Electronic Office
|
||||
|
|
|
@ -30,7 +30,6 @@ install: build
|
|||
usr/lib/csc usr/bin etc/ldap/schema
|
||||
dh_install pylib/* usr/lib/$(PYTHON)/site-packages/
|
||||
dh_install etc/* etc/csc/
|
||||
dh_install sql/* usr/share/csc/
|
||||
|
||||
dh_install bin/ceo bin/ceo-old bin/addhomedir bin/ceoquery bin/csc-chsh bin/csc-chfn usr/lib/csc/
|
||||
dh_install build/ceo build/ceo-old build/addhomedir build/ceoquery build/csc-chsh build/csc-chfn usr/bin/
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
# /etc/csc/members.cf: CSC Members Configuration
|
||||
|
||||
include /etc/csc/pgsql.cf
|
||||
include /etc/csc/ldap.cf
|
||||
|
||||
### Validation Tuning ###
|
||||
|
|
11
etc/pgsql.cf
11
etc/pgsql.cf
|
@ -1,11 +0,0 @@
|
|||
# /etc/csc/pgsql.cf: PostgreSQL database configuration
|
||||
|
||||
### Database Configuration ###
|
||||
|
||||
# server = "localhost"
|
||||
server = ""
|
||||
database = "ceo"
|
||||
|
||||
# not used
|
||||
user = "ceo"
|
||||
password = "secret"
|
|
@ -76,14 +76,14 @@ class NoSuchMember(MemberException):
|
|||
ldap_connection = ldapi.LDAPConnection()
|
||||
|
||||
def connect():
|
||||
"""Connect to PostgreSQL."""
|
||||
"""Connect to LDAP."""
|
||||
|
||||
load_configuration()
|
||||
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."""
|
||||
"""Disconnect from LDAP."""
|
||||
|
||||
ldap_connection.disconnect()
|
||||
|
||||
|
|
|
@ -1,671 +0,0 @@
|
|||
"""
|
||||
Database Backend Interface
|
||||
|
||||
This module is intended to be a thin wrapper around CEO database operations.
|
||||
Methods on the connection class correspond in a straightforward way to SQL
|
||||
queries. These methods may restructure and clean up query output but may make
|
||||
no other assumptions about its content or purpose.
|
||||
|
||||
This module makes use of the PyGreSQL Python bindings to libpq,
|
||||
PostgreSQL's native C client library.
|
||||
"""
|
||||
import pgdb
|
||||
|
||||
|
||||
class DBException(Exception):
|
||||
"""Exception class for database-related errors."""
|
||||
pass
|
||||
|
||||
|
||||
class DBConnection(object):
|
||||
"""
|
||||
A connection to CEO's backend database. All database queries
|
||||
and updates are made via this class.
|
||||
|
||||
Exceptions: (all methods)
|
||||
DBException - on database query failure
|
||||
|
||||
Note: Updates will never take place until commit() is called.
|
||||
|
||||
Note: In the event that any method of this class raises a
|
||||
DBException and that exception is caught, rollback()
|
||||
must be called before further queries will be successful.
|
||||
|
||||
Example:
|
||||
connection = DBConnection()
|
||||
connection.connect("localhost", "ceo")
|
||||
|
||||
# make queries and updates, i.e.
|
||||
connection.insert_member("Calum T. Dalek")
|
||||
|
||||
connection.commit()
|
||||
connection.disconnect()
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.cnx = None
|
||||
self.cursor = None
|
||||
|
||||
|
||||
def connect(self, hostname=None, database=None, username=None, password=None):
|
||||
"""
|
||||
Establishes the connection to CEO's PostgreSQL database.
|
||||
|
||||
Parameters:
|
||||
hostname - hostname:port to connect to
|
||||
database - name of database
|
||||
username - user to authenticate as
|
||||
password - password of username
|
||||
"""
|
||||
|
||||
if self.cnx: raise DBException("unable to connect: already connected")
|
||||
|
||||
try:
|
||||
self.cnx = pgdb.connect(host=hostname, database=database,
|
||||
user=username, password=password)
|
||||
self.cursor = self.cnx.cursor()
|
||||
except pgdb.Error, e:
|
||||
raise DBException("unable to connect: %s" % e)
|
||||
|
||||
|
||||
def disconnect(self):
|
||||
"""Closes the connection to CEO's PostgreSQL database."""
|
||||
|
||||
if self.cursor:
|
||||
self.cursor.close()
|
||||
self.cursor = None
|
||||
|
||||
if self.cnx:
|
||||
self.cnx.close()
|
||||
self.cnx = None
|
||||
|
||||
|
||||
def connected(self):
|
||||
"""Determine whether the connection has been established."""
|
||||
|
||||
return self.cnx is not None
|
||||
|
||||
|
||||
def commit(self):
|
||||
"""Commits the current transaction and starts a new one."""
|
||||
|
||||
self.cnx.commit()
|
||||
|
||||
|
||||
def rollback(self):
|
||||
"""Aborts the current transaction."""
|
||||
|
||||
self.cnx.rollback()
|
||||
|
||||
|
||||
|
||||
### Member-related methods ###
|
||||
|
||||
def select_members(self, sql, params=None):
|
||||
"""
|
||||
Retrieves a list CSC members selected by given SQL statement.
|
||||
|
||||
This is a helper function that should generally not be called directly.
|
||||
|
||||
Parameters:
|
||||
sql - the SELECT sql statement
|
||||
params - parameters for the SQL statement
|
||||
|
||||
The sql statement must select the six columns
|
||||
(memberid, name, studentid, program, type, userid)
|
||||
from the members table in that order.
|
||||
|
||||
Returns: a memberid-keyed dictionary whose values are
|
||||
column-keyed dictionaries with member attributes
|
||||
"""
|
||||
|
||||
# retrieve a list of all members
|
||||
try:
|
||||
self.cursor.execute(sql, params)
|
||||
members_list = self.cursor.fetchall()
|
||||
except pgdb.Error, e:
|
||||
raise DBException("SELECT statement failed: %s" % e)
|
||||
|
||||
# build a dictionary of dictionaries from the result (a list of lists)
|
||||
members_dict = {}
|
||||
for member in members_list:
|
||||
members_dict[member[0]] = {
|
||||
'memberid': member[0],
|
||||
'name': member[1],
|
||||
'studentid': member[2],
|
||||
'program': member[3],
|
||||
'type': member[4],
|
||||
'userid': member[5],
|
||||
}
|
||||
|
||||
return members_dict
|
||||
|
||||
|
||||
def select_single_member(self, sql, params=None):
|
||||
"""
|
||||
Retrieves a single member by memberid.
|
||||
|
||||
This is a helper function that should generally not be called directly.
|
||||
|
||||
See: self.select_members()
|
||||
|
||||
Returns: a column-keyed dictionary with member attributes, or
|
||||
None if no member matching member exists
|
||||
"""
|
||||
|
||||
# retrieve the member
|
||||
results = self.select_members(sql, params)
|
||||
|
||||
# too many members returned
|
||||
if len(results) > 1:
|
||||
raise DBException("multiple members selected: sql='%s' params=%s" % (sql, repr(params)))
|
||||
|
||||
# no such member
|
||||
elif len(results) < 1:
|
||||
return None
|
||||
|
||||
# return the single match
|
||||
memberid = results.keys()[0]
|
||||
return results[memberid]
|
||||
|
||||
|
||||
def select_all_members(self):
|
||||
"""
|
||||
Retrieves a list of all CSC members (past and present).
|
||||
|
||||
See: self.select_members()
|
||||
|
||||
Example: connection.select_all_members() -> {
|
||||
0: { 'memberid': 0, 'name': 'Calum T. Dalek' ...}
|
||||
3349: { 'memberid': 3349, 'name': 'Michael Spang' ...}
|
||||
...
|
||||
}
|
||||
"""
|
||||
sql = "SELECT memberid, name, studentid, program, type, userid FROM members"
|
||||
return self.select_members(sql)
|
||||
|
||||
|
||||
def select_members_by_name(self, name_re):
|
||||
"""
|
||||
Retrieves a list of all CSC members whose name matches name_re.
|
||||
|
||||
See: self.select_members()
|
||||
|
||||
Example: connection.select_members_by_name('Michael') -> {
|
||||
3349: { 'memberid': 3349, 'name': 'Michael Spang' ...}
|
||||
...
|
||||
}
|
||||
"""
|
||||
sql = "SELECT memberid, name, studentid, program, type, userid FROM members WHERE name ~* %s"
|
||||
params = [ str(name_re) ]
|
||||
|
||||
return self.select_members(sql, params)
|
||||
|
||||
|
||||
def select_members_by_term(self, term):
|
||||
"""
|
||||
Retrieves a list of all CSC members who were members in the specified term.
|
||||
|
||||
See: self.select_members()
|
||||
|
||||
Example: connection.select_members_by_term('f2006') -> {
|
||||
3349: { 'memberid': 3349, 'name': 'Michael Spang' ...}
|
||||
...
|
||||
}
|
||||
"""
|
||||
sql = "SELECT members.memberid, name, studentid, program, type, userid FROM members JOIN terms ON members.memberid=terms.memberid WHERE term=%s"
|
||||
params = [ str(term) ]
|
||||
|
||||
return self.select_members(sql, params)
|
||||
|
||||
|
||||
def select_member_by_id(self, memberid):
|
||||
"""
|
||||
Retrieves a single member by memberid.
|
||||
|
||||
See: self.select_single_member()
|
||||
|
||||
Example: connection.select_member_by_id(0) ->
|
||||
{ 'memberid': 0, 'name': 'Calum T. Dalek' ...}
|
||||
"""
|
||||
sql = "SELECT memberid, name, studentid, program, type, userid FROM members WHERE memberid=%d"
|
||||
params = [ int(memberid) ]
|
||||
|
||||
return self.select_single_member(sql, params)
|
||||
|
||||
|
||||
def select_member_by_userid(self, username):
|
||||
"""
|
||||
Retrieves a single member by UNIX account username.
|
||||
|
||||
See: self.select_single_member()
|
||||
|
||||
Example: connection.select_member_by_userid('ctdalek') ->
|
||||
{ 'memberid': 0, 'name': 'Calum T. Dalek' ...}
|
||||
"""
|
||||
sql = "SELECT memberid, name, studentid, program, type, userid FROM members WHERE userid=%s"
|
||||
params = [ username ]
|
||||
|
||||
return self.select_single_member(sql, params)
|
||||
|
||||
|
||||
def select_member_by_studentid(self, studentid):
|
||||
"""
|
||||
Retrieves a single member by student id number.
|
||||
|
||||
See: self.select_single_member()
|
||||
|
||||
Example: connection.select_member_by_studentid('nnnnnnnn') ->
|
||||
{ 'memberid': 3349, 'name': 'Michael Spang' ...}
|
||||
"""
|
||||
sql = "SELECT memberid, name, studentid, program, type, userid FROM members WHERE studentid=%s"
|
||||
params = [ studentid ]
|
||||
|
||||
return self.select_single_member(sql, params)
|
||||
|
||||
|
||||
def insert_member(self, name, studentid=None, program=None, mtype='user', userid=None):
|
||||
"""
|
||||
Creates a member with the specified attributes.
|
||||
|
||||
Parameters:
|
||||
name - full name of member
|
||||
studentid - student id number
|
||||
program - program of study
|
||||
mtype - member type
|
||||
userid - account id
|
||||
|
||||
Example: connection.insert_member('Michael Spang', '99999999', 'Math/CS') -> 3349
|
||||
|
||||
Returns: a memberid of created user
|
||||
"""
|
||||
try:
|
||||
# retrieve the next memberid
|
||||
sql = "SELECT nextval('memberid_seq')"
|
||||
self.cursor.execute(sql)
|
||||
result = self.cursor.fetchone()
|
||||
memberid = result[0]
|
||||
|
||||
# insert the member
|
||||
sql = "INSERT INTO members (memberid, name, studentid, program, type, userid) VALUES (%d, %s, %s, %s, %s, %s)"
|
||||
params = [ memberid, name, studentid, program, mtype, userid ]
|
||||
self.cursor.execute(sql, params)
|
||||
|
||||
return memberid
|
||||
except pgdb.Error, e:
|
||||
raise DBException("failed to create member: %s" % e)
|
||||
|
||||
|
||||
def delete_member(self, memberid):
|
||||
"""
|
||||
Deletes a member. Note that a member cannot
|
||||
be deleted until it has been unregistered from
|
||||
all terms.
|
||||
|
||||
Parameters:
|
||||
memberid - the member id number to delete
|
||||
|
||||
Example: connection.delete_member(3349)
|
||||
"""
|
||||
sql = "DELETE FROM members WHERE memberid=%d"
|
||||
params = [ memberid ]
|
||||
|
||||
try:
|
||||
self.cursor.execute(sql, params)
|
||||
except pgdb.Error, e:
|
||||
raise DBException("DELETE statement failed: %s" %e)
|
||||
|
||||
|
||||
def update_member(self, member):
|
||||
"""
|
||||
Modifies member attributes.
|
||||
|
||||
Parameters:
|
||||
member - a column-keyed dictionary with the new state of the member.
|
||||
member['memberid'] must be present. ommitted columns
|
||||
will not be changed. None is NULL.
|
||||
|
||||
Returns: the full new state of the member as a column-keyed dictionary
|
||||
|
||||
Example: connection.update_member({
|
||||
'memberid': 3349,
|
||||
'name': 'Michael C. Spang',
|
||||
'program': 'CS!'
|
||||
}) -> {
|
||||
'memberid': 3349,
|
||||
'name': 'Michael C. Spang',
|
||||
'program': CS!',
|
||||
'studentid': '99999999' # unchanged
|
||||
}
|
||||
|
||||
Equivalent Example:
|
||||
member = connection.select_member_by_id(3349)
|
||||
member['name'] = 'Michael C. Spang'
|
||||
member['program'] = 'CS!'
|
||||
connection.update_member(member) -> { see above }
|
||||
"""
|
||||
try:
|
||||
|
||||
# memberid to update
|
||||
memberid = member['memberid']
|
||||
|
||||
# retrieve current state of member
|
||||
member_state = self.select_member_by_id(memberid)
|
||||
|
||||
# build a list of changes to make
|
||||
changes = []
|
||||
for column in member.keys():
|
||||
if member[column] != member_state[column]:
|
||||
|
||||
# column's value must be updated
|
||||
changes.append( (column, member[column]) )
|
||||
member_state[column] = member[column]
|
||||
|
||||
# no changes?
|
||||
if len(changes) < 1:
|
||||
return member_state
|
||||
|
||||
# make the necessary changes in an update statement
|
||||
changes = zip(*changes)
|
||||
sql = "UPDATE members SET " + ", ".join(["%s=%%s"] * len(changes[0])) % changes[0] + " WHERE memberid=%d"
|
||||
params = changes[1] + ( memberid, )
|
||||
self.cursor.execute(sql, params)
|
||||
|
||||
return member_state
|
||||
except pgdb.Error, e:
|
||||
raise DBException("member update failed: %s" % e)
|
||||
|
||||
|
||||
|
||||
### Term-related methods ###
|
||||
|
||||
def select_term(self, memberid, term):
|
||||
"""
|
||||
Determines whether a member is registered for a term.
|
||||
|
||||
Parameters:
|
||||
memberid - the member id number
|
||||
term - the term to check
|
||||
|
||||
Returns: a matching term, or None
|
||||
|
||||
Example: connection.select_term(3349, 'f2006') -> 'f2006'
|
||||
"""
|
||||
sql = "SELECT term FROM terms WHERE memberid=%d AND term=%s"
|
||||
params = [ memberid, term ]
|
||||
|
||||
# retrieve matches
|
||||
try:
|
||||
self.cursor.execute(sql, params)
|
||||
result = self.cursor.fetchall()
|
||||
except pgdb.Error, e:
|
||||
raise DBException("SELECT statement failed: %s" % e)
|
||||
|
||||
if len(result) > 1:
|
||||
raise DBException("multiple rows in terms with memberid=%d term=%s" % (memberid, term))
|
||||
elif len(result) == 0:
|
||||
return None
|
||||
else:
|
||||
return result[0][0]
|
||||
|
||||
|
||||
def select_terms(self, memberid):
|
||||
"""
|
||||
Retrieves a list of terms a member is registered for.
|
||||
|
||||
Parameters:
|
||||
memberid - the member id number
|
||||
|
||||
Returns: a sorted list of terms
|
||||
|
||||
Example: connection.select_terms(3349) -> ['f2006']
|
||||
"""
|
||||
sql = "SELECT term FROM terms WHERE memberid=%d"
|
||||
params = [ memberid ]
|
||||
|
||||
# retrieve the list of terms
|
||||
try:
|
||||
self.cursor.execute(sql, params)
|
||||
result = self.cursor.fetchall()
|
||||
except pgdb.Error, e:
|
||||
raise DBException("SELECT statement failed: %s" % e)
|
||||
|
||||
result = [ row[0] for row in result ]
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def insert_term(self, memberid, term):
|
||||
"""
|
||||
Registers a member for a term.
|
||||
|
||||
Parameters:
|
||||
memberid - the member id number to register
|
||||
term - string representation of the term
|
||||
|
||||
Example: connection.insert_term(3349, 'f2006')
|
||||
"""
|
||||
sql = "INSERT INTO terms (memberid, term) VALUES (%d, %s)"
|
||||
params = [ memberid, term ]
|
||||
|
||||
try:
|
||||
self.cursor.execute(sql, params)
|
||||
except pgdb.Error, e:
|
||||
raise DBException("INSERT statement failed: %s" % e)
|
||||
|
||||
|
||||
def delete_term(self, memberid, term):
|
||||
"""
|
||||
Unregisters a member for a term.
|
||||
|
||||
Parameters:
|
||||
memberid - the member id number to register
|
||||
term - string representation of the term
|
||||
|
||||
Example: connection.delete_term(3349, 'f2006')
|
||||
"""
|
||||
sql = "DELETE FROM terms WHERE memberid=%d and term=%s"
|
||||
params = [ memberid, term ]
|
||||
|
||||
try:
|
||||
self.cursor.execute(sql, params)
|
||||
except pgdb.Error, e:
|
||||
raise DBException("DELETE statement failed: %s" % e)
|
||||
|
||||
|
||||
def delete_term_all(self, memberid):
|
||||
"""
|
||||
Unregisters a member for all registered terms.
|
||||
|
||||
Parameters:
|
||||
memberid - the member id number to unregister
|
||||
|
||||
Example: connection.delete_term_all(3349)
|
||||
"""
|
||||
sql = "DELETE FROM terms WHERE memberid=%d"
|
||||
params = [ memberid ]
|
||||
|
||||
# retrieve a list of terms
|
||||
try:
|
||||
self.cursor.execute(sql, params)
|
||||
except pgdb.Error, e:
|
||||
raise DBException("DELETE statement failed: %s" % e)
|
||||
|
||||
|
||||
### Miscellaneous methods ###
|
||||
|
||||
def trim_memberid_sequence(self):
|
||||
"""
|
||||
Sets the value of the member id sequence to the id of the newest
|
||||
member. For use after testing to prevent large intervals of unused
|
||||
memberids from developing.
|
||||
|
||||
Note: this does nothing unless the most recently added member(s) have been deleted
|
||||
"""
|
||||
self.cursor.execute("SELECT setval('memberid_seq', (SELECT max(memberid) FROM members))")
|
||||
|
||||
|
||||
|
||||
### Tests ###
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
from csc.common.test import *
|
||||
|
||||
conffile = "/etc/csc/pgsql.cf"
|
||||
|
||||
cfg = dict([map(str.strip, a.split("=", 1)) for a in map(str.strip, open(conffile).read().split("\n")) if "=" in a ])
|
||||
hostnm = cfg['server'][1:-1]
|
||||
dbase = cfg['database'][1:-1]
|
||||
|
||||
# t=test m=member s=student d=default e=expected u=updated
|
||||
tmname = 'Test Member'
|
||||
tmuname = 'Member Test'
|
||||
tmsid = '00000004'
|
||||
tmusid = '00000008'
|
||||
tmprogram = 'Undecidable'
|
||||
tmuprogram = 'Nondetermined'
|
||||
tmtype = 'Untyped'
|
||||
tmutype = 'Poly'
|
||||
tmuserid = 'tmem'
|
||||
tmuuserid = 'identifier'
|
||||
tm2name = 'Test Member 2'
|
||||
tm2sid = '00000005'
|
||||
tm2program = 'Undeclared'
|
||||
tm3name = 'T. M. 3'
|
||||
dtype = 'user'
|
||||
tmterm = 'w0000'
|
||||
tm3term = 'f1112'
|
||||
tm3term2 = 's1010'
|
||||
|
||||
emdict = { 'name': tmname, 'program': tmprogram, 'studentid': tmsid, 'type': tmtype, 'userid': tmuserid }
|
||||
emudict = { 'name': tmuname, 'program': tmuprogram, 'studentid': tmusid, 'type': tmutype, 'userid': tmuuserid }
|
||||
em2dict = { 'name': tm2name, 'program': tm2program, 'studentid': tm2sid, 'type': dtype, 'userid': None }
|
||||
em3dict = { 'name': tm3name, 'program': None, 'studentid': None, 'type': dtype, 'userid': None }
|
||||
|
||||
test(DBConnection)
|
||||
connection = DBConnection()
|
||||
success()
|
||||
|
||||
test(connection.connect)
|
||||
connection.connect(hostnm, dbase)
|
||||
success()
|
||||
|
||||
test(connection.connected)
|
||||
assert_equal(True, connection.connected())
|
||||
success()
|
||||
|
||||
test(connection.insert_member)
|
||||
tmid = connection.insert_member(tmname, tmsid, tmprogram, tmtype, tmuserid)
|
||||
tm2id = connection.insert_member(tm2name, tm2sid, tm2program)
|
||||
tm3id = connection.insert_member(tm3name)
|
||||
assert_equal(True, int(tmid) >= 0)
|
||||
assert_equal(True, int(tmid) >= 0)
|
||||
success()
|
||||
|
||||
emdict['memberid'] = tmid
|
||||
emudict['memberid'] = tmid
|
||||
em2dict['memberid'] = tm2id
|
||||
em3dict['memberid'] = tm3id
|
||||
|
||||
test(connection.select_member_by_id)
|
||||
m1 = connection.select_member_by_id(tmid)
|
||||
m2 = connection.select_member_by_id(tm2id)
|
||||
m3 = connection.select_member_by_id(tm3id)
|
||||
assert_equal(emdict, m1)
|
||||
assert_equal(em2dict, m2)
|
||||
assert_equal(em3dict, m3)
|
||||
success()
|
||||
|
||||
test(connection.select_all_members)
|
||||
members = connection.select_all_members()
|
||||
assert_equal(True, tmid in members)
|
||||
assert_equal(True, tm2id in members)
|
||||
assert_equal(True, tm3id in members)
|
||||
assert_equal(emdict, members[tmid])
|
||||
success()
|
||||
|
||||
test(connection.select_members_by_name)
|
||||
members = connection.select_members_by_name(tmname)
|
||||
assert_equal(True, tmid in members)
|
||||
assert_equal(False, tm3id in members)
|
||||
assert_equal(emdict, members[tmid])
|
||||
success()
|
||||
|
||||
test(connection.select_member_by_userid)
|
||||
assert_equal(emdict, connection.select_member_by_userid(tmuserid))
|
||||
success()
|
||||
|
||||
test(connection.insert_term)
|
||||
connection.insert_term(tmid, tmterm)
|
||||
connection.insert_term(tm3id, tm3term)
|
||||
connection.insert_term(tm3id, tm3term2)
|
||||
success()
|
||||
|
||||
test(connection.select_members_by_term)
|
||||
members = connection.select_members_by_term(tmterm)
|
||||
assert_equal(True, tmid in members)
|
||||
assert_equal(False, tm2id in members)
|
||||
assert_equal(False, tm3id in members)
|
||||
success()
|
||||
|
||||
test(connection.select_term)
|
||||
assert_equal(tmterm, connection.select_term(tmid, tmterm))
|
||||
assert_equal(None, connection.select_term(tm2id, tmterm))
|
||||
assert_equal(tm3term, connection.select_term(tm3id, tm3term))
|
||||
assert_equal(tm3term2, connection.select_term(tm3id, tm3term2))
|
||||
success()
|
||||
|
||||
test(connection.select_terms)
|
||||
trms = connection.select_terms(tmid)
|
||||
trms2 = connection.select_terms(tm2id)
|
||||
assert_equal([tmterm], trms)
|
||||
assert_equal([], trms2)
|
||||
success()
|
||||
|
||||
test(connection.delete_term)
|
||||
assert_equal(tm3term, connection.select_term(tm3id, tm3term))
|
||||
connection.delete_term(tm3id, tm3term)
|
||||
assert_equal(None, connection.select_term(tm3id, tm3term))
|
||||
success()
|
||||
|
||||
test(connection.update_member)
|
||||
connection.update_member({'memberid': tmid, 'name': tmuname})
|
||||
connection.update_member({'memberid': tmid, 'program': tmuprogram, 'studentid': tmusid })
|
||||
connection.update_member({'memberid': tmid, 'userid': tmuuserid, 'type': tmutype })
|
||||
assert_equal(emudict, connection.select_member_by_id(tmid))
|
||||
connection.update_member(emdict)
|
||||
assert_equal(emdict, connection.select_member_by_id(tmid))
|
||||
success()
|
||||
|
||||
test(connection.delete_term_all)
|
||||
connection.delete_term_all(tm2id)
|
||||
connection.delete_term_all(tm3id)
|
||||
assert_equal([], connection.select_terms(tm2id))
|
||||
assert_equal([], connection.select_terms(tm3id))
|
||||
success()
|
||||
|
||||
test(connection.delete_member)
|
||||
connection.delete_member(tm3id)
|
||||
assert_equal(None, connection.select_member_by_id(tm3id))
|
||||
negative(connection.delete_member, (tmid,), DBException, "delete of term-registered member")
|
||||
success()
|
||||
|
||||
test(connection.rollback)
|
||||
connection.rollback()
|
||||
assert_equal(None, connection.select_member_by_id(tm2id))
|
||||
success()
|
||||
|
||||
test(connection.commit)
|
||||
connection.commit()
|
||||
success()
|
||||
|
||||
test(connection.trim_memberid_sequence)
|
||||
connection.trim_memberid_sequence()
|
||||
success()
|
||||
|
||||
test(connection.disconnect)
|
||||
connection.disconnect()
|
||||
assert_equal(False, connection.connected())
|
||||
connection.disconnect()
|
||||
success()
|
|
@ -1,13 +0,0 @@
|
|||
#!/bin/sh
|
||||
# Initializes a database for CEO.
|
||||
|
||||
# initialize the database
|
||||
createdb $1
|
||||
createlang plpythonu $1
|
||||
|
||||
# initialize the tables
|
||||
psql $1 < structure.sql
|
||||
|
||||
# initialize check triggers
|
||||
psql $1 < verify_studentid.sql
|
||||
psql $1 < verify_term.sql
|
|
@ -1,24 +0,0 @@
|
|||
-- Table structure for CEO's SQL database.
|
||||
|
||||
-- Usage:
|
||||
-- su postgres
|
||||
-- createdb ceo
|
||||
-- psql ceo < structure.sql
|
||||
|
||||
CREATE SEQUENCE memberid_seq;
|
||||
|
||||
CREATE TABLE members (
|
||||
memberid integer PRIMARY KEY DEFAULT nextval('memberid_seq') NOT NULL,
|
||||
name character varying(50) NOT NULL,
|
||||
studentid character varying(10) UNIQUE,
|
||||
program character varying(50),
|
||||
"type" character varying(10),
|
||||
userid character varying(32) UNIQUE
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE terms (
|
||||
memberid integer NOT NULL,
|
||||
term character(5) NOT NULL,
|
||||
UNIQUE(memberid, term)
|
||||
);
|
|
@ -1,30 +0,0 @@
|
|||
-- PL/Python trigger to verify student ids for validity
|
||||
-- Dedicated to office staff who can't type student ids.
|
||||
|
||||
-- To (re)install:
|
||||
-- su postgres
|
||||
-- psql ceo < verify_studentid.sql
|
||||
|
||||
-- To uninstall:
|
||||
-- su postgres
|
||||
-- echo 'DROP FUNCTION verify_studentid() CASCADE' | psql ceo
|
||||
|
||||
DROP FUNCTION verify_studentid() CASCADE;
|
||||
|
||||
CREATE FUNCTION verify_studentid() RETURNS trigger AS '
|
||||
import re
|
||||
|
||||
# update this line if the student id format changes
|
||||
STUDENTID_REGEX = "^[0-9]{8}$"
|
||||
|
||||
studentid = TD["new"]["studentid"]
|
||||
if studentid and not re.match(STUDENTID_REGEX, studentid):
|
||||
plpy.error("student id is invalid (%s)" % studentid)
|
||||
|
||||
' LANGUAGE plpythonu;
|
||||
|
||||
CREATE TRIGGER verify_studentid_insert BEFORE INSERT on members
|
||||
FOR ROW EXECUTE PROCEDURE verify_studentid();
|
||||
|
||||
CREATE TRIGGER verify_studentid_update BEFORE UPDATE ON members
|
||||
FOR ROW EXECUTE PROCEDURE verify_studentid();
|
|
@ -1,29 +0,0 @@
|
|||
-- PL/Python trigger to verify terms for validity
|
||||
|
||||
-- To (re)install:
|
||||
-- su postgres
|
||||
-- psql ceo < verify_term.sql
|
||||
|
||||
-- To uninstall:
|
||||
-- su postgres
|
||||
-- echo 'DROP FUNCTION verify_term() CASCADE' | psql ceo
|
||||
|
||||
DROP FUNCTION verify_term() CASCADE;
|
||||
|
||||
CREATE FUNCTION verify_term() RETURNS trigger AS '
|
||||
import re
|
||||
|
||||
# update this line if the term format changes
|
||||
TERM_REGEX = "^[wsf][0-9]{4}$"
|
||||
|
||||
term = TD["new"]["term"]
|
||||
if term and not re.match(TERM_REGEX, term):
|
||||
plpy.error("term is invalid (%s)" % term)
|
||||
|
||||
' LANGUAGE plpythonu;
|
||||
|
||||
CREATE TRIGGER verify_term_insert BEFORE INSERT on terms
|
||||
FOR ROW EXECUTE PROCEDURE verify_term();
|
||||
|
||||
CREATE TRIGGER verify_term_update BEFORE UPDATE ON terms
|
||||
FOR ROW EXECUTE PROCEDURE verify_term();
|
Loading…
Reference in New Issue