|
1 <?php |
|
2 /* |
|
3 Plugin Name: EnanoPress |
|
4 Plugin URI: http://enano.homelinux.org/EnanoPress |
|
5 Description: Adds WordPress-like blogging functionality to the site. The blog can be viewed on the page Special:Blog, and posts can be written with Special:WriteBlogPost. |
|
6 Author: Dan Fuhry |
|
7 Version: 1.0 |
|
8 Author URI: http://enano.homelinux.org/ |
|
9 */ |
|
10 |
|
11 global $db, $session, $paths, $template, $plugins; // Common objects |
|
12 |
|
13 $plugins->attachHook('base_classes_initted', ' |
|
14 $paths->add_page(Array( |
|
15 \'name\'=>\'Site Blog\', |
|
16 \'urlname\'=>\'Blog\', |
|
17 \'namespace\'=>\'Special\', |
|
18 \'special\'=>0,\'visible\'=>1,\'comments_on\'=>0,\'protected\'=>1,\'delvotes\'=>0,\'delvote_ips\'=>\'\', |
|
19 )); |
|
20 $paths->add_page(Array( |
|
21 \'name\'=>\'Write blog post\', |
|
22 \'urlname\'=>\'WriteBlogPost\', |
|
23 \'namespace\'=>\'Special\', |
|
24 \'special\'=>0,\'visible\'=>1,\'comments_on\'=>0,\'protected\'=>1,\'delvotes\'=>0,\'delvote_ips\'=>\'\', |
|
25 )); |
|
26 $paths->addAdminNode(\'Plugin configuration\', \'EnanoPress settings\', \'EnanoPress\'); |
|
27 '); |
|
28 |
|
29 $plugins->attachHook('compile_template', 'global $template; $template->tpl_bool[\'in_blog\'] = false;'); |
|
30 $plugins->attachHook('paths_init_before', 'global $paths; $paths->create_namespace("Blog", "BlogPost:");'); |
|
31 $plugins->attachHook('page_not_found', 'return EnanoPress_BlogNamespaceHandler();'); |
|
32 $plugins->attachHook('page_type_string_set', 'global $paths, $template; if($paths->namespace == "Blog") $template->namespace_string = "blog post";'); |
|
33 |
|
34 define('BLOG_POST_PUBLISHED', 1); |
|
35 define('BLOG_POST_DRAFT', 0); |
|
36 define('BLOG_POSTS_PER_PAGE', 20); |
|
37 |
|
38 function EnanoPress_BlogNamespaceHandler() |
|
39 { |
|
40 global $db, $session, $paths, $template, $plugins; // Common objects |
|
41 $pid = intval($paths->cpage['urlname_nons']); |
|
42 if($pid == 0) return null; |
|
43 $q = $db->sql_query('SELECT post_id, post_title, post_content, time, author FROM '.table_prefix.'blog WHERE status='.BLOG_POST_PUBLISHED.' AND post_id='.$pid.';'); |
|
44 if(!$q) $db->_die(''); |
|
45 if($db->numrows() < 1) return null; |
|
46 $row = $db->fetchrow($q); |
|
47 $paths->cpage['name'] = $row['post_title']; |
|
48 $template->header(); |
|
49 echo EnanoPress_FormatBlogPost($row['post_title'], RenderMan::render($row['post_content']), $row['time'], $row['author'], 0, $row['post_id']); |
|
50 echo EnanoPress_Separator(); |
|
51 $sub = ( isset ($_GET['sub']) ) ? $_GET['sub'] : false; |
|
52 $act = ( isset ($_GET['action']) ) ? $_GET['action'] : false; |
|
53 $id = ( isset ($_GET['id']) ) ? intval($_GET['id']) : -1; |
|
54 $comments = EnanoPress_GetComments($id); |
|
55 echo $comments; |
|
56 $template->footer(); |
|
57 return true; |
|
58 } |
|
59 |
|
60 function page_Special_Blog() |
|
61 { |
|
62 global $db, $session, $paths, $template, $plugins; // Common objects |
|
63 if(!getConfig('blog_table_version')) |
|
64 { |
|
65 $q = $db->sql_query('CREATE TABLE '.table_prefix.'blog ( post_id mediumint(8) NOT NULL auto_increment, post_title text, post_content text, time int(12), status tinyint(1) NOT NULL DEFAULT 0, author varchar(63) NOT NULL, num_comments mediumint(8) NOT NULL DEFAULT 0, PRIMARY KEY ( post_id ) );'); |
|
66 if(!$q) $db->_die('The blog table could not be created'); |
|
67 setConfig('blog_table_version', '1'); |
|
68 } |
|
69 if($n = getConfig('blog_name')) $paths->cpage['name'] = $n; |
|
70 if(!defined('ENANO_TEMPLATE_LOADED')) |
|
71 $template->init_vars(); |
|
72 $template->tpl_bool['in_blog'] = true; |
|
73 $template->header(); |
|
74 if($s = $paths->getParam(0)) |
|
75 { |
|
76 if($s == 'archive') |
|
77 { |
|
78 $y = (int)$paths->getParam(1); |
|
79 $m = (int)$paths->getParam(2); |
|
80 $d = (int)$paths->getParam(3); |
|
81 $t = $paths->getParam(4); |
|
82 if(!$y || !$m || !$d || !$t) |
|
83 { |
|
84 echo '<p>Invalid permalink syntax</p>'; |
|
85 $template->footer(); |
|
86 return false; |
|
87 } |
|
88 $t = $db->escape(str_replace(Array('-', '_'), Array('_', '_'), $t)); // It's impossible to reconstruct the title from the URL, so let MySQL do it for us using wildcards |
|
89 // Determine the valid UNIX timestamp values |
|
90 $lower_limit = mktime(0, 0, 0, $m, $d, $y); |
|
91 // EnanoPress will officially stop working on February 29, 2052. To extend the date, add more leap years here. |
|
92 $leapyears = Array(2000,2004,2008,2012,2016,2020,2024,2028,2032,2040,2044,2048); |
|
93 // add one to the day |
|
94 // 30 days hath September, April, June, and November, all the rest have 31, except el enano, February :-P |
|
95 if (in_array($m, Array(4, 6, 9, 11)) && $d == 30) $m++; |
|
96 elseif(in_array($m, Array(1, 3, 5, 7, 8, 10, 12)) && $d == 31) $m++; |
|
97 elseif($m == 2 && in_array($y, $leapyears) && $d == 29) $m++; |
|
98 elseif($m == 2 && !in_array($y, $leapyears) && $d == 28) $m++; |
|
99 else $d++; |
|
100 $upper_limit = mktime(0, 0, 0, $m, $d, $y); |
|
101 $q = $db->sql_query('SELECT b.post_id, b.post_title, b.post_content, b.time, COUNT(c.comment_id) AS num_comments, b.author FROM '.table_prefix.'blog AS b LEFT JOIN '.table_prefix.'comments AS c ON (c.page_id=b.post_id AND c.namespace=\'Blog\' AND c.approved=1) WHERE b.status='.BLOG_POST_PUBLISHED.' AND b.post_title LIKE \''.$t.'\' AND b.time >= '.$lower_limit.' AND b.time <= '.$upper_limit.' GROUP BY b.post_id ORDER BY b.time DESC;'); |
|
102 if(!$q) |
|
103 { |
|
104 echo $db->get_error(); |
|
105 $template->footer(); |
|
106 return; |
|
107 } |
|
108 if($db->numrows() < 1) |
|
109 { |
|
110 // Try it with no date specifiation |
|
111 $q = $db->sql_query('SELECT b.post_id, b.post_title, b.post_content, b.time, COUNT(c.comment_id) AS num_comments, b.author FROM '.table_prefix.'blog AS b LEFT JOIN '.table_prefix.'comments AS c ON (c.page_id=b.post_id AND c.namespace=\'Blog\' AND c.approved=1) WHERE b.status='.BLOG_POST_PUBLISHED.' AND b.post_title LIKE \''.$t.'\' GROUP BY b.post_id ORDER BY b.time DESC;'); |
|
112 if(!$q) |
|
113 { |
|
114 echo $db->get_error(); |
|
115 $template->footer(); |
|
116 return; |
|
117 } |
|
118 if($db->numrows() < 1) |
|
119 { |
|
120 echo '<p>No posts matching that permalink could be found.</p>'; |
|
121 $template->footer(); |
|
122 return; |
|
123 } |
|
124 } |
|
125 $row = $db->fetchrow(); |
|
126 echo EnanoPress_FormatBlogPost($row['post_title'], RenderMan::render($row['post_content']), $row['time'], $row['author'], (int)$row['num_comments'], (int)$row['post_id']); |
|
127 echo EnanoPress_Separator(); |
|
128 $sub = ( isset ($_GET['sub']) ) ? $_GET['sub'] : false; |
|
129 $act = ( isset ($_GET['action']) ) ? $_GET['action'] : false; |
|
130 $id = ( isset ($_GET['id']) ) ? intval($_GET['id']) : -1; |
|
131 $comments = EnanoPress_GetComments((int)$row['post_id']); |
|
132 if(is_array($comments)) |
|
133 { |
|
134 $comments = EnanoPress_FormatComments($comments); |
|
135 echo $comments; |
|
136 } |
|
137 $template->footer(); |
|
138 return; |
|
139 } |
|
140 else |
|
141 { |
|
142 $start = intval($s); |
|
143 } |
|
144 } |
|
145 else $start = 0; |
|
146 $end = $start + BLOG_POSTS_PER_PAGE + 1; |
|
147 $q = $db->sql_query('SELECT b.post_id, b.post_title, b.post_content, b.time, b.author, COUNT(c.comment_id) AS num_comments FROM '.table_prefix.'blog AS b LEFT JOIN '.table_prefix.'comments AS c ON (c.page_id=b.post_id AND c.namespace=\'Blog\' AND c.approved=1) WHERE b.status='.BLOG_POST_PUBLISHED.' GROUP BY b.post_id ORDER BY b.time DESC LIMIT '.$start.','. $end .';'); |
|
148 if(!$q) { echo $db->get_error('The blog data could not be selected'); $template->footer(); return false; } |
|
149 $numrows = $db->numrows(); |
|
150 if($numrows == BLOG_POSTS_PER_PAGE+1) |
|
151 { |
|
152 $nextpage = true; |
|
153 $numrows = BLOG_POSTS_PER_PAGE; |
|
154 } |
|
155 if($numrows < 1) |
|
156 { |
|
157 echo '<p>No posts yet! <a href="'.makeUrlNS('Special', 'WriteBlogPost').'">Write a post...</a></p>'; |
|
158 } |
|
159 else |
|
160 { |
|
161 $i = 0; |
|
162 while($row = $db->fetchrow()) |
|
163 { |
|
164 $i++; |
|
165 if($i == BLOG_POSTS_PER_PAGE+1) break; |
|
166 echo EnanoPress_FormatBlogPost($row['post_title'], RenderMan::render($row['post_content']), $row['time'], $row['author'], (int)$row['num_comments'], (int)$row['post_id']); |
|
167 if($i < $numrows) echo EnanoPress_Separator(); |
|
168 } |
|
169 if($session->user_level >= USER_LEVEL_MOD) echo '<h2>More actions</h2><p><a href="'.makeUrlNS('Special', 'WriteBlogPost').'">Write a post...</a></p>'; |
|
170 } |
|
171 $template->footer(); |
|
172 } |
|
173 |
|
174 function page_Special_WriteBlogPost() |
|
175 { |
|
176 global $db, $session, $paths, $template, $plugins; // Common objects |
|
177 if($session->user_level < USER_LEVEL_MOD) die_friendly('Access denied', '<p>You are not authorized to post blog messages.</p>'); |
|
178 $errors = Array(); |
|
179 $template->header(); |
|
180 $editing = false; |
|
181 if(isset($_POST['__save'])) $status = BLOG_POST_DRAFT; |
|
182 if(isset($_POST['__publish'])) $status = BLOG_POST_PUBLISHED; |
|
183 if(isset($_POST['__save']) || isset($_POST['__publish'])) |
|
184 { |
|
185 $text = RenderMan::preprocess_text($_POST['content'], false, true); |
|
186 $title = $db->escape(htmlspecialchars($_POST['title'])); |
|
187 $author = $db->escape($session->username); |
|
188 $time = time(); |
|
189 if($text == '') $errors[] = 'You must enter a post.'; |
|
190 if($title == '') $errors[] = 'You must enter a title for your post.'; |
|
191 if(sizeof($errors) < 1) |
|
192 { |
|
193 if(isset($_POST['edit_id']) && preg_match('#^([0-9]+)$#', $_POST['edit_id'])) |
|
194 { |
|
195 $q = $db->sql_query('UPDATE '.table_prefix."blog SET post_title='{$title}',post_content='{$text}',time={$time},author='{$author}',status=".$status." WHERE post_id={$_POST['edit_id']};"); |
|
196 } |
|
197 else |
|
198 { |
|
199 $q = $db->sql_query('INSERT INTO '.table_prefix."blog(post_title,post_content,time,author,status) VALUES('{$title}', '{$text}', {$time}, '{$author}', ".$status.");"); |
|
200 } |
|
201 if(!$q) |
|
202 { |
|
203 echo $db->get_error(); |
|
204 $template->footer(); |
|
205 return; |
|
206 } |
|
207 $q = $db->sql_query('SELECT post_id FROM '.table_prefix.'blog WHERE time='.$time.' ORDER BY post_id DESC;'); |
|
208 if(!$q) { echo $db->get_error(); $template->footer(); return false; } |
|
209 if($db->numrows() > 0) |
|
210 { |
|
211 $row = $db->fetchrow(); |
|
212 $editing = $row['post_id']; |
|
213 } |
|
214 switch($status): |
|
215 case BLOG_POST_DRAFT: |
|
216 echo '<div class="info-box">Your post has been saved; however it will not appear on the main blog page until it is published.</div>'; |
|
217 break; |
|
218 case BLOG_POST_PUBLISHED: |
|
219 echo '<div class="info-box">Your post has been published to the main blog page.</div>'; |
|
220 break; |
|
221 endswitch; |
|
222 } |
|
223 |
|
224 $text =& $_POST['content']; |
|
225 $title =& $_POST['title']; |
|
226 } |
|
227 elseif(isset($_POST['__delete']) && isset($_POST['del_confirm'])) |
|
228 { |
|
229 $pid = intval($_POST['edit_id']); |
|
230 if($pid > 0) |
|
231 { |
|
232 $q = $db->sql_query('DELETE FROM '.table_prefix.'blog WHERE post_id='.$pid.';'); |
|
233 if(!$q) |
|
234 { |
|
235 echo $db->get_error(); |
|
236 $template->footer(); |
|
237 return; |
|
238 } |
|
239 else |
|
240 echo '<div class="info-box">Your post has been deleted.</div>'; |
|
241 } |
|
242 $text = ''; |
|
243 $title = ''; |
|
244 $editing = false; |
|
245 } |
|
246 elseif($t = $paths->getParam(0)) |
|
247 { |
|
248 $id = intval($t); |
|
249 if($t == 0) die('SQL injection attempt'); |
|
250 $q = $db->sql_query('SELECT post_title,post_content FROM '.table_prefix.'blog WHERE post_id='.$t.';'); |
|
251 if(!$q) { echo $db->get_error(); $template->footer(); return false; } |
|
252 if($db->numrows() > 0) |
|
253 { |
|
254 $row = $db->fetchrow(); |
|
255 $text =& $row['post_content']; |
|
256 $title =& $row['post_title']; |
|
257 $editing = $t; |
|
258 } |
|
259 else |
|
260 { |
|
261 $text = ''; |
|
262 $title = ''; |
|
263 } |
|
264 } |
|
265 elseif(isset($_POST['__preview'])) |
|
266 { |
|
267 $text = RenderMan::preprocess_text($_POST['content'], false, false); |
|
268 $text = RenderMan::render($text); |
|
269 ob_start(); |
|
270 eval('?>'.$text); |
|
271 $text = ob_get_contents(); |
|
272 ob_end_clean(); |
|
273 echo '<div class="warning-box"><b>Reminder:</b><br />This is only a preview - your changes to this post will not be saved until you click Save Draft or Save and Publish below.</div>' |
|
274 . PageUtils::scrollBox(EnanoPress_FormatBlogPost($_POST['title'], $text, time(), $session->username, 0, false)); |
|
275 $text =& $_POST['content']; |
|
276 $title = $_POST['title']; |
|
277 } |
|
278 else |
|
279 { |
|
280 $text = ''; |
|
281 $title = ''; |
|
282 } |
|
283 if(sizeof($errors) > 0) |
|
284 { |
|
285 echo '<div class="error-box"><b>The following errors were encountered:</b><br />' . implode('<br />', $errors) . '</div>'; |
|
286 } |
|
287 $q = $db->sql_query('SELECT post_id, post_title FROM '.table_prefix.'blog WHERE status='.BLOG_POST_DRAFT.' ORDER BY post_title ASC;'); |
|
288 if(!$q) { echo $db->get_error('The blog data could not be selected'); $template->footer(); return false; } |
|
289 $n = $db->numrows(); |
|
290 if($n > 0) |
|
291 { |
|
292 echo '<br /><div class="mdg-comment"><b>Your drafts: </b>'; |
|
293 $posts = Array(); |
|
294 while($r = $db->fetchrow()) |
|
295 { |
|
296 $posts[$r['post_id']] = $r['post_title']; |
|
297 } |
|
298 $i=0; |
|
299 foreach($posts as $id => $t) |
|
300 { |
|
301 $i++; |
|
302 echo '<a href="'.makeUrlNS('Special', 'WriteBlogPost/'.$id).'">'.$t.'</a>'; |
|
303 if($i < $n) echo ' » '; |
|
304 } |
|
305 echo '</div>'; |
|
306 } |
|
307 $idthing = ( $editing ) ? '<input type="hidden" name="edit_id" value="'.$editing.'" />' : ''; |
|
308 $delbtn = ( $editing ) ? ' <input onclick="return confirm(\'Are you REALLY sure you want to delete this post?\')" type="submit" name="__delete" value="Delete this post" style="color: red; font-weight: bold;" /> <label><input type="checkbox" name="del_confirm" /> I\'m sure</label>' : ''; |
|
309 $textarea = $template->tinymce_textarea('content', $text); |
|
310 echo '<form action="'.makeUrl($paths->page).'" method="post">' |
|
311 . '<p>Post title:<br /><input type="text" name="title" size="60" style="width: 98%;" value="'.htmlspecialchars($title).'" /><br /><br />Post:<br />' |
|
312 . $textarea |
|
313 . '<p>The following information will be added to your post:</p><ul><li>Date and time: '.date('F d, Y h:i a').'</li><li>Username: '.$session->username.'</li></ul>' |
|
314 . '<p><input type="submit" name="__preview" value="Show preview" title="Allows you to preview your blog post before it is saved or posted" /> <input title="Saves the post but prevents it from being shown on the main blog page" type="submit" name="__save" value="Save Draft" /> <input title="Saves the blog post and shows it on the main blog page" type="submit" name="__publish" value="Save and Publish" />' |
|
315 . $delbtn |
|
316 . '</p>' |
|
317 . $idthing |
|
318 . '</form>'; |
|
319 $template->footer(); |
|
320 } |
|
321 |
|
322 /** |
|
323 * Convert a blog post to HTML |
|
324 * @param string $title the name of the blog post |
|
325 * @param string $text the content, needs to be HTML formatted as no renderer is called |
|
326 * @param int $time UNIX timestamp for the time of the post |
|
327 * @param string $author [user]name of the person who wrote the post |
|
328 * @param int $num_comments The number of comments attached to the post |
|
329 * @param int $post_id The numerical ID of the post |
|
330 * @return string |
|
331 */ |
|
332 |
|
333 function EnanoPress_FormatBlogPost($title, $text, $time, $author, $num_comments = 0, $post_id) |
|
334 { |
|
335 global $db, $session, $paths, $template, $plugins; // Common objects |
|
336 static $cached_template = false; |
|
337 if(!$cached_template) |
|
338 { |
|
339 if(file_exists(ENANO_ROOT.'/themes/'.$session->theme.'/blogpost.tpl')) |
|
340 $cached_template = file_get_contents(ENANO_ROOT.'/themes/'.$session->theme.'/blogpost.tpl', 'r'); |
|
341 if(!$cached_template) |
|
342 $cached_template = <<<TPLCODE |
|
343 <div> |
|
344 <div style="border-bottom: 1px solid #AAAAAA;"> |
|
345 <p style="float: right; background-color: #F0F0F0; margin: 3px 10px 0 0; padding: 8px 3px; width: 55px; text-align: center;">{D} {j} {M} {Y}</p> |
|
346 <div style="margin-bottom: 16px;"><h3 style="margin-bottom: 0;"><a href="{PERMALINK}" rel="bookmark" title="Permanent link to this post">{TITLE}</a></h3>Posted by <a href="{AUTHOR_LINK}" {AUTHOR_USERPAGE_CLASS}>{AUTHOR}</a><br /><a href="{COMMENT_LINK}">{COMMENT_LINK_TEXT}</a><!-- BEGIN can_edit --> | <a href="{EDIT_LINK}">edit this post</a><!-- END can_edit --></div> |
|
347 </div> |
|
348 <div> |
|
349 {CONTENT} |
|
350 </div> |
|
351 </div> |
|
352 TPLCODE; |
|
353 } |
|
354 $parser = $template->makeParserText($cached_template); |
|
355 $datechars = 'dDjlSwzWFmMntLYyaABGhHisIOTZrU'; // A list of valid metacharacters for date() |
|
356 $datechars = enano_str_split($datechars); |
|
357 $datevals = Array(); |
|
358 foreach($datechars as $d) |
|
359 { |
|
360 $datevals[$d] = date($d, $time); |
|
361 } |
|
362 unset($datechars); |
|
363 $parser->assign_vars($datevals); |
|
364 $parser->assign_bool(Array( |
|
365 'can_edit'=> ( $session->user_level >= USER_LEVEL_MOD ), |
|
366 )); |
|
367 $permalink = makeUrlNS('Special', 'Blog/archive/'.date('Y', $time).'/'.date('m', $time).'/'.date('d', $time).'/'.enanopress_sanitize_title($title)); |
|
368 $commentlink = $permalink . '#post-comments'; |
|
369 if($num_comments == 0) $ctext = 'No comments'; |
|
370 elseif($num_comments == 1) $ctext = '1 comment'; |
|
371 else $ctext = $num_comments . ' comments'; |
|
372 $edit_link = ( is_int($post_id) ) ? makeUrlNS('Special', 'WriteBlogPost/'.$post_id) : '#" onclick="return false;'; |
|
373 $parser->assign_vars(Array( |
|
374 'TITLE' => $title, |
|
375 'PERMALINK' => $permalink, |
|
376 'AUTHOR' => $author, |
|
377 'AUTHOR_LINK' => makeUrlNS('User', $author), |
|
378 'AUTHOR_USERPAGE_CLASS' => ( isset($paths->pages[$paths->nslist['User'].$author]) ) ? '' : ' class="wikilink-nonexistent" ', |
|
379 'COMMENT_LINK' => $commentlink, |
|
380 'COMMENT_LINK_TEXT' => $ctext, |
|
381 'CONTENT' => $text, |
|
382 'EDIT_LINK' => $edit_link, |
|
383 )); |
|
384 return $parser->run(); |
|
385 } |
|
386 |
|
387 /** |
|
388 * Draws a separator for use between blog posts - searches for the appropriate template file |
|
389 * @return string |
|
390 */ |
|
391 |
|
392 function EnanoPress_Separator() |
|
393 { |
|
394 global $db, $session, $paths, $template, $plugins; // Common objects |
|
395 static $cached_template = false; |
|
396 if(!$cached_template) |
|
397 { |
|
398 if(file_exists(ENANO_ROOT.'/themes/'.$session->theme.'/blogseparator.tpl')) |
|
399 $cached_template = file_get_contents(ENANO_ROOT.'/themes/'.$session->theme.'/blogseparator.tpl'); |
|
400 if(!$cached_template) |
|
401 $cached_template = <<<TPLCODE |
|
402 <div style="border-bottom: 1px dashed #666666; margin: 15px auto; width: 200px;"></div> |
|
403 TPLCODE; |
|
404 } |
|
405 $parser = $template->makeParserText($cached_template); |
|
406 return $parser->run(); |
|
407 } |
|
408 |
|
409 /** |
|
410 * Make a blog post title acceptable for URLs |
|
411 * @param string $text the input text |
|
412 * @return string |
|
413 */ |
|
414 |
|
415 function enanopress_sanitize_title($text) |
|
416 { |
|
417 $text = strtolower(str_replace(' ', '_', $text)); |
|
418 $badchars = '/*+-,.?!@#$%^&*|{}[];:\'"`~'; |
|
419 $badchars = enano_str_split($badchars); |
|
420 $dash = Array(); |
|
421 foreach($badchars as $i => $b) $dash[] = "-"; |
|
422 $text = str_replace($badchars, $dash, $text); |
|
423 return $text; |
|
424 } |
|
425 |
|
426 /** |
|
427 * Fetch comments for a post |
|
428 * @param int $post_id The numerical ID of the post to get comments for |
|
429 * @return array A hierarchial array - numbered keys, each key is a subarray with keys "name", "subject", "text", "time", and "comment_id" with time being a UNIX timestamp |
|
430 */ |
|
431 |
|
432 function EnanoPress_GetComments($post_id) |
|
433 { |
|
434 global $db, $session, $paths, $template, $plugins; // Common objects |
|
435 |
|
436 if(!is_int($post_id)) return false; |
|
437 |
|
438 if(isset($_GET['sub'])) |
|
439 { |
|
440 $e = $db->sql_query('SELECT comment_id,name,subject,comment_data,user_id FROM '.table_prefix.'comments WHERE comment_id='.intval($_REQUEST['id']).';'); |
|
441 if($e) |
|
442 { |
|
443 $comment = $db->fetchrow(); |
|
444 $auth_edit = ( ( intval($comment['user_id']) == $session->user_id && $session->user_logged_in ) || $session->user_level >= USER_LEVEL_MOD ); |
|
445 if($auth_edit) |
|
446 { |
|
447 switch($_GET['sub']) |
|
448 { |
|
449 case 'editcomment': |
|
450 if(!isset($_GET['id']) || ( isset($_GET['id']) && !preg_match('#^([0-9]+)$#', $_GET['id']) )) { echo '<p>Invalid comment ID</p>'; break; } |
|
451 $row =& $comment; |
|
452 echo '<h3>Edit comment</h3><form action="'.makeUrl($paths->fullpage, 'sub=savecomment').'" method="post">'; |
|
453 echo "<br /><div class='mdg-comment' style='padding: 0;'><table border='0' width='100%' cellspacing='1' cellpadding='4'> |
|
454 <tr><td class='row1'>Subject:</td><td class='row1'><input type='text' name='subj' value='{$row['subject']}' /></td></tr> |
|
455 <tr><td class='row2'>Comment:</td><td class='row2'><textarea rows='10' cols='40' style='width: 98%;' name='text'>{$row['comment_data']}</textarea></td></tr> |
|
456 <tr><td class='row1' colspan='2' class='row1' style='text-align: center;'><input type='hidden' name='id' value='{$row['comment_id']}' /><input type='submit' value='Save Changes' /></td></tr> |
|
457 </table></div>"; |
|
458 echo '</form>'; |
|
459 return false; |
|
460 break; |
|
461 case 'savecomment': |
|
462 if(empty($_POST['subj']) || empty($_POST['text'])) { echo '<p>Invalid request</p>'; break; } |
|
463 $r = PageUtils::savecomment_neater((string)$post_id, 'Blog', $_POST['subj'], $_POST['text'], (int)$_POST['id']); |
|
464 if($r != 'good') { echo "<pre>$r</pre>"; return false; } |
|
465 break; |
|
466 case 'deletecomment': |
|
467 if(isset($_GET['id'])) |
|
468 { |
|
469 $q = 'DELETE FROM '.table_prefix.'comments WHERE comment_id='.intval($_GET['id']).' LIMIT 1;'; |
|
470 $e=$db->sql_query($q); |
|
471 if(!$e) |
|
472 { |
|
473 echo 'Error during query: '.mysql_error().'<br /><br />Query:<br />'.$q; |
|
474 return false; |
|
475 } |
|
476 $e=$db->sql_query('UPDATE '.table_prefix.'blog SET num_comments=num_comments-1 WHERE post_id='.$post_id.';'); |
|
477 if(!$e) |
|
478 { |
|
479 echo 'Error during query: '.mysql_error().'<br /><br />Query:<br />'.$q; |
|
480 return false; |
|
481 } |
|
482 } |
|
483 break; |
|
484 case 'admin': |
|
485 if(isset($_GET['action']) && $session->user_level >= USER_LEVEL_MOD) // Nip hacking attempts in the bud |
|
486 { |
|
487 switch($_GET['action']) { |
|
488 case "delete": |
|
489 if(isset($_GET['id'])) |
|
490 { |
|
491 $q = 'DELETE FROM '.table_prefix.'comments WHERE comment_id='.intval($_GET['id']).' LIMIT 1;'; |
|
492 $e=$db->sql_query($q); |
|
493 if(!$e) |
|
494 { |
|
495 echo 'Error during query: '.mysql_error().'<br /><br />Query:<br />'.$q; |
|
496 return false; |
|
497 } |
|
498 $e=$db->sql_query('UPDATE '.table_prefix.'blog SET num_comments=num_comments-1 WHERE post_id='.$post_id.';'); |
|
499 if(!$e) |
|
500 { |
|
501 echo 'Error during query: '.mysql_error().'<br /><br />Query:<br />'.$q; |
|
502 return false; |
|
503 } |
|
504 } |
|
505 break; |
|
506 case "approve": |
|
507 if(isset($_GET['id'])) |
|
508 { |
|
509 $where = 'comment_id='.intval($_GET['id']); |
|
510 $q = 'SELECT approved FROM '.table_prefix.'comments WHERE '.$where.' LIMIT 1;'; |
|
511 $e = $db->sql_query($q); |
|
512 if(!$e) die('alert(unesape(\''.rawurlencode('Error selecting approval status: '.mysql_error().'\n\nQuery:\n'.$q).'\'));'); |
|
513 $r = $db->fetchrow(); |
|
514 $a = ( $r['approved'] ) ? '0' : '1'; |
|
515 $q = 'UPDATE '.table_prefix.'comments SET approved='.$a.' WHERE '.$where.';'; |
|
516 $e=$db->sql_query($q); |
|
517 if(!$e) |
|
518 { |
|
519 echo 'Error during query: '.mysql_error().'<br /><br />Query:<br />'.$q; |
|
520 return false; |
|
521 } |
|
522 if($a == '1') |
|
523 { |
|
524 $q = 'UPDATE '.table_prefix.'blog SET num_comments=num_comments+1 WHERE post_id='.$post_id.';'; |
|
525 } |
|
526 else |
|
527 { |
|
528 $q = 'UPDATE '.table_prefix.'blog SET num_comments=num_comments-1 WHERE post_id='.$post_id.';'; |
|
529 } |
|
530 $e=$db->sql_query($q); |
|
531 if(!$e) |
|
532 { |
|
533 echo 'Error during query: '.mysql_error().'<br /><br />Query:<br />'.$q; |
|
534 return false; |
|
535 } |
|
536 } |
|
537 break; |
|
538 } |
|
539 } |
|
540 break; |
|
541 } |
|
542 } |
|
543 else |
|
544 { |
|
545 echo '<div class="error-box">You are not authorized to perform this action.</div>'; |
|
546 } |
|
547 } |
|
548 } |
|
549 |
|
550 if(isset($_POST['__doPostBack'])) |
|
551 { |
|
552 if(getConfig('comments_need_login') == '2' && !$session->user_logged_in) echo('Access denied to post comments: you need to be logged in first.'); |
|
553 else |
|
554 { |
|
555 $cb=false; |
|
556 if(getConfig('comments_need_login') == '1' && !$session->user_logged_in) |
|
557 { |
|
558 if(!isset($_POST['captcha_input']) || !isset($_POST['captcha_id'])) |
|
559 { |
|
560 echo('BUG: PageUtils::addcomment: no CAPTCHA data passed to method'); |
|
561 $cb=true; |
|
562 } |
|
563 else |
|
564 { |
|
565 $result = $session->get_captcha($_POST['captcha_id']); |
|
566 if($_POST['captcha_input'] != $result) { $cb=true; echo('The confirmation code you entered was incorrect.'); } |
|
567 } |
|
568 } |
|
569 if(!$cb) |
|
570 { |
|
571 $text = RenderMan::preprocess_text($_POST['text']); |
|
572 $name = $session->user_logged_in ? RenderMan::preprocess_text($session->username) : RenderMan::preprocess_text($_POST['name']); |
|
573 $subj = RenderMan::preprocess_text($_POST['subj']); |
|
574 if(getConfig('approve_comments')=='1') $appr = '0'; else $appr = '1'; |
|
575 $q = 'INSERT INTO '.table_prefix.'comments(page_id,namespace,subject,comment_data,name,user_id,approved,time) VALUES(\''.$post_id.'\',\'Blog\',\''.$subj.'\',\''.$text.'\',\''.$name.'\','.$session->user_id.','.$appr.','.time().')'; |
|
576 $e = $db->sql_query($q); |
|
577 if(!$e) echo 'Error inserting comment data: '.mysql_error().'<br /><br />Query:<br />'.$q; |
|
578 else |
|
579 { |
|
580 echo '<div class="info-box">Your comment has been posted.</div>'; |
|
581 if(getConfig('approve_comments')=='1') |
|
582 { |
|
583 $e=$db->sql_query('UPDATE '.table_prefix.'blog SET num_comments=num_comments+1 WHERE post_id='.$post_id.';'); |
|
584 if(!$e) |
|
585 { |
|
586 echo 'Error during query: '.mysql_error().'<br /><br />Query:<br />'.$q; |
|
587 return false; |
|
588 } |
|
589 } |
|
590 } |
|
591 } |
|
592 } |
|
593 } |
|
594 |
|
595 $apprv_clause = ( $session->user_level >= USER_LEVEL_MOD ) ? '' : 'AND approved=1'; |
|
596 |
|
597 $q = $db->sql_query('SELECT c.comment_id,c.subject,c.comment_data,c.name,c.time,c.approved,c.time,u.signature,u.user_level,u.user_id FROM '.table_prefix.'comments AS c |
|
598 LEFT JOIN '.table_prefix.'users AS u |
|
599 ON u.user_id=c.user_id |
|
600 WHERE page_id='.$post_id.' |
|
601 AND namespace=\'Blog\' |
|
602 '.$apprv_clause.' |
|
603 ORDER BY time DESC;'); |
|
604 if(!$q) |
|
605 { |
|
606 echo $db->get_error(); |
|
607 return false; |
|
608 } |
|
609 $posts = Array(); |
|
610 while($row = $db->fetchrow()) |
|
611 { |
|
612 $row['text'] =& $row['comment_data']; |
|
613 $posts[] = $row; |
|
614 } |
|
615 return $posts; |
|
616 } |
|
617 |
|
618 /** |
|
619 * Formats a comments array from EnanoPress_GetComments() as HTML |
|
620 * @param array $comments The array of fetched comments |
|
621 * @return string |
|
622 */ |
|
623 |
|
624 function EnanoPress_FormatComments($comments) |
|
625 { |
|
626 global $db, $session, $paths, $template, $plugins; // Common objects |
|
627 |
|
628 ob_start(); |
|
629 $tpl = $template->makeParser('comment.tpl'); |
|
630 |
|
631 $seed = substr(md5(microtime() . mt_rand()), 0, 12); |
|
632 |
|
633 ?> |
|
634 <script type="text/javascript"> |
|
635 function toggleCommentForm() |
|
636 { |
|
637 document.getElementById('commentform_<?php echo $seed; ?>').style.display = 'block'; |
|
638 document.getElementById('commentlink_<?php echo $seed; ?>').style.display = 'none'; |
|
639 } |
|
640 </script> |
|
641 <?php |
|
642 |
|
643 echo "<h3 id='post-comments'>Post comments</h3>"; |
|
644 if ( count($comments) < 1 ) |
|
645 { |
|
646 $commentlink = ( getConfig('comments_need_login') == '2' && !$session->user_logged_in ) ? '<a href="'.makeUrl('Special:Login/'.$paths->fullpage).'">Log in to post a comment...</a>' : '<a href="'.makeUrl($paths->fullpage, 'act=postcomment', true).'" id="commentlink_'.$seed.'" onclick="toggleCommentForm(); return false;">Leave a comment...</a>' ; |
|
647 echo '<p>There are no comments on this post. Yours could be the first! '.$commentlink.'</p>'; |
|
648 } |
|
649 $i = -1; |
|
650 |
|
651 foreach($comments as $comment) |
|
652 { |
|
653 $auth_edit = ( ( intval($comment['user_id']) == $session->user_id && $session->user_logged_in ) || $session->user_level >= USER_LEVEL_MOD ); |
|
654 $auth_mod = ( $session->user_level >= USER_LEVEL_MOD ); |
|
655 |
|
656 // Comment ID (used in the Javascript apps) |
|
657 $strings['ID'] = (string)$i; |
|
658 |
|
659 // Determine the name, and whether to link to the user page or not |
|
660 $name = ''; |
|
661 if($comment['user_id'] > 0) $name .= '<a href="'.makeUrlNS('User', str_replace(' ', '_', $comment['name'])).'">'; |
|
662 $name .= $comment['name']; |
|
663 if($comment['user_id'] > 0) $name .= '</a>'; |
|
664 $strings['NAME'] = $name; unset($name); |
|
665 |
|
666 // Subject |
|
667 $s = $comment['subject']; |
|
668 if(!$comment['approved']) $s .= ' <span style="color: #D84308">(Unapproved)</span>'; |
|
669 $strings['SUBJECT'] = $s; |
|
670 |
|
671 // Date and time |
|
672 $strings['DATETIME'] = date('F d, Y h:i a', $comment['time']); |
|
673 |
|
674 // User level |
|
675 switch($comment['user_level']) |
|
676 { |
|
677 default: |
|
678 case USER_LEVEL_GUEST: |
|
679 $l = 'Guest'; |
|
680 break; |
|
681 case USER_LEVEL_MEMBER: |
|
682 $l = 'Member'; |
|
683 break; |
|
684 case USER_LEVEL_MOD: |
|
685 $l = 'Moderator'; |
|
686 break; |
|
687 case USER_LEVEL_ADMIN: |
|
688 $l = 'Administrator'; |
|
689 break; |
|
690 } |
|
691 $strings['USER_LEVEL'] = $l; unset($l); |
|
692 |
|
693 // The actual comment data |
|
694 $strings['DATA'] = RenderMan::render($comment['text']); |
|
695 |
|
696 // Edit link |
|
697 $strings['EDIT_LINK'] = '<a href="'.makeUrl($paths->fullpage, 'sub=editcomment&id='.$comment['comment_id']).'" id="editbtn_'.$i.'">edit</a>'; |
|
698 |
|
699 // Delete link |
|
700 $strings['DELETE_LINK'] = '<a href="'.makeUrl($paths->fullpage, 'sub=deletecomment&id='.$comment['comment_id']).'">delete</a>'; |
|
701 |
|
702 // Send PM link |
|
703 $strings['SEND_PM_LINK'] = ( $session->user_logged_in && $comment['user_id'] > 0 ) ? '<a href="'.makeUrlNS('Special', 'PrivateMessages/Compose/To/'.$comment['name']).'">Send private message</a>' : ''; |
|
704 |
|
705 // Add Buddy link |
|
706 $strings['ADD_BUDDY_LINK'] = ( $session->user_logged_in && $comment['user_id'] > 0 ) ? '<a href="'.makeUrlNS('Special', 'PrivateMessages/FriendList/Add/'.$comment['name']).'">Add Buddy</a>' : ''; |
|
707 |
|
708 // Mod links |
|
709 $applink = ''; |
|
710 $applink .= '<a href="'.makeUrl($paths->fullpage, 'sub=admin&action=approve&id='.$comment['comment_id']).'" id="mdgApproveLink'.$i.'">'; |
|
711 if($comment['approved']) $applink .= 'Unapprove'; |
|
712 else $applink .= 'Approve'; |
|
713 $applink .= '</a>'; |
|
714 $strings['MOD_APPROVE_LINK'] = $applink; |
|
715 unset($applink); |
|
716 $strings['MOD_DELETE_LINK'] = '<a href="'.makeUrl($paths->fullpage, 'sub=admin&action=delete&id='.$comment['comment_id']).'">Delete</a>'; |
|
717 |
|
718 // Signature |
|
719 $strings['SIGNATURE'] = ''; |
|
720 if($comment['signature'] != '') $strings['SIGNATURE'] = RenderMan::render($comment['signature']); |
|
721 |
|
722 $bool['auth_mod'] = $auth_mod; |
|
723 $bool['can_edit'] = $auth_edit; |
|
724 $bool['signature'] = ( $strings['SIGNATURE'] == '' ) ? false : true; |
|
725 |
|
726 $tpl->assign_vars($strings); |
|
727 $tpl->assign_bool($bool); |
|
728 echo $tpl->run(); |
|
729 } |
|
730 |
|
731 $sn = $session->user_logged_in ? $session->username . '<input name="name" id="mdgScreenName" type="hidden" value="'.$session->username.'" />' : '<input name="name" id="mdgScreenName" type="text" size="35" />'; |
|
732 if(getConfig('comments_need_login') == '1') |
|
733 { |
|
734 $session->kill_captcha(); |
|
735 $captcha = $session->make_captcha(); |
|
736 } |
|
737 $captcha = ( getConfig('comments_need_login') == '1' && !$session->user_logged_in ) ? '<tr><td>Visual confirmation:<br /><small>Please enter the code you see on the right.</small></td><td><img src="'.makeUrlNS('Special', 'Captcha/'.$captcha).'" alt="Visual confirmation" style="cursor: pointer;" onclick="this.src = \''.makeUrlNS("Special", "Captcha/".$captcha).'/\'+Math.floor(Math.random() * 100000);" /><input name="captcha_id" id="mdgCaptchaID" type="hidden" value="'.$captcha.'" /><br />Code: <input name="captcha_input" id="mdgCaptchaInput" type="text" size="10" /><br /><small><script type="text/javascript">document.write("If you can\'t read the code, click on the image to generate a new one.");</script><noscript>If you can\'t read the code, please refresh this page to generate a new one.</noscript></small></td></tr>' : ''; |
|
738 |
|
739 echo '<div id="commentform_'.$seed.'"> |
|
740 '.EnanoPress_Separator().' |
|
741 <form action="'.makeUrl($paths->fullpage, 'act=postcomment', true).'" method="post"> |
|
742 <table border="0"> |
|
743 <tr><td>Your name or screen name:</td><td>'.$sn.'</td></tr> |
|
744 <tr><td>Comment subject:</td><td><input name="subj" id="mdgSubject" type="text" size="35" /></td></tr> |
|
745 '.$captcha.' |
|
746 <tr><td valign="top">Comment text:<br />(most HTML will be stripped)</td><td><textarea name="text" id="mdgCommentArea" rows="10" cols="40"></textarea></td></tr> |
|
747 <tr><td colspan="2" style="text-align: center;"><input type="submit" name="__doPostBack" value="Submit Comment" /></td></tr> |
|
748 </table> |
|
749 </form> |
|
750 </div> |
|
751 <script type="text/javascript"> |
|
752 document.getElementById(\'commentform_'.$seed.'\').style.display = \'none\'; |
|
753 </script> |
|
754 '; |
|
755 |
|
756 $ret = ob_get_contents(); |
|
757 ob_end_clean(); |
|
758 return $ret; |
|
759 } |
|
760 |
|
761 function page_Admin_EnanoPress() |
|
762 { |
|
763 global $db, $session, $paths, $template, $plugins; if($session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN) { header('Location: '.makeUrl($paths->nslist['Special'].'Administration'.urlSeparator.'noheaders')); die('Hacking attempt'); } |
|
764 echo '<p>Coming soon!</p>'; |
|
765 } |
|
766 |
|
767 ?> |