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