PageRenderTime 40ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/Comments/Controller/CommentsController.php

https://github.com/kareypowell/croogo
PHP | 382 lines | 228 code | 40 blank | 114 comment | 34 complexity | 453673ddb240c3616c006793c94e7cd5 MD5 | raw file
  1. <?php
  2. App::uses('CakeEmail', 'Network/Email');
  3. App::uses('CommentsAppController', 'Comments.Controller');
  4. /**
  5. * Comments Controller
  6. *
  7. * @category Controller
  8. * @package Croogo.Comments.Controller
  9. * @version 1.0
  10. * @author Fahad Ibnay Heylaal <contact@fahad19.com>
  11. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  12. * @link http://www.croogo.org
  13. */
  14. class CommentsController extends CommentsAppController {
  15. /**
  16. * Controller name
  17. *
  18. * @var string
  19. * @access public
  20. */
  21. public $name = 'Comments';
  22. /**
  23. * Components
  24. *
  25. * @var array
  26. * @access public
  27. */
  28. public $components = array(
  29. 'Croogo.Akismet',
  30. 'Croogo.BulkProcess',
  31. 'Croogo.Recaptcha',
  32. 'Search.Prg' => array(
  33. 'presetForm' => array(
  34. 'paramType' => 'querystring',
  35. ),
  36. 'commonProcess' => array(
  37. 'paramType' => 'querystring',
  38. 'filterEmpty' => true,
  39. ),
  40. ),
  41. );
  42. /**
  43. * Models used by the Controller
  44. *
  45. * @var array
  46. * @access public
  47. */
  48. public $uses = array('Comments.Comment');
  49. /**
  50. * Preset Variable Search
  51. * @var array
  52. */
  53. public $presetVars = true;
  54. /**
  55. * beforeFilter
  56. *
  57. * @return void
  58. * @access public
  59. */
  60. public function beforeFilter() {
  61. parent::beforeFilter();
  62. if ($this->action == 'admin_edit') {
  63. $this->Security->disabledFields = array('ip');
  64. }
  65. }
  66. /**
  67. * Admin index
  68. *
  69. * @return void
  70. * @access public
  71. */
  72. public function admin_index() {
  73. $this->set('title_for_layout', __d('croogo', 'Comments'));
  74. $this->Prg->commonProcess();
  75. $this->Comment->recursive = 0;
  76. $this->paginate['Comment']['conditions'] = array(
  77. 'Comment.status' => $this->Comment->status('approval'),
  78. 'Comment.comment_type' => 'comment',
  79. );
  80. $criteria = $this->Comment->parseCriteria($this->Prg->parsedParams());
  81. if (array_key_exists('Comment.status', $criteria)) {
  82. $criteria = array_merge($this->paginate['Comment']['conditions'], $criteria);
  83. }
  84. $comments = $this->paginate($criteria);
  85. $this->set(compact('comments', 'criteria'));
  86. }
  87. /**
  88. * Admin edit
  89. *
  90. * @param integer $id
  91. * @return void
  92. * @access public
  93. */
  94. public function admin_edit($id = null) {
  95. $this->set('title_for_layout', __d('croogo', 'Edit Comment'));
  96. if (!$id && empty($this->request->data)) {
  97. $this->Session->setFlash(__d('croogo', 'Invalid Comment'), 'default', array('class' => 'error'));
  98. return $this->redirect(array('action' => 'index'));
  99. }
  100. if (!empty($this->request->data)) {
  101. if ($this->Comment->save($this->request->data)) {
  102. $this->Session->setFlash(__d('croogo', 'The Comment has been saved'), 'default', array('class' => 'success'));
  103. return $this->redirect(array('action' => 'index'));
  104. } else {
  105. $this->Session->setFlash(__d('croogo', 'The Comment could not be saved. Please, try again.'), 'default', array('class' => 'error'));
  106. }
  107. }
  108. if (empty($this->request->data)) {
  109. $this->request->data = $this->Comment->read(null, $id);
  110. }
  111. }
  112. /**
  113. * Admin delete
  114. *
  115. * @param integer $id
  116. * @return void
  117. * @access public
  118. */
  119. public function admin_delete($id = null) {
  120. if (!$id) {
  121. $this->Session->setFlash(__d('croogo', 'Invalid id for Comment'), 'default', array('class' => 'error'));
  122. return $this->redirect(array('action' => 'index'));
  123. }
  124. if ($this->Comment->delete($id)) {
  125. $this->Session->setFlash(__d('croogo', 'Comment deleted'), 'default', array('class' => 'success'));
  126. return $this->redirect(array('action' => 'index'));
  127. }
  128. }
  129. /**
  130. * Admin process
  131. *
  132. * @return void
  133. * @access public
  134. */
  135. public function admin_process() {
  136. $Comment = $this->{$this->modelClass};
  137. list($action, $ids) = $this->BulkProcess->getRequestVars($Comment->alias);
  138. $options = array(
  139. 'messageMap' => array(
  140. 'delete' => __d('croogo', 'Comments deleted'),
  141. 'publish' => __d('croogo', 'Comments published'),
  142. 'unpublish' => __d('croogo', 'Comments unpublished'),
  143. ),
  144. );
  145. return $this->BulkProcess->process($Comment, $action, $ids, $options);
  146. }
  147. /**
  148. * index
  149. *
  150. * @return void
  151. * @access public
  152. */
  153. public function index() {
  154. $this->set('title_for_layout', __d('croogo', 'Comments'));
  155. if (!isset($this->request['ext']) ||
  156. $this->request['ext'] != 'rss') {
  157. return $this->redirect('/');
  158. }
  159. $this->paginate['Comment']['order'] = 'Comment.created DESC';
  160. $this->paginate['Comment']['limit'] = Configure::read('Comment.feed_limit');
  161. $this->paginate['Comment']['conditions'] = array(
  162. 'Comment.status' => $this->Comment->status('approval'),
  163. );
  164. $comments = $this->paginate();
  165. $this->set(compact('comments'));
  166. }
  167. /**
  168. * add
  169. *
  170. * @param integer $foreignKey
  171. * @param integer $parentId
  172. * @return void
  173. * @access public
  174. * @throws UnexpectedValueException
  175. */
  176. public function add($model, $foreignKey = null, $parentId = null) {
  177. if (!$foreignKey) {
  178. $this->Session->setFlash(__d('croogo', 'Invalid id'), 'default', array('class' => 'error'));
  179. return $this->redirect('/');
  180. }
  181. if (empty($this->Comment->{$model})) {
  182. throw new UnexpectedValueException(
  183. sprintf('%s not configured for Comments', $model)
  184. );
  185. }
  186. $Model = $this->Comment->{$model};
  187. $data = $Model->find('first', array(
  188. 'conditions' => array(
  189. $Model->escapeField($Model->primaryKey) => $foreignKey,
  190. $Model->escapeField('status') => $Model->status('approval'),
  191. ),
  192. ));
  193. if (isset($data[$Model->alias]['path'])) {
  194. $redirectUrl = $data[$Model->alias]['path'];
  195. } else {
  196. $redirectUrl = $this->referer();
  197. }
  198. if (!is_null($parentId) && !$this->Comment->isValidLevel($parentId)) {
  199. $this->Session->setFlash(__d('croogo', 'Maximum level reached. You cannot reply to that comment.'), 'default', array('class' => 'error'));
  200. return $this->redirect($redirectUrl);
  201. }
  202. $typeSetting = $Model->getTypeSetting($data);
  203. extract(array_intersect_key($typeSetting, array(
  204. 'commentable' => null,
  205. 'autoApprove' => null,
  206. 'spamProtection' => null,
  207. 'captchaProtection' => null,
  208. ))
  209. );
  210. $continue = $commentable && $data[$Model->alias]['comment_status'];
  211. if (!$continue) {
  212. $this->Session->setFlash(__d('croogo', 'Comments are not allowed.'), 'default', array('class' => 'error'));
  213. return $this->redirect($redirectUrl);
  214. }
  215. // spam protection and captcha
  216. $continue = $this->_spamProtection($continue, $spamProtection, $data);
  217. $continue = $this->_captcha($continue, $captchaProtection, $data);
  218. $success = false;
  219. if (!empty($this->request->data) && $continue === true) {
  220. $comment = $this->request->data;
  221. $comment['Comment']['ip'] = env('REMOTE_ADDR');
  222. $comment['Comment']['status'] = $autoApprove ? CroogoStatus::APPROVED : CroogoStatus::PENDING;
  223. $userData = array();
  224. if ($this->Auth->user()) {
  225. $userData['User'] = $this->Auth->user();
  226. }
  227. $options = array(
  228. 'parentId' => $parentId,
  229. 'userData' => $userData,
  230. );
  231. $success = $this->Comment->add($comment, $model, $foreignKey, $options);
  232. if ($success) {
  233. if ($autoApprove) {
  234. $messageFlash = __d('croogo', 'Your comment has been added successfully.');
  235. } else {
  236. $messageFlash = __d('croogo', 'Your comment will appear after moderation.');
  237. }
  238. $this->Session->setFlash($messageFlash, 'default', array('class' => 'success'));
  239. if (Configure::read('Comment.email_notification')) {
  240. $this->_sendEmail($data, $comment);
  241. }
  242. return $this->redirect(Router::url($data[$Model->alias]['url'], true) . '#comment-' . $this->Comment->id);
  243. }
  244. }
  245. $this->set(compact('success', 'data', 'type', 'model', 'foreignKey', 'parentId'));
  246. }
  247. /**
  248. * Spam Protection
  249. *
  250. * @param boolean $continue
  251. * @param boolean $spamProtection
  252. * @param array $node
  253. * @return boolean
  254. * @access protected
  255. * @deprecated This method will be renamed to _spamProtection() in the future
  256. */
  257. protected function _spamProtection($continue, $spamProtection, $node) {
  258. if (!empty($this->request->data) &&
  259. $spamProtection &&
  260. $continue === true) {
  261. $this->Akismet->setCommentAuthor($this->request->data['Comment']['name']);
  262. $this->Akismet->setCommentAuthorEmail($this->request->data['Comment']['email']);
  263. $this->Akismet->setCommentAuthorURL($this->request->data['Comment']['website']);
  264. $this->Akismet->setCommentContent($this->request->data['Comment']['body']);
  265. if ($this->Akismet->isCommentSpam()) {
  266. $continue = false;
  267. $this->Session->setFlash(__d('croogo', 'Sorry, the comment appears to be spam.'), 'default', array('class' => 'error'));
  268. }
  269. }
  270. return $continue;
  271. }
  272. /**
  273. * Captcha
  274. *
  275. * @param boolean $continue
  276. * @param boolean $captchaProtection
  277. * @param array $node
  278. * @return boolean
  279. * @access protected
  280. */
  281. protected function _captcha($continue, $captchaProtection, $node) {
  282. if (!empty($this->request->data) &&
  283. $captchaProtection &&
  284. $continue === true &&
  285. !$this->Recaptcha->valid($this->request)) {
  286. $continue = false;
  287. $this->Session->setFlash(__d('croogo', 'Invalid captcha entry'), 'default', array('class' => 'error'));
  288. }
  289. return $continue;
  290. }
  291. /**
  292. * sendEmail
  293. *
  294. * @param array $node Node data
  295. * @param array $comment Comment data
  296. * @return void
  297. * @access protected
  298. */
  299. protected function _sendEmail($node, $data) {
  300. $email = new CakeEmail();
  301. $commentId = $this->Comment->id;
  302. try {
  303. $email->from(Configure::read('Site.title') . ' ' .
  304. '<croogo@' . preg_replace('#^www\.#', '', strtolower($_SERVER['SERVER_NAME'])) . '>')
  305. ->to(Configure::read('Site.email'))
  306. ->subject('[' . Configure::read('Site.title') . '] ' .
  307. __d('croogo', 'New comment posted under') . ' ' . $node['Node']['title'])
  308. ->viewVars(compact('node', 'data', 'commentId'))
  309. ->template('Comments.comment');
  310. if ($this->theme) {
  311. $email->theme($this->theme);
  312. }
  313. return $email->send();
  314. } catch (SocketException $e) {
  315. $this->log(sprintf('Error sending comment notification: %s', $e->getMessage()));
  316. }
  317. }
  318. /**
  319. * delete
  320. *
  321. * @param integer $id
  322. * @return void
  323. * @access public
  324. */
  325. public function delete($id) {
  326. $success = 0;
  327. if ($this->Session->check('Auth.User.id')) {
  328. $userId = $this->Session->read('Auth.User.id');
  329. $comment = $this->Comment->find('first', array(
  330. 'conditions' => array(
  331. 'Comment.id' => $id,
  332. 'Comment.user_id' => $userId,
  333. ),
  334. ));
  335. if (isset($comment['Comment']['id']) &&
  336. $this->Comment->delete($id)) {
  337. $success = 1;
  338. }
  339. }
  340. $this->set(compact('success'));
  341. }
  342. }