PageRenderTime 44ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/core/components/quip/controllers/web/ThreadReply.php

https://github.com/b03tz/Quip
PHP | 341 lines | 228 code | 36 blank | 77 comment | 59 complexity | c0ae0a679e60218cf36c8c7b601cae1f MD5 | raw file
  1. <?php
  2. /**
  3. * Quip
  4. *
  5. * Copyright 2010-11 by Shaun McCormick <shaun@modx.com>
  6. *
  7. * This file is part of Quip, a simple commenting component for MODx Revolution.
  8. *
  9. * Quip is free software; you can redistribute it and/or modify it under the
  10. * terms of the GNU General Public License as published by the Free Software
  11. * Foundation; either version 2 of the License, or (at your option) any later
  12. * version.
  13. *
  14. * Quip is distributed in the hope that it will be useful, but WITHOUT ANY
  15. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  16. * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along with
  19. * Quip; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
  20. * Suite 330, Boston, MA 02111-1307 USA
  21. *
  22. * @package quip
  23. * @subpackage controllers
  24. */
  25. /**
  26. * Returns the number of comments a given thread/user/family has
  27. *
  28. * @package quip
  29. * @subpackage controllers
  30. */
  31. class QuipThreadReplyController extends QuipController {
  32. /** @var quipThread $thread */
  33. public $thread;
  34. /** @var boolean $hasAuth */
  35. public $hasAuth;
  36. /** @var boolean $isModerator */
  37. public $isModerator;
  38. /** @var boolean $hasPreview */
  39. public $hasPreview;
  40. /** @var string $parentThread */
  41. public $parentThread = '';
  42. /**
  43. * Initialize this controller, setting up default properties
  44. * @return void
  45. */
  46. public function initialize() {
  47. $this->setDefaultProperties(array(
  48. 'thread' => '',
  49. 'requireAuth' => false,
  50. 'requireUsergroups' => false,
  51. 'tplAddComment' => 'quipAddComment',
  52. 'tplLoginToComment' => 'quipLoginToComment',
  53. 'tplPreview' => 'quipPreviewComment',
  54. 'closeAfter' => 14,
  55. 'requirePreview' => false,
  56. 'previewAction' => 'quip-preview',
  57. 'postAction' => 'quip-post',
  58. 'unsubscribeAction' => 'quip_unsubscribe',
  59. 'allowedTags' => '<br><b><i>',
  60. 'preHooks' => '',
  61. 'postHooks' => '',
  62. 'debug' => false,
  63. ));
  64. if (!empty($_REQUEST['quip_thread'])) {
  65. $this->setProperty('thread',$_REQUEST['quip_thread']);
  66. }
  67. }
  68. /**
  69. * @return boolean|quipThread
  70. */
  71. public function getThread() {
  72. $threadName = $this->getProperty('thread','');
  73. if (empty($threadName)) return false;
  74. $this->thread = $this->modx->getObject('quipThread',array('name' => $threadName));
  75. if (empty($this->thread)) {
  76. $this->thread = $this->modx->newObject('quipThread');
  77. $this->thread->fromArray(array(
  78. 'name' => $threadName,
  79. 'createdon' => strftime('%Y-%m-%d %H:%M:%S',time()),
  80. 'moderated' => $this->getProperty('moderate',0,'isset'),
  81. 'resource' => $this->modx->resource->get('id'),
  82. 'idprefix' => $this->getProperty('idprefix','qcom'),
  83. ),'',true,true);
  84. $this->thread->save();
  85. }
  86. /* sync properties with thread row values */
  87. $this->thread->sync($this->getProperties());
  88. $ps = $this->thread->get('quipreply_call_params');
  89. if (!empty($ps)) {
  90. $diff = array_diff_assoc($ps,$this->getProperties());
  91. if (empty($diff)) $diff = array_diff_assoc($this->getProperties(),$ps);
  92. }
  93. if (empty($_REQUEST['quip_thread']) && (!empty($diff) || empty($ps))) { /* only sync call params if not on threaded reply page */
  94. $this->thread->set('quipreply_call_params',$this->getProperties());
  95. $this->thread->save();
  96. }
  97. /* if in threaded reply page, get the original passing values to QuipReply in the thread's main page and use those */
  98. if (!empty($_REQUEST['quip_thread']) && is_array($ps) && !empty($ps)) {
  99. $scriptProperties = array_merge($this->getProperties(),$ps);
  100. $this->setProperties($scriptProperties);
  101. }
  102. unset($ps,$diff);
  103. return $this->thread;
  104. }
  105. public function checkPermissions() {
  106. /* get parent and auth */
  107. $requireAuth = $this->getProperty('requireAuth',false,'isset');
  108. $requireUsergroups = $this->getProperty('requireUsergroups',false,'isset');
  109. $this->parentThread = $this->modx->getOption('quip_parent',$_REQUEST,$this->getProperty('parent',0));
  110. $this->hasAuth = $this->modx->user->hasSessionContext($this->modx->context->get('key')) || $this->getProperty('debug',false,'isset') || empty($requireAuth);
  111. if (!empty($requireUsergroups)) {
  112. $requireUsergroups = explode(',',$this->getProperty('requireUsergroups',false,'isset'));
  113. $this->hasAuth = $this->modx->user->isMember($requireUsergroups);
  114. }
  115. $this->isModerator = $this->thread->checkPolicy('moderate');
  116. }
  117. public function process() {
  118. if (!$this->getThread()) return '';
  119. $this->checkPermissions();
  120. /* setup default placeholders */
  121. $p = $this->modx->request->getParameters();
  122. unset($p['reported'],$p['quip_approved']);
  123. $this->setPlaceholder('url',$this->modx->makeUrl($this->modx->resource->get('id'),'',$p));
  124. $this->setPlaceholder('parent',$this->parentThread);
  125. $this->setPlaceholder('thread',$this->thread->get('name'));
  126. $this->setPlaceholder('idprefix',$this->thread->get('idprefix'));
  127. /* handle POST */
  128. $this->hasPreview = false;
  129. if (!empty($_POST)) {
  130. $this->handlePost();
  131. }
  132. /* display moderated success message */
  133. $this->checkForModeration();
  134. $this->checkForUnSubscribe();
  135. /* if using recaptcha, load recaptcha html if user is not logged in */
  136. $this->loadReCaptcha();
  137. /* build reply form */
  138. $isOpen = $this->isOpen();
  139. if ($this->hasAuth && $isOpen) {
  140. $replyForm = $this->getReplyForm();
  141. } else if (!$isOpen) {
  142. $replyForm = $this->modx->lexicon('quip.thread_autoclosed');
  143. } else {
  144. $replyForm = $this->quip->getChunk($this->getProperty('tplLoginToComment','quipLoginToComment'),$this->getPlaceholders());
  145. }
  146. /* output or set to placeholder */
  147. $toPlaceholder = $this->getProperty('toPlaceholder',false);
  148. if ($toPlaceholder) {
  149. $this->modx->setPlaceholder($toPlaceholder,$replyForm);
  150. return '';
  151. }
  152. return $replyForm;
  153. }
  154. public function isOpen() {
  155. return $this->thread->checkIfStillOpen($this->getProperty('closeAfter',14,'isset')) && !$this->getProperty('closed',false,'isset');
  156. }
  157. public function getReplyForm() {
  158. $this->setPlaceholder('username',$this->modx->user->get('username'));
  159. $this->setPlaceholder('unsubscribe','');
  160. /* prefill fields */
  161. $profile = $this->modx->user->getOne('Profile');
  162. if ($profile) {
  163. $this->setPlaceholder('name',!empty($fields['name']) ? $fields['name'] : $profile->get('fullname'));
  164. $this->setPlaceholder('email',!empty($fields['email']) ? $fields['email'] : $profile->get('email'));
  165. $this->setPlaceholder('website',!empty($fields['website']) ? $fields['website'] : $profile->get('website'));
  166. $this->getUnSubscribeForm();
  167. }
  168. /* if requirePreview == false, auto-can post */
  169. if (!$this->getProperty('requirePreview',false,'isset')) {
  170. $this->setPlaceholder('can_post',true);
  171. }
  172. $this->setPlaceholders(array(
  173. 'post_action' => $this->getProperty('postAction','quip-post'),
  174. 'preview_action' => $this->getProperty('previewAction','quip-preview'),
  175. 'allowed_tags' => $this->getProperty('allowedTags','<b><i><strong><em><br>'),
  176. 'notifyChecked' => !empty($fields['notify']) ? ' checked="checked"' : '',
  177. ));
  178. return $this->quip->getChunk($this->getProperty('tplAddComment','quipAddComment'),$this->getPlaceholders());
  179. }
  180. /**
  181. * Load unsubscribe form for logged-in users only
  182. * @return boolean
  183. */
  184. public function getUnSubscribeForm() {
  185. if (!$this->modx->user->hasSessionContext($this->modx->context->get('key'))) return false;
  186. /** @var quipCommentNotify $notify */
  187. $notify = $this->modx->getObject('quipCommentNotify',array(
  188. 'email' => $this->modx->user->Profile->get('email'),
  189. 'thread' => $this->thread,
  190. ));
  191. if ($notify) {
  192. $this->setPlaceholder('notifyId',$notify->get('id'));
  193. $this->setPlaceholder('unsubscribe',$this->quip->getChunk('quipUnsubscribe',$this->getPlaceholders()));
  194. $params = $this->modx->request->getParameters();
  195. $params[$this->getProperty('unsubscribeAction','quip_unsubscribe')] = 1;
  196. $this->setPlaceholder('unsubscribeUrl',$this->modx->makeUrl($this->modx->resource->get('id'),'',$params));
  197. }
  198. return true;
  199. }
  200. public function handlePost() {
  201. $fields = array();
  202. $errors = array();
  203. foreach ($_POST as $k => $v) {
  204. $fields[$k] = str_replace(array('[',']'),array('&#91;','&#93;'),$v);
  205. }
  206. $fields['name'] = strip_tags($fields['name']);
  207. $fields['email'] = strip_tags($fields['email']);
  208. $fields['website'] = strip_tags($fields['website']);
  209. /* verify a message was posted */
  210. if (empty($fields['comment'])) $errors['comment'] = $this->modx->lexicon('quip.message_err_ns');
  211. if (empty($fields['name'])) $errors['name'] = $this->modx->lexicon('quip.name_err_ns');
  212. if (empty($fields['email'])) $errors['email'] = $this->modx->lexicon('quip.email_err_ns');
  213. if (!empty($_POST[$this->getProperty('postAction','quip-post')]) && empty($errors)) {
  214. /** @var quipComment $comment */
  215. $comment = $this->runProcessor('web/comment/create',$fields);
  216. if (is_object($comment) && $comment instanceof quipComment) {
  217. $params = $this->modx->request->getParameters();
  218. unset($params[$this->getProperty('postAction')],$params['quip_parent'],$params['quip_thread']);
  219. $params['quip_approved'] = $comment->get('approved') ? 1 : 0;
  220. /* redirect urls for custom FURL scheme */
  221. $redirectToUrl = $this->getProperty('redirectToUrl','');
  222. $redirectTo = $this->getProperty('redirectTo','');
  223. if (!empty($redirectToUrl)) {
  224. $url = $redirectToUrl.'?'.http_build_query($params);
  225. } else if (!empty($redirectTo)) {
  226. $url = $this->modx->makeUrl($redirectTo,'',$params,'full');
  227. } else {
  228. $url = $comment->makeUrl('',$params);
  229. }
  230. /* if not approved, remove # and replace with success message #
  231. * since comment is not yet visible
  232. */
  233. if (!$comment->get('approved')) {
  234. $url = str_replace('#'.$this->thread->get('idprefix').$comment->get('id'),'#quip-success-'.$this->thread->get('idprefix'),$url);
  235. }
  236. $this->modx->sendRedirect($url);
  237. } else if (is_array($comment)) {
  238. $errors = array_merge($errors,$comment);
  239. }
  240. $fields[$this->getProperty('previewAction','quip-preview')] = true;
  241. }
  242. /* handle preview */
  243. else if (!empty($fields[$this->getProperty('previewAction','quip-preview')]) && empty($errors)) {
  244. $errors = $this->runProcessor('web/comment/preview',$fields);
  245. }
  246. if (!empty($errors)) {
  247. $placeholders['error'] = implode("<br />\n",$errors);
  248. foreach ($errors as $k => $v) {
  249. $placeholders['error.'.$k] = $v;
  250. }
  251. $this->setPlaceholders(array_merge($placeholders,$fields));
  252. }
  253. }
  254. /**
  255. * @return bool|string
  256. */
  257. public function loadReCaptcha() {
  258. $disableRecaptchaWhenLoggedIn = (boolean)$this->getProperty('disableRecaptchaWhenLoggedIn',true,'isset');
  259. $useRecaptcha = (boolean)$this->getProperty('recaptcha',false,'isset');
  260. if ($useRecaptcha && !($disableRecaptchaWhenLoggedIn && $this->hasAuth) && !$this->hasPreview) {
  261. /** @var reCaptcha $recaptcha */
  262. $recaptcha = $this->modx->getService('recaptcha','reCaptcha',$this->quip->config['modelPath'].'recaptcha/');
  263. if ($recaptcha instanceof reCaptcha) {
  264. $recaptchaTheme = $this->getProperty('recaptchaTheme','clean');
  265. $html = $recaptcha->getHtml($recaptchaTheme);
  266. $this->modx->setPlaceholder('quip.recaptcha_html',$html);
  267. } else {
  268. return $this->modx->lexicon('quip.recaptcha_err_load');
  269. }
  270. }
  271. return true;
  272. }
  273. /**
  274. * Handle if the user is unsubscribing from this thread
  275. * @return boolean
  276. */
  277. public function checkForUnSubscribe() {
  278. $unSubscribed = false;
  279. if (!empty($_GET[$this->getProperty('unsubscribeAction')]) && $this->modx->user->hasSessionContext($this->modx->context->get('key'))) {
  280. $profile = $this->modx->user->getOne('Profile');
  281. if ($profile) {
  282. /** @var quipCommentNotify $notify */
  283. $notify = $this->modx->getObject('quipCommentNotify',array(
  284. 'email' => $profile->get('email'),
  285. 'thread' => $this->thread,
  286. ));
  287. if ($notify && $notify->remove()) {
  288. $unSubscribed = true;
  289. $this->setPlaceholder('successMsg',$this->modx->lexicon('quip.unsubscribed'));
  290. }
  291. }
  292. }
  293. return $unSubscribed;
  294. }
  295. /**
  296. * Check to see if their comment was to be moderated; if so, display a message
  297. * @return void
  298. */
  299. public function checkForModeration() {
  300. if (isset($_GET['quip_approved']) && $_GET['quip_approved'] == 0) {
  301. $this->setPlaceholder('successMsg',$this->modx->lexicon('quip.comment_will_be_moderated'));
  302. }
  303. }
  304. }
  305. return 'QuipThreadReplyController';