Attachment 'PageComment2-096.py'
Download 1 # -*- coding: iso-8859-1 -*-
2 """
3 PageComment2.py Version 0.96 Nov. 29, 2005
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://cds.icu.ac.kr/~silee/
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 2. e.g., rows=2
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 Change Log
75
76 - Nov. 29, 2005 - Version 0.96
77 - some format parameters are added
78 - random password feature is added
79
80 - Nov. 20, 2005 - Version 0.95
81 - some minor bugs are fixed
82
83 - Nov. 20, 2005 - Version 0.94
84 - some parameters are added
85 - some minor bugs are fixed
86
87 - Nov. 19, 2005 - Version 0.92
88 - some minor bugs are fixed
89 - 'olderfirst' parameter replaced with 'newerfirst'
90
91 - Nov. 19, 2005 - Version 0.91
92 - some parameters are added
93 - validates smiley markup
94 - modified view
95
96 - Nov. 18, 2005 - Version 0.90 (Release 2)
97 - No text data file support any more: Comment is stored in the sub wiki page.
98 - (does not compatible with Release 1: PageComment.py)
99 - Custom icon (smiley) can be inserted
100 - Pre-fill the name input field with his/her login name
101 - Logs at add/remove comments
102 - Added some parameters
103
104 - Oct. 08, 2005 - Version 0.82
105 - Changed the directory the data file stored to be secured
106
107 - Oct. 07, 2005 - Version 0.81
108 - Unicode encoding related bugs in deletecomment function are patched.
109 - Instruction bugs are patched.
110
111 - Oct. 06, 2005 - Version 0.80
112 - The initial version is released.
113
114
115 Notes
116
117 - 'Gallery.py' developed by Simon Ryan has inspired this macro.
118 - Thanks to many of the MoinMoin users for valuable comments.
119 - Visit http://moinmoin.wikiwikiweb.de/MacroMarket/PageComment2 for more detail
120
121 """
122
123 from MoinMoin import config, wikiutil
124 import StringIO, time, re
125 from MoinMoin.Page import Page
126 from MoinMoin.PageEditor import PageEditor
127 from MoinMoin.parser import wiki
128
129
130 class Globs:
131 # A quick place to plonk those shared variables
132
133 adminmsg = ''
134 datapagename = ''
135 pagename = ''
136 curpagename = ''
137 cursubname = ''
138 admin = ''
139 macro = ''
140 defaultacl = ''
141 defaulticon = ''
142 formid = 0
143 smileys = []
144
145 class Params:
146
147 rows = 0
148 cols = 0
149 maxlength = 0
150 newerfirst = 0
151 tablewidth = ''
152 commentfirst = 0
153 pagename = ''
154 commentonly = 0
155 inputonly = 0
156 countonly = 0
157 section = ''
158 articleview = 0
159
160
161 def execute(macro, args):
162
163 # INITIALIZATION ----------------------------------------
164 getparams(args)
165 setglobalvalues(macro)
166
167 # internal variables
168 request = macro.request
169 _ = request.getText
170
171 if not Globs.pagename == Globs.curpagename:
172 if not macro.request.user.may.read(Globs.pagename):
173 return macro.formatter.rawHTML(u'PageComment: %s' % _('You are not allowed to view this page.'))
174 elif not Page(request, Globs.pagename).exists():
175 return macro.formatter.rawHTML(u'PageComment: %s' % _('This page is already deleted or was never created!'))
176
177
178 if Params.countonly:
179 html = len(fetchcomments())
180 return macro.formatter.rawHTML('%s' % html)
181
182 datapagename = Globs.datapagename
183
184 # form vals
185 comicon = Globs.defaulticon
186 comauthor = ''
187 comtext = ''
188 compasswd = ''
189 comrev = 0
190 comautopass = ''
191
192 addcommand = u'addcomment%d' % Globs.formid
193 delcommand = u'delcomment%d' % Globs.formid
194
195 action = macro.form.get('commentaction', [''])[0]
196
197 if action == addcommand:
198
199 # process form input for comment add
200 form_fields = {'comicon': Globs.defaulticon, 'comauthor': '', 'comtext': '', 'compasswd': '', 'comrev': 0, 'autopasswd': ''}
201 required_fields = {'comauthor': _('Name'), 'comtext': _('Text'), 'compasswd': _('Password'), 'comrev': 'Rev. #'}
202
203 formvals, missingfields = getforminput(macro.form, form_fields, required_fields)
204
205 comicon = formvals['comicon']
206 comauthor = formvals['comauthor']
207 comtext = formvals['comtext']
208 compasswd = formvals['compasswd']
209 comrev = formvals['comrev']
210 comautopass = formvals['autopasswd']
211
212 if not len(missingfields) == len(required_fields):
213 if not missingfields:
214 flag = addcomment(macro, comicon, comauthor, comtext, compasswd, comrev, comautopass)
215
216 if flag:
217 comicon = Globs.defaulticon
218 comauthor = ''
219 comtext = ''
220 compasswd = ''
221 comrev = 0
222 else:
223 message( _('Required attribute "%(attrname)s" missing') % { 'attrname': u', '.join(missingfields) } )
224
225 elif action == delcommand:
226
227 # process form input for comment delete
228 form_fields = {'delkey': '', 'delpasswd': ''}
229 required_fields = {'delkey': 'Comment Key', 'delpasswd': 'Password'}
230
231 formvals, missingfields = getforminput(macro.form, form_fields, required_fields)
232
233 delkey = formvals['delkey']
234 delpasswd = formvals['delpasswd']
235
236 if not len(missingfields) == len(required_fields):
237 if not missingfields:
238 deletecomment(macro, delkey, delpasswd)
239 else:
240 message( _('Required attribute "%(attrname)s" missing') % { 'attrname': u', '.join(missingfields) } )
241
242 # format output
243 html = []
244
245 html.append(u'<div id="pagecomment">')
246 html.append(u'<a name="pagecomment%d"></a>' % Globs.formid)
247 html.append(u'<table class="pagecomment" %s>' % Params.tablewidth)
248 html.append(u'<tr><td colspan="5" style="border-width: 0px;">')
249 html.append(u'<font color="#aa0000">%s</font>' % Globs.adminmsg)
250 html.append(u'</td></tr>')
251
252 if Params.commentfirst:
253 html.append(showcommentsection())
254 html.append(commentformsection(comauthor, comtext, compasswd, comicon, comrev, comautopass))
255 else:
256 html.append(commentformsection(comauthor, comtext, compasswd, comicon, comrev, comautopass))
257 html.append(showcommentsection())
258
259 html.append(u'</table>')
260 html.append(u'</div>')
261
262 return macro.formatter.rawHTML(u'\n'.join(html))
263
264
265 def commentformsection(comauthor, comtext, compasswd, comicon, comrev, autopass):
266 html = []
267
268 if not Params.commentonly:
269 html.append(u'<tr><td style="border-width: 0px;" colspan="5">')
270 html.append(u'<table class="commentform"><tr><td style="border-width: 1px;">')
271 html.append(commentform(comauthor, comtext, compasswd, comicon, comrev, autopass))
272 html.append(u'</td></tr></table>')
273 html.append(u'</td></tr>')
274
275 return u'\n'.join(html)
276
277
278 def showcommentsection():
279 html = []
280 if (not Params.inputonly) or Globs.admin:
281 html.append(deleteform())
282 html.append(showcomment())
283 else:
284 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>')
285
286 return u'\n'.join(html)
287
288 def getforminput(form, inputfields, requiredfields):
289
290 formvals = {}
291 missingfields = []
292
293 for item in inputfields.keys():
294 formvals[item] = form.get(item, [inputfields[item]])[0]
295 if (not formvals[item]) and (item in requiredfields):
296 missingfields.append(requiredfields[item])
297
298 return formvals, missingfields
299
300 def getparams(args):
301 # process arguments
302
303 params = {}
304 if args:
305 # Arguments are comma delimited key=value pairs
306 sargs = args.split(',')
307
308 for item in sargs:
309 sitem = item.split('=')
310
311 if len(sitem) == 2:
312 key, value = sitem[0], sitem[1]
313 params[key.strip()] = value.strip()
314
315 Params.pagename = params.get('pagename', '')
316
317 Params.section = params.get('section', '')
318 if Params.section:
319 Params.section = getescapedsectionname(Params.section)
320
321 try:
322 Params.inputonly = int(params.get('inputonly', 0))
323 except ValueError:
324 Params.inputonly = 0
325
326 try:
327 Params.commentonly = int(params.get('commentonly', 0))
328 except ValueError:
329 Params.commentonly = 0
330
331 try:
332 Params.countonly = int(params.get('countonly', 0))
333 except ValueError:
334 Params.countonly = 0
335
336 try:
337 Params.newerfirst = int(params.get('newerfirst', 0))
338 except ValueError:
339 Params.newerfirst = 0
340
341 try:
342 Params.commentfirst = int(params.get('commentfirst', 0))
343 except ValueError:
344 Params.commentfirst = 0
345
346 try:
347 Params.articleview = int(params.get('articleview', 0))
348 except ValueError:
349 Params.articleview = 0
350
351 try:
352 Params.smileylist = int(params.get('smileylist', 0))
353 except ValueError:
354 Params.smileylist = 0
355
356 try:
357 Params.nosmiley = int(params.get('nosmiley', 0))
358 except ValueError:
359 Params.nosmiley = 0
360
361 try:
362 Params.rows = int(params.get('rows', 2))
363 except ValueError:
364 Params.rows = 2
365
366 try:
367 Params.cols = int(params.get('cols', 60))
368 except ValueError:
369 Params.cols = 60
370
371 try:
372 Params.maxlength = int(params.get('maxlength', 0))
373 except ValueError:
374 Params.maxlength = 0
375
376 Params.tablewidth = params.get('tablewidth', '')
377 if Params.tablewidth:
378 Params.tablewidth = ' width="%s" ' % Params.tablewidth
379
380 def setglobalvalues(macro):
381
382 # Global variables
383 Globs.macro = macro
384 Globs.defaultacl = u'#acl All:'
385 Globs.adminmsg = ''
386 Globs.defaulticon = ''
387 Globs.smileys = [':)', ':))', ':(', ';)', ':\\', '|)', 'X-(', 'B)']
388
389 Globs.curpagename = macro.formatter.page.page_name
390
391 if Params.pagename:
392 Globs.pagename = Params.pagename
393 else:
394 Globs.pagename = Globs.curpagename
395
396 Globs.cursubname = Globs.curpagename.split('/')[-1]
397 Globs.datapagename = u'%s/%s%s' % (Globs.pagename, 'PageCommentData', Params.section)
398
399 # Figure out if we have delete privs
400 try:
401 if macro.request.user.may.delete(Globs.datapagename):
402 Globs.admin = 'true'
403 else:
404 Globs.admin = ''
405 except AttributeError:
406 Globs.admin = ''
407 pass
408
409 # set form id
410
411 formid = int(macro.form.get('formid', ['0'])[0])
412 formid += 1
413
414 Globs.formid = formid
415 macro.form['formid'] = ['%d' % formid]
416
417 def message(astring):
418 Globs.adminmsg = u'PageComment: %s\n' % astring
419
420
421 def commentform(tmpauthor, tmptext, tmppasswd, tmpicon, comrev, tmpautopass):
422 # A form for posting a new comment
423 request = Globs.macro.request
424 datapagename = Globs.datapagename
425 _ = request.getText
426
427 cellstyle = u'border-width: 0px; vertical-align: middle; font-size: 0.9em;'
428
429 pg = Page( request, datapagename )
430
431 if pg.exists():
432 comrev = pg.current_rev()
433 else:
434 comrev = 0
435
436 if not Params.nosmiley:
437 if not Params.smileylist:
438 iconlist = getsmileymarkupradio(tmpicon)
439 else:
440 iconlist = getsmileymarkuplist(tmpicon)
441 else:
442 iconlist = ''
443
444 initName = ''
445 initPass = ''
446 initText = ''
447
448 if not tmpauthor:
449 import socket
450 host = request.remote_addr
451
452 try:
453 hostname = socket.gethostbyaddr(host)[0]
454 except socket.error:
455 hostname = host
456
457 tmpauthor = hostname.split('.')[0]
458 initName = tmpauthor
459
460 if not tmppasswd:
461 tmppasswd = nicepass()
462 initPass = tmppasswd
463 elif tmpautopass and tmpautopass == tmppasswd:
464 tmppasswd = nicepass()
465 initPass = tmppasswd
466
467 if not tmptext:
468 tmptext = u'Add your comment'
469 initText = tmptext
470 elif tmptext and tmptext == u'Add your comment':
471 initText = tmptext
472
473 if request.user.valid:
474 html1 = [
475 u'<input type="hidden" value="%s" name="comauthor">' % request.user.name,
476 u'<input type="hidden" value="*" name="compasswd">',
477 ]
478 else:
479 html1 = [
480 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': initName, 'cellstyle': cellstyle, 'author': tmpauthor },
481 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': initPass, 'passwd': tmppasswd },
482 u'<input type="hidden" value="%s" name="autopasswd">' % initPass,
483 ]
484
485 html1 = u'\n'.join(html1)
486 scripthtml = u'onfocus="if (this.value==\'%(msg)s\') {this.value=\'\';};" onblur="if (this.value==\'\') {this.value=\'%(msg)s\';};"' % {'msg': initText }
487 html2 = [
488 u'<form action="%s#pagecomment%d" name="comment" METHOD="POST">' % (Globs.cursubname, Globs.formid),
489 u'<table class="addcommentform">',
490 u'<tr>',
491 u'<td style="%s"><textarea name="comtext" rows="%d" cols="%d" style="font-size: 9pt;" ' % (cellstyle, Params.rows, Params.cols),
492 u'%s>%s</textarea></td>' % (scripthtml, tmptext),
493 u'<td style="%s vertical-align: bottom;"><input type="submit" value="%s" style="font-size: 9pt; height:3em;"></td>' % (cellstyle, _('Save')),
494 u'</tr>',
495 u'<tr><td style="%s">' % cellstyle,
496 u'%s' % html1,
497 u'%s' % iconlist,
498 u'</td></tr>',
499 u'</table>',
500 u'<input type="hidden" name="action" value="show" >',
501 u'<input type="hidden" name="comrev" value="%s">' % comrev,
502 u'<input type="hidden" name="commentaction" value="addcomment%d">' % Globs.formid,
503 u'</form>',
504 ]
505
506
507 return u'\n'.join(html2)
508
509 def addcomment(macro, comicon, comauthor, comtext, compasswd, comrev, comautopass):
510 # Add a comment with inputs
511
512 request = Globs.macro.request
513 cfg = request.cfg
514 _ = request.getText
515
516 # check input
517 if comicon and (not comicon in config.smileys.keys()):
518 message('Please use smiley markup only')
519 return 0
520
521 if Params.maxlength and (len(comtext) > Params.maxlength):
522 message('Comment text is limited to %d characters. (%d characters now)' % (Params.maxlength, len(comtext)) )
523 return 0
524
525 if not comtext.strip() or comtext == u'Add your comment':
526 message('Please fill the comment text')
527 return 0
528
529 datapagename = Globs.datapagename
530
531 pg = PageEditor( request, datapagename )
532 pagetext = pg.get_raw_body()
533
534 comtext = convertdelimiter(comtext)
535
536 if request.user.valid:
537 comloginuser = 'TRUE'
538 comauthor = request.user.name
539 else:
540 comloginuser = ''
541 comauthor = convertdelimiter(comauthor)
542
543 newcomment = [
544 u'{{{',
545 u'%s' % comicon,
546 u'%s' % comauthor,
547 u'%s' % time.strftime(cfg.datetime_fmt, time.localtime(time.time())),
548 u'',
549 u'%s' % comtext,
550 u'}}}',
551 u'##PASSWORD %s' % compasswd,
552 u'##LOGINUSER %s' % comloginuser,
553 ]
554
555 newpagetext = u'%s\n\n%s' % (pagetext, u'\n'.join(newcomment))
556
557 if not pg.exists():
558 action = 'SAVENEW'
559 defaultacl = Globs.defaultacl
560 warnmessages = '\'\'\'\'\'DO NOT EDIT THIS PAGE!!\'\'\' This page is automatically generated by Page``Comment macro.\'\'\n----'
561 newpagetext = u'%s\n%s\n%s' % (defaultacl, warnmessages, newpagetext)
562 else:
563 action = 'SAVE'
564
565 newpagetext = pg.normalizeText( newpagetext )
566
567 comment = 'New comment by "%s"' % comauthor
568 pg._write_file(newpagetext, action, u'Modified by PageComment macro')
569 addLogEntry(request, 'COMNEW', Globs.pagename, comment)
570
571 # message(_('The comment is added'))
572 msg = _('Thank you for your changes. Your attention to detail is appreciated.')
573
574 if comautopass and comautopass == compasswd:
575 msg2 = u'<i>You did not enter a password. A random password has been generated for you: <b>%s</b></i>' % comautopass
576 msg = u'%s<br>%s' % (msg, msg2)
577
578 message(msg)
579 return 1
580
581 def showcomment():
582
583 request = Globs.macro.request
584 _ = request.getText
585
586 commentlist = fetchcomments()
587
588 if Params.newerfirst:
589 commentlist.reverse()
590
591 html = []
592 cur_index = 0
593
594 if Params.articleview:
595 cellstyle = u'border-width: 1px; border-color: #cccccc; vertical-align: top; font-size: 9pt;'
596 htmlcomment = [
597 u'<tr><td colspan="5" class="commentbox" style="border-width: 0px;"><table width="99%%">',
598 u'<tr><td colspan="5" class="commenttext" style="%(cellstyle)s">%(text)s</td></tr>',
599 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>',
600 u'</table></td></tr>',
601 ]
602 else:
603 cellstyle = u'border-width: 0px; border-top-width: 1px; vertical-align: top; font-size: 9pt;'
604 htmlcomment = [
605 u'<tr><td class="commenticon" style="%(cellstyle)s">%(icon)s</td>',
606 u'<td class="commentauthor" style="%(cellstyle)s">%(author)s</td>',
607 u'<td style="%(cellstyle)s width: 10px;"> </td>',
608 u'<td class="commenttext" style="%(cellstyle)s">%(text)s</td>',
609 u'<td class="commentdate" style="%(cellstyle)s text-align: right; font-size: 8pt; " nowrap>%(date)s%(delform)s</td></tr>',
610 ]
611
612 htmlcommentdel_admin = [
613 u' <font style="font-size: 8pt;">',
614 u'<a style="color: #aa0000;" href="javascript: requesttodeleteadmin%(formid)d(document.delform%(formid)d, \'%(key)s\');" title="%(msg)s">X</a>',
615 u'</font>',
616 ]
617
618 htmlcommentdel_guest = [
619 u' <font style="font-size: 8pt;">',
620 u'<a style="color: #aa0000;" href="javascript: requesttodelete%(formid)d(document.delform%(formid)d, \'%(key)s\');" title="%(msg)s">X</a>',
621 u'</font>',
622 ]
623
624 for item in commentlist:
625 if Globs.admin or (item['loginuser'] and request.user.valid and request.user.name == item['name']):
626 htmlcommentdel = htmlcommentdel_admin
627 elif item['loginuser']:
628 htmlcommentdel = ''
629 else:
630 htmlcommentdel = htmlcommentdel_guest
631
632 htmlcommentdel = u'\n'.join(htmlcommentdel) % {
633 'formid': Globs.formid,
634 'key': item['key'],
635 'msg': _('Delete')
636 }
637
638 htmlcommentitem = u'\n'.join(htmlcomment) % {
639 'cellstyle': cellstyle,
640 'icon': getsmiley(item['icon']),
641 'author': converttext(item['name']),
642 'text': converttext(item['text']),
643 'date': item['date'],
644 'delform': htmlcommentdel
645 }
646
647 html.append(htmlcommentitem)
648
649 return u'\n'.join(html)
650
651 def getescapedsectionname(targettext):
652 regex = r'\W'
653 pattern = re.compile(regex, re.UNICODE)
654 sectionname = pattern.sub('', targettext)
655
656 return sectionname
657
658
659 def getsmiley(markup):
660
661 if markup in config.smileys.keys():
662 formatter = Globs.macro.formatter
663 return formatter.smiley(markup)
664 else:
665 return ''
666
667
668 def converttext(targettext):
669 # Converts some special characters of html to plain-text style
670 # What else to handle?
671
672 # targettext = targettext.strip()
673 targettext = targettext.replace(u'&', '&')
674 targettext = targettext.replace(u'>', '>')
675 targettext = targettext.replace(u'<', '<')
676 targettext = targettext.replace(u'\n', '<br>')
677 targettext = targettext.replace(u'"', '"')
678 targettext = targettext.replace(u'\t', ' ')
679 targettext = targettext.replace(u' ', ' ')
680
681 return targettext
682
683 def convertdelimiter(targettext):
684 # Converts delimeter to other string to avoid a crash
685
686 targettext = targettext.replace('{{{', '{ { {')
687 targettext = targettext.replace('}}}', '} } }')
688
689 return targettext
690
691
692 def deleteform():
693 # Javascript codes for deleting or restoring a comment
694
695 request = Globs.macro.request
696 _ = request.getText
697
698 htmlresult = []
699
700 html = [
701 '<script language="javascript">',
702 '<!--',
703 ]
704 htmlresult.append(u'\n'.join(html))
705
706 html = [
707 ' function requesttodeleteadmin%d(delform, comkey) {' % Globs.formid,
708 ' if (confirm("%s")) {;' % _('Really delete this page?'),
709 ' delform.delkey.value = comkey;',
710 ' delform.delpasswd.value = "****";',
711 ' delform.submit();',
712 ' }',
713 ' }',
714 ' function requesttodelete%d(delform, comkey) {' % Globs.formid,
715 ' var passwd = prompt("%s:", "");' % _('Please specify a password!'),
716 ' if(!(passwd == "" || passwd == null)) {',
717 ' delform.delkey.value = comkey;',
718 ' delform.delpasswd.value = passwd;',
719 ' delform.submit();',
720 ' }',
721 ' }',
722 ]
723
724 htmlresult.append(u'\n'.join(html))
725
726 html = [
727 '//-->',
728 '</script>',
729 '<form name="delform%d" action="%s#pagecomment%d" METHOD="post">' % (Globs.formid, Globs.cursubname, Globs.formid),
730 '<input type="hidden" value="show" name="action">',
731 '<input name="delpasswd" type="hidden" value="****">',
732 '<input name="delkey" type="hidden" value="">',
733 '<input type="hidden" name="commentaction" value="delcomment%s">' % Globs.formid,
734 '</form>',
735 ]
736 htmlresult.append(u'\n'.join(html))
737
738 return u'\n'.join(htmlresult)
739
740
741 def filtercomment(index='', name='', passwd=''):
742
743 # filter by index
744 if index:
745 filteredlist1 = fetchcomments(index, index)
746 else:
747 filteredlist1 = fetchcomments()
748
749 # filter by name
750 filteredlist2 = []
751 if name:
752 for item in filteredlist1:
753 if name == item['name']:
754 filteredlist2.append(item)
755 else:
756 filteredlist2 = filteredlist1
757
758 # filter by password
759 filteredlist3 = []
760 if passwd:
761 for item in filteredlist2:
762 if passwd == item['passwd']:
763 filteredlist3.append(item)
764 else:
765 filteredlist3 = filteredlist2
766
767 return filteredlist3
768
769
770 def fetchcomments(startindex=1, endindex=9999):
771
772 commentlist = []
773
774 request = Globs.macro.request
775 formatter = Globs.macro.formatter
776 datapagename = Globs.datapagename
777
778 pg = Page( request, datapagename )
779 pagetext = pg.get_raw_body()
780
781 regex = r'^(#acl\s*.*)$'
782 pattern = re.compile(regex, re.UNICODE + re.MULTILINE + re.IGNORECASE)
783 pagetext = pattern.sub('', pagetext)
784
785 regex = ur"""
786 ^[\{]{3}\n
787 ^(?P<icon>[^\n]*)\n
788 ^(?P<name>[^\n]*)\n
789 ^(?P<date>[^\n]*)\n\n
790 ^(?P<text>\s*.*?[^}]*)[\}]{3}[\n]*
791 ^[#]{2}PASSWORD[ ](?P<passwd>[^\n]*)[\n]*
792 ^[#]{2}LOGINUSER[ ](?P<loginuser>[^\n]*)[\n]*"""
793
794 pattern = re.compile(regex, re.UNICODE + re.MULTILINE + re.VERBOSE)
795 commentitems = pattern.findall(pagetext)
796
797 cur_index = 0
798
799 for item in commentitems:
800 comment = {}
801 cur_index += 1
802
803 if cur_index < startindex:
804 continue
805
806 comment['index'] = cur_index
807 comment['icon'] = item[0]
808 comment['name'] = item[1]
809 comment['date'] = item[2]
810 comment['text'] = item[3]
811 comment['passwd'] = item[4]
812 comment['loginuser'] = item[5]
813
814 # experimental
815 comment['key'] = comment['date'].strip()
816
817 commentlist.append(comment)
818
819 if cur_index >= endindex:
820 break
821
822 return commentlist
823
824 def deletecomment(macro, delkey, delpasswd):
825 # Deletes a comment with given index and password
826
827 request = Globs.macro.request
828 formatter = Globs.macro.formatter
829 datapagename = Globs.datapagename
830 _ = request.getText
831
832 pg = PageEditor( request, datapagename )
833 pagetext = pg.get_raw_body()
834
835 regex = ur"""
836 (?P<comblock>^[\{]{3}\n
837 ^(?P<icon>[^\n]*)\n
838 ^(?P<name>[^\n]*)\n
839 ^(?P<date>[^\n]*)[\n]+
840 ^(?P<text>\s*.*?[^}]*)[\}]{3}[\n]*
841 ^[#]{2}PASSWORD[ ](?P<passwd>[^\n]*)[\n]*
842 ^[#]{2}LOGINUSER[ ](?P<loginuser>[^\n]*)[\n$]*)"""
843
844 pattern = re.compile(regex, re.UNICODE + re.MULTILINE + re.VERBOSE)
845 commentitems = pattern.findall(pagetext)
846
847 for item in commentitems:
848
849 if delkey == item[3].strip():
850 comauthor = item[2]
851 if Globs.admin or (request.user.valid and request.user.name == comauthor) or delpasswd == item[5]:
852 newpagetext = pagetext.replace(item[0], '', 1)
853
854 action = 'SAVE'
855 comment = 'comment deleted by "%s"' % comauthor
856 pg._write_file(newpagetext, action, u'Modified by PageComment macro')
857 addLogEntry(request, 'COMDEL', Globs.pagename, comment)
858
859 message(_('The comment is deleted'))
860
861 return
862 else:
863 message(_('Sorry, wrong password.'))
864 return
865
866 message(_('No such comment'))
867
868
869 def addLogEntry(request, action, pagename, msg):
870 # Add an entry to the edit log on adding comments.
871 from MoinMoin.logfile import editlog
872 t = wikiutil.timestamp2version(time.time())
873 msg = unicode(msg)
874
875 # TODO: for now we simply write 2 logs, maybe better use some multilog stuff
876 # Write to global log
877 log = editlog.EditLog(request)
878 log.add(request, t, 99999999, action, pagename, request.remote_addr, msg)
879
880 # Write to local log
881 log = editlog.EditLog(request, rootpagename=pagename)
882 log.add(request, t, 99999999, action, pagename, request.remote_addr, msg)
883
884 def getsmileymarkuplist(defaulticon):
885
886 html = [
887 u'Smiley: <select name="comicon">',
888 u' <option value=""></option>',
889 ]
890
891 for smiley in config.smileys.keys():
892 if defaulticon.strip() == smiley:
893 html.append(u' <option selected>%s</option>' % wikiutil.escape(smiley))
894 else:
895 html.append(u' <option>%s</option>' % wikiutil.escape(smiley))
896
897 html.append(u'</select>')
898
899 return u'\n'.join(html)
900
901 def getsmileymarkupradio(defaulticon):
902
903 smileys = Globs.smileys
904 html = []
905
906 for smiley in smileys:
907 if defaulticon.strip() == smiley:
908 html.append(u'<input type="radio" name="comicon" value="%s" checked>%s ' % (wikiutil.escape(smiley), getsmiley(smiley)) )
909 else:
910 html.append(u'<input type="radio" name="comicon" value="%s">%s ' % (wikiutil.escape(smiley), getsmiley(smiley)) )
911
912 html.append(u'</select>')
913
914 return u'\n'.join(html)
915
916
917
918 def nicepass(alpha=2,numeric=2):
919 """
920 returns a human-readble password (say rol86din instead of
921 a difficult to remember K8Yn9muL )
922 """
923 import string
924 import random
925 vowels = ['a','e','i','o','u']
926 consonants = [a for a in string.ascii_lowercase if a not in vowels]
927 digits = string.digits
928
929 ####utility functions
930 def a_part(slen):
931 ret = ''
932 for i in range(slen):
933 if i%2 ==0:
934 randid = random.randint(0,20) #number of consonants
935 ret += consonants[randid]
936 else:
937 randid = random.randint(0,4) #number of vowels
938 ret += vowels[randid]
939 return ret
940
941 def n_part(slen):
942 ret = ''
943 for i in range(slen):
944 randid = random.randint(0,9) #number of digits
945 ret += digits[randid]
946 return ret
947
948 ####
949 fpl = alpha/2
950 if alpha % 2 :
951 fpl = int(alpha/2) + 1
952 lpl = alpha - fpl
953
954 start = a_part(fpl)
955 mid = n_part(numeric)
956 end = a_part(lpl)
957
958 return "%s%s%s" % (start,mid,end)
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.