Attachment 'PageComment2-0981.py'

Download

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