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.

304 lines
12KB

  1. <?php
  2. /**
  3. * Class: Comment
  4. * The model for the Comments SQL table.
  5. *
  6. * See Also:
  7. * <Model>
  8. */
  9. class Comment extends Model {
  10. public $no_results = false;
  11. public $belongs_to = array("post", "user");
  12. /**
  13. * Function: __construct
  14. * See Also:
  15. * <Model::grab>
  16. */
  17. public function __construct($comment_id, $options = array()) {
  18. parent::grab($this, $comment_id, $options);
  19. if ($this->no_results)
  20. return false;
  21. $this->body_unfiltered = $this->body;
  22. $group = ($this->user_id and !$this->user->no_results) ?
  23. $this->user->group :
  24. new Group(Config::current()->guest_group) ;
  25. $this->filtered = !isset($options["filter"]) or $options["filter"];
  26. $trigger = Trigger::current();
  27. $trigger->filter($this, "comment");
  28. if ($this->filtered) {
  29. if (($this->status != "pingback" and $this->status != "trackback") and !$group->can("code_in_comments"))
  30. $this->body = strip_tags($this->body, "<".join("><", Config::current()->allowed_comment_html).">");
  31. $this->body_unfiltered = $this->body;
  32. $trigger->filter($this->body, array("markup_text", "markup_comment_text"));
  33. $trigger->filter($this, "filter_comment");
  34. }
  35. }
  36. /**
  37. * Function: find
  38. * See Also:
  39. * <Model::search>
  40. */
  41. static function find($options = array(), $options_for_object = array()) {
  42. return parent::search(get_class(), $options, $options_for_object);
  43. }
  44. /**
  45. * Function: create
  46. * Attempts to create a comment using the passed information. If a Defensio API key is present, it will check it.
  47. *
  48. * Parameters:
  49. * $author - The name of the commenter.
  50. * $email - The commenter's email.
  51. * $url - The commenter's website.
  52. * $body - The comment.
  53. * $post - The <Post> they're commenting on.
  54. * $type - The type of comment. Optional, used for trackbacks/pingbacks.
  55. */
  56. static function create($author, $email, $url, $body, $post, $type = null) {
  57. if (!self::user_can($post->id) and !in_array($type, array("trackback", "pingback")))
  58. return;
  59. $config = Config::current();
  60. $route = Route::current();
  61. $visitor = Visitor::current();
  62. if (!$type) {
  63. $status = ($post->user_id == $visitor->id) ? "approved" : $config->default_comment_status ;
  64. $type = "comment";
  65. } else
  66. $status = $type;
  67. if (!empty($config->akismet_api_key)) {
  68. $akismet = new Akismet($config->url, $config->akismet_api_key);
  69. $akismet->setCommentAuthor($author);
  70. $akismet->setCommentAuthorEmail($email);
  71. $akismet->setCommentAuthorURL($url);
  72. $akismet->setCommentContent($body);
  73. $akismet->setPermalink($post->url());
  74. $akismet->setCommentType($type);
  75. $akismet->setReferrer($_SERVER['HTTP_REFERER']);
  76. $akismet->setUserIP($_SERVER['REMOTE_ADDR']);
  77. if ($akismet->isCommentSpam()) {
  78. self::add($body,
  79. $author,
  80. $url,
  81. $email,
  82. $_SERVER['REMOTE_ADDR'],
  83. $_SERVER['HTTP_USER_AGENT'],
  84. "spam",
  85. null,
  86. null,
  87. $post,
  88. $visitor->id);
  89. error(__("Spam Comment"), __("Your comment has been marked as spam. It will have to be approved before it will show up.", "comments"));
  90. } else {
  91. $comment = self::add($body,
  92. $author,
  93. $url,
  94. $email,
  95. $_SERVER['REMOTE_ADDR'],
  96. $_SERVER['HTTP_USER_AGENT'],
  97. $status,
  98. null,
  99. null,
  100. $post,
  101. $visitor->id);
  102. fallback($_SESSION['comments'], array());
  103. $_SESSION['comments'][] = $comment->id;
  104. if (isset($_POST['ajax']))
  105. exit("{ \"comment_id\": \"".$comment->id."\", \"comment_timestamp\": \"".$comment->created_at."\" }");
  106. Flash::notice(__("Comment added."), $post->url()."#comment_".$comment->id);
  107. }
  108. } else {
  109. $comment = self::add($body,
  110. $author,
  111. $url,
  112. $email,
  113. $_SERVER['REMOTE_ADDR'],
  114. $_SERVER['HTTP_USER_AGENT'],
  115. $status,
  116. null,
  117. null,
  118. $post,
  119. $visitor->id);
  120. fallback($_SESSION['comments'], array());
  121. $_SESSION['comments'][] = $comment->id;
  122. if (isset($_POST['ajax']))
  123. exit("{ \"comment_id\": \"".$comment->id."\", \"comment_timestamp\": \"".$comment->created_at."\" }");
  124. Flash::notice(__("Comment added."), $post->url()."#comment_".$comment->id);
  125. }
  126. }
  127. /**
  128. * Function: add
  129. * Adds a comment to the database.
  130. *
  131. * Parameters:
  132. * $body - The comment.
  133. * $author - The name of the commenter.
  134. * $url - The commenter's website.
  135. * $email - The commenter's email.
  136. * $ip - The commenter's IP address.
  137. * $agent - The commenter's user agent.
  138. * $status - The new comment's status.
  139. * $created_at - The new comment's "created" timestamp.
  140. * $updated_at - The new comment's "last updated" timestamp.
  141. * $post - The <Post> they're commenting on.
  142. * $user_id - The ID of this <User> this comment was made by.
  143. */
  144. static function add($body, $author, $url, $email, $ip, $agent, $status, $created_at = null, $updated_at = null, $post, $user_id) {
  145. if (!empty($url)) # Add the http:// if it isn't there.
  146. if (!@parse_url($url, PHP_URL_SCHEME))
  147. $url = "http://".$url;
  148. $ip = ip2long($ip);
  149. if ($ip === false)
  150. $ip = 0;
  151. $sql = SQL::current();
  152. $sql->insert("comments",
  153. array("body" => $body,
  154. "author" => strip_tags($author),
  155. "author_url" => strip_tags($url),
  156. "author_email" => strip_tags($email),
  157. "author_ip" => $ip,
  158. "author_agent" => $agent,
  159. "status" => $status,
  160. "created_at" => oneof($created_at, datetime()),
  161. "updated_at" => oneof($updated_at, "0000-00-00 00:00:00"),
  162. "post_id" => $post->id,
  163. "user_id"=> $user_id));
  164. $new = new self($sql->latest("comments"));
  165. Trigger::current()->call("add_comment", $new);
  166. return $new;
  167. }
  168. public function update($author, $author_email, $author_url, $body, $status, $timestamp, $update_timestamp = true) {
  169. $sql = SQL::current();
  170. $sql->update("comments",
  171. array("id" => $this->id),
  172. array("author" => strip_tags($author),
  173. "author_email" => strip_tags($author_email),
  174. "author_url" => strip_tags($author_url),
  175. "body" => $body,
  176. "status" => $status,
  177. "created_at" => $timestamp,
  178. "updated_at" => ($update_timestamp) ? datetime() : $this->updated_at));
  179. Trigger::current()->call("update_comment", $this, $author, $author_email, $author_url, $body, $status, $timestamp, $update_timestamp);
  180. }
  181. static function delete($comment_id) {
  182. $trigger = Trigger::current();
  183. if ($trigger->exists("delete_comment"))
  184. $trigger->call("delete_comment", new self($comment_id));
  185. SQL::current()->delete("comments", array("id" => $comment_id));
  186. }
  187. public function editable($user = null) {
  188. fallback($user, Visitor::current());
  189. return ($user->group->can("edit_comment") or ($user->group->can("edit_own_comment") and $user->id == $this->user_id));
  190. }
  191. public function deletable($user = null) {
  192. fallback($user, Visitor::current());
  193. return ($user->group->can("delete_comment") or ($user->group->can("delete_own_comment") and $user->id == $this->user_id));
  194. }
  195. /**
  196. * Function: any_editable
  197. * Checks if the <Visitor> can edit any comments.
  198. */
  199. static function any_editable() {
  200. $visitor = Visitor::current();
  201. # Can they edit comments?
  202. if ($visitor->group->can("edit_comment"))
  203. return true;
  204. # Can they edit their own comments, and do they have any?
  205. if ($visitor->group->can("edit_own_comment") and
  206. SQL::current()->count("comments", array("user_id" => $visitor->id)))
  207. return true;
  208. return false;
  209. }
  210. /**
  211. * Function: any_deletable
  212. * Checks if the <Visitor> can delete any comments.
  213. */
  214. static function any_deletable() {
  215. $visitor = Visitor::current();
  216. # Can they delete comments?
  217. if ($visitor->group->can("delete_comment"))
  218. return true;
  219. # Can they delete their own comments, and do they have any?
  220. if ($visitor->group->can("delete_own_comment") and
  221. SQL::current()->count("comments", array("user_id" => $visitor->id)))
  222. return true;
  223. return false;
  224. }
  225. public function author_link() {
  226. if ($this->author_url != "") # If a URL is set
  227. return '<a href="'.$this->author_url.'">'.$this->author.'</a>';
  228. else # If not, just return their name
  229. return $this->author;
  230. }
  231. static function user_can($post) {
  232. $visitor = Visitor::current();
  233. if (!$visitor->group->can("add_comment")) return false;
  234. // assume allowed comments by default
  235. return empty($post->comment_status) or
  236. !($post->comment_status == "closed" or
  237. ($post->comment_status == "registered_only" and !logged_in()) or
  238. ($post->comment_status == "private" and !$visitor->group->can("add_comment_private")));
  239. }
  240. static function user_count($user_id) {
  241. $count = SQL::current()->count("comments", array("user_id" => $user_id));
  242. return $count;
  243. }
  244. # !! DEPRECATED AFTER 2.0 !!
  245. public function post() {
  246. return new Post($this->post_id);
  247. }
  248. # !! DEPRECATED AFTER 2.0 !!
  249. public function user() {
  250. if ($this->user_id)
  251. return new User($this->user_id);
  252. else
  253. return false;
  254. }
  255. }