Merge branch 'positions'
[www/www.git] / scripts / xsltproc.py
1 #!/usr/bin/python2.4
2 import os, sys, urllib, libxml2, libxslt, ldap, time
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     'librarian'       : ( 'Librarian',            False,  False,     6, ),
21     'imapd'           : ( 'Imapd',                False,  False,     7, ),
22     'webmaster'       : ( 'Web Master',           False,  False,     8, ),
23 }
24 cscYesNo = { True : 'yes', False : 'no' }
25
26 #
27 # cscLdapConnect
28 #
29 def cscLdapConnect():
30     global cscLdap
31     cscLdap = ldap.initialize(cscLdapUri)
32     cscLdap.simple_bind_s("", "")
33
34 #
35 # csc:encode-for-uri
36 #
37 def cscEncodeForUri(ctx, arg):
38     if type(arg) == type([]):
39         arg = libxml2.xmlNode(arg[0]).getContent()
40     return urllib.quote(arg)
41
42 #
43 # csc:term
44 #
45 def cscTerm(ctx, arg):
46     if type(arg) == type([]):
47         arg = libxml2.xmlNode(arg[0]).getContent()
48     try:
49         [year, month, day] = arg.split("-")
50         term = (int(month) - 1) / 4
51         return cscTerms[term] + " " + year
52     except:
53         print "Invalid term '%s'" % arg
54         raise
55
56 #
57 # csc:member-list
58 #
59 def cscMemberList(ctx, arg):
60     try:
61         if cscLdap == None:
62             cscLdapConnect()
63         curDate = time.strftime('%d-%m-%Y')
64         year = time.localtime().tm_year
65         term = cscShortTerms[int(time.localtime().tm_mon - 1) / 4]
66         members = cscLdap.search_s(cscPeopleBase, ldap.SCOPE_SUBTREE,
67             '(&(objectClass=member)(term=%s%d))' % (term, year))
68         doc = libxml2.newDoc("1.0")
69         root = doc.newChild(None, "root", None)
70         for (_, member) in members:
71             node = root.newChild(None, "member", None)
72             node.setProp("userid", member['uid'][0])
73             node.setProp("name", member['cn'][0])
74             if not 'program' in member:
75                 member['program'] = ['']
76             node.setProp("program", member['program'][0])
77         return [root]
78     except Exception, e:
79         print e
80         raise
81
82 #
83 # csc:position-list
84 #
85 def cscPositionList(ctx, arg):
86     try:
87         if cscLdap == None:
88             cscLdapConnect()
89         members = cscLdap.search_s(cscPeopleBase, ldap.SCOPE_SUBTREE,
90             '(&(objectClass=member)(position=*))')
91         doc = libxml2.newDoc("1.0")
92         root = doc.newChild(None, "root", None)
93         positions = {}
94         for (_, member) in members:
95             for position in member['position']:
96                 if not position in positions:
97                     positions[position] = []
98                 positions[position].append(member)
99         for position in cscPositions.keys():
100             if not position in positions:
101                 positions[position] = []
102         for (position, members) in positions.iteritems():
103             node = root.newChild(None, "position", None)
104             node.setProp("position", position)
105             if not position in cscPositions:
106                 raise Exception("Position '%s' not known" % position)
107             position = cscPositions[position]
108             node.setProp("name", position[0])
109             node.setProp("exec", cscYesNo[position[1]])
110             node.setProp("elected", cscYesNo[position[2]])
111             node.setProp("order", str(position[3]))
112             for member in members:
113                 child = node.newChild(None, "holder", None)
114                 child.setProp("userid", member['uid'][0])
115                 child.setProp("name", member['cn'][0])
116         return [root]
117     except Exception, e:
118         print e
119         raise
120
121 #
122 # csc:email
123 #
124 def cscEmail(ctx, arg):
125     if type(arg) == type([]):
126         str = libxml2.xmlNode(arg[0]).getContent()
127     return "_EMAIL_TODO_"
128
129 #
130 # main
131 #
132
133 # check argv
134 if len(sys.argv) < 4:
135     print "Usage: xsltproc.py input-file style-sheet output-file [params...]"
136     sys.exit(1)
137 inFile = sys.argv[1]
138 xsltFile = sys.argv[2]
139 outFile = sys.argv[3]
140 rawParams = sys.argv[4:]
141
142 # check params
143 params = {}
144 for p in rawParams:
145     try:
146         [key, val] = p.split("=")
147         params[key] = "'" + val + "'"
148     except:
149         print "Missing value for parameter '%s'" % p
150         sys.exit(1)
151
152 try:
153     # register extensions
154     libxslt.registerExtModuleFunction("encode-for-uri", cscUri, cscEncodeForUri)
155     libxslt.registerExtModuleFunction("term", cscUri, cscTerm)
156     libxslt.registerExtModuleFunction("member-list", cscUri, cscMemberList)
157     libxslt.registerExtModuleFunction("position-list", cscUri, cscPositionList)
158     libxslt.registerExtModuleFunction("email", cscUri, cscEmail)
159
160     # parse xml/xslt and apply style-sheet
161     style = libxslt.parseStylesheetFile(xsltFile)
162     if style == None: sys.exit(1)
163     doc = libxml2.parseFile(inFile)
164     res = style.applyStylesheet(doc, params)
165     ret = style.saveResultToFilename(outFile, res, 0)
166
167 except Exception, e:
168     sys.exit(1)