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