Attachment 'PageComment-082-tw.py'

Download

   1 # -*- coding: iso-8859-1 -*-
   2 """
   3     PageComment.py  Version 0.82-tw  2005. 10. 08.
   4                                                                                                            
   5     This macro gives a form to post a new comment to the page and 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: [[PageComment]]
  11 
  12     Features:
  13         
  14         Simple usage, just put [[PageComment]] 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             - to restore a deleted comment
  21             - to show the host IP address where a comment is posted
  22             
  23 
  24     Change Log
  25 
  26         Oct. 08, 2005 - Version 0.82
  27             - Changed the directory the data file stored to be secured
  28         Oct. 07, 2005 - Version 0.81 
  29             - Unicode encoding related bugs in deletecomment function are patched. 
  30             - Instruction bugs are patched. 
  31         Oct. 06, 2005 - Version 0.80 
  32             - The initial version is released.
  33 
  34 
  35     Notes
  36         
  37         'Gallery.py' developed by Simon Ryan has inspired this macro.
  38    
  39     Notes to developer:
  40     - do a diff -u yourversion myversion to see what I changed
  41     - read and follow PEP 0008, esp. concerning tabs and blanks usage
  42     - almost never use "except:"
  43     - almost never "import string"
  44     - read about "template %s %d" % (somestring, someint)
  45 """
  46 
  47 import os, StringIO, time
  48 import codecs
  49 from MoinMoin import config, wikiutil
  50 
  51 class Globs:
  52     # A quick place to plonk those shared variables
  53     adminmsg = ''
  54     datafiledir = ''
  55     pagename = ''
  56     admin = ''
  57     baseurl = ''
  58     welcome_msg = 'Please leave your comment for this page.'
  59 
  60 def message(astring):
  61     Globs.adminmsg = '<font style="color: #aa0000; font-size: 0.9em;">PageComment: ' + astring + '</font>\n'
  62 
  63 
  64 def commentform(tmpauthor, tmptext, tmppasswd):
  65     # A form for posting a new comment
  66     
  67     html = [
  68         u'<div id="commentform">',
  69         u'<table id="commentform">',
  70         u'<form action="' + Globs.subname + '" name="comment" method="POST">',
  71 		u'<tr><td>Name</td><td>Comment Text</td><td>Password</td><td></td></tr>',
  72 		u'<tr><td><input type="text" size="10" maxlength="20" name="comauthor" value="' + tmpauthor + '"></td>',
  73 		#u'<td><textarea name="comtext" rows="3" size="40">content</textarea></td>',
  74 		u'<td><input type="text" size="50" maxlength="255" name="comtext" value="' + tmptext + '"></td>',
  75 		u'<td><input type="password" size="6" maxlength="10" name="compasswd" value="' + tmppasswd + '"></td>',
  76         u'<td><input type="submit" value="POST"></td></tr>',
  77 		u'<input type="hidden" value="show" name="action">',
  78 		u'</form>',
  79 		u'</table>',
  80 		u'</div>',
  81         ]
  82 
  83     return u'\n'.join(html) + u'\n'
  84       
  85 def addcomment(macro, comauthor, comtext, compasswd):
  86     # Add a comment with inputs
  87     
  88     com_delimeter = Globs.com_delimeter
  89     cfg = macro.request.cfg
  90     
  91     try:
  92         # If the data file exists
  93         inx_fname = os.path.join(Globs.datafiledir, 'pagecommentsindex.txt')
  94         inx_file = codecs.open(inx_fname, 'r+', encoding='utf-8')
  95     except: # XXX TODO: be more specific!
  96         try:
  97             # If the directory does not exist
  98             if not os.path.isdir(Globs.datafiledir):
  99                 # Create a attachments directory first
 100                 # Is conflict with moinmoin?
 101                 os.mkdir(Globs.datafiledir)
 102             
 103             inx_file = codecs.open(inx_fname, 'w', encoding='utf-8')
 104 
 105         except: # XXX TODO: be more specific!
 106             message('Failed to add the comment (unable to create an index file)')
 107             return
 108     
 109     try:
 110         cur_index = inx_file.readline()
 111         cur_index = int(cur_index)
 112     except:
 113         cur_index = 0
 114 
 115     cur_index = cur_index + 1
 116     cur_index = str(cur_index)
 117     
 118     try:
 119         out_fname = os.path.join(Globs.datafiledir, 'pagecomments.txt')
 120         out_file = codecs.open(out_fname, 'a+', encoding='utf-8')
 121     except: # XXX TODO: be more specific!
 122         message('Failed to add the comment (unable to create a data file)')
 123         return
 124     
 125     commentitem = [
 126         'o', 
 127         com_delimeter,
 128         cur_index,
 129         com_delimeter,
 130         convertdelimiter(comauthor),
 131         com_delimeter,
 132         convertdelimiter(comtext),
 133         com_delimeter,
 134         compasswd,
 135         com_delimeter,
 136         macro.request.user.host(),
 137         com_delimeter,
 138         time.strftime(cfg.datetime_fmt, time.localtime(time.time())),
 139         #str('%s  %s/%s  %s:%s' % (cur_year, cur_month, cur_day, cur_time, cur_min)),
 140         ]
 141     
 142     commentitem = u''.join(commentitem)
 143     
 144     out_file.write(commentitem + u'\r\n')
 145     out_file.close()
 146     
 147     inx_file.seek(0)
 148     inx_file.write(cur_index)
 149     inx_file.close()
 150     
 151     message('The comment is added')
 152     
 153 def showcomment():
 154 
 155     html = ''
 156     com_delimeter = Globs.com_delimeter
 157     
 158     com_fname = os.path.join(Globs.datafiledir, 'pagecomments.txt')
 159     if not os.path.isfile(com_fname):
 160         return ''
 161     
 162     try:
 163         com_file = codecs.open(com_fname, 'r', encoding='utf-8')
 164     except: # XXX TODO: be more specific!
 165         #return u'<div=commentlist><table><tr><td style="border: 0px;">no comments</td></tr></td></table></div>'
 166         return ''
 167     
 168     html = u'<div=commentlist><table width="100%">'
 169     
 170     #cur_pos = 0
 171     
 172     while True:
 173         in_line = com_file.readline()
 174         #cur_pos = cur_pos + len(in_line.encode('utf-8'))
 175         
 176         if not in_line:
 177             break
 178         
 179         if in_line[0] == 'x':
 180             if Globs.admin == 'true':
 181                 text_style = 'color: #d0d0d0;'
 182                 signature_style = text_style
 183             else:
 184                 continue
 185         else:
 186             text_style = ''
 187             signature_style = 'color: #999999;'
 188         
 189         try:
 190             in_line = in_line[:-2] # what are you doing here?
 191             [flg_active, cur_index, comauthor, comtext, compasswd, comhost, comtime] = in_line.split(com_delimeter)
 192         except: # XXX TODO: be more specific!
 193             message('Failed to show the comment (the data file may be corrupt)')
 194             return ''
 195         
 196         if Globs.admin == 'true':
 197             signature = comhost + ' | ' + comtime
 198         else:
 199             signature = comtime
 200         
 201         htmlcomment = [
 202             u'<tr><td colspan="2" style="border: 0px; height: 0.2px; background-color: #c0c0c0;"></td></tr>',
 203             u'<tr><td style="border: 0px; width: 9em; vertical-align: top; ' + text_style + '">',
 204             #u'(' + str(cur_pos) + ')',
 205             converttext(comauthor),
 206             u'</td><td style="border: 0px; ' + text_style + '">',
 207             converttext(comtext),
 208             u' <font style="font-size: 0.8em; ' + signature_style + '">(',
 209             signature,        
 210             u')</font>',
 211             ]
 212 
 213         htmlcomment = u'\n'.join(htmlcomment)
 214             
 215         if Globs.admin == 'true' and flg_active == 'x':
 216             htmlcomment2 = [
 217                 u'<font style="font-size: 0.9em;">',
 218                 u'<a style="color: #aa0000;" href="javascript: requesttorestore(\'' + cur_index + u'\');" alt="Restore">o</a>',
 219                 u'</font></td></tr>'
 220                 ]
 221         else:
 222             htmlcomment2 = [
 223                 u'<font style="font-size: 0.9em;">',
 224                 u'<a style="color: #aa0000;" href="javascript: requesttodelete(\'' + cur_index + u'\');" alt="Delete">x</a>',
 225                 u'</font></td></tr>'
 226                 ]
 227         
 228         htmlcomment2 = u'\n'.join(htmlcomment2)
 229         html =  html + htmlcomment + htmlcomment2 + '\n'
 230     
 231     com_file.close()
 232     html = html + u'</table></div>'
 233     return html
 234 
 235 
 236 def execute(macro, args):
 237 
 238     # Containers
 239     formvals = {}
 240     try:
 241         import wikiconfig # HUH!? you know macro.request.cfg?
 242     except: # ...
 243         wikiconfig = ''
 244 
 245     # Class variables need to be specifically set 
 246     Globs.datafiledir = ''
 247     Globs.admin = ''
 248     Globs.adminmsg = ''
 249     Globs.pagename = ''
 250     Globs.com_delimeter = ' {||} '
 251 
 252     # process arguments
 253     if args:
 254 	sargs = args.split(',')
 255 	for item in sargs:
 256 	    sitem = item.split('=')
 257 	    if len(sitem) == 2:
 258     		key, value = sitem
 259 
 260     # Useful variables
 261     Globs.baseurl = macro.request.getBaseURL() + '/'
 262     if not Globs.pagename:
 263 	#Globs.pagename = string.replace(macro.formatter.page.page_name,'/','_2f')
 264 	Globs.pagename = macro.formatter.page.page_name
 265 	# This fixes the subpages bug. subname is now used instead of pagename when creating certain urls
 266 	Globs.subname = Globs.pagename.split('/')[-1]
 267     # Hmmm. A bug in moinmoin? underscores are getting escaped. These doubly escaped pagenames are even appearing in data/pages
 268     try:
 269         # Try the old MoinMoin-1.2.x way first (/me blows the dust off :)
 270         textdir = config.text_dir
 271         pagepath = string.replace(wikiutil.getPagePath(Globs.pagename),'_5f','_') # ugly
 272     except: # ...
 273         pagepath = macro.formatter.page.getPagePath()
 274     Globs.datafiledir = os.path.join(pagepath, 'pagecommentdata')
 275     
 276     if args:
 277         args = macro.request.getText(args)
 278 
 279     for item in macro.form.items():
 280         if not formvals.has_key(item[0]):
 281 	    try: # TODO remove tabs from src!!!
 282                 formvals[item[0]] = item[1][0]
 283 	    except AttributeError:
 284 	        pass
 285 
 286     # Figure out if we have delete privs
 287     try:
 288         # If a user can delete the page containing the PageComment, then they are considered a PageComment administrator
 289         if macro.request.user.may.delete(macro.formatter.page.page_name):
 290             Globs.admin = 'true'
 291     except AttributeError:
 292         pass
 293     
 294     out = StringIO.StringIO()
 295 
 296     comauthor = ''
 297     comtext = ''
 298     compasswd = ''
 299     
 300     tmpauthor = ''
 301     tmptext = ''
 302     tmppasswd = ''
 303     
 304     message(Globs.welcome_msg)
 305     
 306     if formvals.has_key('comauthor') or formvals.has_key('comtext') or formvals.has_key('compasswd'):
 307         
 308         all_input = 1 # -> True
 309         
 310         try:
 311             comauthor = formvals['comauthor']
 312         except: # you maybe want to use formvals.get(name, defaulvalue)
 313             comauthor = ''
 314             all_input = 0
 315         
 316         try:
 317             comtext = formvals['comtext']
 318         except:
 319             comtext = ''
 320             all_input = 0
 321             
 322         try:
 323             compasswd = formvals['compasswd']
 324         except:
 325             compasswd = ''
 326             all_input = 0
 327         
 328         try:
 329             if all_input == 1:
 330                 addcomment(macro, comauthor, comtext, compasswd)
 331             else:
 332                 message('Failed to add the comment (insufficient input)')
 333                 
 334                 tmpauthor = comauthor
 335                 tmptext = comtext
 336                 tmppasswd = compasswd
 337 
 338         except:
 339             message('Failed to add the comment (internal error)')
 340             
 341             tmpauthor = comauthor
 342             tmptext = comtext
 343             tmppasswd = compasswd
 344 
 345     if formvals.has_key('delindex'):
 346         
 347         try:
 348             delindex = formvals['delindex']
 349             delpasswd = formvals['delpasswd']
 350             delaction = formvals['delaction']
 351             
 352             deletecomment(macro, delindex, delpasswd, delaction)
 353         except:
 354             message('Failed to delete the comment (internal error or insufficient input)')
 355     
 356     out.write(deleteform())
 357     out.write(u'<table><tr><td style="border: 0px;">')
 358     out.write(Globs.adminmsg)
 359     out.write(commentform(tmpauthor, tmptext, tmppasswd))
 360     out.write(u'</td></tr><tr><td style="border: 0px; height: 0.5em;"></td></tr><tr><td style="border: 0px;">')
 361     out.write(showcomment())
 362     out.write(u'</td></tr></table>')
 363     
 364 	
 365     out.seek(0)
 366     # Finally output any administrative messages at the top followed by any generated content
 367     return macro.formatter.rawHTML(
 368         out.read()	# . ??
 369     )
 370 
 371 def converttext(targettext):
 372     # Converts some special characters of html to plain-text style
 373     # What else to handle?
 374     # ugly, use some existing escape function, see wikiutil, urllib, ...
 375     targettext = targettext.replace(u'&', '&amp')
 376     targettext = targettext.replace(u'>', '&gt;')
 377     targettext = targettext.replace(u'<', '&lt;')
 378     targettext = targettext.replace(u'\n', '<br>')
 379     targettext = targettext.replace(u'\t', '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;')
 380     targettext = targettext.replace(u'  ', '&nbsp;&nbsp;')
 381         
 382     return targettext
 383     
 384 def convertdelimiter(targettext):
 385     # Converts delimeter to other string to avoid a crash
 386     targettext = targettext.replace(Globs.com_delimeter, '(del)')
 387     return targettext
 388 
 389     
 390 def deleteform():
 391     # Javascript codes for deleting or restoring a comment
 392 
 393     html = [
 394         '<script language=javascript>', # "javascript" ?
 395         '<!--',
 396         ]
 397     html = '\n'.join(html)
 398            
 399     if Globs.admin == 'true':
 400         html2 = [    
 401             '  function requesttodelete(comindex) {',
 402             '      document.delform.delindex.value = comindex;',
 403             '      document.delform.delpasswd.value = "****";',
 404             '      document.delform.delaction.value = "delete";',
 405             '      document.delform.submit();',
 406             '  }',
 407             '  function requesttorestore(comindex) {',
 408             '      document.delform.delindex.value = comindex;',
 409             '      document.delform.delpasswd.value = "****";',
 410             '      document.delform.delaction.value = "restore";',
 411             '      document.delform.submit();',
 412             '  }',
 413             ]
 414         html2 = '\n'.join(html2)
 415     else:
 416         html2 = [    
 417             '  function requesttodelete(comindex) {',
 418             '      var passwd = prompt("Enter password:", "");',
 419             '      if(!(passwd == "" || passwd == null)) {',
 420             '          document.delform.delindex.value = comindex;',
 421             '          document.delform.delpasswd.value = passwd;',
 422             '          document.delform.delaction.value = "delete";',
 423             '          document.delform.submit();',
 424             '      }',
 425             '  }',
 426             ]
 427         html2 = '\n'.join(html2)
 428                 
 429     html3 = [
 430         '//-->',
 431         '</script>',
 432         '<form name="delform" action="' + Globs.subname + '" METHOD="post"> <input type=hidden value="show" name="action">',
 433         '<input name="delpasswd" type="hidden" value="****"><input name="delindex" type="hidden" value=""><input name="delaction" type="hidden" value=""> </form>',
 434         ]
 435     html3 = '\n'.join(html3)
 436 
 437     return '\n' + html + '\n' + html2 + '\n' + html3 # why not join here?
 438         
 439 def deletecomment(macro, delindex, delpasswd, delaction):
 440     # Deletes or restores a comment with give index and password
 441     html = ''
 442     com_delimeter = Globs.com_delimeter
 443     try:
 444         com_fname = os.path.join(Globs.datafiledir, 'pagecomments.txt')
 445         com_file = codecs.open(com_fname, 'r+', encoding='utf-8')
 446     except: # ...
 447         message('No such comment')
 448         return
 449     
 450     delindex = int(delindex)
 451     
 452     if delindex < 1:
 453         message('No such comment')
 454         return
 455     
 456     cur_byte = 0
 457     selectedcomment = ''
 458     
 459     for x in range(delindex):
 460         cur_byte = cur_byte + len(selectedcomment.encode('utf-8'))
 461         selectedcomment = com_file.readline()
 462         
 463     if not selectedcomment:
 464         message('No such comment')
 465         return
 466     
 467     if selectedcomment[0] == 'x' and delaction == 'delete':
 468         message('The comment is already deleted')
 469         return
 470         
 471     if Globs.admin == 'true' and selectedcomment[0] == 'o' and delaction == 'restore':
 472         message('The comment is already restored')
 473         return
 474     
 475     selectedcomment = selectedcomment[:-2] # ?
 476     [flg_active, cur_index, comauthor, comtext, compasswd, comhost, comtime] = selectedcomment.split(com_delimeter)
 477     
 478     if Globs.admin != 'true' and compasswd != delpasswd:
 479         message('Failed to delete the comment (incorrect password)')
 480         return
 481         
 482     com_file.seek(cur_byte)
 483     if Globs.admin == 'true' and delaction == 'restore':
 484         com_file.write(u'o')
 485         message('The comment is restored')
 486     else:
 487         com_file.write(u'x')
 488         message('The comment is deleted')
 489     
 490     com_file.close()
 491     
 492     return

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] (2005-10-07 01:55:46, 15.6 KB) [[attachment:PageComment-080.py]]
  • [get | view] (2005-10-07 01:56:31, 15.7 KB) [[attachment:PageComment-081.py]]
  • [get | view] (2005-10-28 10:35:49, 16.4 KB) [[attachment:PageComment-082-tw.py]]
  • [get | view] (2005-10-07 22:55:29, 15.5 KB) [[attachment:PageComment-082.py]]
  • [get | view] (2005-10-06 11:34:45, 13.7 KB) [[attachment:snap-pagecomment.jpg]]
 All files | Selected Files: delete move to page copy to page

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