KXStudio Website https://kx.studio/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

760 lines
34KB

  1. <?php
  2. require_once "model.Comment.php";
  3. require_once "lib/Akismet.php";
  4. class Comments extends Modules {
  5. public function __init() {
  6. $this->addAlias("metaWeblog_newPost_preQuery", "metaWeblog_editPost_preQuery");
  7. $this->addAlias("comment_grab", "comments_get");
  8. }
  9. static function __install() {
  10. $sql = SQL::current();
  11. $sql->query("CREATE TABLE IF NOT EXISTS __comments (
  12. id INTEGER PRIMARY KEY AUTO_INCREMENT,
  13. body LONGTEXT,
  14. author VARCHAR(250) DEFAULT '',
  15. author_url VARCHAR(128) DEFAULT '',
  16. author_email VARCHAR(128) DEFAULT '',
  17. author_ip INTEGER DEFAULT '0',
  18. author_agent VARCHAR(255) DEFAULT '',
  19. status VARCHAR(32) default 'denied',
  20. post_id INTEGER DEFAULT 0,
  21. user_id INTEGER DEFAULT 0,
  22. created_at DATETIME DEFAULT NULL,
  23. updated_at DATETIME DEFAULT NULL
  24. ) DEFAULT CHARSET=utf8");
  25. $config = Config::current();
  26. $config->set("default_comment_status", "denied");
  27. $config->set("allowed_comment_html", array("strong", "em", "blockquote", "code", "pre", "a"));
  28. $config->set("comments_per_page", 25);
  29. $config->set("akismet_api_key", null);
  30. $config->set("auto_reload_comments", 30);
  31. $config->set("enable_reload_comments", false);
  32. Group::add_permission("add_comment", "Add Comments");
  33. Group::add_permission("add_comment_private", "Add Comments to Private Posts");
  34. Group::add_permission("edit_comment", "Edit Comments");
  35. Group::add_permission("edit_own_comment", "Edit Own Comments");
  36. Group::add_permission("delete_comment", "Delete Comments");
  37. Group::add_permission("delete_own_comment", "Delete Own Comments");
  38. Group::add_permission("code_in_comments", "Can Use HTML In Comments");
  39. }
  40. static function __uninstall($confirm) {
  41. if ($confirm)
  42. SQL::current()->query("DROP TABLE __comments");
  43. $config = Config::current();
  44. $config->remove("default_comment_status");
  45. $config->remove("allowed_comment_html");
  46. $config->remove("comments_per_page");
  47. $config->remove("akismet_api_key");
  48. $config->remove("auto_reload_comments");
  49. $config->remove("enable_reload_comments");
  50. Group::remove_permission("add_comment");
  51. Group::remove_permission("add_comment_private");
  52. Group::remove_permission("edit_comment");
  53. Group::remove_permission("edit_own_comment");
  54. Group::remove_permission("delete_comment");
  55. Group::remove_permission("delete_own_comment");
  56. Group::remove_permission("code_in_comments");
  57. }
  58. static function route_add_comment() {
  59. $post = new Post($_POST['post_id'], array("drafts" => true));
  60. if (!Comment::user_can($post))
  61. show_403(__("Access Denied"), __("You cannot comment on this post.", "comments"));
  62. if (empty($_POST['author'])) error(__("Error"), __("Author can't be blank.", "comments"));
  63. if (empty($_POST['email'])) error(__("Error"), __("E-Mail address can't be blank.", "comments"));
  64. if (empty($_POST['body'])) error(__("Error"), __("Message can't be blank.", "comments"));
  65. Comment::create($_POST['author'],
  66. $_POST['email'],
  67. $_POST['url'],
  68. $_POST['body'],
  69. $post);
  70. }
  71. static function admin_update_comment() {
  72. if (empty($_POST))
  73. redirect("/admin/?action=manage_comments");
  74. $comment = new Comment($_POST['id']);
  75. if (!$comment->editable())
  76. show_403(__("Access Denied"), __("You do not have sufficient privileges to edit this comment.", "comments"));
  77. $visitor = Visitor::current();
  78. $status = ($visitor->group->can("edit_comment")) ? $_POST['status'] : $comment->status ;
  79. $created_at = ($visitor->group->can("edit_comment")) ? datetime($_POST['created_at']) : $comment->created_at ;
  80. $comment->update($_POST['author'],
  81. $_POST['author_email'],
  82. $_POST['author_url'],
  83. $_POST['body'],
  84. $status,
  85. $created_at);
  86. if (isset($_POST['ajax']))
  87. exit("{ \"comment_id\": \"".$_POST['id']."\", \"comment_timestamp\": \"".$created_at."\" }");
  88. if ($_POST['status'] == "spam")
  89. Flash::notice(__("Comment updated."), "/admin/?action=manage_spam");
  90. else
  91. Flash::notice(_f("Comment updated. <a href=\"%s\">View Comment &rarr;</a>",
  92. array($comment->post->url()."#comment_".$comment->id),
  93. "comments"),
  94. "/admin/?action=manage_comments");
  95. }
  96. static function admin_delete_comment($admin) {
  97. $comment = new Comment($_GET['id']);
  98. if (!$comment->deletable())
  99. show_403(__("Access Denied"), __("You do not have sufficient privileges to delete this comment.", "comments"));
  100. $admin->display("delete_comment", array("comment" => $comment));
  101. }
  102. static function admin_destroy_comment() {
  103. if (empty($_POST['id']))
  104. error(__("No ID Specified"), __("An ID is required to delete a comment.", "comments"));
  105. if ($_POST['destroy'] == "bollocks")
  106. redirect("/admin/?action=manage_comments");
  107. if (!isset($_POST['hash']) or $_POST['hash'] != Config::current()->secure_hashkey)
  108. show_403(__("Access Denied"), __("Invalid security key."));
  109. $comment = new Comment($_POST['id']);
  110. if (!$comment->deletable())
  111. show_403(__("Access Denied"), __("You do not have sufficient privileges to delete this comment.", "comments"));
  112. Comment::delete($_POST['id']);
  113. if (isset($_POST['ajax']))
  114. exit;
  115. Flash::notice(__("Comment deleted."));
  116. if ($comment->status == "spam")
  117. redirect("/admin/?action=manage_spam");
  118. else
  119. redirect("/admin/?action=manage_comments");
  120. }
  121. static function admin_manage_spam($admin) {
  122. if (!Visitor::current()->group->can("edit_comment", "delete_comment", true))
  123. show_403(__("Access Denied"), __("You do not have sufficient privileges to manage any comments.", "comments"));
  124. fallback($_GET['query'], "");
  125. list($where, $params) = keywords($_GET['query'], "body LIKE :query");
  126. $where["status"] = "spam";
  127. $admin->display("manage_spam",
  128. array("comments" => new Paginator(Comment::find(array("placeholders" => true,
  129. "where" => $where,
  130. "params" => $params)),
  131. 25)));
  132. }
  133. static function admin_purge_spam() {
  134. if (!Visitor::current()->group->can("delete_comment"))
  135. show_403(__("Access Denied"), __("You do not have sufficient privileges to delete comments.", "comments"));
  136. SQL::current()->delete("comments", "status = 'spam'");
  137. Flash::notice(__("All spam deleted.", "comments"), "/admin/?action=manage_spam");
  138. }
  139. public function post_options($fields, $post = null) {
  140. if ($post)
  141. $post->comment_status = oneof(@$post->comment_status, "open");
  142. $fields[] = array("attr" => "option[comment_status]",
  143. "label" => __("Comment Status", "comments"),
  144. "type" => "select",
  145. "options" => array(array("name" => __("Open", "comments"),
  146. "value" => "open",
  147. "selected" => ($post ? $post->comment_status == "open" : true)),
  148. array("name" => __("Closed", "comments"),
  149. "value" => "closed",
  150. "selected" => ($post ? $post->comment_status == "closed" : false)),
  151. array("name" => __("Private", "comments"),
  152. "value" => "private",
  153. "selected" => ($post ? $post->comment_status == "private" : false)),
  154. array("name" => __("Registered Only", "comments"),
  155. "value" => "registered_only",
  156. "selected" => ($post ? $post->comment_status == "registered_only" : false))));
  157. return $fields;
  158. }
  159. static function trackback_receive($url, $title, $excerpt, $blog_name) {
  160. $sql = SQL::current();
  161. $count = $sql->count("comments",
  162. array("post_id" => $_GET['id'],
  163. "author_url" => $_POST['url']));
  164. if ($count)
  165. trackback_respond(true, __("A ping from that URL is already registered.", "comments"));
  166. $post = new Post($_GET["id"]);
  167. if ($post->no_results)
  168. return false;
  169. Comment::create($blog_name,
  170. "",
  171. $_POST["url"],
  172. '<strong><a href="'.fix($url).'">'.fix($title).'</a></strong>'."\n".$excerpt,
  173. $post,
  174. "trackback");
  175. }
  176. public function pingback($post, $to, $from, $title, $excerpt) {
  177. $sql = SQL::current();
  178. $count = $sql->count("comments",
  179. array("post_id" => $post->id,
  180. "author_url" => $from));
  181. if ($count)
  182. return new IXR_Error(48, __("A ping from that URL is already registered.", "comments"));
  183. Comment::create($title,
  184. "",
  185. $from,
  186. $excerpt,
  187. $post,
  188. "pingback");
  189. }
  190. static function delete_post($post) {
  191. SQL::current()->delete("comments", array("post_id" => $post->id));
  192. }
  193. static function delete_user($user) {
  194. SQL::current()->update("comments", array("user_id" => $user->id), array("user_id" => 0));
  195. }
  196. static function admin_comment_settings($admin) {
  197. if (!Visitor::current()->group->can("change_settings"))
  198. show_403(__("Access Denied"), __("You do not have sufficient privileges to change settings."));
  199. if (empty($_POST))
  200. return $admin->display("comment_settings");
  201. if (!isset($_POST['hash']) or $_POST['hash'] != Config::current()->secure_hashkey)
  202. show_403(__("Access Denied"), __("Invalid security key."));
  203. $config = Config::current();
  204. $set = array($config->set("allowed_comment_html", explode(", ", $_POST['allowed_comment_html'])),
  205. $config->set("default_comment_status", $_POST['default_comment_status']),
  206. $config->set("comments_per_page", $_POST['comments_per_page']),
  207. $config->set("auto_reload_comments", $_POST['auto_reload_comments']),
  208. $config->set("enable_reload_comments", isset($_POST['enable_reload_comments'])));
  209. if (!empty($_POST['akismet_api_key'])) {
  210. $_POST['akismet_api_key'] = trim($_POST['akismet_api_key']);
  211. $akismet = new Akismet($config->url, $_POST['akismet_api_key']);
  212. if (!$akismet->isKeyValid()) {
  213. Flash::warning(__("Invalid Akismet API key."), "/admin/?action=comment_settings");
  214. $set[] = false;
  215. } else
  216. $set[] = $config->set("akismet_api_key", $_POST['akismet_api_key']);
  217. }
  218. if (!in_array(false, $set))
  219. Flash::notice(__("Settings updated."), "/admin/?action=comment_settings");
  220. }
  221. static function settings_nav($navs) {
  222. if (Visitor::current()->group->can("change_settings"))
  223. $navs["comment_settings"] = array("title" => __("Comments", "comments"));
  224. return $navs;
  225. }
  226. static function manage_nav($navs) {
  227. if (!Comment::any_editable() and !Comment::any_deletable())
  228. return $navs;
  229. $sql = SQL::current();
  230. $comment_count = $sql->count("comments", array("status not" => "spam"));
  231. $spam_count = $sql->count("comments", array("status" => "spam"));
  232. $navs["manage_comments"] = array("title" => _f("Comments (%d)", $comment_count, "comments"),
  233. "selected" => array("edit_comment", "delete_comment"));
  234. if (Visitor::current()->group->can("edit_comment", "delete_comment"))
  235. $navs["manage_spam"] = array("title" => _f("Spam (%d)", $spam_count, "comments"));
  236. return $navs;
  237. }
  238. static function manage_nav_pages($pages) {
  239. array_push($pages, "manage_comments", "manage_spam", "edit_comment", "delete_comment");
  240. return $pages;
  241. }
  242. public function admin_edit_comment($admin) {
  243. if (empty($_GET['id']))
  244. error(__("No ID Specified"), __("An ID is required to edit a comment.", "comments"));
  245. $comment = new Comment($_GET['id'], array("filter" => false));
  246. if (!$comment->editable())
  247. show_403(__("Access Denied"), __("You do not have sufficient privileges to edit this comment.", "comments"));
  248. $admin->display("edit_comment", array("comment" => $comment));
  249. }
  250. static function admin_manage_comments($admin) {
  251. if (!Comment::any_editable() and !Comment::any_deletable())
  252. show_403(__("Access Denied"), __("You do not have sufficient privileges to manage any comments.", "comments"));
  253. fallback($_GET['query'], "");
  254. list($where, $params) = keywords($_GET['query'], "body LIKE :query");
  255. $where[] = "status != 'spam'";
  256. $visitor = Visitor::current();
  257. if (!$visitor->group->can("edit_comment", "delete_comment", true))
  258. $where["user_id"] = $visitor->id;
  259. $admin->display("manage_comments",
  260. array("comments" => new Paginator(Comment::find(array("placeholders" => true,
  261. "where" => $where,
  262. "params" => $params)),
  263. 25)));
  264. }
  265. static function admin_bulk_comments() {
  266. $from = (!isset($_GET['from'])) ? "manage_comments" : "manage_spam" ;
  267. if (!isset($_POST['comment']))
  268. Flash::warning(__("No comments selected."), "/admin/?action=".$from);
  269. $comments = array_keys($_POST['comment']);
  270. if (isset($_POST['delete'])) {
  271. foreach ($comments as $comment) {
  272. $comment = new Comment($comment);
  273. if ($comment->deletable())
  274. Comment::delete($comment->id);
  275. }
  276. Flash::notice(__("Selected comments deleted.", "comments"));
  277. }
  278. $false_positives = array();
  279. $false_negatives = array();
  280. $sql = SQL::current();
  281. $config = Config::current();
  282. if (isset($_POST['deny'])) {
  283. foreach ($comments as $comment) {
  284. $comment = new Comment($comment);
  285. if (!$comment->editable())
  286. continue;
  287. if ($comment->status == "spam")
  288. $false_positives[] = $comment;
  289. $sql->update("comments", array("id" => $comment->id), array("status" => "denied"));
  290. }
  291. Flash::notice(__("Selected comments denied.", "comments"));
  292. }
  293. if (isset($_POST['approve'])) {
  294. foreach ($comments as $comment) {
  295. $comment = new Comment($comment);
  296. if (!$comment->editable())
  297. continue;
  298. if ($comment->status == "spam")
  299. $false_positives[] = $comment;
  300. $sql->update("comments", array("id" => $comment->id), array("status" => "approved"));
  301. }
  302. Flash::notice(__("Selected comments approved.", "comments"));
  303. }
  304. if (isset($_POST['spam'])) {
  305. foreach ($comments as $comment) {
  306. $comment = new Comment($comment);
  307. if (!$comment->editable())
  308. continue;
  309. $sql->update("comments", array("id" => $comment->id), array("status" => "spam"));
  310. $false_negatives[] = $comment;
  311. }
  312. Flash::notice(__("Selected comments marked as spam.", "comments"));
  313. }
  314. if (!empty($config->akismet_api_key)) {
  315. if (!empty($false_positives))
  316. self::reportHam($false_positives);
  317. if (!empty($false_negatives))
  318. self::reportSpam($false_negatives);
  319. }
  320. redirect("/admin/?action=".$from);
  321. }
  322. static function reportHam($comments) {
  323. $config = Config::current();
  324. foreach($comments as $comment) {
  325. $akismet = new Akismet($config->url, $config->akismet_api_key);
  326. $akismet->setCommentAuthor($comment->author);
  327. $akismet->setCommentAuthorEmail($comment->author_email);
  328. $akismet->setCommentAuthorURL($comment->author_url);
  329. $akismet->setCommentContent($comment->body);
  330. $akismet->setPermalink($comment->post_id);
  331. $akismet->setReferrer($comment->author_agent);
  332. $akismet->setUserIP($comment->author_ip);
  333. $akismet->submitHam();
  334. }
  335. }
  336. static function reportSpam($comments) {
  337. $config = Config::current();
  338. foreach($comments as $comment) {
  339. $akismet = new Akismet($config->url, $config->akismet_api_key);
  340. $akismet->setCommentAuthor($comment->author);
  341. $akismet->setCommentAuthorEmail($comment->author_email);
  342. $akismet->setCommentAuthorURL($comment->author_url);
  343. $akismet->setCommentContent($comment->body);
  344. $akismet->setPermalink($comment->post_id);
  345. $akismet->setReferrer($comment->author_agent);
  346. $akismet->setUserIP($comment->author_ip);
  347. $akismet->submitSpam();
  348. }
  349. }
  350. static function manage_posts_column_header() {
  351. echo '<th>'.__("Comments", "comments").'</th>';
  352. }
  353. static function manage_posts_column($post) {
  354. echo '<td align="center"><a href="'.$post->url().'#comments">'.$post->comment_count.'</a></td>';
  355. }
  356. static function scripts($scripts) {
  357. $scripts[] = Config::current()->chyrp_url."/modules/comments/javascript.php";
  358. return $scripts;
  359. }
  360. static function ajax() {
  361. header("Content-Type: application/x-javascript", true);
  362. $config = Config::current();
  363. $sql = SQL::current();
  364. $trigger = Trigger::current();
  365. $visitor = Visitor::current();
  366. $theme = Theme::current();
  367. $main = MainController::current();
  368. switch($_POST['action']) {
  369. case "reload_comments":
  370. $post = new Post($_POST['post_id']);
  371. if ($post->no_results)
  372. break;
  373. if ($post->latest_comment > $_POST['last_comment']) {
  374. $new_comments = $sql->select("comments",
  375. "id, created_at",
  376. array("post_id" => $_POST['post_id'],
  377. "created_at >" => $_POST['last_comment'],
  378. "status not" => "spam", "status != 'denied' OR (
  379. (user_id != 0 AND user_id = :visitor_id) OR (
  380. id IN ".self::visitor_comments()."))"
  381. ),
  382. "created_at ASC",
  383. array(":visitor_id" => $visitor->id));
  384. $ids = array();
  385. $last_comment = "";
  386. while ($the_comment = $new_comments->fetchObject()) {
  387. $ids[] = $the_comment->id;
  388. if (strtotime($last_comment) < strtotime($the_comment->created_at))
  389. $last_comment = $the_comment->created_at;
  390. }
  391. ?>
  392. { comment_ids: [ <?php echo implode(", ", $ids); ?> ], last_comment: "<?php echo $last_comment; ?>" }
  393. <?php
  394. }
  395. break;
  396. case "show_comment":
  397. $comment = new Comment($_POST['comment_id']);
  398. $trigger->call("show_comment", $comment);
  399. $main->display("content/comment", array("comment" => $comment));
  400. break;
  401. case "delete_comment":
  402. $comment = new Comment($_POST['id']);
  403. if (!$comment->deletable())
  404. break;
  405. Comment::delete($_POST['id']);
  406. break;
  407. case "edit_comment":
  408. $comment = new Comment($_POST['comment_id'], array("filter" => false));
  409. if (!$comment->editable())
  410. break;
  411. if ($theme->file_exists("forms/comment/edit"))
  412. $main->display("forms/comment/edit", array("comment" => $comment));
  413. else
  414. require "edit_form.php";
  415. break;
  416. }
  417. }
  418. public function import_chyrp_post($entry, $post) {
  419. $chyrp = $entry->children("http://chyrp.net/export/1.0/");
  420. if (!isset($chyrp->comment)) return;
  421. $sql = SQL::current();
  422. foreach ($chyrp->comment as $comment) {
  423. $chyrp = $comment->children("http://chyrp.net/export/1.0/");
  424. $comment = $comment->children("http://www.w3.org/2005/Atom");
  425. $login = $comment->author->children("http://chyrp.net/export/1.0/")->login;
  426. $user_id = $sql->select("users", "id", array("login" => $login), "id DESC")->fetchColumn();
  427. Comment::add(unfix($comment->content),
  428. unfix($comment->author->name),
  429. unfix($comment->author->uri),
  430. unfix($comment->author->email),
  431. $chyrp->author->ip,
  432. unfix($chyrp->author->agent),
  433. $chyrp->status,
  434. datetime($comment->published),
  435. ($comment->published == $comment->updated) ? null : datetime($comment->updated),
  436. $post,
  437. ($user_id ? $user_id : 0));
  438. }
  439. }
  440. static function import_wordpress_post($item, $post) {
  441. $wordpress = $item->children("http://wordpress.org/export/1.0/");
  442. if (!isset($wordpress->comment)) return;
  443. foreach ($wordpress->comment as $comment) {
  444. $comment = $comment->children("http://wordpress.org/export/1.0/");
  445. fallback($comment->comment_content, "");
  446. fallback($comment->comment_author, "");
  447. fallback($comment->comment_author_url, "");
  448. fallback($comment->comment_author_email, "");
  449. fallback($comment->comment_author_IP, "");
  450. Comment::add($comment->comment_content,
  451. $comment->comment_author,
  452. $comment->comment_author_url,
  453. $comment->comment_author_email,
  454. $comment->comment_author_IP,
  455. "",
  456. ((isset($comment->comment_approved) and $comment->comment_approved == "1") ? "approved" : "denied"),
  457. $comment->comment_date,
  458. null,
  459. $post,
  460. 0);
  461. }
  462. }
  463. static function import_textpattern_post($array, $post, $link) {
  464. $get_comments = mysql_query("SELECT * FROM {$_POST['prefix']}txp_discuss WHERE parentid = {$array["ID"]} ORDER BY discussid ASC", $link) or error(__("Database Error"), mysql_error());
  465. while ($comment = mysql_fetch_array($get_comments)) {
  466. $translate_status = array(-1 => "spam",
  467. 0 => "denied",
  468. 1 => "approved");
  469. $status = str_replace(array_keys($translate_status), array_values($translate_status), $comment["visible"]);
  470. Comment::add($comment["message"],
  471. $comment["name"],
  472. $comment["web"],
  473. $comment["email"],
  474. $comment["ip"],
  475. "",
  476. $status,
  477. $comment["posted"],
  478. null,
  479. $post,
  480. 0);
  481. }
  482. }
  483. static function import_movabletype_post($array, $post, $link) {
  484. $get_comments = mysql_query("SELECT * FROM mt_comment WHERE comment_entry_id = {$array["entry_id"]} ORDER BY comment_id ASC", $link) or error(__("Database Error"), mysql_error());
  485. while ($comment = mysql_fetch_array($get_comments))
  486. Comment::add($comment["comment_text"],
  487. $comment["comment_author"],
  488. $comment["comment_url"],
  489. $comment["comment_email"],
  490. $comment["comment_ip"],
  491. "",
  492. ($comment["comment_visible"] ? "approved" : "denied"),
  493. $comment["comment_created_on"],
  494. $comment["comment_modified_on"],
  495. $post,
  496. 0);
  497. }
  498. static function view_feed($context) {
  499. $post = $context["post"];
  500. $title = $post->title();
  501. fallback($title, ucfirst($post->feather)." Post #".$post->id);
  502. $title = _f("Comments on &#8220;%s&#8221;", array(fix($title)), "comments");
  503. $comments = $post->comments;
  504. require "pages/comments_feed.php";
  505. }
  506. static function metaWeblog_getPost($struct, $post) {
  507. if (isset($post->comment_status))
  508. $struct['mt_allow_comments'] = intval($post->comment_status == 'open');
  509. else
  510. $struct['mt_allow_comments'] = 1;
  511. return $struct;
  512. }
  513. static function metaWeblog_editPost_preQuery($struct, $post = null) {
  514. if (isset($struct['mt_allow_comments']))
  515. $_POST['option']['comment_status'] = ($struct['mt_allow_comments'] == 1) ? 'open' : 'closed';
  516. }
  517. public function post($post) {
  518. $post->has_many[] = "comments";
  519. }
  520. public function post_comment_count_attr($attr, $post) {
  521. if (isset($this->comment_counts))
  522. return oneof(@$this->comment_counts[$post->id], 0);
  523. $counts = SQL::current()->select("comments",
  524. array("COUNT(post_id) AS total", "post_id as post_id"),
  525. array("status not" => "spam", "status != 'denied' OR (
  526. (user_id != 0 AND user_id = :visitor_id) OR (
  527. id IN ".self::visitor_comments()."))"
  528. ),
  529. null,
  530. array(":visitor_id" => Visitor::current()->id),
  531. null,
  532. null,
  533. "post_id");
  534. foreach ($counts->fetchAll() as $count)
  535. $this->comment_counts[$count["post_id"]] = (int) $count["total"];
  536. return oneof(@$this->comment_counts[$post->id], 0);
  537. }
  538. public function post_latest_comment_attr($attr, $post) {
  539. if (isset($this->latest_comments))
  540. return fallback($this->latest_comments[$post->id], null);
  541. $times = SQL::current()->select("comments",
  542. array("MAX(created_at) AS latest", "post_id"),
  543. array("status not" => "spam", "status != 'denied' OR (
  544. (user_id != 0 AND user_id = :visitor_id) OR (
  545. id IN ".self::visitor_comments()."))"
  546. ),
  547. null,
  548. array(":visitor_id" => Visitor::current()->id),
  549. null,
  550. null,
  551. "post_id");
  552. foreach ($times->fetchAll() as $row)
  553. $this->latest_comments[$row["post_id"]] = $row["latest"];
  554. return fallback($this->latest_comments[$post->id], null);
  555. }
  556. public function comments_get($options) {
  557. if (ADMIN)
  558. return;
  559. $options["where"]["status not"] = "spam";
  560. $options["where"][] = "status != 'denied' OR (
  561. (user_id != 0 AND user_id = :visitor_id) OR (
  562. id IN ".self::visitor_comments()."))";
  563. $options["order"] = "created_at ASC";
  564. $options["params"][":visitor_id"] = Visitor::current()->id;
  565. }
  566. public function post_commentable_attr($attr, $post) {
  567. return Comment::user_can($post);
  568. }
  569. public function cacher_regenerate_posts_triggers($array) {
  570. $array = array_merge($array, array("add_comment", "update_comment", "delete_comment"));
  571. return $array;
  572. }
  573. public function posts_export($atom, $post) {
  574. $comments = Comment::find(array("where" => array("post_id" => $post->id)),
  575. array("filter" => false));
  576. foreach ($comments as $comment) {
  577. $updated = ($comment->updated) ? $comment->updated_at : $comment->created_at ;
  578. $atom.= " <chyrp:comment>\r";
  579. $atom.= ' <updated>'.when("c", $updated).'</updated>'."\r";
  580. $atom.= ' <published>'.when("c", $comment->created_at).'</published>'."\r";
  581. $atom.= ' <author chyrp:user_id="'.$comment->user_id.'">'."\r";
  582. $atom.= " <name>".fix($comment->author)."</name>\r";
  583. if (!empty($comment->author_url))
  584. $atom.= " <uri>".fix($comment->author_url)."</uri>\r";
  585. $atom.= " <email>".fix($comment->author_email)."</email>\r";
  586. $atom.= " <chyrp:login>".fix(@$comment->user->login)."</chyrp:login>\r";
  587. $atom.= " <chyrp:ip>".long2ip($comment->author_ip)."</chyrp:ip>\r";
  588. $atom.= " <chyrp:agent>".fix($comment->author_agent)."</chyrp:agent>\r";
  589. $atom.= " </author>\r";
  590. $atom.= " <content>".fix($comment->body)."</content>\r";
  591. $atom.= " <chyrp:status>".fix($comment->status)."</chyrp:status>\r";
  592. $atom.= " </chyrp:comment>\r";
  593. }
  594. return $atom;
  595. }
  596. public function manage_nav_show($possibilities) {
  597. $possibilities[] = (Comment::any_editable() or Comment::any_deletable());
  598. return $possibilities;
  599. }
  600. public function determine_action($action) {
  601. if ($action != "manage") return;
  602. if (Comment::any_editable() or Comment::any_deletable())
  603. return "manage_comments";
  604. }
  605. public function route_comments_rss() {
  606. header("HTTP/1.1 301 Moved Permanently");
  607. redirect("comments_feed/");
  608. }
  609. static function visitor_comments() {
  610. if (empty($_SESSION['comments']))
  611. return "(0)";
  612. else
  613. return QueryBuilder::build_list($_SESSION['comments']);
  614. }
  615. }