Revert "Revert "Added Bloomberg and Google Neural Net talks""
[www/www.git] / scripts / xsltproc.py
1 #!/usr/bin/python
2 import os, sys, urllib, libxml2, libxslt, ldap, time, datetime, re, pytz
3
4 #
5 # globals
6 #
7 cscUri = "http://csclub.uwaterloo.ca/xsltproc"
8 cscTerms = ["Winter", "Spring", "Fall"]
9 cscShortTerms = ['w', 's', 'f']
10 cscLdapUri = "ldap://ldap1.csclub.uwaterloo.ca ldap://ldap2.csclub.uwaterloo.ca"
11 cscLdap = None
12 cscPeopleBase = 'ou=People,dc=csclub,dc=uwaterloo,dc=ca'
13 cscPositions = {
14     # position            name                       exec    elected   order
15     'president'       : ( 'President',               True,   True,     1, ),
16     'vice-president'  : ( 'Vice-president',          True,   True,     2, ),
17     'treasurer'       : ( 'Treasurer',               True,   True,     3, ),
18     'secretary'       : ( 'Secretary',               True,   True,     4, ),
19     'sysadmin'        : ( 'System Administrator',    True,   False,    5, ),
20     'cro'             : ( 'Chief Returning Officer', False,  False,    6, ),
21     'offsck'          : ( 'Office Manager',          False,  False,    7, ),
22     'librarian'       : ( 'Librarian',               False,  False,    8, ),
23     'imapd'           : ( 'Imapd',                   False,  False,    9, ),
24     'webmaster'       : ( 'Web Master',              False,  False,    10, ),
25 }
26 cscYesNo = { True : 'yes', False : 'no' }
27
28 def xslArgToString(arg):
29     if type(arg) == type([]):
30         return libxml2.xmlNode(arg[0]).getContent()
31     else:
32         return arg
33
34 #
35 # cscLdapConnect
36 #
37 def cscLdapConnect():
38     global cscLdap
39     cscLdap = ldap.initialize(cscLdapUri)
40     cscLdap.simple_bind_s("", "")
41
42 #
43 # csc:encode-for-uri
44 #
45 def cscEncodeForUri(ctx, uri):
46     uri = xslArgToString(uri)
47     return urllib.quote(uri)
48
49 #
50 # csc:term
51 #
52 def cscTerm(ctx, date):
53     date = xslArgToString(date)
54     try:
55         [year, month, day] = date.split("-")
56         term = (int(month) - 1) / 4
57         return cscTerms[term] + " " + year
58     except:
59         print "Invalid date '%s'" % date
60         raise
61
62 #
63 # csc:member-list
64 #
65 def cscMemberList(ctx, _):
66     try:
67         if cscLdap == None:
68             cscLdapConnect()
69         curDate = time.strftime('%d-%m-%Y')
70         year = time.localtime().tm_year
71         term = cscShortTerms[int(time.localtime().tm_mon - 1) / 4]
72         members = cscLdap.search_s(cscPeopleBase, ldap.SCOPE_SUBTREE,
73             '(&(objectClass=member)(term=%s%d))' % (term, year))
74         doc = libxml2.newDoc("1.0")
75         root = doc.newChild(None, "root", None)
76         for (_, member) in members:
77             node = root.newChild(None, "member", None)
78             node.setProp("userid", member['uid'][0])
79             node.setProp("name", member['cn'][0])
80             if not 'program' in member:
81                 member['program'] = ['']
82             node.setProp("program", member['program'][0])
83         return [root]
84     except Exception, e:
85         print e
86         raise
87
88 #
89 # csc:position-list
90 #
91 def cscPositionList(ctx, _):
92     try:
93         if cscLdap == None:
94             cscLdapConnect()
95         members = cscLdap.search_s(cscPeopleBase, ldap.SCOPE_SUBTREE,
96             '(&(objectClass=member)(position=*))')
97         doc = libxml2.newDoc("1.0")
98         root = doc.newChild(None, "root", None)
99         positions = {}
100         for (_, member) in members:
101             for position in member['position']:
102                 if not position in positions:
103                     positions[position] = []
104                 positions[position].append(member)
105         for position in cscPositions.keys():
106             if not position in positions:
107                 positions[position] = []
108         for (position, members) in positions.iteritems():
109             node = root.newChild(None, "position", None)
110             node.setProp("position", position)
111             if not position in cscPositions:
112                 raise Exception("Position '%s' not known" % position)
113             position = cscPositions[position]
114             node.setProp("name", position[0])
115             node.setProp("exec", cscYesNo[position[1]])
116             node.setProp("elected", cscYesNo[position[2]])
117             node.setProp("order", str(position[3]))
118             for member in members:
119                 child = node.newChild(None, "holder", None)
120                 child.setProp("userid", member['uid'][0])
121                 child.setProp("name", member['cn'][0])
122         return [root]
123     except Exception, e:
124         print e
125         raise
126
127 #
128 # csc:ical-datetime
129 #
130 def cscIcalDatetime(ctx, date, time, addmin = "0"):
131     date = xslArgToString(date)
132     time = xslArgToString(time)
133     addmin = int(xslArgToString(addmin))
134     r = re.search("(\d*)-(\d*)-(\d*)", date)
135     year, month, day = 0, 0, 0
136     if r != None:
137         year, month, day = (int(i) for i in r.groups())
138     r = re.search("(\d*):(\d*)\s*([apAP])", time)
139     hour, minute = (0, 0)
140     if r != None:
141         hour, minute = (int(i) for i in r.groups()[:2])
142
143         # 12-hour times
144         if r.group(3) in 'aA':
145             hour %= 12 #hour % 12
146         elif r.group(3) in 'pP':
147             hour %= 12
148             hour += 12
149
150         # 24-hour time
151         else:
152             hour %= 24
153             
154     dt = datetime.datetime(year, month, day, hour, minute)
155     dt = pytz.timezone('Canada/Eastern').localize(dt)
156     dt += datetime.timedelta(0, 0, 0, 0, addmin)
157     return dt.astimezone(pytz.utc).strftime("%Y%m%dT%H%M%SZ")
158
159 #
160 # csc:ical-escape
161 #
162 def cscIcalEscape(ctx, str):
163     str = xslArgToString(str)
164     str = str.replace("\n", " ")
165     #str = str.replace(":", "")
166     #str = str.replace(";", "")
167     #str = str.replace(",", "")
168     str = re.sub("\s+", " ", str)
169     str = re.sub("^\s+", "", str)
170     str = re.sub("\s+$", "", str)
171     return str
172
173 #
174 # csc:email
175 #
176 def cscEmail(ctx, email):
177     email = xslArgToString(email)
178     return "_EMAIL_TODO_"
179
180 #
181 # main
182 #
183
184 # check argv
185 if len(sys.argv) < 4:
186     print "Usage: xsltproc.py input-file style-sheet output-file [params...]"
187     sys.exit(1)
188 inFile = sys.argv[1]
189 xsltFile = sys.argv[2]
190 outFile = sys.argv[3]
191 rawParams = sys.argv[4:]
192
193 # check params
194 params = {}
195 for p in rawParams:
196     try:
197         [key, val] = p.split("=")
198         params[key] = "'" + val + "'"
199     except:
200         print "Missing value for parameter '%s'" % p
201         sys.exit(1)
202
203 try:
204     # register extensions
205     libxslt.registerExtModuleFunction("encode-for-uri", cscUri, cscEncodeForUri)
206     libxslt.registerExtModuleFunction("term", cscUri, cscTerm)
207     libxslt.registerExtModuleFunction("member-list", cscUri, cscMemberList)
208     libxslt.registerExtModuleFunction("position-list", cscUri, cscPositionList)
209     libxslt.registerExtModuleFunction("ical-datetime", cscUri, cscIcalDatetime)
210     libxslt.registerExtModuleFunction("ical-escape", cscUri, cscIcalEscape)
211     libxslt.registerExtModuleFunction("email", cscUri, cscEmail)
212
213     # parse xml/xslt and apply style-sheet
214     style = libxslt.parseStylesheetFile(xsltFile)
215     if style == None: sys.exit(1)
216     doc = libxml2.parseFile(inFile)
217     res = style.applyStylesheet(doc, params)
218     ret = style.saveResultToFilename(outFile, res, 0)
219
220 except Exception, e:
221     print e
222     sys.exit(1)