Attachment 'PageComment-082-tw.py'
Download 1 # -*- coding: iso-8859-1 -*-
2 """
3 PageComment.py Version 0.82-tw 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 Notes to developer:
40 - do a diff -u yourversion myversion to see what I changed
41 - read and follow PEP 0008, esp. concerning tabs and blanks usage
42 - almost never use "except:"
43 - almost never "import string"
44 - read about "template %s %d" % (somestring, someint)
45 """
46
47 import os, StringIO, time
48 import codecs
49 from MoinMoin import config, wikiutil
50
51 class Globs:
52 # A quick place to plonk those shared variables
53 adminmsg = ''
54 datafiledir = ''
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_fname = os.path.join(Globs.datafiledir, 'pagecommentsindex.txt')
94 inx_file = codecs.open(inx_fname, 'r+', encoding='utf-8')
95 except: # XXX TODO: be more specific!
96 try:
97 # If the directory does not exist
98 if not os.path.isdir(Globs.datafiledir):
99 # Create a attachments directory first
100 # Is conflict with moinmoin?
101 os.mkdir(Globs.datafiledir)
102
103 inx_file = codecs.open(inx_fname, 'w', encoding='utf-8')
104
105 except: # XXX TODO: be more specific!
106 message('Failed to add the comment (unable to create an index file)')
107 return
108
109 try:
110 cur_index = inx_file.readline()
111 cur_index = int(cur_index)
112 except:
113 cur_index = 0
114
115 cur_index = cur_index + 1
116 cur_index = str(cur_index)
117
118 try:
119 out_fname = os.path.join(Globs.datafiledir, 'pagecomments.txt')
120 out_file = codecs.open(out_fname, 'a+', encoding='utf-8')
121 except: # XXX TODO: be more specific!
122 message('Failed to add the comment (unable to create a data file)')
123 return
124
125 commentitem = [
126 'o',
127 com_delimeter,
128 cur_index,
129 com_delimeter,
130 convertdelimiter(comauthor),
131 com_delimeter,
132 convertdelimiter(comtext),
133 com_delimeter,
134 compasswd,
135 com_delimeter,
136 macro.request.user.host(),
137 com_delimeter,
138 time.strftime(cfg.datetime_fmt, time.localtime(time.time())),
139 #str('%s %s/%s %s:%s' % (cur_year, cur_month, cur_day, cur_time, cur_min)),
140 ]
141
142 commentitem = u''.join(commentitem)
143
144 out_file.write(commentitem + u'\r\n')
145 out_file.close()
146
147 inx_file.seek(0)
148 inx_file.write(cur_index)
149 inx_file.close()
150
151 message('The comment is added')
152
153 def showcomment():
154
155 html = ''
156 com_delimeter = Globs.com_delimeter
157
158 com_fname = os.path.join(Globs.datafiledir, 'pagecomments.txt')
159 if not os.path.isfile(com_fname):
160 return ''
161
162 try:
163 com_file = codecs.open(com_fname, 'r', encoding='utf-8')
164 except: # XXX TODO: be more specific!
165 #return u'<div=commentlist><table><tr><td style="border: 0px;">no comments</td></tr></td></table></div>'
166 return ''
167
168 html = u'<div=commentlist><table width="100%">'
169
170 #cur_pos = 0
171
172 while True:
173 in_line = com_file.readline()
174 #cur_pos = cur_pos + len(in_line.encode('utf-8'))
175
176 if not in_line:
177 break
178
179 if in_line[0] == 'x':
180 if Globs.admin == 'true':
181 text_style = 'color: #d0d0d0;'
182 signature_style = text_style
183 else:
184 continue
185 else:
186 text_style = ''
187 signature_style = 'color: #999999;'
188
189 try:
190 in_line = in_line[:-2] # what are you doing here?
191 [flg_active, cur_index, comauthor, comtext, compasswd, comhost, comtime] = in_line.split(com_delimeter)
192 except: # XXX TODO: be more specific!
193 message('Failed to show the comment (the data file may be corrupt)')
194 return ''
195
196 if Globs.admin == 'true':
197 signature = comhost + ' | ' + comtime
198 else:
199 signature = comtime
200
201 htmlcomment = [
202 u'<tr><td colspan="2" style="border: 0px; height: 0.2px; background-color: #c0c0c0;"></td></tr>',
203 u'<tr><td style="border: 0px; width: 9em; vertical-align: top; ' + text_style + '">',
204 #u'(' + str(cur_pos) + ')',
205 converttext(comauthor),
206 u'</td><td style="border: 0px; ' + text_style + '">',
207 converttext(comtext),
208 u' <font style="font-size: 0.8em; ' + signature_style + '">(',
209 signature,
210 u')</font>',
211 ]
212
213 htmlcomment = u'\n'.join(htmlcomment)
214
215 if Globs.admin == 'true' and flg_active == 'x':
216 htmlcomment2 = [
217 u'<font style="font-size: 0.9em;">',
218 u'<a style="color: #aa0000;" href="javascript: requesttorestore(\'' + cur_index + u'\');" alt="Restore">o</a>',
219 u'</font></td></tr>'
220 ]
221 else:
222 htmlcomment2 = [
223 u'<font style="font-size: 0.9em;">',
224 u'<a style="color: #aa0000;" href="javascript: requesttodelete(\'' + cur_index + u'\');" alt="Delete">x</a>',
225 u'</font></td></tr>'
226 ]
227
228 htmlcomment2 = u'\n'.join(htmlcomment2)
229 html = html + htmlcomment + htmlcomment2 + '\n'
230
231 com_file.close()
232 html = html + u'</table></div>'
233 return html
234
235
236 def execute(macro, args):
237
238 # Containers
239 formvals = {}
240 try:
241 import wikiconfig # HUH!? you know macro.request.cfg?
242 except: # ...
243 wikiconfig = ''
244
245 # Class variables need to be specifically set
246 Globs.datafiledir = ''
247 Globs.admin = ''
248 Globs.adminmsg = ''
249 Globs.pagename = ''
250 Globs.com_delimeter = ' {||} '
251
252 # process arguments
253 if args:
254 sargs = args.split(',')
255 for item in sargs:
256 sitem = item.split('=')
257 if len(sitem) == 2:
258 key, value = sitem
259
260 # Useful variables
261 Globs.baseurl = macro.request.getBaseURL() + '/'
262 if not Globs.pagename:
263 #Globs.pagename = string.replace(macro.formatter.page.page_name,'/','_2f')
264 Globs.pagename = macro.formatter.page.page_name
265 # This fixes the subpages bug. subname is now used instead of pagename when creating certain urls
266 Globs.subname = Globs.pagename.split('/')[-1]
267 # Hmmm. A bug in moinmoin? underscores are getting escaped. These doubly escaped pagenames are even appearing in data/pages
268 try:
269 # Try the old MoinMoin-1.2.x way first (/me blows the dust off :)
270 textdir = config.text_dir
271 pagepath = string.replace(wikiutil.getPagePath(Globs.pagename),'_5f','_') # ugly
272 except: # ...
273 pagepath = macro.formatter.page.getPagePath()
274 Globs.datafiledir = os.path.join(pagepath, 'pagecommentdata')
275
276 if args:
277 args = macro.request.getText(args)
278
279 for item in macro.form.items():
280 if not formvals.has_key(item[0]):
281 try: # TODO remove tabs from src!!!
282 formvals[item[0]] = item[1][0]
283 except AttributeError:
284 pass
285
286 # Figure out if we have delete privs
287 try:
288 # If a user can delete the page containing the PageComment, then they are considered a PageComment administrator
289 if macro.request.user.may.delete(macro.formatter.page.page_name):
290 Globs.admin = 'true'
291 except AttributeError:
292 pass
293
294 out = StringIO.StringIO()
295
296 comauthor = ''
297 comtext = ''
298 compasswd = ''
299
300 tmpauthor = ''
301 tmptext = ''
302 tmppasswd = ''
303
304 message(Globs.welcome_msg)
305
306 if formvals.has_key('comauthor') or formvals.has_key('comtext') or formvals.has_key('compasswd'):
307
308 all_input = 1 # -> True
309
310 try:
311 comauthor = formvals['comauthor']
312 except: # you maybe want to use formvals.get(name, defaulvalue)
313 comauthor = ''
314 all_input = 0
315
316 try:
317 comtext = formvals['comtext']
318 except:
319 comtext = ''
320 all_input = 0
321
322 try:
323 compasswd = formvals['compasswd']
324 except:
325 compasswd = ''
326 all_input = 0
327
328 try:
329 if all_input == 1:
330 addcomment(macro, comauthor, comtext, compasswd)
331 else:
332 message('Failed to add the comment (insufficient input)')
333
334 tmpauthor = comauthor
335 tmptext = comtext
336 tmppasswd = compasswd
337
338 except:
339 message('Failed to add the comment (internal error)')
340
341 tmpauthor = comauthor
342 tmptext = comtext
343 tmppasswd = compasswd
344
345 if formvals.has_key('delindex'):
346
347 try:
348 delindex = formvals['delindex']
349 delpasswd = formvals['delpasswd']
350 delaction = formvals['delaction']
351
352 deletecomment(macro, delindex, delpasswd, delaction)
353 except:
354 message('Failed to delete the comment (internal error or insufficient input)')
355
356 out.write(deleteform())
357 out.write(u'<table><tr><td style="border: 0px;">')
358 out.write(Globs.adminmsg)
359 out.write(commentform(tmpauthor, tmptext, tmppasswd))
360 out.write(u'</td></tr><tr><td style="border: 0px; height: 0.5em;"></td></tr><tr><td style="border: 0px;">')
361 out.write(showcomment())
362 out.write(u'</td></tr></table>')
363
364
365 out.seek(0)
366 # Finally output any administrative messages at the top followed by any generated content
367 return macro.formatter.rawHTML(
368 out.read() # . ??
369 )
370
371 def converttext(targettext):
372 # Converts some special characters of html to plain-text style
373 # What else to handle?
374 # ugly, use some existing escape function, see wikiutil, urllib, ...
375 targettext = targettext.replace(u'&', '&')
376 targettext = targettext.replace(u'>', '>')
377 targettext = targettext.replace(u'<', '<')
378 targettext = targettext.replace(u'\n', '<br>')
379 targettext = targettext.replace(u'\t', ' ')
380 targettext = targettext.replace(u' ', ' ')
381
382 return targettext
383
384 def convertdelimiter(targettext):
385 # Converts delimeter to other string to avoid a crash
386 targettext = targettext.replace(Globs.com_delimeter, '(del)')
387 return targettext
388
389
390 def deleteform():
391 # Javascript codes for deleting or restoring a comment
392
393 html = [
394 '<script language=javascript>', # "javascript" ?
395 '<!--',
396 ]
397 html = '\n'.join(html)
398
399 if Globs.admin == 'true':
400 html2 = [
401 ' function requesttodelete(comindex) {',
402 ' document.delform.delindex.value = comindex;',
403 ' document.delform.delpasswd.value = "****";',
404 ' document.delform.delaction.value = "delete";',
405 ' document.delform.submit();',
406 ' }',
407 ' function requesttorestore(comindex) {',
408 ' document.delform.delindex.value = comindex;',
409 ' document.delform.delpasswd.value = "****";',
410 ' document.delform.delaction.value = "restore";',
411 ' document.delform.submit();',
412 ' }',
413 ]
414 html2 = '\n'.join(html2)
415 else:
416 html2 = [
417 ' function requesttodelete(comindex) {',
418 ' var passwd = prompt("Enter password:", "");',
419 ' if(!(passwd == "" || passwd == null)) {',
420 ' document.delform.delindex.value = comindex;',
421 ' document.delform.delpasswd.value = passwd;',
422 ' document.delform.delaction.value = "delete";',
423 ' document.delform.submit();',
424 ' }',
425 ' }',
426 ]
427 html2 = '\n'.join(html2)
428
429 html3 = [
430 '//-->',
431 '</script>',
432 '<form name="delform" action="' + Globs.subname + '" METHOD="post"> <input type=hidden value="show" name="action">',
433 '<input name="delpasswd" type="hidden" value="****"><input name="delindex" type="hidden" value=""><input name="delaction" type="hidden" value=""> </form>',
434 ]
435 html3 = '\n'.join(html3)
436
437 return '\n' + html + '\n' + html2 + '\n' + html3 # why not join here?
438
439 def deletecomment(macro, delindex, delpasswd, delaction):
440 # Deletes or restores a comment with give index and password
441 html = ''
442 com_delimeter = Globs.com_delimeter
443 try:
444 com_fname = os.path.join(Globs.datafiledir, 'pagecomments.txt')
445 com_file = codecs.open(com_fname, '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 not 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] = selectedcomment.split(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
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.