Redbrick User management tool
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

938 lines
25 KiB

  1. #-----------------------------------------------------------------------------#
  2. # MODULE DESCRIPTION #
  3. #-----------------------------------------------------------------------------#
  4. """RedBrick Registration System CGI."""
  5. # System modules
  6. import atexit
  7. import cgi
  8. import cgitb
  9. import os
  10. import re
  11. import sys
  12. from xml.sax.saxutils import quoteattr
  13. # RedBrick modules
  14. from rbuserdb import *
  15. #-----------------------------------------------------------------------------#
  16. # DATA #
  17. #-----------------------------------------------------------------------------#
  18. __version__ = '$Revision: 1.6 $'
  19. __author__ = 'Cillian Sharkey'
  20. cmds = {
  21. 'card': 'Card reader interface',
  22. 'add': 'Add new user',
  23. 'delete': 'Delete user',
  24. 'renew': 'Renew user',
  25. 'update': 'Update user',
  26. 'rename': 'Rename user',
  27. 'convert': 'Convert user to new usertype',
  28. 'show': 'Show user information',
  29. 'freename': 'Check if a username is free',
  30. 'search': 'Search user and DCU databases',
  31. 'stats': 'Database statistics',
  32. 'log': 'Log of all actions'
  33. }
  34. cmds_list = ('card', 'add', 'delete', 'renew', 'update', 'rename', 'convert', 'show', 'freename', 'search', 'stats', 'log')
  35. cmds_noform = {
  36. 'stats': 1,
  37. 'log': 1
  38. }
  39. cmds_custom = {
  40. 'show': 1,
  41. 'search': 1
  42. }
  43. fields = (
  44. ('updatedby', 'Updated By', ('card', 'add', 'delete', 'renew', 'update', 'rename', 'convert')),
  45. ('cardid', 'DCU card id', ('card',)),
  46. ('uid', 'Username', ('card', 'add', 'delete', 'renew', 'update', 'rename', 'convert', 'show', 'search')),
  47. ('newuid', 'New username', ('renew', 'rename', 'freename')),
  48. ('newbie', 'New user?', ('update',)),
  49. ('birthday', 'Birthday', ('add', 'renew', 'update')),
  50. ('id', 'DCU ID', ('add', 'renew', 'update', 'search')),
  51. ('usertype', 'Usertype', ('add', 'renew', 'convert')),
  52. ('cn', 'Name', ('add', 'renew', 'update', 'search')),
  53. ('altmail', 'Email', ('add', 'renew', 'update')),
  54. ('course', 'Course Code', ('add', 'renew', 'update')),
  55. ('year', 'Course Year', ('add', 'renew', 'update')),
  56. ('yearsPaid', 'Years Paid', ('add', 'renew', 'update')),
  57. ('setpasswd', 'Set new password?', ('renew',)),
  58. ('override', 'Override errors?', ('card', 'add', 'renew', 'update', 'rename')),
  59. ('dummyid', "Use 'dummy' ID?", ('card',)),
  60. )
  61. # Optional side note for form fields. For a particular mode only, use
  62. # "fieldname.mode".
  63. #
  64. fields_note = {
  65. 'updatedby': 'your RedBrick username',
  66. 'birthday': 'DD-MM-YYYY',
  67. 'year': "'X' for exchange students",
  68. 'yearsPaid': '5 is only for associates',
  69. 'dummyid': 'New members only',
  70. 'uid.search': 'Search user database',
  71. 'id.search': 'Search user & DCU databases',
  72. 'cn.search': 'Search user & DCU databases'
  73. }
  74. # Fields that are simple yes/no choices. These are implemented using radio
  75. # dialogs instead of a checkbox, as they allow neither yes nor no to be set
  76. # (i.e. None).
  77. #
  78. fields_yesno = {
  79. 'setpasswd': 1,
  80. 'override': 1,
  81. 'dummyid': 1,
  82. 'newbie': 1
  83. }
  84. # HTML for custom form input fields.
  85. #
  86. fields_input = {
  87. 'cardid': 'class=fixed size=18 maxlength=16',
  88. 'cn': 'size=30',
  89. 'altmail': 'size=30',
  90. 'course': 'size=10 maxlength=50',
  91. 'year': 'size=10 maxlength=10'
  92. }
  93. # Global variables.
  94. #
  95. usr = RBUser()
  96. opt = RBOpt()
  97. udb = form = None # Initalised later in main()
  98. okay = 0
  99. start_done = end_done = 0
  100. error_string = notice_string = okay_string = ''
  101. #-----------------------------------------------------------------------------#
  102. # MAIN #
  103. #-----------------------------------------------------------------------------#
  104. def main():
  105. """Program entry function."""
  106. # XXX: Stupid Apache on shrapnel has TZ set to US/Eastern, no idea why!
  107. os.environ['TZ'] = 'Eire'
  108. print "Content-type: text/html"
  109. print
  110. atexit.register(shutdown)
  111. # Sets up an exception handler for uncaught exceptions and saves
  112. # traceback information locally.
  113. #
  114. cgitb.enable(logdir = '%s/tracebacks' % os.getcwd())
  115. global form
  116. form = cgi.FieldStorage()
  117. opt.mode = form.getfirst('mode')
  118. if not cmds.has_key(opt.mode):
  119. opt.mode = 'card'
  120. opt.action = form.getfirst('action')
  121. #XXX remove usr.override
  122. #usr.override = opt.override = form.getfirst('override') == '1'
  123. opt.override = form.getfirst('override') == '1'
  124. # Start HTML now only for modes that print output *before* html_form is
  125. # called (which calls start_html itself). We delay the printing of the
  126. # header for all other modes as mode switching may occur (e.g.
  127. # cardid <-> add/renew).
  128. #
  129. if cmds_noform.has_key(opt.mode) or (cmds_custom.has_key(opt.mode) and opt.action):
  130. html_start()
  131. global udb
  132. udb = RBUserDB()
  133. udb.setopt(opt)
  134. # Open database and call function for specific command only if action
  135. # is required or the command needs no user input (i.e. no blank form
  136. # stage).
  137. #
  138. if cmds_noform.has_key(opt.mode) or opt.action:
  139. try:
  140. udb.connect()
  141. except ldap.LDAPError, e:
  142. error(e, 'Could not connect to user database')
  143. # not reached
  144. try:
  145. eval(opt.mode + '()')
  146. except (ldap.LDAPError, RBError), e:
  147. error(e)
  148. # not reached
  149. html_form()
  150. sys.exit(0)
  151. def shutdown():
  152. """Cleanup function registered with atexit."""
  153. html_end()
  154. if udb: udb.close()
  155. def html_start():
  156. """Start HTML output."""
  157. global start_done
  158. if start_done:
  159. return
  160. start_done = 1
  161. print \
  162. """<html>
  163. <head>
  164. <title>RedBrick Registration System v3.0 - %s</title>
  165. <link rel="stylesheet" href="common.css" type="text/css">
  166. <script language="JavaScript" type="text/javascript">
  167. <!--
  168. function page_load()
  169. {
  170. if (document.mainform)
  171. f = document.mainform;
  172. else
  173. return;
  174. if (f.updatedby && f.updatedby.value.length == 0)
  175. f.updatedby.focus();
  176. else if (f.cardid && f.cardid.value.length == 0)
  177. f.cardid.focus();
  178. else if (f.uid && f.uid.value.length == 0)
  179. f.uid.focus();
  180. else if (f.newuid && f.newuid.value.length == 0)
  181. f.newuid.focus();
  182. else if (f.cardid)
  183. f.cardid.focus();
  184. else if (f.uid)
  185. f.uid.focus();
  186. else if (f.newuid)
  187. f.newuid.focus();
  188. }
  189. function radio_value(r)
  190. {
  191. for (var i = 0; i < r.length; i++)
  192. if (r[i].checked == true)
  193. return (r[i].value);
  194. return (null);
  195. }
  196. function check_form(f)
  197. {
  198. if (f.updatedby && f.updatedby.value.length == 0) {
  199. alert("updatedby must be given");
  200. f.updatedby.focus();
  201. return false;
  202. }
  203. return true;
  204. }
  205. // -->
  206. </script>
  207. </head>
  208. <body text=black bgcolor=white onLoad="javascript:page_load()">
  209. <div id=top>RedBrick Registration System v3.0</div>
  210. <div id=menu>
  211. <form name=menuform action='rrs.cgi' method=get>""" % opt.mode.capitalize()
  212. if form.getfirst('updatedby'):
  213. print "<input type=hidden name=updatedby value=%s>" % quoteattr(form.getfirst('updatedby') or '')
  214. for i in cmds_list:
  215. print "<input id=button type=submit name=mode value=%s> " % i
  216. print \
  217. """</form>
  218. </div>
  219. <div id=top>%s</div>
  220. <div id=main>
  221. """ % cmds[opt.mode]
  222. def html_form():
  223. """Output HTML form for current mode."""
  224. global usr
  225. html_start()
  226. if notice_string or error_string or okay_string:
  227. print "<table align=center id=msgs><tr><td>"
  228. if error_string:
  229. print "<span id=warn>%s</span>" % error_string.replace('\n', '<br>\n')
  230. if notice_string:
  231. print "<span id=notice>%s</span>" % notice_string.replace('\n', '<br>\n')
  232. if okay_string:
  233. print "<span id=okay>%s</span>" % okay_string.replace('\n', '<br>\n')
  234. print "</td></tr></table>"
  235. # Modes that never use a form or don't want a form when action has been
  236. # requested and successful.
  237. #
  238. if cmds_noform.has_key(opt.mode) or (cmds_custom.has_key(opt.mode) and opt.action and okay):
  239. return
  240. if okay:
  241. # Need a blank form, so create new user but keep updatedby set.
  242. # Set override & setpassword options back to default (off).
  243. #
  244. usr = RBUser(updatedby = form.getfirst('updatedby'))
  245. opt.override = 0
  246. opt.setpasswd = 0
  247. else:
  248. # We want to preserve the form input so fill in as much data on
  249. # the form as possible.
  250. #
  251. for k in form.keys():
  252. if hasattr(usr, k) and getattr(usr, k) == None:
  253. setattr(usr, k, form.getfirst(k))
  254. print \
  255. """<form name=mainform onSubmit="javascript:return check_form(this)" action="rrs.cgi" method=get>
  256. <input type=hidden name=mode value=%s>
  257. <input type=hidden name=action value=1>""" % opt.mode
  258. print '<table align=center class=main border=0 cellpadding=1 cellspacing=5>'
  259. for field, desc, modes in fields:
  260. if opt.mode not in modes:
  261. # If updatedby isn't an actual visible field on the
  262. # form, add it as a hidden field so its value gets
  263. # passed on.
  264. #
  265. if field == 'updatedby' and form.getfirst('updatedby'):
  266. print '<input type=hidden name=updatedby value=%s>' % quoteattr(form.getfirst('updatedby') or '')
  267. else:
  268. usrval = ''
  269. if hasattr(usr, field) and getattr(usr, field) != None:
  270. usrval = getattr(usr, field)
  271. if field == 'override':
  272. usrval = opt.override
  273. elif field == 'cardid' and not usrval and usr.id:
  274. usrval = usr.id
  275. print '<tr>'
  276. print ' <td class=side>%s</td>' % desc
  277. print ' <td>',
  278. if fields_input.has_key(field):
  279. print '<input %s name=%s value=%s>' % (fields_input[field], field, quoteattr(str(usrval)))
  280. elif fields_yesno.has_key(field):
  281. print '<input name=%s type=radio value=1%s> Yes <input name=%s type=radio value=0%s> No' % (field, usrval == 1 and ' checked' or '', field, usrval == 0 and ' checked' or '')
  282. elif field == 'usertype':
  283. # Show default usertype of member if none set.
  284. if not usr.usertype:
  285. usr.usertype = 'member'
  286. print '<select name=usertype>'
  287. for i in rbconfig.usertypes_paying:
  288. print '<option value=%s' % i,
  289. if usr.usertype == i:
  290. print ' selected',
  291. print '>', i.capitalize()
  292. print '</select>'
  293. elif field == 'birthday':
  294. if usr.birthday:
  295. res = re.search(r'^(\d{4})-(\d{2})-(\d{2})', usr.birthday)
  296. if res:
  297. usr.bday = res.group(3)
  298. usr.bmonth = res.group(2)
  299. usr.byear = res.group(1)
  300. print "<input size=2 maxlength=2 name=bday value='%s'>-<input size=2 maxlength=2 name=bmonth value='%s'>-<input size=4 maxlength=4 name=byear value='%s'>" % (usr.bday or '', usr.bmonth or '', usr.byear or '')
  301. else:
  302. print "<input class=fixed size=10 maxlength=8 name=%s value=%s" % (field, quoteattr(str(usrval))),
  303. if field == 'uid' and usr.uid and opt.mode in ('renew', 'update'):
  304. print ' readonly',
  305. print '>'
  306. print '</td>'
  307. print ' <td><span id=note>',
  308. if fields_note.has_key('%s.%s' % (field, opt.mode)):
  309. print fields_note['%s.%s' % (field, opt.mode)],
  310. elif fields_note.has_key(field):
  311. print fields_note[field],
  312. print '</span></td>'
  313. print '</tr>'
  314. print \
  315. """</table>
  316. <p><input id=button type=submit value='%s &gt;&gt;'></p>
  317. </form>""" % opt.mode.capitalize()
  318. def html_end():
  319. """Finish HTML output."""
  320. global end_done
  321. if end_done:
  322. return
  323. end_done = 1
  324. print \
  325. """</div>
  326. </body>
  327. </html>"""
  328. #-----------------------------------------------------------------------------#
  329. # MAIN FUNCTIONS #
  330. #-----------------------------------------------------------------------------#
  331. def card():
  332. """Process input from card reader form. Mode will be switched to add or
  333. renew as appropriate if there were no problems with user input."""
  334. get_updatedby(usr)
  335. get_cardid(usr)
  336. newmode = None
  337. # We have an ID, is it a newbie or a renewal?
  338. #
  339. if usr.id != None:
  340. try:
  341. udb.check_user_byid(usr.id)
  342. except RBError:
  343. # Doesn't exist, must be new user.
  344. newmode = 'add'
  345. else:
  346. # Exists, must be renewal.
  347. newmode = 'renew'
  348. elif form.getfirst('dummyid'):
  349. get_dummyid(usr)
  350. newmode = 'add'
  351. elif form.getfirst('uid'):
  352. usr.uid = form.getfirst('uid')
  353. udb.check_username(usr.uid)
  354. try:
  355. udb.check_user_byname(usr.uid)
  356. except RBError:
  357. # Doesn't exist, must be new user.
  358. newmode = 'add'
  359. else:
  360. # Exists, must be renewal.
  361. newmode = 'renew'
  362. else:
  363. raise RBFatalError("DCU Card ID, username or dummy ID must be given")
  364. if newmode == 'add':
  365. if usr.id != None:
  366. udb.get_userinfo_new(usr)
  367. udb.get_userdefaults_new(usr)
  368. elif newmode == 'renew':
  369. curusr = RBUser()
  370. udb.get_userinfo_renew(usr, curusr, override = 1)
  371. udb.check_unpaid(curusr)
  372. udb.get_userdefaults_renew(usr)
  373. if newmode:
  374. opt.mode = newmode
  375. def add():
  376. """Add a new user."""
  377. global okay, okay_string
  378. get_updatedby(usr)
  379. get_usertype(usr)
  380. get_newusername(usr)
  381. get_id(usr)
  382. udb.get_userinfo_new(usr)
  383. udb.get_userdefaults_new(usr)
  384. get_name(usr)
  385. get_email(usr)
  386. get_course(usr)
  387. get_year(usr)
  388. get_years_paid(usr)
  389. get_birthday(usr)
  390. # Add user to database.
  391. #
  392. udb.add(usr)
  393. # If we reached here, operation was successful, so show result of
  394. # operation, log it and switch back to card mode.
  395. #
  396. okay = 1
  397. okay_string += 'OKAY: User added: %s %s (%s)' % (usr.usertype, usr.uid, usr.cn)
  398. rrs_log_add('add:%s:%s:%s:%s:%s:%s:%s:%s:%s' % (usr.uid, usr.usertype, usr.id != None and usr.id or '', usr.cn, usr.course or '', usr.year or '', usr.altmail, usr.birthday or '', usr.yearsPaid))
  399. opt.mode = 'card'
  400. def delete():
  401. """Delete user."""
  402. global okay, okay_string
  403. get_updatedby(usr)
  404. get_username(usr)
  405. udb.delete(usr)
  406. okay = 1
  407. okay_string += 'OKAY: User deleted: %s\n' % usr.uid
  408. rrs_log_add('delete:%s' % (usr.uid))
  409. def renew():
  410. """Renew user."""
  411. global okay, okay_string
  412. newusr = RBUser()
  413. curusr = RBUser()
  414. get_updatedby(usr)
  415. get_username(usr)
  416. get_newusername(newusr)
  417. udb.get_userinfo_renew(usr, curusr)
  418. udb.get_userdefaults_renew(usr)
  419. get_setpasswd(usr)
  420. get_usertype(usr)
  421. get_id(usr)
  422. udb.get_userinfo_renew(usr)
  423. get_name(usr)
  424. get_email(usr)
  425. get_course(usr)
  426. get_year(usr)
  427. get_years_paid(usr)
  428. get_birthday(usr)
  429. udb.renew(usr)
  430. okay_string += 'OKAY: User renewed: %s %s%s\n' % (usr.oldusertype, usr.uid, opt.setpasswd and ' [new password set]' or '')
  431. rrs_log_add('renew:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s' % (usr.uid, newusr.uid or '', opt.setpasswd and 1 or 0, usr.usertype, usr.id != None and usr.id or '', usr.cn, usr.course or '', usr.year != None and usr.year or '', usr.altmail, usr.birthday or '', usr.yearsPaid))
  432. # NOTE: We don't actually generate/set a password here, just flag it in
  433. # the 'transaction log' so that sync_renew in useradm will set it
  434. # instead.
  435. # NOTE: If a renewal changed usertype, convert it and log it.
  436. # sync_renew in useradm will detect the usertype change and convert the
  437. # account.
  438. #
  439. if usr.oldusertype != usr.usertype:
  440. udb.convert(curusr, usr)
  441. okay_string += 'OKAY: User converted: %s -> %s\n' % (usr.uid, usr.usertype)
  442. rrs_log_add('convert:%s:%s' % (usr.uid, usr.usertype))
  443. # NOTE: If new username is given, rename database entry and log it.
  444. # sync_rename in useradm will use this log entry to rename the account
  445. # but only if it's a rename of an existing user only (i.e newbie is
  446. # false).
  447. #
  448. if newusr.uid:
  449. udb.rename(usr, newusr)
  450. okay_string += 'OKAY: User renamed: %s -> %s\n' % (usr.uid, newusr.uid)
  451. rrs_log_add('rename-%s:%s:%s' % (usr.newbie and 'new' or 'existing', usr.uid, newusr.uid))
  452. okay = 1
  453. opt.mode = 'card'
  454. def update():
  455. """Update user."""
  456. global okay, okay_string
  457. get_updatedby(usr)
  458. get_username(usr)
  459. udb.get_user_byname(usr)
  460. get_newbie(usr)
  461. get_id(usr)
  462. get_name(usr)
  463. get_email(usr)
  464. get_course(usr)
  465. get_year(usr)
  466. get_years_paid(usr)
  467. get_birthday(usr)
  468. udb.update(usr)
  469. okay = 1
  470. okay_string += 'OKAY: User updated: %s\n' % usr.uid
  471. rrs_log_add('update:%s:%s:%s:%s:%s:%s:%s:%s:%s' % (usr.uid, usr.newbie and 1 or 0, usr.id != None and usr.id or '', usr.cn, usr.course or '', usr.year != None and usr.year or '', usr.altmail, usr.birthday or '', usr.yearsPaid))
  472. def rename():
  473. """Rename user."""
  474. global okay, okay_string
  475. newusr = RBUser()
  476. get_updatedby(usr)
  477. get_username(usr)
  478. udb.get_user_byname(usr)
  479. get_newusername(newusr)
  480. udb.rename(usr, newusr)
  481. okay = 1
  482. okay_string += 'OKAY: User renamed: %s -> %s\n' % (usr.uid, newusr.uid)
  483. rrs_log_add('rename-%s:%s:%s' % (usr.newbie and 'new' or 'existing', usr.uid, newusr.uid))
  484. def convert():
  485. """Convert user."""
  486. global okay, okay_string
  487. newusr = RBUser()
  488. get_updatedby(usr)
  489. get_username(usr)
  490. get_usertype(newusr)
  491. udb.convert(usr, newusr)
  492. okay = 1
  493. okay_string += 'OKAY: User converted: %s -> %s\n' % (usr.uid, newusr.usertype)
  494. rrs_log_add('convert:%s:%s' % (usr.uid, newusr.usertype))
  495. def show():
  496. """Show user's details."""
  497. global okay
  498. get_username(usr)
  499. udb.get_user_byname(usr)
  500. print '<pre>'
  501. udb.show(usr)
  502. print '</pre>'
  503. okay = 1
  504. def freename():
  505. """Check if a username is free."""
  506. global okay_string
  507. get_newusername(usr)
  508. if usr.uid:
  509. okay_string += "OKAY: Username '%s' is free.\n" % usr.uid
  510. def search():
  511. """Search user and/or DCU databases."""
  512. global okay
  513. if form.getfirst('uid'):
  514. uid = form.getfirst('uid')
  515. res = udb.search_users_byusername(uid)
  516. print "<p align=center>User database search for username '%s' - %d match%s</p>" % (uid, len(res), len(res) != 1 and 'es' or '')
  517. show_search_results(res)
  518. okay = 1
  519. elif form.has_key('id') or form.has_key('cn'):
  520. id = form.getfirst('id')
  521. cn = form.getfirst('cn')
  522. if id != None:
  523. res = udb.search_users_byid(id)
  524. print "<p align=center>User database search for ID '%s' - %d match%s</p>" % (id, len(res), len(res) != 1 and 'es' or '')
  525. else:
  526. res = udb.search_users_byname(cn)
  527. print "<p align=center>User database search for name '%s' - %d match%s</p>" % (cn, len(res), len(res) != 1 and 'es' or '')
  528. show_search_results(res)
  529. if id != None:
  530. res = udb.search_dcu_byid(id)
  531. print "<p align=center>DCU database search for ID '%s' - %d match%s</p>" % (id, len(res), len(res) != 1 and 'es' or '')
  532. else:
  533. res = udb.search_dcu_byname(cn)
  534. print "<p align=center>DCU database search for name '%s' - %d match%s</p>" % (cn, len(res), len(res) != 1 and 'es' or '')
  535. show_search_results(res)
  536. okay = 1
  537. else:
  538. raise RBFatalError('No search term given!')
  539. def show_search_results(res):
  540. """Actual routine to display search results."""
  541. if res:
  542. print '<table align=center class=search>'
  543. print '<tr><td></td><td class=top>Username</td><td class=top>Usertype</td><td class=top>Id</td><td class=top>Name</td><td class=top>Course</td><td class=top>Year</td><td class=top>Email</td></tr>'
  544. for uid, usertype, id, cn, course, year, altmail in res:
  545. print '<tr><td class=button>',
  546. if uid:
  547. print '<form action=rrs.cgi method=get><input type=hidden name=updatedby value=%s><input type=hidden name=uid value=%s><input type=hidden name=action value=1><input id=button type=submit name=mode value=show></form>' % (quoteattr(form.getfirst('updatedby') or ''), uid),
  548. print '</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>' % (uid or '-', usertype or '-', id or '-', cn, course or '-', year or '-', altmail)
  549. print '</table>'
  550. def stats():
  551. """Show database statistics."""
  552. print "<pre>"
  553. udb.stats()
  554. print "</pre>"
  555. def log():
  556. """Show contents of rrs log file."""
  557. try:
  558. fd = open('rrs.log', 'r')
  559. except IOError, e:
  560. error(e, 'Could not open rrs.log')
  561. print '<pre>\n'
  562. if os.path.getsize('rrs.log') == 0:
  563. print 'Logfile is empty.'
  564. else:
  565. for line in fd.xreadlines():
  566. print line,
  567. print '</pre>'
  568. fd.close()
  569. #-----------------------------------------------------------------------------#
  570. # GET USER DATA FUNCTIONS #
  571. #-----------------------------------------------------------------------------#
  572. def get_username(usr):
  573. """Get an existing username."""
  574. if form.getfirst('uid'):
  575. usr.uid = form.getfirst('uid')
  576. else:
  577. raise RBFatalError('Username must be given')
  578. udb.check_username(usr.uid)
  579. udb.check_user_byname(usr.uid)
  580. def get_newusername(usr):
  581. """Get a new (free) username."""
  582. if opt.mode == 'add':
  583. if form.getfirst('uid'):
  584. usr.uid = form.getfirst('uid')
  585. else:
  586. if form.getfirst('newuid'):
  587. usr.uid = form.getfirst('newuid')
  588. # New username is optional for renewals but compulsory for all other
  589. # modes that require it (add, rename, freename).
  590. #
  591. if opt.mode == 'renew' and not usr.uid:
  592. return
  593. if not usr.uid:
  594. raise RBFatalError('New username must be given')
  595. try:
  596. udb.check_username(usr.uid)
  597. udb.check_userfree(usr.uid)
  598. except RBWarningError, e:
  599. error(e)
  600. def get_cardid(usr):
  601. """Set usr.id to DCU ID number in cardid field.
  602. The ID will either be the 8 digit number when entered manually or the
  603. 13 digit code produced by barcode and magnetic readers of the form
  604. xxIDNUMBERnnn with possible start and/or end sentinel characters such
  605. as ';' or '?'. Some readers will output a code number at the start,
  606. (to indicate the type of barcode or something) so we assume the 13 digit
  607. number is at the end (i.e. right-hand side) of the string.
  608. If invalid input is given, raises RBFatalError.
  609. NOTE: It is up to the caller to check if usr.id has been set,
  610. get_cardid does not require it to be set.
  611. """
  612. usr.id = form.getfirst('cardid')
  613. if usr.id != None:
  614. res = re.search(r'\d{2}(\d{8})\d{3}\D*$', usr.id)
  615. if res:
  616. usr.id = int(res.group(1))
  617. return
  618. res = re.search(r'^(\d{8})$', usr.id)
  619. if res:
  620. usr.id = int(usr.id)
  621. return
  622. raise RBFatalError('Invalid ID number/card reader input')
  623. def get_updatedby(usr):
  624. """Get username of who is performing the action."""
  625. if form.getfirst('updatedby'):
  626. usr.updatedby = form.getfirst('updatedby')
  627. else:
  628. raise RBFatalError('Updated by must be given')
  629. if usr.updatedby == 'root':
  630. raise RBFatalError('root not allowed for updatedby')
  631. udb.check_updatedby(usr.updatedby)
  632. def get_usertype(usr):
  633. """Get usertype."""
  634. usr.oldusertype = usr.usertype
  635. if form.getfirst('usertype'):
  636. usr.usertype = form.getfirst('usertype')
  637. else:
  638. raise RBFatalError('Usertype must be given')
  639. udb.check_usertype(usr.usertype)
  640. def get_id(usr):
  641. """Get DCU ID."""
  642. if usr.usertype in rbconfig.usertypes_dcu:
  643. if form.getfirst('id'):
  644. usr.id = int(form.getfirst('id'))
  645. else:
  646. raise RBFatalError('ID must be given')
  647. udb.check_id(usr)
  648. def get_dummyid(usr):
  649. """Get 'dummy' DCU ID."""
  650. if form.getfirst('dummyid'):
  651. udb.get_dummyid(usr)
  652. #XXX remove usr.override
  653. #usr.override = opt.override = 1
  654. opt.override = 1
  655. def get_name(usr):
  656. """Get name."""
  657. if form.getfirst('cn'):
  658. usr.cn = form.getfirst('cn')
  659. else:
  660. raise RBFatalError('Name must be given')
  661. udb.check_name(usr)
  662. def get_years_paid(usr):
  663. """Get years paid."""
  664. if not usr.usertype in rbconfig.usertypes_paying:
  665. return
  666. if form.getfirst('yearsPaid'):
  667. usr.yearsPaid = int(form.getfirst('yearsPaid'))
  668. else:
  669. raise RBFatalError('Years paid must be given')
  670. udb.check_years_paid(usr)
  671. def get_course(usr):
  672. """Get DCU course."""
  673. if not usr.usertype in ('member', 'committe'):
  674. return
  675. if form.getfirst('course'):
  676. usr.course = form.getfirst('course')
  677. else:
  678. raise RBFatalError('Course must be given')
  679. def get_year(usr):
  680. """Get DCU year."""
  681. if not usr.usertype in ('member', 'committe'):
  682. return
  683. if form.getfirst('year'):
  684. usr.year = form.getfirst('year')
  685. else:
  686. raise RBFatalError('Year must be given')
  687. def get_email(usr):
  688. """Get alternative email address."""
  689. if form.getfirst('altmail'):
  690. usr.altmail = form.getfirst('altmail')
  691. else:
  692. raise RBFatalError('Email must be given')
  693. try:
  694. udb.check_email(usr)
  695. except RBWarningError, e:
  696. error(e)
  697. def get_birthday(usr):
  698. """Get (optional) birthday."""
  699. if form.getfirst('byear') or form.getfirst('bmonth') or form.getfirst('bday'):
  700. if not (form.getfirst('byear') and form.getfirst('bmonth') and form.getfirst('bday')):
  701. raise RBFatalError('Incomplete birthday given')
  702. try:
  703. usr.birthday = '%.4d-%0.2d-%0.2d' % (int(form.getfirst('byear')), int(form.getfirst('bmonth')), int(form.getfirst('bday')))
  704. except ValueError:
  705. raise RBFatalError('Invalid birthday given')
  706. udb.check_birthday(usr)
  707. def get_setpasswd(usr):
  708. """Get set new password boolean."""
  709. if form.getfirst('setpasswd') != None:
  710. opt.setpasswd = form.getfirst('setpasswd') == '1'
  711. def get_newbie(usr):
  712. """Get newbie boolean."""
  713. if form.getfirst('newbie') != None:
  714. usr.newbie = form.getfirst('newbie') == '1'
  715. #-----------------------------------------------------------------------------#
  716. # LOGFILE HANDLING #
  717. #-----------------------------------------------------------------------------#
  718. def rrs_log_add(msg):
  719. """Add an entry for the current command to the logfile."""
  720. if not msg:
  721. msg = "%s:EMPTY MESSAGE" % opt.mode
  722. msg = "%s:%s:%s" % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), usr.updatedby, msg)
  723. try:
  724. fd = open('rrs.log', 'a')
  725. except IOError, e:
  726. error('Could not write to rrs.log', e)
  727. print >> fd, msg
  728. fd.close()
  729. #-----------------------------------------------------------------------------#
  730. # ERROR HANDLING #
  731. #-----------------------------------------------------------------------------#
  732. def error(e, mesg = ''):
  733. """Handle (mainly) RBError exceptions."""
  734. if not isinstance(e, RBError):
  735. prefix = 'FATAL: %s' % (mesg and mesg + '\n' or '')
  736. elif isinstance(e, RBWarningError) and opt.override:
  737. prefix = 'IGNORED: '
  738. else:
  739. prefix = ''
  740. global error_string
  741. error_string += '%s%s\n' % (prefix, e)
  742. if isinstance(e, RBWarningError) and opt.override:
  743. return
  744. # If we reach here the override option wasn't set, so all errors result
  745. # in program exit.
  746. #
  747. html_form()
  748. sys.exit(1)
  749. #-----------------------------------------------------------------------------#
  750. # If module is called as script, run main() #
  751. #-----------------------------------------------------------------------------#
  752. if __name__ == "__main__":
  753. main()