Attachment 'PageComment2-097.py'

Download

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