Attachment 'PageCommentSF.py'

Download

   1 # -*- coding: iso-8859-1 -*-
   2 """
   3     PageComment2.py  Version 0.98.1sf  Jan. 6, 2007
   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://www.silee.net/
   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 
  23         - pagename: the page name which the comments are retrieved for. by default the page itself.
  24             If the user has no 'read' ACL for that page, it does not allow to insert/view comments.
  25             e.g., pagename=AnotherPage
  26         
  27         - section: the section name of the page. The comments in different sections are managed in separated sub pages.
  28             Section name should be alphanumeric format ([a-zA-Z0-9] in regular expression). 
  29             If not, all the non-alphanumric characters are removed.
  30             e.g., section=1, section=News, section=Opinion
  31             
  32         - inputonly: shows input form only. list of the comments are shown to admin users only.
  33             - inputonly=0; default, all list is shown to all users including anonymous users
  34             - inputonly=1; shown to admin users only (who has the page delete privilege)
  35             
  36         - commentonly: shows the list of comments only.
  37             - commentonly=0; default, both of the list and input form will be shown
  38             - commentonly=1; only the list of comments will be shown
  39                 
  40         - countonly: returns the number of the comments posted to this page
  41             - countonly=0; default, normal form (input form; list of comments)
  42             - countonly=1; just return the number of comments. 
  43                 e.g., 'There are [[PageComments(countonly=1)]] comments here'
  44     
  45         - rows: the # of rows of the textarea. default 4. e.g., rows=4
  46         
  47         - cols: the # of columns of the textarea. default 60. e.g., cols=60
  48         
  49         - maxlength: limitation on # of characters for comment text. default 0 (no limit). e.g., maxlength=500
  50         
  51         - newerfirst: order of the list of comments.
  52             - newerfirst=0: default, newer ones are listed at the end
  53             - newerfirst=1: newer ones are listed at the top
  54         
  55         - commentfirst: shows comment list before the input form.
  56             - commentfirst=0: default, the input form first
  57             - commentfirst=1: comment list first
  58 
  59         - commentclass: specifies the class of the rows in the comment table
  60 	    - commentclass=baz: means the class is "baz" for ordinary view and
  61 	         "bazpreview" for preview (when markup=1); default is
  62 	         determined by articleview parameter for backwards compat.
  63 
  64         - commentformat: specifies which fields of the comment are specified,
  65 	    and in what order. Its value should be a string composed of the
  66             following characters, which will cause the corresponding item
  67             to be placed in the table of comments:
  68               't': The text of the comment (cell has class commenttext)    
  69               'a': The author of the comment (class  commentauthor)
  70               'A': author in verbose "Posted by <author>" 
  71                    (class commentauthorverbose)
  72               'i': smiley (class commenticon)
  73               'd': date/time (class commentdate)
  74               'D': verbose date/time (class commentdate)
  75               'x': link to delete the comment
  76               ' ': bit o' horizontal whitespace
  77               '{': break line, start a right-justified group of fields
  78                    (class commentcontinuation) 
  79               '}': Close group started by { - note this is mandatory 
  80               'V': bit o' vertical whitespace, produced by a cell spanning the
  81                    entire entry of style commentblankline. Probably only
  82                    really works at the end of the format string. 
  83             So note that the style for each cell is composed of the style
  84             given by the commentclass, overridden by the style of 
  85             the class listed for that field type. Note that the blank lines do
  86             not have class commentclass.   
  87  
  88         - articleview: basically superseded by commentclass and commentformat
  89             For backwards compatibility, sets their defaults: 
  90             - articleview=0: (default) commentclass deflts to "commentclassic"
  91                              commentformat deflts to "ia tdx"     
  92             - articleview=1: commentclass deflts to "commentarticle"
  93                              commentformat deflts to "t{AiDx}V"
  94   
  95         - tablewidth: the width of the table format for PageComment2, default '' (none). 
  96             e.g., tablewidth=600, tablewidth=100%
  97   
  98         - smileylist: shows smiley options with drop-down list box
  99             - smileylist=0: default, a part of the smiley in radio button
 100             - smileylist=1: smiley in drop-down list box
 101         
 102         - nosmiley: shows no smiley
 103             - nosmiley=0: default, shows smiley selection
 104             - nosmiley=1: no smiley selection
 105 
 106         - prompt: what should go in the box at start (default 'Add your comment')
 107         
 108         - notify: notifies to the subscribers of the page which includes the macro when a comment is added
 109             - notify=0: default, notification disabled
 110             - notify=1: notification enabled
 111 
 112         - encryptpass: encrypts entered password
 113             - encryptpass=0: default, the password is stored in plain text
 114             - encryptpass=1: the password is stored in encrypted format
 115             
 116         - markup: enables wiki markup in the comment text except some specified macros.
 117             - markup=0: default, use of wiki markup in the text is disabled
 118             - markup=1: use of wiki markup in the text is enabled and preview button is activated
 119 
 120     Change Log
 121         
 122 	- Jan. 6, 2007 - Version 0.98sf
 123             - Moved as nearly all of the style information to the stylesheet
 124             - Implemented configurable styles and fields in the comment list
 125             - added a prompt parameter for what's in the box to start
 126             - changes by Glen Whitney gwhitneycom1 AT pobox OBFUSCATE DOT com
 127  
 128         - April 17, 2006 - Version 0.98
 129             - fixed a bug on revision history
 130             - added a despam action
 131         
 132         - Jan. 05, 2006 - Version 0.97
 133             - added features:
 134                 - mail notification
 135                 - password encryption
 136                 - wiki markup support with preview
 137                 - remember author name last used
 138             - administrative actions (delete without password) are allowed to those who has WRITE acl.
 139         
 140         - Nov. 29, 2005 - Version 0.96
 141             - some format parameters are added
 142             - random password feature is added
 143 
 144         - Nov. 20, 2005 - Version 0.95
 145             - some minor bugs are fixed
 146         
 147         - Nov. 20, 2005 - Version 0.94
 148             - some parameters are added
 149             - some minor bugs are fixed
 150         
 151         - Nov. 19, 2005 - Version 0.92
 152             - some minor bugs are fixed
 153             - 'olderfirst' parameter replaced with 'newerfirst'
 154         
 155         - Nov. 19, 2005 - Version 0.91
 156             - some parameters are added
 157             - validates smiley markup
 158             - modified view
 159         
 160         - Nov. 18, 2005 - Version 0.90 (Release 2)
 161             - No text data file support any more: Comment is stored in the sub wiki page.
 162             - (does not compatible with Release 1: PageComment.py)
 163             - Custom icon (smiley) can be inserted
 164             - Pre-fill the name input field with his/her login name
 165             - Logs at add/remove comments
 166             - Added some parameters    
 167         
 168         - Oct. 08, 2005 - Version 0.82
 169             - Changed the directory the data file stored to be secured
 170         
 171         - Oct. 07, 2005 - Version 0.81 
 172             - Unicode encoding related bugs in deletecomment function are patched. 
 173             - Instruction bugs are patched. 
 174         
 175         - Oct. 06, 2005 - Version 0.80 
 176             - The initial version is released.
 177 
 178 
 179     Notes
 180         
 181         - 'Gallery.py' developed by Simon Ryan has inspired this macro.
 182         - Thanks to many of the MoinMoin users for valuable comments.
 183         - Visit http://moinmoin.wikiwikiweb.de/MacroMarket/PageComment2 for more detail
 184 
 185 """
 186 
 187 from MoinMoin import config, wikiutil
 188 import StringIO, time, re
 189 from MoinMoin.Page import Page
 190 from MoinMoin.PageEditor import PageEditor
 191 from MoinMoin.parser import wiki
 192 
 193 
 194 class Globs:
 195     # A quick place to plonk those shared variables
 196     
 197     adminmsg = ''
 198     datapagename = ''
 199     pagename = ''
 200     curpagename = ''
 201     cursubname = ''
 202     fieldinterps = {}
 203     colspan = u''
 204     blankline = u''
 205     admin = ''
 206     macro = ''
 207     defaultacl = ''
 208     defaulticon = ''        
 209     formid = 0
 210     smileys = []
 211 
 212 class Params:
 213 
 214     rows = 0
 215     cols = 0
 216     maxlength = 0
 217     newerfirst = 0
 218     tablewidth = ''
 219     commentfirst = 0
 220     pagename = ''
 221     commentonly = 0
 222     inputonly = 0
 223     countonly = 0
 224     section = ''
 225     articleview = 0
 226     commentclass = ''
 227     commentformat = ''
 228     notify = 0
 229     prompt = u''
 230     encryptpass = 0
 231     markup = 0
 232     
 233 
 234 def execute(macro, args):
 235 
 236     # INITIALIZATION ----------------------------------------
 237     getparams(args)
 238     setglobalvalues(macro)
 239     
 240     # internal variables
 241     request = macro.request
 242     _ = request.getText
 243     
 244     if not Globs.pagename == Globs.curpagename:
 245         if not macro.request.user.may.read(Globs.pagename):
 246             return macro.formatter.rawHTML(u'PageComment: %s' % _('You are not allowed to view this page.'))
 247         elif not Page(request, Globs.pagename).exists():
 248             return macro.formatter.rawHTML(u'PageComment: %s' % _('This page is already deleted or was never created!'))
 249 
 250     
 251     if Params.countonly:
 252         html = len(fetchcomments())
 253         return macro.formatter.rawHTML('%s' % html)
 254     
 255     datapagename = Globs.datapagename
 256     
 257     # form vals
 258     comicon = Globs.defaulticon
 259     comauthor = ''
 260     comtext = ''
 261     compasswd = ''
 262     comrev = 0
 263     comautopass = ''
 264     commentpreview = ''
 265     commarkup = ''
 266     
 267     addcommand = u'addcomment%d' % Globs.formid
 268     delcommand = u'delcomment%d' % Globs.formid
 269     
 270     action = macro.form.get('commentaction', [''])[0]
 271     
 272     if action == addcommand:
 273     
 274         # process form input for comment add
 275         form_fields = {'comicon': Globs.defaulticon, 'comauthor': '', 'comtext': '', 'compasswd': '', 'comrev': 0, 'autopasswd': '', 'button_save': '', 'button_preview': '', 'commarkup%d' % Globs.formid: '0'}
 276         required_fields = {'comauthor': _('Name'), 'comtext': _('Text'), 'compasswd': _('Password'), 'comrev': 'Rev. #'}
 277         
 278         formvals, missingfields = getforminput(macro.form, form_fields, required_fields)
 279         
 280         comicon = formvals['comicon']
 281         comauthor = formvals['comauthor']
 282         comtext = formvals['comtext']
 283         compasswd = formvals['compasswd']
 284         comrev = int(formvals['comrev'])
 285         comautopass = formvals['autopasswd']
 286         btnsave = formvals['button_save']
 287         btnpreview = formvals['button_preview']
 288         commarkup = formvals['commarkup%d' % Globs.formid]
 289     	
 290         if not len(missingfields) == len(required_fields):
 291             if not missingfields:
 292                 
 293                 # check input
 294                 if comicon and (not comicon in config.smileys.keys()):
 295                     message('Please use smiley markup only')
 296             
 297                 elif Params.maxlength and (len(comtext) > Params.maxlength):
 298                     message('Comment text is limited to %d characters. (%d characters now)' % (Params.maxlength, len(comtext)) )
 299                 
 300                 elif not comtext.strip() or comtext == Params.prompt:
 301                     message('Please fill the comment text')
 302                 
 303                 ## PREVIEW
 304                 elif btnpreview:
 305                     commentpreview = previewcomment(comicon, comauthor, comtext, commarkup)
 306                 
 307                 ## ADD
 308                 elif btnsave:
 309                     flag = addcomment(macro, comicon, comauthor, comtext, compasswd, comrev, comautopass, commarkup)
 310                     
 311                     if flag:
 312                         comicon = Globs.defaulticon
 313                         comauthor = ''
 314                         comtext = ''
 315                         compasswd = ''
 316                         comrev = 0
 317                         commentpreview = ''
 318                         commarkup = ''
 319                 
 320                 ## ERROR
 321                 else:
 322                     message( 'What do you want?' )
 323                 
 324             else:
 325                 message( _('Required attribute "%(attrname)s" missing') % { 'attrname': u', '.join(missingfields) } )
 326     
 327     elif action == delcommand:
 328     
 329         # process form input for comment delete
 330         form_fields = {'delkey': '', 'delpasswd': ''}
 331         required_fields = {'delkey': 'Comment Key', 'delpasswd': 'Password'}
 332         
 333         formvals, missingfields = getforminput(macro.form, form_fields, required_fields)
 334         
 335         delkey = formvals['delkey']
 336         delpasswd = formvals['delpasswd']
 337         
 338         if not len(missingfields) == len(required_fields):
 339             if not missingfields:
 340                 deletecomment(macro, delkey, delpasswd)
 341             else:
 342                 message( _('Required attribute "%(attrname)s" missing') % { 'attrname': u', '.join(missingfields) } )
 343     
 344     # format output
 345     html = []
 346     
 347     html.append(u'<div id="pagecomment">')
 348     html.append(u'<a name="pagecomment%d"></a>' % Globs.formid)
 349     
 350     html.append(u'<table border="0" class="pagecomment" %s>' % Params.tablewidth)
 351     
 352     if Globs.adminmsg:
 353         html.append(u'<tr><td %sstyle="border-width: 0px;">' % Globs.colspan)
 354         html.append(u'<font color="#aa0000">%s</font>' % Globs.adminmsg)
 355         html.append(u'</td></tr>')
 356 
 357     commentlisthtml = showcommentsection()
 358     commentformhtml = commentformsection(comauthor, comtext, compasswd, comicon, comrev, comautopass, commarkup)
 359 
 360     if Params.commentfirst:
 361         if commentpreview:
 362             html.append(commentpreview)
 363             
 364         html.append(commentlisthtml)
 365         html.append(Globs.blankline)
 366         html.append(commentformhtml)
 367     else:
 368         html.append(commentformhtml)
 369         html.append(Globs.blankline*2)
 370         if commentpreview:
 371             html.append(commentpreview)
 372 
 373         html.append(commentlisthtml)
 374 
 375     if Globs.debugmsg:
 376         html.append(u'<tr><td %sstyle="border-width: 0px;">' % Globs.colspan)
 377         html.append(u'<font color="#aa0000">%s</font>' % Globs.debugmsg)
 378         html.append(u'</td></tr>')
 379     
 380     html.append(u'</table>')
 381 
 382     if Globs.customscript:
 383         html.append(u'%s' % Globs.customscript)
 384 
 385     html.append(u'</div>')
 386     
 387     return macro.formatter.rawHTML(u'\n'.join(html))
 388 
 389 
 390 def commentformsection(comauthor, comtext, compasswd, comicon, comrev, autopass, commarkup):
 391     html = []
 392     
 393     if not Params.commentonly:
 394         html.append(u'<tr><td style="border-width: 1px; margin: 10px 0 10px 0;" %s>' % Globs.colspan)
 395         #html.append(u'<table class="commentform"><tr><td style="border-width: 1px;">')
 396         html.append(commentform(comauthor, comtext, compasswd, comicon, comrev, autopass, commarkup))
 397         #html.append(u'</td></tr></table>')
 398         html.append(u'</td></tr>')
 399     
 400     return u'\n'.join(html)
 401 
 402 
 403 def showcommentsection():
 404     html = []
 405     if (not Params.inputonly) or Globs.admin:
 406         html.append(deleteform())
 407         html.append(showcomment())
 408     else:
 409         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>')
 410 
 411     return u'\n'.join(html)
 412 
 413 def getforminput(form, inputfields, requiredfields):
 414     
 415     formvals = {}
 416     missingfields = []
 417     
 418     for item in inputfields.keys():
 419         formvals[item] = form.get(item, [inputfields[item]])[0]
 420         if (not formvals[item]) and (item in requiredfields):
 421             missingfields.append(requiredfields[item])
 422         
 423     return formvals, missingfields
 424 
 425 def getparams(args):
 426     # process arguments
 427     
 428     params = {}
 429     if args:
 430         # Arguments are comma delimited key=value pairs
 431         sargs = args.split(',')
 432     
 433         for item in sargs:
 434             sitem = item.split('=')
 435         
 436             if len(sitem) == 2:
 437                 key, value = sitem[0], sitem[1]
 438                 params[key.strip()] = value.strip()
 439 
 440     Params.pagename = params.get('pagename', '')
 441     
 442     Params.section = params.get('section', '')
 443     if Params.section:
 444         Params.section = getescapedsectionname(Params.section)
 445 
 446     try:
 447         Params.inputonly = int(params.get('inputonly', 0))
 448     except ValueError:
 449         Params.inputonly = 0
 450 
 451     try:
 452         Params.commentonly = int(params.get('commentonly', 0))
 453     except ValueError:
 454         Params.commentonly = 0
 455 
 456     try:
 457         Params.countonly = int(params.get('countonly', 0))
 458     except ValueError:
 459         Params.countonly = 0
 460 
 461     try:
 462         Params.newerfirst = int(params.get('newerfirst', 0))
 463     except ValueError:
 464         Params.newerfirst = 0
 465         
 466     try:
 467         Params.commentfirst = int(params.get('commentfirst', 0))
 468     except ValueError:
 469         Params.commentfirst = 0
 470 
 471     try:
 472         Params.articleview = int(params.get('articleview', 0))
 473     except ValueError:
 474         Params.articleview = 0
 475 
 476     defltclass = 'commentclassic'
 477     defltformat = 'ia tdx'
 478     if Params.articleview:
 479         defltclass = 'commentarticle'
 480         defltformat = 't{AiDx}V'
 481 
 482     Params.commentclass = params.get('commentclass', defltclass)
 483     Params.commentformat = params.get('commentformat', defltformat) 
 484 
 485     try:
 486         Params.smileylist = int(params.get('smileylist', 0))
 487     except ValueError:
 488         Params.smileylist = 0
 489         
 490     try:
 491         Params.nosmiley = int(params.get('nosmiley', 0))
 492     except ValueError:
 493         Params.nosmiley = 0
 494 
 495     try:
 496         Params.rows = int(params.get('rows', 4))
 497     except ValueError:
 498         Params.rows = 4
 499 
 500     try:
 501         Params.cols = int(params.get('cols', 60))
 502     except ValueError:
 503         Params.cols = 60
 504 
 505     try:
 506         Params.maxlength = int(params.get('maxlength', 0))
 507     except ValueError:
 508         Params.maxlength = 0
 509 
 510     Params.prompt = params.get('prompt', u'Add your comment');
 511 
 512     try:
 513         Params.notify = int(params.get('notify', 0))
 514     except ValueError:
 515         Params.notify = 0
 516         
 517     try:
 518         Params.encryptpass = int(params.get('encryptpass', 0))
 519     except ValueError:
 520         Params.encryptpass = 0
 521         
 522     try:
 523         Params.markup = int(params.get('markup', 0))
 524     except ValueError:
 525         Params.markup = 0
 526 
 527     Params.tablewidth = params.get('tablewidth', '')
 528     if Params.tablewidth:
 529         Params.tablewidth = ' width="%s" ' % Params.tablewidth
 530 
 531 def setglobalvalues(macro):
 532     
 533     # Global variables
 534     Globs.macro = macro
 535     Globs.defaultacl = u'#acl All:'
 536     Globs.adminmsg = ''
 537     Globs.debugmsg = ''
 538     Globs.customscript = ''
 539     Globs.defaulticon = ''
 540     request = macro.request
 541     
 542     # ADD SMILEYS HERE TO BE USED:
 543     Globs.smileys = [':)', ':))', ':(', ';)', ':\\', '|)', 'X-(', 'B)']
 544 
 545     totalcols = Params.commentformat.find('{')
 546     if totalcols < 0: totalcols = len(Params.commentformat)
 547     totalcols -= Params.commentformat.count('V',0,totalcols)
 548     if totalcols > 1: Globs.colspan = u'colspan="%d" ' % totalcols
 549 
 550     # Now that we've computed all the derived values, stick a dummy start
 551     # character onto the front and a dummy end character on the end
 552     # to make the generation code more uniform:
 553     Params.commentformat = 'S%sF' % Params.commentformat
 554 
 555     Globs.blankline = u'<tr><td %sclass="commentblankline"></td></tr>' % Globs.colspan
 556 
 557     Globs.fieldinterps = {
 558         'S' : u'<tr class=%(commentclass)s>',
 559         't' : u'<td class="commenttext">%(text)s</td>',
 560     	'a' : u'<td class="commentauthor">%(author)s</td>',
 561         'A' : u'<td class="commentauthorverbose">Posted by <b>%(author)s</b></td>',
 562         'i' : u'<td class="commenticon">%(icon)s</td>',
 563         'd' : u'<td class="commentdate" nowrap>%(date)s</td>',
 564 	'D' : u'<td class="commentdate" nowrap>at %(date)s</td>',
 565         'x' : u'<td>%(delform)s</td>',
 566 	' ' : u'<td style="width: 10px;">&nbsp;</td>',
 567 	'V' : u'</tr><tr><td %sclass="commentblankline"></td>' % Globs.colspan,
 568         '{' : u'</tr><tr class="%%(commentclass)s"><td %s class="commentcontinuation" style="padding: 0px;"><table style="padding:0px; margin:0px; float:right;"><tr>' % Globs.colspan,
 569         '}' : u'</tr></table></td>',
 570         'F' : u'</tr>'
 571     }
 572 
 573     if Params.markup:
 574         
 575         # ADD MACROS HERE TO ALLOW TO BE USED IN THE TEXT:
 576         Globs.macroallowed = [ 'BR', 'Date', 'DateTime', 'MailTo', 'Icon' ]
 577         
 578         from MoinMoin import wikimacro
 579         macronames = wikimacro.getNames(request.cfg)
 580         
 581         for names in Globs.macroallowed:
 582             macronames.remove(names)
 583         
 584         # ADD REGEX PATTERN HERE TO MAKE IT FORBIDDEN TO USE IN MARKUP:
 585         Globs.markupforbidden = { 
 586             #ur'(^\s*)((?P<hmarker>=+)\s.*\s(?P=hmarker))( $)': r'\1`\2`\4',
 587             #ur'(?P<rule>-{4,})': r'`\1`',
 588             ur'(?P<macro>\[\[(%(macronames)s)(?:\(.*?\))?\]\])' % { 'macronames': u'|'.join(macronames) } : r'`\1`'
 589             }
 590         
 591     Globs.curpagename = macro.formatter.page.page_name
 592     
 593     if Params.pagename:
 594         Globs.pagename = Params.pagename
 595     else:
 596         Globs.pagename = Globs.curpagename
 597         
 598     Globs.cursubname = Globs.curpagename.split('/')[-1]
 599     Globs.datapagename = u'%s/%s%s' % (Globs.pagename, 'PageCommentData', Params.section)
 600 
 601     try:
 602         #if request.user.may.delete(Globs.pagename):
 603         if request.user.may.write(Globs.pagename):
 604             Globs.admin = 'true'
 605         else:
 606             Globs.admin = ''
 607     except AttributeError:
 608         Globs.admin = ''
 609         pass
 610 
 611     # set form id
 612     
 613     if not hasattr(request, 'pgformid'):
 614         request.pgformid = 0
 615     
 616     request.pgformid += 1
 617     Globs.formid = request.pgformid
 618     
 619 
 620 def message(astring):
 621     Globs.adminmsg = u'PageComment: %s\n' % astring
 622 
 623 def debug(astring):
 624     Globs.debugmsg += u'%s\n<br>' % astring
 625 
 626 
 627 def commentform(tmpauthor, tmptext, tmppasswd, tmpicon, comrev, tmpautopass, tmpmarkup):
 628     # A form for posting a new comment
 629     request = Globs.macro.request
 630     datapagename = Globs.datapagename
 631     _ = request.getText
 632     
 633     cellstyle = u'border-width: 0px; vertical-align: middle; font-size: 0.9em;'
 634     
 635     pg = Page( request, datapagename )
 636     
 637     if pg.exists():
 638         comrev = pg.current_rev()
 639     else:
 640         comrev = 0
 641     
 642     if not Params.nosmiley:
 643         if not Params.smileylist:
 644             iconlist = getsmileymarkupradio(tmpicon)
 645         else:
 646             iconlist = getsmileymarkuplist(tmpicon)
 647     else:
 648         iconlist = ''
 649     
 650     initName = ''
 651     initPass = ''
 652     initText = ''
 653 
 654     if not (request.user.valid or tmpauthor):
 655         
 656         tmpauthor = getAuthorFromCookie()
 657         
 658         if not tmpauthor:
 659         
 660             import socket
 661             host = request.remote_addr
 662     
 663             try:
 664                 hostname = socket.gethostbyaddr(host)[0]
 665             except socket.error:
 666                 hostname = host
 667     
 668             tmpauthor = hostname.split('.')[0]
 669             
 670         initName = tmpauthor
 671     
 672     if not tmppasswd:
 673         tmppasswd = nicepass()
 674         initPass = tmppasswd
 675     elif tmpautopass and tmpautopass == tmppasswd:
 676         tmppasswd = nicepass()
 677         initPass = tmppasswd
 678     
 679     if not tmptext:
 680         tmptext = Params.prompt
 681         initText = tmptext
 682     elif tmptext and tmptext == Params.prompt:
 683         initText = tmptext
 684     
 685     previewbutton = ''
 686     markupcheckbox = ''
 687     
 688     if Params.markup:
 689         if not (tmpmarkup == '0'):
 690             markupchecked = "checked"
 691         else:
 692             markupchecked = ''
 693             
 694         previewbutton = '<br><input type="submit" name="button_preview" value="%s" style="color: #ff7777; font-size: 9pt; width: 6em; ">' % _('Preview')
 695         markupcheckbox = '<input type="checkbox" name="commarkup%d" value="1" %s> Markup' % (Globs.formid, markupchecked)
 696         
 697         
 698     if request.user.valid:
 699         html1 = [
 700             u'<input type="hidden" value="%s" name="comauthor">' % request.user.name,
 701 		    u'<input type="hidden" value="*" name="compasswd">',
 702     		]
 703         authorJavascriptCode = ''
 704         onSubmitCode = ''
 705     else:
 706         html1 = [
 707             u'<input type="text" style="font-size: 9pt;" size="6" maxlength="20" name="comauthor" value="%(author)s" onfocus="if (this.value==\'%(msg)s\') {this.value=\'\';};" onblur="if (this.value==\'\') {this.value=\'%(msg)s\';};">' % { 'msg': wikiutil.escape(initName), 'cellstyle': cellstyle, 'author': wikiutil.escape(tmpauthor) },
 708     		u'<input type="password" style="font-size: 9pt;" size="4" maxlength="10" name="compasswd" value="%(passwd)s" onfocus="if (this.value==\'%(msg)s\') {this.value=\'\';};" onblur="if (this.value==\'\') {this.value=\'%(msg)s\';};">' % { 'msg': wikiutil.escape(initPass), 'passwd': wikiutil.escape(tmppasswd)  },
 709     		u'<input type="hidden" value="%s" name="autopasswd">' % wikiutil.escape(initPass),
 710     		]
 711     		
 712         authorJavascriptCode = """
 713 <script language="javascript">
 714 <!--
 715 function setCookie(name, value) {
 716     var today = new Date();
 717     var expire = new Date(today.getTime() + 60*60*24*365*1000);
 718     document.cookie = name + "=" + encodeURIComponent(value) + "; expires=" + expire.toGMTString() + "; path=%s";
 719 }
 720 //-->
 721 </script>""" % request.getScriptname()
 722         
 723         onSubmitCode = 'onSubmit="setCookie(\'PG2AUTHOR\', this.comauthor.value);"'
 724     
 725     html1 = u'\n'.join(html1)
 726     scripthtml = u'onfocus="if (this.value==\'%(msg)s\') {this.value=\'\';};" onblur="if (this.value==\'\') {this.value=\'%(msg)s\';};"' % {'msg': wikiutil.escape(initText) }
 727     
 728     page_url = wikiutil.quoteWikinameURL(Globs.cursubname)
 729     
 730     html2 = [
 731         u'%s' % authorJavascriptCode,
 732         u'<form action="%s#pagecomment%d" name="comment" METHOD="POST" %s>' % (page_url, Globs.formid, onSubmitCode),
 733         u'<table class="addcommentform">',
 734 		u'<tr>',
 735 		u'<td style="%s"><textarea name="comtext" rows="%d" cols="%d" style="font-size: 9pt;" ' % (cellstyle, Params.rows, Params.cols),
 736         u'%s>%s</textarea></td>' % (scripthtml, wikiutil.escape(tmptext)),
 737         u'<td style="%s vertical-align: bottom;"><input type="submit" name="button_save" value="%s" style="font-size: 9pt; width: 6em; height:3em; ">%s</td>' % (cellstyle, _('Save'), previewbutton),
 738         u'</tr>',
 739         u'<tr><td style="%s">' % cellstyle,
 740         u'%s' % html1,
 741         u'%s' % iconlist,
 742         u'</td>',
 743         u'<td style="%s text-align: right; font-size: 9pt;">%s</td>' % (cellstyle, markupcheckbox),
 744         u'</tr>',
 745 		u'</table>',
 746 		u'<input type="hidden" name="action" value="show" >',
 747 		u'<input type="hidden" name="comrev" value="%s">' % comrev,
 748 		u'<input type="hidden" name="commentaction" value="addcomment%d">' % Globs.formid,
 749 		u'</form>',
 750         ]
 751     
 752     
 753     return u'\n'.join(html2)
 754       
 755 def addcomment(macro, comicon, comauthor, comtext, compasswd, comrev, comautopass, commarkup):
 756     # Add a comment with inputs
 757     
 758     request = Globs.macro.request
 759     cfg = request.cfg
 760     _ = request.getText
 761     
 762     datapagename = Globs.datapagename
 763     
 764     pg = PageEditor( request, datapagename )
 765     pagetext = pg.get_raw_body()
 766     
 767     # HACK for despam
 768     try:
 769         if not request.user.may.save( pg, comtext, pg.current_rev()):
 770             #message("No permission to save this text.")
 771             #return 0
 772             pass
 773             
 774     except pg.SaveError, msg:
 775         message(msg)
 776         return 0
 777     
 778     comtext = convertdelimeter(comtext)
 779     
 780     if request.user.valid:
 781         comloginuser = 'TRUE'
 782         comauthor = request.user.name
 783     else:
 784         comloginuser = ''
 785         comauthor = convertdelimeter(comauthor)
 786     
 787     orgcompasswd = compasswd
 788     
 789     if Params.encryptpass:
 790         from MoinMoin import user
 791         compasswd = user.encodePassword(compasswd)
 792     
 793     newcomment = [
 794         u'{{{',
 795         u'%s,%s' % (comicon, commarkup),
 796         u'%s' % comauthor,
 797         u'%s' % time.strftime(cfg.datetime_fmt, time.localtime(time.time())),
 798         u'',
 799         u'%s' % comtext,
 800         u'}}}',
 801         u'##PASSWORD %s' % compasswd,
 802         u'##LOGINUSER %s' % comloginuser,
 803         ]
 804         
 805     newpagetext = u'%s\n\n%s' % (pagetext, u'\n'.join(newcomment))
 806 
 807     if not pg.exists():
 808         action = 'SAVENEW'
 809         defaultacl = Globs.defaultacl
 810         warnmessages = '\'\'\'\'\'DO NOT EDIT THIS PAGE!!\'\'\' This page is automatically generated by Page``Comment macro.\'\'\n----'
 811         newpagetext = u'%s\n%s\n%s' % (defaultacl, warnmessages, newpagetext)
 812     else:
 813         action = 'SAVE'
 814     
 815     newpagetext = pg.normalizeText( newpagetext )
 816     
 817     comment = u'PageComment modification at %s' % Globs.curpagename
 818     pg._write_file(newpagetext, action, comment)
 819     
 820     comment = u'New comment by "%s"' % comauthor
 821     
 822     trivial = 0
 823     addLogEntry(request, 'COMNEW', Globs.curpagename, comment)
 824     
 825     #msg = _('Thank you for your changes. Your attention to detail is appreciated.')
 826     msg = _('The comment is added.')
 827     
 828     # send notification mails
 829     if Params.notify:
 830         msg = msg + commentNotify(comment, trivial, comtext)
 831         
 832     if comautopass and comautopass == orgcompasswd:
 833         msg2 = u'<i>You did not enter a password. A random password has been generated for you: <b>%s</b></i>' % comautopass
 834         msg = u'%s%s' % (msg, msg2)
 835     
 836     message(msg)    
 837     return 1
 838 
 839 
 840 def previewcomment(comicon, comauthor, comtext, commarkup):
 841     request = Globs.macro.request
 842     _ = request.getText
 843     cfg = request.cfg
 844     
 845     # normalize text
 846     lines = comtext.splitlines()
 847     if not lines[-1] == u'':
 848         # '' will make newline after join
 849         lines.append(u'')
 850     
 851     comtext = u'\n'.join(lines)
 852     
 853     #comtext = convertdelimeter(comtext)
 854     #comauthor = convertdelimeter(comauthor)
 855     
 856     htmlcommentitem = u'\n'.join([Globs.fieldinterps.get(x,u'') for x in Params.commentformat]) % {
 857         'commentclass': Params.commentclass + 'preview',
 858         'icon': getsmiley(comicon),
 859         'author': converttext(comauthor),
 860         'text': converttext(comtext, commarkup),
 861         'date': time.strftime(cfg.datetime_fmt, time.localtime(time.time())),
 862         'delform': ''
 863         }
 864         
 865     return htmlcommentitem
 866     
 867 def showcomment():
 868     
 869     request = Globs.macro.request
 870     _ = request.getText
 871     
 872     commentlist = fetchcomments()
 873     
 874     if Params.newerfirst:
 875         commentlist.reverse()
 876     
 877     html = []
 878     cur_index = 0
 879     
 880     htmlcomment = [Globs.fieldinterps.get(x, u'') for x in Params.commentformat]
 881     htmlcommentdel_admin = [
 882         u' <font style="font-size: 8pt;">',
 883         u'<a style="color: #aa0000;" href="javascript: requesttodeleteadmin%(formid)d(document.delform%(formid)d, \'%(key)s\');" title="%(msg)s">X</a>',
 884         u'</font>',
 885         ]
 886         
 887     htmlcommentdel_guest = [
 888         u' <font style="font-size: 8pt;">',
 889         u'<a style="color: #aa0000;" href="javascript: requesttodelete%(formid)d(document.delform%(formid)d, \'%(key)s\');" title="%(msg)s">X</a>',
 890         u'</font>',
 891         ]
 892     
 893     for item in commentlist:
 894         if Globs.admin or (item['loginuser'] and request.user.valid and request.user.name == item['name']):
 895             htmlcommentdel = htmlcommentdel_admin
 896         elif item['loginuser']:
 897             htmlcommentdel = ''
 898         else:
 899             htmlcommentdel = htmlcommentdel_guest
 900         
 901         htmlcommentdel = u'\n'.join(htmlcommentdel) % {
 902             'formid': Globs.formid, 
 903             'key': item['key'],
 904             'msg': _('Delete')
 905             }
 906                 
 907         htmlcommentitem = u'\n'.join(htmlcomment) % {
 908             'commentclass': Params.commentclass,
 909             'icon': getsmiley(item['icon']),
 910             'author': converttext(item['name']),
 911             'text': converttext(item['text'], item['markup']),
 912             'date': item['date'],
 913             'delform': htmlcommentdel
 914             }
 915         
 916         html.append(htmlcommentitem)
 917     
 918     return u'\n'.join(html)
 919 
 920 def getescapedsectionname(targettext):
 921     regex = r'\W'
 922     pattern = re.compile(regex, re.UNICODE)
 923     sectionname = pattern.sub('', targettext)
 924     
 925     return sectionname
 926 
 927 
 928 def getsmiley(markup):
 929     
 930     if markup in config.smileys.keys():
 931         formatter = Globs.macro.formatter
 932         return formatter.smiley(markup)
 933     else:
 934         return ''
 935 
 936 
 937 def converttext(targettext, markup='0'):
 938     # Converts some special characters of html to plain-text style
 939     # What else to handle?
 940     
 941     if Params.markup and markup == '1':
 942         targettext = getMarkupText(targettext)
 943     else:
 944         # targettext = targettext.strip()
 945         targettext = targettext.replace(u'&', '&amp')
 946         targettext = targettext.replace(u'>', '&gt;')
 947         targettext = targettext.replace(u'<', '&lt;')
 948         targettext = targettext.replace(u'\n', '<br>')
 949         targettext = targettext.replace(u'"', '&quot;')
 950         targettext = targettext.replace(u'\t', '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;')
 951         targettext = targettext.replace(u'  ', '&nbsp;&nbsp;')
 952 
 953     return targettext
 954     
 955 def convertdelimeter(targettext, reverse=0):
 956     # Converts delimeter to other string to avoid a crash
 957     
 958     if reverse:
 959         targettext = targettext.replace(u'{_{_{', u'{{{')
 960         targettext = targettext.replace(u'}_}_}', u'}}}')
 961     
 962     else:
 963         targettext = targettext.replace(u'{{{', u'{_{_{')
 964         targettext = targettext.replace(u'}}}', u'}_}_}')
 965     
 966     return targettext
 967 
 968 
 969 def deleteform():
 970     # Javascript codes for deleting or restoring a comment
 971     
 972     request = Globs.macro.request
 973     _ = request.getText
 974     
 975     htmlresult = []
 976     
 977     html = [
 978         '<script language="javascript">',
 979         '<!--',
 980         ]
 981     htmlresult.append(u'\n'.join(html))
 982            
 983     html = [    
 984         '  function requesttodeleteadmin%d(delform, comkey) {' % Globs.formid,
 985         '      if (confirm("%s")) {;' % _('Really delete this comment?'),
 986         '          delform.delkey.value = comkey;',
 987         '          delform.delpasswd.value = "****";',
 988         '          delform.submit();',
 989         '      }',
 990         '  }',
 991         '  function requesttodelete%d(delform, comkey) {' % Globs.formid,
 992         '      var passwd = prompt("%s:", "");' % _('Please specify a password!'),
 993         '      if(!(passwd == "" || passwd == null)) {',
 994         '          delform.delkey.value = comkey;',
 995         '          delform.delpasswd.value = passwd;',
 996         '          delform.submit();',
 997         '      }',
 998         '  }',
 999         ]
1000     
1001     htmlresult.append(u'\n'.join(html))
1002 
1003     page_url = wikiutil.quoteWikinameURL(Globs.cursubname)
1004 
1005     html = [
1006         '//-->',
1007         '</script>',
1008         '<form name="delform%d" action="%s#pagecomment%d" METHOD="post">' % (Globs.formid, page_url, Globs.formid),
1009         '<input type="hidden" value="show" name="action">',
1010         '<input name="delpasswd" type="hidden" value="****">',
1011         '<input name="delkey" type="hidden" value="">',
1012         '<input type="hidden" name="commentaction" value="delcomment%s">' % Globs.formid,
1013         '</form>',
1014         ]
1015     htmlresult.append(u'\n'.join(html))
1016 
1017     return u'\n'.join(htmlresult)
1018 
1019 
1020 def filtercomment(index='', name='', passwd=''):
1021     
1022     # filter by index
1023     if index:
1024         filteredlist1 = fetchcomments(index, index)
1025     else:
1026         filteredlist1 = fetchcomments()
1027     
1028     # filter by name
1029     filteredlist2 = []
1030     if name:
1031         for item in filteredlist1:
1032             if name == item['name']:
1033                 filteredlist2.append(item)
1034     else:
1035         filteredlist2 = filteredlist1
1036     
1037     # filter by password
1038     filteredlist3 = []
1039     if passwd:
1040         for item in filteredlist2:
1041             if passwd == item['passwd']:
1042                 filteredlist3.append(item)
1043     else:
1044         filteredlist3 = filteredlist2
1045 
1046     return filteredlist3
1047         
1048 
1049 def fetchcomments(startindex=1, endindex=9999):
1050     
1051     commentlist = []
1052     
1053     request = Globs.macro.request
1054     formatter = Globs.macro.formatter
1055     datapagename = Globs.datapagename
1056 
1057     pg = Page( request, datapagename )
1058     pagetext = pg.get_raw_body()
1059     
1060     regex = ur"""
1061 ^[\{]{3}\n
1062 ^(?P<icon>[^\n]*)\n
1063 ^(?P<name>[^\n]*)\n
1064 ^(?P<date>[^\n]*)\n\n
1065 ^(?P<text>
1066     \s*.*?
1067     (?=[\}]{3})
1068 )[\}]{3}[\n]*
1069 ^[#]{2}PASSWORD[ ](?P<passwd>[^\n]*)[\n]*
1070 ^[#]{2}LOGINUSER[ ](?P<loginuser>[^\n]*)[\n]*"""
1071 
1072     pattern = re.compile(regex, re.UNICODE + re.MULTILINE + re.VERBOSE + re.DOTALL)
1073     commentitems = pattern.findall(pagetext)
1074     
1075     cur_index = 0
1076     
1077     for item in commentitems:
1078         comment = {}
1079         cur_index += 1
1080         
1081         if cur_index < startindex:
1082             continue
1083         
1084         comment['index'] = cur_index
1085         
1086         custom_fields = item[0].split(',')
1087         
1088         comment['icon'] = custom_fields[0]
1089         
1090         if len(custom_fields) > 1:
1091             comment['markup'] = custom_fields[1].strip()
1092         else:
1093             comment['markup'] = ''
1094         
1095         comment['name'] = convertdelimeter(item[1], 1)
1096         comment['date'] = item[2]
1097         comment['text'] = convertdelimeter(item[3], 1)
1098         comment['passwd'] = item[4]
1099         comment['loginuser'] = item[5]
1100         
1101         # experimental
1102         comment['key'] = comment['date'].strip()
1103         
1104         commentlist.append(comment)
1105         
1106         if cur_index >= endindex:
1107             break
1108 
1109     return commentlist
1110 
1111 def deletecomment(macro, delkey, delpasswd):
1112     # Deletes a comment with given index and password
1113     
1114     request = Globs.macro.request
1115     formatter = Globs.macro.formatter
1116     datapagename = Globs.datapagename
1117     _ = request.getText
1118     
1119     if Params.encryptpass:
1120         from MoinMoin import user
1121         delpasswd = user.encodePassword(delpasswd)
1122     
1123     pg = PageEditor( request, datapagename )
1124     pagetext = pg.get_raw_body()
1125     
1126     regex = ur"""
1127 (?P<comblock>
1128     ^[\{]{3}\n
1129     ^(?P<icon>[^\n]*)\n
1130     ^(?P<name>[^\n]*)\n
1131     ^(?P<date>[^\n]*)[\n]+
1132     ^(?P<text>
1133         \s*.*?
1134         (?=[\}]{3})
1135     )[\}]{3}[\n]*
1136     ^[#]{2}PASSWORD[ ](?P<passwd>[^\n]*)[\n]*
1137     ^[#]{2}LOGINUSER[ ](?P<loginuser>[^\n]*)[\n$]*
1138 )"""
1139 
1140     pattern = re.compile(regex, re.UNICODE + re.MULTILINE + re.VERBOSE + re.DOTALL)
1141     commentitems = pattern.findall(pagetext)
1142     
1143     for item in commentitems:
1144         
1145         if delkey == item[3].strip():
1146             comauthor = item[2]
1147             if Globs.admin or (request.user.valid and request.user.name == comauthor) or delpasswd == item[5]:
1148                 newpagetext = pagetext.replace(item[0], '', 1)
1149                 
1150                 action = 'SAVE'
1151                 comment = 'Deleted comment by "%s"' % comauthor
1152                 trivial = 1
1153                 pg._write_file(newpagetext, action, u'PageComment modification at %s' % Globs.curpagename)
1154                 addLogEntry(request, 'COMDEL', Globs.curpagename, comment)
1155                 
1156                 msg = _('The comment is deleted.')
1157                 
1158                 # send notification mails
1159                 if Params.notify:
1160                     msg = msg + commentNotify(comment, trivial)
1161                 
1162                 message(msg)
1163                 
1164                 return
1165             else:
1166                 message(_('Sorry, wrong password.'))
1167                 return
1168                 
1169     message(_('No such comment'))
1170 
1171 
1172 def getAuthorFromCookie():
1173 
1174     import Cookie
1175     request = Globs.macro.request
1176     cookieauthor = ''
1177     
1178     try:
1179         cookie = Cookie.SimpleCookie(request.saved_cookie)
1180     except Cookie.CookieError:
1181         # ignore invalid cookies
1182         cookie = None
1183     
1184     if cookie and cookie.has_key('PG2AUTHOR'):
1185         cookieauthor = cookie['PG2AUTHOR'].value
1186     
1187     cookieauthor = decodeURI(cookieauthor)
1188     
1189     return cookieauthor
1190 
1191 
1192 def commentNotify(comment, trivial, comtext=''):
1193     
1194     request = Globs.macro.request
1195     
1196     if hasattr(request.cfg, 'mail_enabled'):
1197         mail_enabled = request.cfg.mail_enabled
1198     elif hasattr(request.cfg, 'mail_smarthost'):
1199         mail_enabled = request.cfg.mail_smarthost
1200     else:
1201         mail_enabled = ''
1202 
1203     if not mail_enabled:
1204         return ''
1205         
1206     _ = request.getText
1207     pg = PageEditor( request, Globs.curpagename )
1208     
1209     subscribers = pg.getSubscribers(request, return_users=1, trivial=trivial)
1210     if subscribers:
1211         # get a list of old revisions, and append a diff
1212 
1213         # send email to all subscribers
1214         results = [_('Status of sending notification mails:')]
1215         for lang in subscribers.keys():
1216             emails = map(lambda u: u.email, subscribers[lang])
1217             names  = map(lambda u: u.name,  subscribers[lang])
1218             mailok, status = sendNotification(pg, comtext, comment, emails, lang, trivial)
1219             recipients = ", ".join(names)
1220             results.append(_('[%(lang)s] %(recipients)s: %(status)s') % {
1221                 'lang': lang, 'recipients': recipients, 'status': status})
1222 
1223         # Return mail sent results. Ignore trivial - we don't have
1224         # to lie. If mail was sent, just tell about it.
1225         return '<p>\n%s\n</p> ' % '<br>'.join(results) 
1226 
1227     # No mail sent, no message.
1228     return ''
1229 
1230 def sendNotification(pg, comtext, comment, emails, email_lang, trivial):
1231     
1232     from MoinMoin import util, user
1233     request = Globs.macro.request
1234     
1235     _ = lambda s, formatted=True, r=request, l=email_lang: r.getText(s, formatted=formatted, lang=l)
1236 
1237     mailBody = _("Dear Wiki user,\n\n"
1238         'You have subscribed to a wiki page or wiki category on "%(sitename)s" for change notification.\n\n'
1239         "The following page has been changed by %(editor)s:\n"
1240         "%(pagelink)s\n\n", formatted=False) % {
1241             'editor': pg.uid_override or user.getUserIdentification(request),
1242             'pagelink': pg.request.getQualifiedURL(pg.url(request)),
1243             'sitename': pg.cfg.sitename or request.getBaseURL(),
1244     }
1245 
1246     if comment:
1247         mailBody = mailBody + \
1248             _("The comment on the change is:\n%(comment)s\n\n", formatted=False) % {'comment': comment}
1249 
1250     # append comment text
1251     if comtext:
1252         mailBody = mailBody + "%s\n%s\n" % (("-" * 78), comtext)
1253     
1254     return util.mail.sendmail(request, emails,
1255         _('[%(sitename)s] %(trivial)sUpdate of "%(pagename)s" by %(username)s', formatted=False) % {
1256             'trivial' : (trivial and _("Trivial ", formatted=False)) or "",
1257             'sitename': pg.cfg.sitename or "Wiki",
1258             'pagename': pg.page_name,
1259             'username': pg.uid_override or user.getUserIdentification(request),
1260         },
1261         mailBody, mail_from=pg.cfg.mail_from)
1262 
1263 
1264 
1265 def decodeURI(quotedstring):
1266 
1267     try:
1268         unquotedstring = wikiutil.url_unquote(quotedstring)
1269     except AttributeError:
1270         # for compatibility with old versions
1271         unquotedstring = url_unquote(quotedstring)
1272         
1273     return unquotedstring
1274 
1275 
1276 def url_unquote(s, want_unicode=True):
1277     """
1278     From moinmoin 1.5
1279     
1280     Wrapper around urllib.unquote doing the encoding/decoding as usually wanted:
1281     
1282     @param s: the string to unquote (can be str or unicode, if it is unicode,
1283               config.charset is used to encode it before calling urllib)
1284     @param want_unicode: for the less usual case that you want to get back
1285                          str and not unicode, set this to False.
1286                          Default is True.
1287     """
1288     import urllib
1289     
1290     if isinstance(s, unicode):
1291         s = s.encode(config.charset) # ascii would also work
1292     s = urllib.unquote(s)
1293     if want_unicode:
1294         s = s.decode(config.charset)
1295     return s
1296     
1297     
1298 def addLogEntry(request, action, pagename, msg):
1299     # Add an entry to the edit log on adding comments.
1300     from MoinMoin.logfile import editlog
1301     t = wikiutil.timestamp2version(time.time())
1302     msg = unicode(msg)
1303 
1304     pg = Page( request, pagename )
1305     #rev = pg.current_rev()
1306     rev = 99999999
1307 
1308     # TODO: for now we simply write 2 logs, maybe better use some multilog stuff
1309     # Write to global log
1310     log = editlog.EditLog(request)
1311     log.add(request, t, rev, action, pagename, request.remote_addr, '', msg)
1312 
1313     # Write to local log
1314     log = editlog.EditLog(request, rootpagename=pagename)
1315     log.add(request, t, rev, action, pagename, request.remote_addr, '', msg)
1316     
1317 def getsmileymarkuplist(defaulticon):
1318     
1319     html = [
1320         u'Smiley: <select name="comicon">',
1321         u'  <option value=""></option>',
1322         ]
1323     
1324     for smiley in config.smileys.keys():
1325         if defaulticon.strip() == smiley:
1326             html.append(u'  <option selected>%s</option>' % wikiutil.escape(smiley))
1327         else:
1328             html.append(u'  <option>%s</option>' % wikiutil.escape(smiley))
1329 
1330     html.append(u'</select>')
1331     
1332     return u'\n'.join(html)
1333     
1334 def getsmileymarkupradio(defaulticon):
1335     
1336     smileys = Globs.smileys
1337     html = []
1338     
1339     for smiley in smileys:
1340         if defaulticon.strip() == smiley:
1341             html.append(u'<input type="radio" name="comicon" value="%s" checked>%s ' % (wikiutil.escape(smiley), getsmiley(smiley)) )
1342         else:
1343             html.append(u'<input type="radio" name="comicon" value="%s">%s ' % (wikiutil.escape(smiley), getsmiley(smiley)) )
1344 
1345     html.append(u'</select>')
1346     
1347     return u'\n'.join(html)
1348 
1349 
1350 def getMarkupText(lines):
1351     request = Globs.macro.request
1352     formatter = Globs.macro.formatter
1353     
1354     markup = Globs.markupforbidden
1355     
1356     for regex in markup.keys():
1357         pattern = re.compile(regex, re.UNICODE + re.VERBOSE + re.MULTILINE)
1358         lines, nchanges = pattern.subn(markup[regex], lines)
1359         
1360         #if nchanges:
1361         #    debug(regex)
1362         
1363     out = StringIO.StringIO()
1364     request.redirect(out)
1365     wikiizer = wiki.Parser(lines, request)
1366     wikiizer.format(formatter)
1367     targettext = out.getvalue()
1368     request.redirect()
1369     del out
1370     
1371     return targettext    
1372     
1373     
1374 def nicepass(alpha=3,numeric=1):
1375     """
1376     returns a human-readble password (say rol86din instead of 
1377     a difficult to remember K8Yn9muL ) 
1378     """
1379     import string
1380     import random
1381     vowels = ['a','e','i','o','u']
1382     consonants = [a for a in string.ascii_lowercase if a not in vowels]
1383     digits = string.digits
1384     
1385     ####utility functions
1386     def a_part(slen):
1387         ret = ''
1388         for i in range(slen):			
1389             if i%2 ==0:
1390                 randid = random.randint(0,20) #number of consonants
1391                 ret += consonants[randid]
1392             else:
1393                 randid = random.randint(0,4) #number of vowels
1394                 ret += vowels[randid]
1395         return ret
1396     
1397     def n_part(slen):
1398         ret = ''
1399         for i in range(slen):
1400             randid = random.randint(0,9) #number of digits
1401             ret += digits[randid]
1402         return ret
1403         
1404     #### 	
1405     fpl = alpha/2		
1406     if alpha % 2 :
1407         fpl = int(alpha/2) + 1 					
1408     lpl = alpha - fpl	
1409     
1410     start = a_part(fpl)
1411     mid = n_part(numeric)
1412     end = a_part(lpl)
1413     
1414     # return "%s%s%s" % (start,mid,end)
1415     return "%s%s%s" % (start,end,mid)

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] (2007-05-01 16:03:36, 46.5 KB) [[attachment:PageComment2-099-rg.py]]
  • [get | view] (2007-05-01 16:03:44, 1.6 KB) [[attachment:PageComment2-981-099-rg.diff.gz]]
  • [get | view] (2007-01-07 06:44:08, 1.2 KB) [[attachment:PageCommentSF.css]]
  • [get | view] (2007-01-08 12:50:58, 47.2 KB) [[attachment:PageCommentSF.py]]
  • [get | view] (2007-01-08 12:51:26, 17.3 KB) [[attachment:sf.patch]]
 All files | Selected Files: delete move to page copy to page

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