Attachment 'PageComment-080.py'
Download 1 # -*- coding: iso-8859-1 -*-
2 """
3 PageComment.py Version 0.80 2005. 10. 06.
4
5 This macro gives a form to post a new comment to the page and 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: [[PageComment]]
11
12 Features:
13
14 Simple usage, just put [[PageComment]] on any page.
15 Lets anonymous users post a new comment with a 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 - to restore a deleted comment
21 - to show the host IP address where a comment is posted
22
23
24 To do:
25
26 To handle the index overflow (*)
27 To pre-fill the author input with his/her login name (*)
28 To provide selective options for:
29 - formatting text or form (*)
30 - selecting columns to be shown (*)
31 - selecting a list of comments by a given ID not just page name (**)
32 To encrypt/decrypt the entered passwords (****)
33 To give more friendly message or instructions ;) (*)
34 To provide an option to remove a comment permanently (***)
35
36
37 Notes
38
39 'Gallery.py' developed by Simon Ryan has inspired this macro.
40
41
42 """
43
44 __author__ = "Seungik Lee"
45 __version__ = "0.80"
46
47 from MoinMoin import config, wikiutil
48 import string, os, StringIO, time
49 import codecs
50
51 class Globs:
52 # A quick place to plonk those shared variables
53 adminmsg=''
54 attachmentdir=''
55 pagename=''
56 admin=''
57 baseurl=''
58 welcome_msg='Please leave your comment for this page.'
59
60 def message(astring):
61 Globs.adminmsg='<font style="color: #aa0000; font-size: 0.9em;">PageComment: '+astring+'</font>\n'
62
63
64 def commentform(tmpauthor, tmptext, tmppasswd):
65 # A form for posting a new comment
66
67 html = [
68 u'<div id="commentform">',
69 u'<table id=commentform>',
70 u'<form action='+Globs.subname+' name=comment METHOD=POST>',
71 u'<tr><td>Name</td><td>Comment Text</td><td>Password</td><td></td></tr>',
72 u'<tr><td><input type=text size=10 maxlength=20 name=comauthor value="' + tmpauthor + '"></td>',
73 #u'<td><textarea name="comtext" rows="3" size="40">content</textarea></td>',
74 u'<td><input type=text size=50 maxlength=255 name=comtext value="' + tmptext + '"></td>',
75 u'<td><input type=password size=6 maxlength=10 name=compasswd value="' + tmppasswd + '"></td>',
76 u'<td><input type=submit value="POST"></td></tr>',
77 u'<input type=hidden value="show" name="action">',
78 u'</form>',
79 u'</table>',
80 u'</div>',
81 ]
82
83 return u'\n'.join(html) + u'\n'
84
85 def addcomment(macro, comauthor, comtext, compasswd):
86 # Add a comment with inputs
87
88 com_delimeter = Globs.com_delimeter
89 cfg = macro.request.cfg
90
91 try:
92 # If the data file exists
93 inx_file = codecs.open(Globs.attachmentdir+'/pagecommentsindex.txt','r+',encoding='utf-8')
94 except:
95 try:
96 # If the directory does not exist
97 if not os.path.isdir(Globs.attachmentdir):
98 # Create a attachments directory first
99 # Is conflict with moinmoin?
100 os.mkdir(Globs.attachmentdir)
101
102 inx_file = codecs.open(Globs.attachmentdir+'/pagecommentsindex.txt','w',encoding='utf-8')
103
104 except:
105 message('Failed to add the comment (unable to create an index file)')
106 return
107
108 try:
109 cur_index = inx_file.readline()
110 cur_index = int(cur_index)
111 except:
112 cur_index = 0
113
114 cur_index = cur_index + 1
115 cur_index = str(cur_index)
116
117 try:
118 out_file = codecs.open(Globs.attachmentdir+'/pagecomments.txt','a+',encoding='utf-8')
119 except:
120 message('Failed to add the comment (unable to create a data file)')
121 return
122
123 commentitem = [
124 'o',
125 com_delimeter,
126 cur_index,
127 com_delimeter,
128 convertdelimiter(comauthor),
129 com_delimeter,
130 convertdelimiter(comtext),
131 com_delimeter,
132 compasswd,
133 com_delimeter,
134 macro.request.user.host(),
135 com_delimeter,
136 time.strftime(cfg.datetime_fmt, time.localtime(time.time())),
137 #str('%s %s/%s %s:%s' % (cur_year, cur_month, cur_day, cur_time, cur_min)),
138 ]
139
140 commentitem = u''.join(commentitem)
141
142 out_file.write(commentitem + u'\r\n')
143 out_file.close()
144
145 inx_file.seek(0)
146 inx_file.write(cur_index)
147 inx_file.close()
148
149 message('The comment is added')
150
151 def showcomment():
152
153 html = ''
154 com_delimeter = Globs.com_delimeter
155
156 if not os.path.isfile(Globs.attachmentdir+'/pagecomments.txt'):
157 return ''
158
159 try:
160 com_file = codecs.open(Globs.attachmentdir+'/pagecomments.txt','r', encoding='utf-8')
161 except:
162 #return u'<div=commentlist><table><tr><td style="border: 0px;">no comments</td></tr></td></table></div>'
163 return ''
164
165 html = u'<div=commentlist><table width=100%>'
166
167 #cur_pos = 0
168
169 while 1:
170 in_line = com_file.readline()
171 #cur_pos = cur_pos + len(in_line.encode('utf-8'))
172
173 if in_line == "":
174 break
175
176 if in_line[0] == 'x':
177 if Globs.admin == 'true':
178 item_style = 'color: #c0c0c0;'
179 else:
180 continue
181 else:
182 item_style = ''
183
184 try:
185 in_line = in_line[:-2]
186 [flg_active, cur_index,comauthor,comtext,compasswd,comhost,comtime] = string.split(in_line,com_delimeter)
187 except:
188 message('Failed to show the comment (the data file may be corrupt)')
189 return ''
190
191 if Globs.admin == 'true':
192 signature = comhost + ' | ' + comtime
193 else:
194 signature = comtime
195
196 htmlcomment = [
197 u'<tr><td colspan=2 style="border: 0px; height:0.2px; background-color: #c0c0c0;"></td></tr>',
198 u'<tr><td style="border: 0px; width: 9em; vertical-align: top; ' + item_style + '">',
199 #u'(' + str(cur_pos) + ')',
200 converttext(comauthor),
201 u'</td><td style="border: 0px; ' + item_style + '">',
202 converttext(comtext),
203 u' <font style="font-size: 0.8em; color: #999999;">(',
204 signature,
205 u')</font>',
206 ]
207
208 htmlcomment = u'\n'.join(htmlcomment)
209
210 if Globs.admin == 'true' and flg_active == 'x':
211
212 htmlcomment2 = [
213 u'<font style="font-size: 0.9em;">',
214 u'<a style="color: #aa0000;" href="javascript: requesttorestore(\'' + cur_index + u'\');" alt="Restore">o</a>',
215 u'</font></td></tr>'
216 ]
217
218 else:
219
220 htmlcomment2 = [
221 u'<font style="font-size: 0.9em;">',
222 u'<a style="color: #aa0000;" href="javascript: requesttodelete(\'' + cur_index + u'\');" alt="Delete">x</a>',
223 u'</font></td></tr>'
224 ]
225
226 htmlcomment2 = u'\n'.join(htmlcomment2)
227 html = html + htmlcomment + htmlcomment2 + '\n'
228
229 com_file.close()
230
231 html = html + u'</table></div>'
232
233 return html
234
235
236 def execute(macro, args):
237
238 Globs.version=__version__
239
240 # Containers
241 formvals={}
242 try:
243 import wikiconfig
244 except:
245 wikiconfig=''
246
247 # Class variables need to be specifically set
248 Globs.attachmentdir=''
249 Globs.admin=''
250 Globs.adminmsg=''
251 Globs.pagename=''
252 Globs.com_delimeter = ' {||} '
253
254 # process arguments
255 if args:
256 sargs=string.split(args,',')
257 for item in sargs:
258 sitem=string.split(item,'=')
259 if len(sitem)==2:
260 key,value=sitem[0],sitem[1]
261
262 # Useful variables
263 Globs.baseurl=macro.request.getBaseURL()+'/'
264 if not Globs.pagename:
265 #Globs.pagename = string.replace(macro.formatter.page.page_name,'/','_2f')
266 Globs.pagename = macro.formatter.page.page_name
267 # This fixes the subpages bug. subname is now used instead of pagename when creating certain urls
268 Globs.subname = string.split(Globs.pagename,'/')[-1]
269 # Hmmm. A bug in moinmoin? underscores are getting escaped. These doubly escaped pagenames are even appearing in data/pages
270 try:
271 # Try the old MoinMoin-1.2.x way first
272 textdir=config.text_dir
273 pagepath = string.replace(wikiutil.getPagePath(Globs.pagename),'_5f','_')
274 except:
275 pagepath = macro.formatter.page.getPagePath()
276 Globs.attachmentdir = pagepath+'/attachments'
277
278 if args:
279 args=macro.request.getText(args)
280
281 for item in macro.form.items():
282 if not formvals.has_key(item[0]):
283 try:
284 formvals[item[0]]=item[1][0]
285 except AttributeError:
286 pass
287
288 # Figure out if we have delete privs
289 try:
290 # If a user can delete the page containing the PageComment, then they are considered a PageComment administrator
291 if macro.request.user.may.delete(macro.formatter.page.page_name):
292 Globs.admin='true'
293 except AttributeError:
294 pass
295
296 out=StringIO.StringIO()
297
298 comauthor = ''
299 comtext = ''
300 compasswd = ''
301
302 tmpauthor = ''
303 tmptext = ''
304 tmppasswd = ''
305
306 message(Globs.welcome_msg)
307
308 if formvals.has_key('comauthor') or formvals.has_key('comtext') or formvals.has_key('compasswd'):
309
310 all_input = 1
311
312 try:
313 comauthor = formvals['comauthor']
314 except:
315 comauthor = ''
316 all_input = 0
317
318 try:
319 comtext = formvals['comtext']
320 except:
321 comtext = ''
322 all_input = 0
323
324 try:
325 compasswd = formvals['compasswd']
326 except:
327 compasswd = ''
328 all_input = 0
329
330 try:
331 if all_input == 1:
332 addcomment(macro, comauthor, comtext, compasswd)
333 else:
334 message('Failed to add the comment (insufficient input)')
335
336 tmpauthor = comauthor
337 tmptext = comtext
338 tmppasswd = compasswd
339
340 except:
341 message('Failed to add the comment (internal error)')
342
343 tmpauthor = comauthor
344 tmptext = comtext
345 tmppasswd = compasswd
346
347 if formvals.has_key('delindex'):
348
349 try:
350 delindex = formvals['delindex']
351 delpasswd = formvals['delpasswd']
352 delaction = formvals['delaction']
353
354 deletecomment(macro, delindex, delpasswd, delaction)
355 except:
356 message('Failed to delete the comment (internal error or insufficient input)')
357
358 out.write(deleteform())
359 out.write(u'<table><tr><td style="border: 0px;">')
360 out.write(Globs.adminmsg)
361 out.write(commentform(tmpauthor, tmptext, tmppasswd))
362 out.write(u'</td></tr><tr><td style="border: 0px; height: 0.5em;"></td></tr><tr><td style="border: 0px;">')
363 out.write(showcomment())
364 out.write(u'</td></tr></table>')
365
366
367 out.seek(0)
368 # Finally output any administrative messages at the top followed by any generated content
369 return macro.formatter.rawHTML(
370 out.read()
371 )
372
373 def converttext(targettext):
374 # Converts some special characters of html to plain-text style
375 # What else to handle?
376
377 targettext = targettext.replace(u'&', '&')
378 targettext = targettext.replace(u'>', '>')
379 targettext = targettext.replace(u'<', '<')
380 targettext = targettext.replace(u'\n', '<br>')
381 targettext = targettext.replace(u'\t', ' ')
382 targettext = targettext.replace(u' ', ' ')
383
384 return targettext
385
386 def convertdelimiter(targettext):
387 # Converts delimeter to other string to avoid a crash
388
389 targettext = targettext.replace(Globs.com_delimeter, '(del)')
390
391 return targettext
392
393
394 def deleteform():
395 # Javascript codes for deleting or restoring a comment
396
397 html = [
398 '<script language=javascript>',
399 '<!--',
400 ]
401 html = '\n'.join(html)
402
403 if Globs.admin == 'true':
404 html2 = [
405 ' function requesttodelete(comindex) {',
406 ' document.delform.delindex.value = comindex;',
407 ' document.delform.delpasswd.value = "****";',
408 ' document.delform.delaction.value = "delete";',
409 ' document.delform.submit();',
410 ' }',
411 ' function requesttorestore(comindex) {',
412 ' document.delform.delindex.value = comindex;',
413 ' document.delform.delpasswd.value = "****";',
414 ' document.delform.delaction.value = "restore";',
415 ' document.delform.submit();',
416 ' }',
417 ]
418 html2 = '\n'.join(html2)
419 else:
420 html2 = [
421 ' function requesttodelete(comindex) {',
422 ' var passwd = prompt("Enter password:", "");',
423 ' if(!(passwd == "" || passwd == null)) {',
424 ' document.delform.delindex.value = comindex;',
425 ' document.delform.delpasswd.value = passwd;',
426 ' document.delform.delaction.value = "delete";',
427 ' document.delform.submit();',
428 ' }',
429 ' }',
430 ]
431 html2 = '\n'.join(html2)
432
433 html3 = [
434 '//-->',
435 '</script>',
436 '<form name="delform" action="'+Globs.subname+'" METHOD="post"> <input type=hidden value="show" name="action">',
437 '<input name="delpasswd" type="hidden" value="****"><input name="delindex" type="hidden" value=""><input name="delaction" type="hidden" value=""> </form>',
438 ]
439 html3 = '\n'.join(html3)
440
441 return '\n' + html + '\n' + html2 + '\n' + html3
442
443 def deletecomment(macro, delindex, delpasswd, delaction):
444 # Deletes or restores a comment with give index and password
445
446 html = ''
447 com_delimeter = Globs.com_delimeter
448
449 try:
450 com_file = codecs.open(Globs.attachmentdir+'/pagecomments.txt','r+',encoding='utf-8')
451 except:
452 message('No such comment')
453 return
454
455 delindex = int(delindex)
456
457 if delindex < 1:
458 message('No such comment')
459 return
460
461 cur_byte = 0
462 selectedcomment = ''
463
464 for x in range(delindex):
465 cur_byte = cur_byte + len(selectedcomment.encode('utf-8'))
466 selectedcomment = com_file.readline()
467
468 if selectedcomment == "":
469 message('No such comment')
470 return
471
472 if selectedcomment[0] == 'x' and delaction == 'delete':
473 message('The comment is already deleted')
474 return
475
476 if Globs.admin == 'true' and selectedcomment[0] == 'o' and delaction == 'restore':
477 message('The comment is already restored')
478 return
479
480 selectedcomment = selectedcomment[:-2]
481 [flg_active, cur_index,comauthor,comtext,compasswd,comhost,comtime] = string.split(selectedcomment,com_delimeter)
482
483 if Globs.admin != 'true' and compasswd != delpasswd:
484 message('Incorrect password')
485 return
486
487 com_file.seek(cur_byte)
488 if Globs.admin == 'true' and delaction == 'restore':
489 com_file.write('o')
490 message('The comment is restored')
491 else:
492 com_file.write('x')
493 message('The comment is deleted')
494
495 com_file.close()
496
497 return
498
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.