Mercurial > p > roundup > code
comparison roundup/cgi_client.py @ 167:a49c8a2ddd26
Added time logging and file uploading to the templates.
| author | Richard Jones <richard@users.sourceforge.net> |
|---|---|
| date | Mon, 30 Jul 2001 08:12:17 +0000 |
| parents | 8f9a65510139 |
| children | 1573a02b3254 |
comparison
equal
deleted
inserted
replaced
| 166:d469fb3beda1 | 167:a49c8a2ddd26 |
|---|---|
| 1 # $Id: cgi_client.py,v 1.12 2001-07-30 06:26:31 richard Exp $ | 1 # $Id: cgi_client.py,v 1.13 2001-07-30 08:12:17 richard Exp $ |
| 2 | 2 |
| 3 import os, cgi, pprint, StringIO, urlparse, re, traceback | 3 import os, cgi, pprint, StringIO, urlparse, re, traceback, mimetypes |
| 4 | 4 |
| 5 import roundupdb, htmltemplate, date | 5 import roundupdb, htmltemplate, date |
| 6 | 6 |
| 7 class Unauthorised(ValueError): | 7 class Unauthorised(ValueError): |
| 8 pass | 8 pass |
| 224 if value != cl.get(self.nodeid, key): | 224 if value != cl.get(self.nodeid, key): |
| 225 changed.append(key) | 225 changed.append(key) |
| 226 props[key] = value | 226 props[key] = value |
| 227 cl.set(self.nodeid, **props) | 227 cl.set(self.nodeid, **props) |
| 228 | 228 |
| 229 # if this item has messages, generate an edit message | 229 self._post_editnode(self.nodeid) |
| 230 # TODO: don't send the edit message to the person who | |
| 231 # performed the edit | |
| 232 if (cl.getprops().has_key('messages') and | |
| 233 cl.getprops()['messages'].isMultilinkType and | |
| 234 cl.getprops()['messages'].classname == 'msg'): | |
| 235 nid = self.nodeid | |
| 236 m = [] | |
| 237 for name, prop in cl.getprops().items(): | |
| 238 # TODO: the None default is only here because we | |
| 239 # don't have schema migration :( | |
| 240 if prop.isMultilinkType: | |
| 241 value = cl.get(nid, name, []) | |
| 242 else: | |
| 243 value = cl.get(nid, name, None) | |
| 244 if prop.isLinkType: | |
| 245 link = self.db.classes[prop.classname] | |
| 246 key = link.getkey() | |
| 247 if value is not None and key: | |
| 248 value = link.get(value, key) | |
| 249 else: | |
| 250 value = '-' | |
| 251 elif prop.isMultilinkType: | |
| 252 l = [] | |
| 253 link = self.db.classes[prop.classname] | |
| 254 for entry in value: | |
| 255 key = link.getkey() | |
| 256 if key: | |
| 257 l.append(link.get(entry, link.getkey())) | |
| 258 else: | |
| 259 l.append(entry) | |
| 260 value = ', '.join(l) | |
| 261 if name in changed: | |
| 262 chg = '*' | |
| 263 else: | |
| 264 chg = ' ' | |
| 265 m.append('%s %s: %s'%(chg, name, value)) | |
| 266 | |
| 267 # handle the note | |
| 268 if self.form.has_key('__note'): | |
| 269 note = self.form['__note'].value | |
| 270 if '\n' in note: | |
| 271 summary = re.split(r'\n\r?', note)[0] | |
| 272 else: | |
| 273 summary = note | |
| 274 m.insert(0, '%s\n\n'%note) | |
| 275 else: | |
| 276 if len(changed) > 1: | |
| 277 plural = 's were' | |
| 278 else: | |
| 279 plural = ' was' | |
| 280 summary = 'This %s has been edited through the web '\ | |
| 281 'and the %s value%s changed.'%(cn, | |
| 282 ', '.join(changed), plural) | |
| 283 m.insert(0, '%s\n\n'%summary) | |
| 284 | |
| 285 # now create the message | |
| 286 content = '\n'.join(m) | |
| 287 message_id = self.db.msg.create(author='1', recipients=[], | |
| 288 date=date.Date('.'), summary=summary, content=content) | |
| 289 messages = cl.get(nid, 'messages') | |
| 290 messages.append(message_id) | |
| 291 props = {'messages': messages} | |
| 292 cl.set(nid, **props) | |
| 293 | |
| 294 # and some nice feedback for the user | 230 # and some nice feedback for the user |
| 295 message = '%s edited ok'%', '.join(changed) | 231 message = '%s edited ok'%', '.join(changed) |
| 296 except: | 232 except: |
| 297 s = StringIO.StringIO() | 233 s = StringIO.StringIO() |
| 298 traceback.print_exc(None, s) | 234 traceback.print_exc(None, s) |
| 309 # use the template to display the item | 245 # use the template to display the item |
| 310 htmltemplate.item(self, self.TEMPLATES, self.db, self.classname, nodeid) | 246 htmltemplate.item(self, self.TEMPLATES, self.db, self.classname, nodeid) |
| 311 self.pagefoot() | 247 self.pagefoot() |
| 312 showissue = shownode | 248 showissue = shownode |
| 313 showmsg = shownode | 249 showmsg = shownode |
| 250 | |
| 251 def showuser(self, message=None): | |
| 252 ''' display an item | |
| 253 ''' | |
| 254 if self.user in ('admin', self.db.user.get(self.nodeid, 'username')): | |
| 255 self.shownode(message) | |
| 256 else: | |
| 257 raise Unauthorised | |
| 258 | |
| 259 def showfile(self): | |
| 260 ''' display a file | |
| 261 ''' | |
| 262 nodeid = self.nodeid | |
| 263 cl = self.db.file | |
| 264 type = cl.get(nodeid, 'type') | |
| 265 if type == 'message/rfc822': | |
| 266 type = 'text/plain' | |
| 267 self.header(headers={'Content-Type': type}) | |
| 268 self.write(cl.get(nodeid, 'content')) | |
| 269 | |
| 270 def _createnode(self): | |
| 271 ''' create a node based on the contents of the form | |
| 272 ''' | |
| 273 cn = self.classname | |
| 274 cl = self.db.classes[cn] | |
| 275 props = {} | |
| 276 keys = self.form.keys() | |
| 277 num_re = re.compile('^\d+$') | |
| 278 for key in keys: | |
| 279 if not cl.properties.has_key(key): | |
| 280 continue | |
| 281 proptype = cl.properties[key] | |
| 282 if proptype.isStringType: | |
| 283 value = self.form[key].value.strip() | |
| 284 elif proptype.isDateType: | |
| 285 value = date.Date(self.form[key].value.strip()) | |
| 286 elif proptype.isIntervalType: | |
| 287 value = date.Interval(self.form[key].value.strip()) | |
| 288 elif proptype.isLinkType: | |
| 289 value = self.form[key].value.strip() | |
| 290 # handle key values | |
| 291 link = cl.properties[key].classname | |
| 292 if not num_re.match(value): | |
| 293 try: | |
| 294 value = self.db.classes[link].lookup(value) | |
| 295 except: | |
| 296 raise ValueError, 'property "%s": %s not a %s'%( | |
| 297 key, value, link) | |
| 298 elif proptype.isMultilinkType: | |
| 299 value = self.form[key] | |
| 300 if type(value) != type([]): | |
| 301 value = [i.strip() for i in value.value.split(',')] | |
| 302 else: | |
| 303 value = [i.value.strip() for i in value] | |
| 304 link = cl.properties[key].classname | |
| 305 l = [] | |
| 306 for entry in map(str, value): | |
| 307 if not num_re.match(entry): | |
| 308 try: | |
| 309 entry = self.db.classes[link].lookup(entry) | |
| 310 except: | |
| 311 raise ValueError, \ | |
| 312 'property "%s": %s not a %s'%(key, | |
| 313 entry, link) | |
| 314 l.append(entry) | |
| 315 l.sort() | |
| 316 value = l | |
| 317 props[key] = value | |
| 318 return cl.create(**props) | |
| 319 | |
| 320 def _post_editnode(self, nid): | |
| 321 ''' do the linking and message sending part of the node creation | |
| 322 ''' | |
| 323 cn = self.classname | |
| 324 cl = self.db.classes[cn] | |
| 325 # link if necessary | |
| 326 keys = self.form.keys() | |
| 327 for key in keys: | |
| 328 if key == ':multilink': | |
| 329 value = self.form[key].value | |
| 330 if type(value) != type([]): value = [value] | |
| 331 for value in value: | |
| 332 designator, property = value.split(':') | |
| 333 link, nodeid = roundupdb.splitDesignator(designator) | |
| 334 link = self.db.classes[link] | |
| 335 value = link.get(nodeid, property) | |
| 336 value.append(nid) | |
| 337 link.set(nodeid, **{property: value}) | |
| 338 elif key == ':link': | |
| 339 value = self.form[key].value | |
| 340 if type(value) != type([]): value = [value] | |
| 341 for value in value: | |
| 342 designator, property = value.split(':') | |
| 343 link, nodeid = roundupdb.splitDesignator(designator) | |
| 344 link = self.db.classes[link] | |
| 345 link.set(nodeid, **{property: nid}) | |
| 346 | |
| 347 # if this item has messages, | |
| 348 if (cl.getprops().has_key('messages') and | |
| 349 cl.getprops()['messages'].isMultilinkType and | |
| 350 cl.getprops()['messages'].classname == 'msg'): | |
| 351 # generate an edit message - nosyreactor will send it | |
| 352 m = [] | |
| 353 for name, prop in cl.getprops().items(): | |
| 354 value = cl.get(nid, name) | |
| 355 if prop.isLinkType: | |
| 356 link = self.db.classes[prop.classname] | |
| 357 key = link.getkey() | |
| 358 if value is not None and key: | |
| 359 value = link.get(value, key) | |
| 360 else: | |
| 361 value = '-' | |
| 362 elif prop.isMultilinkType: | |
| 363 l = [] | |
| 364 link = self.db.classes[prop.classname] | |
| 365 for entry in value: | |
| 366 key = link.getkey() | |
| 367 if key: | |
| 368 l.append(link.get(entry, link.getkey())) | |
| 369 else: | |
| 370 l.append(entry) | |
| 371 value = ', '.join(l) | |
| 372 m.append('%s: %s'%(name, value)) | |
| 373 | |
| 374 # handle the note | |
| 375 note = None | |
| 376 if self.form.has_key('__note'): | |
| 377 note = self.form['__note'] | |
| 378 if note is not None and note.value: | |
| 379 note = note.value | |
| 380 if '\n' in note: | |
| 381 summary = re.split(r'\n\r?', note)[0] | |
| 382 else: | |
| 383 summary = note | |
| 384 m.append('\n%s\n'%note) | |
| 385 else: | |
| 386 summary = 'This %s has been created through the web.'%cn | |
| 387 m.append('\n%s\s'%summary) | |
| 388 | |
| 389 # now create the message | |
| 390 content = '\n'.join(m) | |
| 391 message_id = self.db.msg.create(author='1', recipients=[], | |
| 392 date=date.Date('.'), summary=summary, content=content) | |
| 393 messages = cl.get(nid, 'messages') | |
| 394 messages.append(message_id) | |
| 395 props = {'messages': messages} | |
| 396 cl.set(nid, **props) | |
| 314 | 397 |
| 315 def newnode(self, message=None): | 398 def newnode(self, message=None): |
| 316 ''' Add a new node to the database. | 399 ''' Add a new node to the database. |
| 317 | 400 |
| 318 The form works in two modes: blank form and submission (that is, | 401 The form works in two modes: blank form and submission (that is, |
| 337 cn = self.classname | 420 cn = self.classname |
| 338 cl = self.db.classes[cn] | 421 cl = self.db.classes[cn] |
| 339 | 422 |
| 340 # possibly perform a create | 423 # possibly perform a create |
| 341 keys = self.form.keys() | 424 keys = self.form.keys() |
| 342 num_re = re.compile('^\d+$') | |
| 343 if [i for i in keys if i[0] != ':']: | 425 if [i for i in keys if i[0] != ':']: |
| 344 props = {} | 426 props = {} |
| 345 try: | 427 try: |
| 346 keys = self.form.keys() | 428 nid = self._createnode() |
| 347 for key in keys: | 429 self._post_editnode(nid) |
| 348 if not cl.properties.has_key(key): | |
| 349 continue | |
| 350 proptype = cl.properties[key] | |
| 351 if proptype.isStringType: | |
| 352 value = self.form[key].value.strip() | |
| 353 elif proptype.isDateType: | |
| 354 value = date.Date(self.form[key].value.strip()) | |
| 355 elif proptype.isIntervalType: | |
| 356 value = date.Interval(self.form[key].value.strip()) | |
| 357 elif proptype.isLinkType: | |
| 358 value = self.form[key].value.strip() | |
| 359 # handle key values | |
| 360 link = cl.properties[key].classname | |
| 361 if not num_re.match(value): | |
| 362 try: | |
| 363 value = self.db.classes[link].lookup(value) | |
| 364 except: | |
| 365 raise ValueError, 'property "%s": %s not a %s'%( | |
| 366 key, value, link) | |
| 367 elif proptype.isMultilinkType: | |
| 368 value = self.form[key] | |
| 369 if type(value) != type([]): | |
| 370 value = [i.strip() for i in value.value.split(',')] | |
| 371 else: | |
| 372 value = [i.value.strip() for i in value] | |
| 373 link = cl.properties[key].classname | |
| 374 l = [] | |
| 375 for entry in map(str, value): | |
| 376 if not num_re.match(entry): | |
| 377 try: | |
| 378 entry = self.db.classes[link].lookup(entry) | |
| 379 except: | |
| 380 raise ValueError, \ | |
| 381 'property "%s": %s not a %s'%(key, | |
| 382 entry, link) | |
| 383 l.append(entry) | |
| 384 l.sort() | |
| 385 value = l | |
| 386 props[key] = value | |
| 387 nid = cl.create(**props) | |
| 388 | |
| 389 # link if necessary | |
| 390 for key in keys: | |
| 391 print key, | |
| 392 if key == ':multilink': | |
| 393 value = self.form[key].value | |
| 394 if type(value) != type([]): value = [value] | |
| 395 for value in value: | |
| 396 designator, property = value.split(':') | |
| 397 print 'miltilinking to ', designator, property | |
| 398 link, nodeid = roundupdb.splitDesignator(designator) | |
| 399 link = self.db.classes[link] | |
| 400 value = link.get(nodeid, property) | |
| 401 value.append(nid) | |
| 402 link.set(nodeid, **{property: value}) | |
| 403 elif key == ':link': | |
| 404 value = self.form[key].value | |
| 405 if type(value) != type([]): value = [value] | |
| 406 for value in value: | |
| 407 designator, property = value.split(':') | |
| 408 print 'linking to ', designator, property | |
| 409 link, nodeid = roundupdb.splitDesignator(designator) | |
| 410 link = self.db.classes[link] | |
| 411 link.set(nodeid, **{property: nid}) | |
| 412 else: | |
| 413 print 'ignoring' | |
| 414 | |
| 415 # if this item has messages, | |
| 416 if (cl.getprops().has_key('messages') and | |
| 417 cl.getprops()['messages'].isMultilinkType and | |
| 418 cl.getprops()['messages'].classname == 'msg'): | |
| 419 # generate an edit message - nosyreactor will send it | |
| 420 m = [] | |
| 421 for name, prop in cl.getprops().items(): | |
| 422 value = cl.get(nid, name) | |
| 423 if prop.isLinkType: | |
| 424 link = self.db.classes[prop.classname] | |
| 425 key = link.getkey() | |
| 426 if value is not None and key: | |
| 427 value = link.get(value, key) | |
| 428 else: | |
| 429 value = '-' | |
| 430 elif prop.isMultilinkType: | |
| 431 l = [] | |
| 432 link = self.db.classes[prop.classname] | |
| 433 for entry in value: | |
| 434 key = link.getkey() | |
| 435 if key: | |
| 436 l.append(link.get(entry, link.getkey())) | |
| 437 else: | |
| 438 l.append(entry) | |
| 439 value = ', '.join(l) | |
| 440 m.append('%s: %s'%(name, value)) | |
| 441 | |
| 442 # handle the note | |
| 443 note = None | |
| 444 if self.form.has_key('__note'): | |
| 445 note = self.form['__note'] | |
| 446 if note and note.value: | |
| 447 note = note.value | |
| 448 if '\n' in note: | |
| 449 summary = re.split(r'\n\r?', note)[0] | |
| 450 else: | |
| 451 summary = note | |
| 452 m.append('\n%s\n'%note) | |
| 453 else: | |
| 454 summary = 'This %s has been created through the web.'%cn | |
| 455 m.append('\n%s\s'%summary) | |
| 456 | |
| 457 # now create the message | |
| 458 content = '\n'.join(m) | |
| 459 message_id = self.db.msg.create(author='1', recipients=[], | |
| 460 date=date.Date('.'), summary=summary, content=content) | |
| 461 messages = cl.get(nid, 'messages') | |
| 462 messages.append(message_id) | |
| 463 props = {'messages': messages} | |
| 464 cl.set(nid, **props) | |
| 465 | |
| 466 # and some nice feedback for the user | 430 # and some nice feedback for the user |
| 467 message = '%s created ok'%cn | 431 message = '%s created ok'%cn |
| 468 except: | 432 except: |
| 469 s = StringIO.StringIO() | 433 s = StringIO.StringIO() |
| 470 traceback.print_exc(None, s) | 434 traceback.print_exc(None, s) |
| 474 self.form) | 438 self.form) |
| 475 self.pagefoot() | 439 self.pagefoot() |
| 476 newissue = newnode | 440 newissue = newnode |
| 477 newuser = newnode | 441 newuser = newnode |
| 478 | 442 |
| 479 def showuser(self, message=None): | 443 def newfile(self, message=None): |
| 480 ''' display an item | 444 ''' Add a new file to the database. |
| 481 ''' | 445 |
| 482 if self.user in ('admin', self.db.user.get(self.nodeid, 'username')): | 446 This form works very much the same way as newnode - it just has a |
| 483 self.shownode(message) | 447 file upload. |
| 484 else: | 448 ''' |
| 485 raise Unauthorised | 449 cn = self.classname |
| 486 | 450 cl = self.db.classes[cn] |
| 487 def showfile(self): | 451 |
| 488 ''' display a file | 452 # possibly perform a create |
| 489 ''' | 453 keys = self.form.keys() |
| 490 nodeid = self.nodeid | 454 if [i for i in keys if i[0] != ':']: |
| 491 cl = self.db.file | 455 try: |
| 492 type = cl.get(nodeid, 'type') | 456 file = self.form['content'] |
| 493 if type == 'message/rfc822': | 457 self._post_editnode(cl.create(content=file.file.read(), |
| 494 type = 'text/plain' | 458 type=mimetypes.guess_type(file.filename)[0], |
| 495 self.header(headers={'Content-Type': type}) | 459 name=file.filename)) |
| 496 self.write(cl.get(nodeid, 'content')) | 460 # and some nice feedback for the user |
| 461 message = '%s created ok'%cn | |
| 462 except: | |
| 463 s = StringIO.StringIO() | |
| 464 traceback.print_exc(None, s) | |
| 465 message = '<pre>%s</pre>'%cgi.escape(s.getvalue()) | |
| 466 | |
| 467 self.pagehead('New %s'%self.classname.capitalize(), message) | |
| 468 htmltemplate.newitem(self, self.TEMPLATES, self.db, self.classname, | |
| 469 self.form) | |
| 470 self.pagefoot() | |
| 497 | 471 |
| 498 def classes(self, message=None): | 472 def classes(self, message=None): |
| 499 ''' display a list of all the classes in the database | 473 ''' display a list of all the classes in the database |
| 500 ''' | 474 ''' |
| 501 if self.user == 'admin': | 475 if self.user == 'admin': |
| 543 def __del__(self): | 517 def __del__(self): |
| 544 self.db.close() | 518 self.db.close() |
| 545 | 519 |
| 546 # | 520 # |
| 547 # $Log: not supported by cvs2svn $ | 521 # $Log: not supported by cvs2svn $ |
| 522 # Revision 1.12 2001/07/30 06:26:31 richard | |
| 523 # Added some documentation on how the newblah works. | |
| 524 # | |
| 548 # Revision 1.11 2001/07/30 06:17:45 richard | 525 # Revision 1.11 2001/07/30 06:17:45 richard |
| 549 # Features: | 526 # Features: |
| 550 # . Added ability for cgi newblah forms to indicate that the new node | 527 # . Added ability for cgi newblah forms to indicate that the new node |
| 551 # should be linked somewhere. | 528 # should be linked somewhere. |
| 552 # Fixed: | 529 # Fixed: |
