#!/usr/bin/python import os, sys, urllib, libxml2, libxslt, ldap, time, datetime, re, pytz # # globals # cscUri = "http://csclub.uwaterloo.ca/xsltproc" cscTerms = ["Winter", "Spring", "Fall"] cscShortTerms = ['w', 's', 'f'] cscLdapUri = "ldap://ldap1.csclub.uwaterloo.ca ldap://ldap2.csclub.uwaterloo.ca" cscLdap = None cscPeopleBase = 'ou=People,dc=csclub,dc=uwaterloo,dc=ca' cscPositions = { # position name exec elected order 'president' : ( 'President', True, True, 1, ), 'vice-president' : ( 'Vice-president', True, True, 2, ), 'treasurer' : ( 'Treasurer', True, True, 3, ), 'secretary' : ( 'Assistant Vice-President',True, True, 4, ), 'sysadmin' : ( 'System Administrator', True, False, 5, ), 'cro' : ( 'Chief Returning Officer', False, False, 6, ), 'offsck' : ( 'Office Manager', False, False, 7, ), 'librarian' : ( 'Librarian', False, False, 8, ), 'imapd' : ( 'Imapd', False, False, 9, ), 'webmaster' : ( 'Web Master', False, False, 10, ), } cscYesNo = { True : 'yes', False : 'no' } def xslArgToString(arg): if type(arg) == type([]): return libxml2.xmlNode(arg[0]).getContent() else: return arg # # cscLdapConnect # def cscLdapConnect(): global cscLdap cscLdap = ldap.initialize(cscLdapUri) cscLdap.simple_bind_s("", "") # # csc:encode-for-uri # def cscEncodeForUri(ctx, uri): uri = xslArgToString(uri) return urllib.quote(uri) # # csc:term # def cscTerm(ctx, date): date = xslArgToString(date) try: [year, month, day] = date.split("-") term = (int(month) - 1) / 4 return cscTerms[term] + " " + year except: print "Invalid date '%s'" % date raise # # csc:member-list # def cscMemberList(ctx, _): try: if cscLdap == None: cscLdapConnect() curDate = time.strftime('%d-%m-%Y') year = time.localtime().tm_year term = cscShortTerms[int(time.localtime().tm_mon - 1) / 4] members = cscLdap.search_s(cscPeopleBase, ldap.SCOPE_SUBTREE, '(&(objectClass=member)(term=%s%d))' % (term, year)) doc = libxml2.newDoc("1.0") root = doc.newChild(None, "root", None) for (_, member) in members: node = root.newChild(None, "member", None) node.setProp("userid", member['uid'][0]) node.setProp("name", member['cn'][0]) if not 'program' in member: member['program'] = [''] node.setProp("program", member['program'][0]) return [root] except Exception, e: print e raise # # csc:position-list # def cscPositionList(ctx, _): try: if cscLdap == None: cscLdapConnect() members = cscLdap.search_s(cscPeopleBase, ldap.SCOPE_SUBTREE, '(&(objectClass=member)(position=*))') doc = libxml2.newDoc("1.0") root = doc.newChild(None, "root", None) positions = {} for (_, member) in members: for position in member['position']: if not position in positions: positions[position] = [] positions[position].append(member) for position in cscPositions.keys(): if not position in positions: positions[position] = [] for (position, members) in positions.iteritems(): node = root.newChild(None, "position", None) node.setProp("position", position) if not position in cscPositions: raise Exception("Position '%s' not known" % position) position = cscPositions[position] node.setProp("name", position[0]) node.setProp("exec", cscYesNo[position[1]]) node.setProp("elected", cscYesNo[position[2]]) node.setProp("order", str(position[3])) for member in members: child = node.newChild(None, "holder", None) child.setProp("userid", member['uid'][0]) child.setProp("name", member['cn'][0]) return [root] except Exception, e: print e raise # # csc:ical-datetime # def cscIcalDatetime(ctx, date, time, addmin = "0"): date = xslArgToString(date) time = xslArgToString(time) addmin = int(xslArgToString(addmin)) r = re.search("(\d*)-(\d*)-(\d*)", date) year, month, day = 0, 0, 0 if r != None: year, month, day = (int(i) for i in r.groups()) r = re.search("(\d*):(\d*)\s*([apAP])", time) hour, minute = (0, 0) if r != None: hour, minute = (int(i) for i in r.groups()[:2]) # 12-hour times if r.group(3) in 'aA': hour %= 12 #hour % 12 elif r.group(3) in 'pP': hour %= 12 hour += 12 # 24-hour time else: hour %= 24 dt = datetime.datetime(year, month, day, hour, minute) dt = pytz.timezone('Canada/Eastern').localize(dt) dt += datetime.timedelta(0, 0, 0, 0, addmin) return dt.astimezone(pytz.utc).strftime("%Y%m%dT%H%M%SZ") # # csc:ical-escape # def cscIcalEscape(ctx, str): str = xslArgToString(str) str = str.replace("\n", " ") #str = str.replace(":", "") #str = str.replace(";", "") #str = str.replace(",", "") str = re.sub("\s+", " ", str) str = re.sub("^\s+", "", str) str = re.sub("\s+$", "", str) return str # # csc:email # def cscEmail(ctx, email): email = xslArgToString(email) return "_EMAIL_TODO_" # # main # # check argv if len(sys.argv) < 4: print "Usage: xsltproc.py input-file style-sheet output-file [params...]" sys.exit(1) inFile = sys.argv[1] xsltFile = sys.argv[2] outFile = sys.argv[3] rawParams = sys.argv[4:] # check params params = {} for p in rawParams: try: [key, val] = p.split("=") params[key] = "'" + val + "'" except: print "Missing value for parameter '%s'" % p sys.exit(1) try: # register extensions libxslt.registerExtModuleFunction("encode-for-uri", cscUri, cscEncodeForUri) libxslt.registerExtModuleFunction("term", cscUri, cscTerm) libxslt.registerExtModuleFunction("member-list", cscUri, cscMemberList) libxslt.registerExtModuleFunction("position-list", cscUri, cscPositionList) libxslt.registerExtModuleFunction("ical-datetime", cscUri, cscIcalDatetime) libxslt.registerExtModuleFunction("ical-escape", cscUri, cscIcalEscape) libxslt.registerExtModuleFunction("email", cscUri, cscEmail) # parse xml/xslt and apply style-sheet style = libxslt.parseStylesheetFile(xsltFile) if style == None: sys.exit(1) doc = libxml2.parseFile(inFile) res = style.applyStylesheet(doc, params) ret = style.saveResultToFilename(outFile, res, 0) except Exception, e: print e sys.exit(1)