Attachment 'PageComment2-091.py'

Download

   1 # -*- coding: iso-8859-1 -*-
   2 """
   3     PageComment2.py  Version 0.91  Nov. 19, 2005
   4                                                                                                            
   5     This macro gives a form to post a new comment to the page and shows a list of the posted comments.
   6                                                                                                            
   7     @copyright: 2005 by Seungik Lee <seungiklee<at>gmail.com>  http://cds.icu.ac.kr/~silee/
   8     @license: GPL
   9 
  10     Usage: [[PageComment2]]
  11 
  12     Features:
  13         
  14         Simple usage, just put [[PageComment2]] on any page.
  15         Lets anonymous users post a new comment with an input form.
  16         Shows a list of the posted comments.
  17         Support for comment deletion by given password.
  18         Support for administrative action, e.g., 
  19             - to delete a comment without entering a given password
  20 
  21     Parameters:
  22         public: if the list of comments is shown to public users
  23             - public=1; default, all list is shown to all users including anonymous users
  24             - public=0; shown to only admin users (who has the page delete privilege)
  25             
  26         countonly: returns the number of the comments posted to this page
  27             - countonly=0; default, normal form (input form; list of comments)
  28             - countonly=1; just return the number of comments. e.g., 'There are [[PageComments(countonly=1)]] comments here'
  29     
  30         rows: the # of rows of the textarea. default 2. e.g., rows=2
  31         
  32         cols: the # of columns of the textarea. default 60. e.g., cols=60
  33         
  34         maxlength: limitation on # of characters for comment text. default 0 (no limit). e.g., maxlength=500
  35         
  36         olderfirst: order of the list of comments. Note that it does not re-sort the existing comments.
  37             - olderfirst=1: default, newer ones are appended to the end
  38             - olderfirst=0: newer ones are inserted at the top
  39             
  40         tablewidth: the width of the table format for PageComment2, default '' (none). 
  41             e.g., tablewidth=600, tablewidth=100%
  42     
  43     Change Log
  44 
  45         Nov. 19, 2005 - Version 0.91
  46             - some parameters added
  47             - validates smiley markup
  48             - modified view
  49         
  50         Nov. 18, 2005 - Version 0.90 (Release 2)
  51             - No text data file support any more: Comment is stored in the sub wiki page.
  52             - (does not compatible with Release 1: PageComment.py)
  53             - Custom icon (smiley) can be inserted
  54             - Pre-fill the name input field with his/her login name
  55             - Logs at add/remove comments
  56             - Added some parameters    
  57         Oct. 08, 2005 - Version 0.82
  58             - Changed the directory the data file stored to be secured
  59         
  60         Oct. 07, 2005 - Version 0.81 
  61             - Unicode encoding related bugs in deletecomment function are patched. 
  62             - Instruction bugs are patched. 
  63         
  64         Oct. 06, 2005 - Version 0.80 
  65             - The initial version is released.
  66 
  67 
  68     Notes
  69         
  70         'Gallery.py' developed by Simon Ryan has inspired this macro.
  71    
  72 
  73 """
  74 
  75 from MoinMoin import config, wikiutil
  76 import StringIO, time, re
  77 from MoinMoin.Page import Page
  78 from MoinMoin.PageEditor import PageEditor
  79 from MoinMoin.parser import wiki
  80 
  81 
  82 class Globs:
  83     # A quick place to plonk those shared variables
  84     adminmsg = ''
  85     datapagename = ''
  86     pagename = ''
  87     subname = ''
  88     admin = ''
  89     macro = ''
  90     defaultacl = ''
  91     defaulticon = ':)'
  92     
  93 class Params:
  94     public = 1
  95     countonly = 0
  96     rows = 2
  97     cols = 60
  98     maxlength = 0
  99     olderfirst = 1
 100     tablewidth = ''
 101 
 102 def execute(macro, args):
 103 
 104     # INITIALIZATION ----------------------------------------
 105     setglobalvalues(macro)
 106     
 107     getparams(args)
 108     
 109     if Params.countonly:
 110         html = len(fetchcomments())
 111         return macro.formatter.rawHTML('%s' % html)
 112     
 113     # internal variables
 114     request = macro.request
 115     datapagename = Globs.datapagename
 116     
 117     _ = request.getText
 118     
 119     # form vals
 120     comicon = Globs.defaulticon
 121     comauthor = ''
 122     comtext = ''
 123     compasswd = ''
 124     comrev = 0
 125     
 126     action = macro.form.get('commentaction', [''])[0]
 127     
 128     if action == 'addcomment':
 129     
 130         # process form input for comment add
 131         form_fields = {'comicon': Globs.defaulticon, 'comauthor': '', 'comtext': '', 'compasswd': '', 'comrev': 0}
 132         required_fields = {'comauthor': _('Name'), 'comtext': _('Text'), 'compasswd': _('Password'), 'comrev': 'Rev. #'}
 133         
 134         formvals, missingfields = getforminput(macro.form, form_fields, required_fields)
 135         
 136         comicon = formvals['comicon']
 137         comauthor = formvals['comauthor']
 138         comtext = formvals['comtext']
 139         compasswd = formvals['compasswd']
 140         comrev = formvals['comrev']
 141     
 142         if not len(missingfields) == len(required_fields):
 143             if not missingfields:
 144                 flag = addcomment(macro, comicon, comauthor, comtext, compasswd, comrev)
 145                 
 146                 if flag:
 147                     comicon = Globs.defaulticon
 148                     comauthor = ''
 149                     comtext = ''
 150                     compasswd = ''
 151                     comrev = ''
 152             else:
 153                 message( _('Required attribute "%(attrname)s" missing') % { 'attrname': u', '.join(missingfields) } )
 154     
 155     elif action == 'delcomment':
 156     
 157         # process form input for comment delete
 158         form_fields = {'delkey': '', 'delpasswd': ''}
 159         required_fields = {'delkey': 'Comment Key', 'delpasswd': 'Password'}
 160         
 161         formvals, missingfields = getforminput(macro.form, form_fields, required_fields)
 162         
 163         delkey = formvals['delkey']
 164         delpasswd = formvals['delpasswd']
 165         
 166         if not len(missingfields) == len(required_fields):
 167             if not missingfields:
 168                 deletecomment(macro, delkey, delpasswd)
 169             else:
 170                 message( _('Required attribute "%(attrname)s" missing') % { 'attrname': u', '.join(missingfields) } )
 171     
 172     # format output
 173     html = []
 174     
 175     html.append(u'<a name="pagecomment">')
 176     html.append(u'<table class="pagecomment" %s>' % Params.tablewidth)
 177     html.append(u'<tr><td style="border-width: 0px;">')
 178     html.append(u'<font style="color: #aa0000;">%s</font>' % Globs.adminmsg)
 179     html.append(u'<table class="commentform"><tr><td style="border-width: 1px;">')
 180     html.append(commentform(comauthor, comtext, compasswd, comicon, comrev))
 181     html.append(u'</td></tr></table>')
 182     html.append(u'</td></tr>')
 183         
 184     if Params.public or Globs.admin:
 185         html.append(deleteform())
 186         html.append(u'<tr><td style="border: 0px;">')
 187         html.append(showcomment())
 188         html.append(u'</td></tr>')
 189     else:
 190         html.append(u'<tr><td style="text-align: center; border: 0px; font-size: 0.8em; color: #aaaaaa;">(The posted comments are shown to administrators only.)</td></tr>')
 191 
 192     html.append(u'</table>')
 193     
 194     return macro.formatter.rawHTML(u'\n'.join(html))
 195 
 196 def getforminput(form, inputfields, requiredfields):
 197     
 198     formvals = {}
 199     missingfields = []
 200     
 201     for item in inputfields.keys():
 202         if (not form.has_key(item)) and (item in requiredfields):
 203             missingfields.append(requiredfields[item])
 204         formvals[item] = form.get(item, [inputfields[item]])[0]
 205         
 206     return formvals, missingfields
 207 
 208 def getparams(args):
 209     # process arguments
 210     
 211     params = {}
 212     if args:
 213         # Arguments are comma delimited key=value pairs
 214         sargs = args.split(',')
 215     
 216         for item in sargs:
 217             sitem = item.split('=')
 218         
 219             if len(sitem) == 2:
 220                 key, value = sitem[0], sitem[1]
 221                 params[key.strip()] = value.strip()
 222 
 223     try:
 224         Params.public = int(params.get('public', 1))
 225     except ValueError:
 226         Params.public = 1
 227 
 228     try:
 229         Params.countonly = int(params.get('countonly', 0))
 230     except ValueError:
 231         Params.countonly = 0
 232         
 233     try:
 234         Params.rows = int(params.get('rows', 2))
 235     except ValueError:
 236         Params.rows = 2
 237 
 238     try:
 239         Params.cols = int(params.get('cols', 60))
 240     except ValueError:
 241         Params.cols = 60
 242 
 243     try:
 244         Params.maxlength = int(params.get('maxlength', 0))
 245     except ValueError:
 246         Params.maxlength = 0
 247         
 248     try:
 249         Params.olderfirst = int(params.get('olderfirst', 1))
 250     except ValueError:
 251         Params.olderfirst = 1
 252         
 253     Params.tablewidth = params.get('tablewidth', '')
 254     if Params.tablewidth:
 255         Params.tablewidth = ' width="%s" ' % Params.tablewidth
 256 
 257 def setglobalvalues(macro):
 258     
 259     # Global variables
 260     Globs.pagename = macro.formatter.page.page_name
 261     Globs.subname = Globs.pagename.split('/')[-1]
 262     Globs.macro = macro
 263     Globs.datapagename = u'%s/%s' % (Globs.pagename, 'PageCommentData')
 264     Globs.defaultacl = u'#acl All:'
 265     
 266     # Figure out if we have delete privs
 267     try:
 268         if macro.request.user.may.delete(Globs.datapagename):
 269             Globs.admin = 'true'
 270     except AttributeError:
 271         pass
 272 
 273 
 274 def message(astring):
 275     Globs.adminmsg += u'%s<br>\n' % astring
 276 
 277 
 278 def commentform(tmpauthor, tmptext, tmppasswd, tmpicon, comrev):
 279     # A form for posting a new comment
 280     request = Globs.macro.request
 281     datapagename = Globs.datapagename
 282     _ = request.getText
 283     
 284     cellstyle = u'border-width: 0px; vertical-align: middle; font-size: 0.9em; line-height: 1em;'
 285     
 286     pg = Page( request, datapagename )
 287     
 288     if pg.exists():
 289         comrev = pg.current_rev()
 290     else:
 291         comrev = 0
 292     
 293     if request.user.valid:
 294         html1 = [
 295             u'<input type="hidden" value="%s" name="comauthor">' % request.user.name,
 296 		    u'<input type="hidden" value="*" name="compasswd">',
 297             u'<tr><td style="%s">%s: <i>%s</i></td>' % (cellstyle, _('Name'), request.user.name),
 298     		u'<td style="%s">%s: ****</td>' % (cellstyle, _('Password')),
 299     		]
 300     else:
 301         html1 = [
 302             u'<tr><td style="%s">%s: <input type="text" size="10" maxlength="20" name="comauthor" value="%s"></td>' % (cellstyle, _('Name'), tmpauthor),
 303     		u'<td style="%s">%s: <input type="password" size="6" maxlength="10" name="compasswd" value="%s"></td>' % (cellstyle, _('Password'), tmppasswd),
 304     		]
 305     
 306     html1 = u'\n'.join(html1)
 307     html2 = [
 308         u'<div id="commentform">',
 309         u'<form action="%s#pagecomment" name="comment" METHOD="POST">' % Globs.subname,
 310         u'<table class="addcommentform">',
 311         u'%s' % html1,
 312 		u'<td style="%s">Smiley: <input type="text" size="4" maxlength="4" name="comicon" value="%s"></td></tr>' % (cellstyle, tmpicon),
 313 		u'<tr><td colspan="3" style="%s"><textarea name="comtext" rows="%d" cols="%d">%s</textarea></td></tr>' % (cellstyle, Params.rows, Params.cols, tmptext),
 314         u'<tr><td colspan="3" align="center" style="%s"><input type="submit" value="%s"></td></tr>' % (cellstyle, _('Save')),
 315 		u'</table>',
 316 		u'<input type="hidden" value="show" name="action">',
 317 		u'<input type="hidden" value="%s" name="comrev">' % comrev,
 318 		u'<input type="hidden" value="addcomment" name="commentaction">',
 319 		u'</form>',
 320 		u'</div>',
 321         ]
 322     
 323     
 324     return u'\n'.join(html2)
 325       
 326 def addcomment(macro, comicon, comauthor, comtext, compasswd, comrev):
 327     # Add a comment with inputs
 328     
 329     request = Globs.macro.request
 330     cfg = request.cfg
 331     _ = request.getText
 332     
 333     # check input
 334     if comicon and (not comicon in config.smileys.keys()):
 335         message('Please use smiley markup only')
 336         return 0
 337 
 338     if Params.maxlength and (len(comtext) > Params.maxlength):
 339         message('Comment text is limited to %d characters. (%d characters now)' % (Params.maxlength, len(comtext)) )
 340         return 0
 341     
 342     datapagename = Globs.datapagename
 343     
 344     pg = PageEditor( request, datapagename )
 345     pagetext = pg.get_raw_body()
 346     
 347     comtext = convertdelimiter(comtext)
 348     
 349     if request.user.valid:
 350         comloginuser = 'TRUE'
 351         comauthor = request.user.name
 352     else:
 353         comloginuser = ''
 354         comauthor = convertdelimiter(comauthor)
 355     
 356     newcomment = [
 357         u'{{{',
 358         u'%s' % comicon,
 359         u'%s' % comauthor,
 360         u'%s' % time.strftime(cfg.datetime_fmt, time.localtime(time.time())),
 361         u'',
 362         u'%s' % comtext,
 363         u'}}}',
 364         u'##PASSWORD %s' % compasswd,
 365         u'##LOGINUSER %s' % comloginuser,
 366         ]
 367         
 368     if Params.olderfirst:
 369         newpagetext = u'%s\n\n%s' % (pagetext, u'\n'.join(newcomment))
 370     else:
 371         newpagetext = u'%s\n\n%s' % (u'\n'.join(newcomment), pagetext)
 372 
 373     if not pg.exists():
 374         action = 'SAVENEW'
 375         defaultacl = Globs.defaultacl
 376         warnmessages = '\'\'\'\'\'DO NOT EDIT THIS PAGE!!\'\'\' This page is automatically generated by Page``Comment2 macro.\'\'\n----'
 377         newpagetext = u'%s\n%s\n%s' % (defaultacl, warnmessages, newpagetext)
 378     else:
 379         action = 'SAVE'
 380 
 381     newpagetext = pg.normalizeText( newpagetext )
 382     
 383     comment = 'New comment by "%s"' % comauthor
 384     pg._write_file(newpagetext, action, u'Modified by PageComment macro')
 385     addLogEntry(request, 'COMNEW', Globs.pagename, comment)
 386     
 387     # message(_('The comment is added'))
 388     message(_('Thank you for your changes. Your attention to detail is appreciated.'))
 389     return 1
 390 
 391 def showcomment():
 392     
 393     request = Globs.macro.request
 394     _ = request.getText
 395     
 396     commentlist = fetchcomments()
 397     
 398     html = []
 399     cur_index = 0
 400     cellstyle = u'border-width: 0px; border-top-width: 1px; vertical-align: top; font-size: 0.9em; line-height: 1em;'
 401     
 402     html.append(u'<div id="commentlist"><table width="100%" class="commentlist">')
 403     
 404     for item in commentlist:
 405         if Globs.admin or (item['loginuser'] and request.user.valid and request.user.name == item['name']):
 406             htmlcommentdel = [
 407                 u' <font style="font-size: 0.9em;">',
 408                 u'<a style="color: #aa0000;" href="javascript: requesttodeleteadmin(\'%s\');" title="%s">X</a>' % (item['key'], _('Delete')),
 409                 u'</font>',
 410                 ]
 411         elif item['loginuser']:
 412             htmlcommentdel = []
 413 
 414         else:
 415             htmlcommentdel = [
 416                 u' <font style="font-size: 0.9em;">',
 417                 u'<a style="color: #aa0000;" href="javascript: requesttodelete(\'%s\');" title="%s">X</a>' % (item['key'], _('Delete')),
 418                 u'</font>',
 419                 ]
 420         
 421         htmlcomment = [
 422             u'<tr><td class="commenticon" style="%s width: 20px;">%s</td>' % (cellstyle, getsmiley(item['icon'])),
 423             u'<td class="commentauthor" style="%s"' % cellstyle,
 424             u'>%s</td>' % converttext(item['name']),
 425             u'<td style="%s width: 10px;">&nbsp;</td>' % cellstyle,
 426             u'<td class="commenttext" style="%s">%s</td>' % (cellstyle, converttext(item['text'])),
 427             u'<td class="commentdate" style="%s text-align: right; font-size: 0.8em; ">%s%s</td></tr>' % (cellstyle, item['date'].replace(' ', '<br>'), u''.join(htmlcommentdel)),
 428             ]
 429         
 430         html.append(u'\n'.join(htmlcomment))
 431     
 432     html.append(u'</table></div>')
 433     
 434     return u'\n'.join(html)
 435 
 436 
 437 def getsmiley(markup):
 438     
 439     if markup in config.smileys.keys():
 440         formatter = Globs.macro.formatter
 441         return formatter.smiley(markup)
 442     else:
 443         return ''
 444 
 445 
 446 def converttext(targettext):
 447     # Converts some special characters of html to plain-text style
 448     # What else to handle?
 449 
 450     # targettext = targettext.strip()
 451     targettext = targettext.replace(u'&', '&amp')
 452     targettext = targettext.replace(u'>', '&gt;')
 453     targettext = targettext.replace(u'<', '&lt;')
 454     targettext = targettext.replace(u'\n', '<br>')
 455     targettext = targettext.replace(u'"', '&quot;')
 456     targettext = targettext.replace(u'\t', '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;')
 457     targettext = targettext.replace(u'  ', '&nbsp;&nbsp;')
 458 
 459     return targettext
 460     
 461 def convertdelimiter(targettext):
 462     # Converts delimeter to other string to avoid a crash
 463     
 464     targettext = targettext.replace('{{{', '{ { {')
 465     targettext = targettext.replace('}}}', '} } }')
 466     
 467     return targettext
 468 
 469     
 470 def deleteform():
 471     # Javascript codes for deleting or restoring a comment
 472     
 473     request = Globs.macro.request
 474     _ = request.getText
 475     
 476     htmlresult = []
 477     
 478     html = [
 479         '<script language="javascript">',
 480         '<!--',
 481         ]
 482     htmlresult.append(u'\n'.join(html))
 483            
 484     html = [    
 485         '  function requesttodeleteadmin(comkey) {',
 486         '      if (confirm("%s")) {;' % _('Really delete this page?'),
 487         '          document.delform.delkey.value = comkey;',
 488         '          document.delform.delpasswd.value = "****";',
 489         '          document.delform.submit();',
 490         '      }',
 491         '  }',
 492         '  function requesttodelete(comkey) {',
 493         '      var passwd = prompt("%s:", "");' % _('Please specify a password!'),
 494         '      if(!(passwd == "" || passwd == null)) {',
 495         '          document.delform.delkey.value = comkey;',
 496         '          document.delform.delpasswd.value = passwd;',
 497         '          document.delform.submit();',
 498         '      }',
 499         '  }',
 500         ]
 501     
 502     htmlresult.append(u'\n'.join(html))
 503                 
 504     html = [
 505         '//-->',
 506         '</script>',
 507         '<form name="delform" action="%s#pagecomment" METHOD="post">' % Globs.subname,
 508         '<input type=hidden value="show" name="action">',
 509         '<input name="delpasswd" type="hidden" value="****">',
 510         '<input name="delkey" type="hidden" value="">',
 511         '<input type="hidden" name="commentaction" value="delcomment">',
 512         '</form>',
 513         ]
 514     htmlresult.append(u'\n'.join(html))
 515 
 516     return u'\n'.join(htmlresult)
 517 
 518 
 519 def filtercomment(index='', name='', passwd=''):
 520     
 521     # filter by index
 522     if index:
 523         filteredlist1 = fetchcomments(index, index)
 524     else:
 525         filteredlist1 = fetchcomments()
 526     
 527     # filter by name
 528     filteredlist2 = []
 529     if name:
 530         for item in filteredlist1:
 531             if name == item['name']:
 532                 filteredlist2.append(item)
 533     else:
 534         filteredlist2 = filteredlist1
 535     
 536     # filter by password
 537     filteredlist3 = []
 538     if passwd:
 539         for item in filteredlist2:
 540             if passwd == item['passwd']:
 541                 filteredlist3.append(item)
 542     else:
 543         filteredlist3 = filteredlist2
 544 
 545     return filteredlist3
 546         
 547 
 548 def fetchcomments(startindex=1, endindex=9999):
 549     
 550     commentlist = []
 551     
 552     request = Globs.macro.request
 553     formatter = Globs.macro.formatter
 554     datapagename = Globs.datapagename
 555 
 556     pg = Page( request, datapagename )
 557     pagetext = pg.get_raw_body()
 558     
 559     regex = r'^(#acl\s*.*)$'
 560     pattern = re.compile(regex, re.UNICODE + re.MULTILINE + re.IGNORECASE)
 561     pagetext = pattern.sub('', pagetext)
 562     
 563     regex = ur"""
 564 ^[\{]{3}\n
 565 ^(?P<icon>[^\n]*)\n
 566 ^(?P<name>[^\n]*)\n
 567 ^(?P<date>[^\n]*)[\n]+
 568 ^(?P<text>\s*.*?[^}]+)[\}]{3}\n
 569 ^[#]{2}PASSWORD[ ](?P<passwd>[^\n]*)\n
 570 ^[#]{2}LOGINUSER[ ](?P<loginuser>[^\n]*)[\n$]+"""
 571 
 572     pattern = re.compile(regex, re.UNICODE + re.MULTILINE + re.VERBOSE)
 573     commentitems = pattern.findall(pagetext)
 574     
 575     cur_index = 0
 576     for item in commentitems:
 577         comment = {}
 578         cur_index += 1
 579         
 580         if cur_index < startindex:
 581             continue
 582         
 583         comment['index'] = cur_index
 584         comment['icon'] = item[0]
 585         comment['name'] = item[1]
 586         comment['text'] = item[3]
 587         comment['date'] = item[2]
 588         comment['passwd'] = item[4]
 589         comment['loginuser'] = item[5]
 590         
 591         # experimental
 592         comment['key'] = comment['date'].strip()
 593         
 594         commentlist.append(comment)
 595         
 596         if cur_index >= endindex:
 597             break
 598 
 599     return commentlist
 600 
 601 def deletecomment(macro, delkey, delpasswd):
 602     # Deletes a comment with given index and password
 603     
 604     request = Globs.macro.request
 605     formatter = Globs.macro.formatter
 606     datapagename = Globs.datapagename
 607     _ = request.getText
 608 
 609     pg = PageEditor( request, datapagename )
 610     pagetext = pg.get_raw_body()
 611     
 612     regex = ur"""
 613 (?P<comblock>^[\{]{3}\n
 614 ^(?P<icon>[^\n]*)\n
 615 ^(?P<name>[^\n]*)\n
 616 ^(?P<date>[^\n]*)[\n]+
 617 ^(?P<text>\s*.*?[^}]+)[\}]{3}\n
 618 ^[#]{2}PASSWORD[ ](?P<passwd>[^\n]*)\n
 619 ^[#]{2}LOGINUSER[ ](?P<loginuser>[^\n]*)[\n$]+)"""
 620 
 621     pattern = re.compile(regex, re.UNICODE + re.MULTILINE + re.VERBOSE)
 622     commentitems = pattern.findall(pagetext)
 623     
 624     for item in commentitems:
 625         
 626         if delkey == item[3].strip():
 627             comauthor = item[2]
 628             if Globs.admin or (request.user.valid and request.user.name == comauthor) or delpasswd == item[5]:
 629                 newpagetext = pagetext.replace(item[0], '', 1)
 630                 
 631                 action = 'SAVE'
 632                 comment = 'comment deleted by "%s"' % comauthor
 633                 pg._write_file(newpagetext, action, u'Modified by PageComment macro')
 634                 addLogEntry(request, 'COMDEL', Globs.pagename, comment)
 635                 
 636                 message(_('The comment is deleted'))
 637                 
 638                 return
 639             else:
 640                 message(_('Sorry, wrong password.'))
 641                 return
 642                 
 643     message(_('No such comment'))
 644 
 645     
 646 def addLogEntry(request, action, pagename, msg):
 647     # Add an entry to the edit log on adding comments.
 648     from MoinMoin.logfile import editlog
 649     t = wikiutil.timestamp2version(time.time())
 650     msg = unicode(msg)
 651 
 652     # TODO: for now we simply write 2 logs, maybe better use some multilog stuff
 653     # Write to global log
 654     log = editlog.EditLog(request)
 655     log.add(request, t, 99999999, action, pagename, request.remote_addr, msg)
 656 
 657     # Write to local log
 658     log = editlog.EditLog(request, rootpagename=pagename)
 659     log.add(request, t, 99999999, action, pagename, request.remote_addr, msg)

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2008-04-30 13:57:43, 45.4 KB) [[attachment:PageComment2-0.981-only_logged_in_user.py]]
  • [get | view] (2005-11-18 08:51:22, 19.1 KB) [[attachment:PageComment2-090.py]]
  • [get | view] (2005-11-18 16:50:49, 21.6 KB) [[attachment:PageComment2-091.py]]
  • [get | view] (2005-11-19 06:31:25, 21.8 KB) [[attachment:PageComment2-092.py]]
  • [get | view] (2005-11-20 07:24:45, 26.0 KB) [[attachment:PageComment2-094.py]]
  • [get | view] (2005-11-20 08:56:20, 26.1 KB) [[attachment:PageComment2-095.py]]
  • [get | view] (2005-11-29 20:06:02, 31.4 KB) [[attachment:PageComment2-096.py]]
  • [get | view] (2006-01-05 08:41:48, 44.6 KB) [[attachment:PageComment2-097.py]]
  • [get | view] (2006-04-17 13:35:45, 45.4 KB) [[attachment:PageComment2-098.py]]
  • [get | view] (2006-05-02 00:31:43, 45.4 KB) [[attachment:PageComment2-0981.py]]
  • [get | view] (2008-01-29 19:38:32, 45.4 KB) [[attachment:PageComment2-099-moin16.py]]
  • [get | view] (2007-05-01 15:51:21, 46.5 KB) [[attachment:PageComment2-099-rg.py]]
  • [get | view] (2008-02-19 19:41:42, 45.4 KB) [[attachment:PageComment2-0991-moin16.py]]
  • [get | view] (2008-02-27 14:38:41, 45.8 KB) [[attachment:PageComment2-0992-moin16.py]]
  • [get | view] (2011-07-19 13:47:24, 47.7 KB) [[attachment:PageComment2-0993-moin193.py]]
  • [get | view] (2007-05-01 15:52:09, 1.6 KB) [[attachment:PageComment2-981-099-rg.diff.gz]]
  • [get | view] (2005-11-29 19:59:21, 42.1 KB) [[attachment:snap-pagecomment2.jpg]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.