PageRenderTime 36ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/phpBB/phpbb/notification/type/post.php

https://github.com/Jipem/phpbb
PHP | 448 lines | 257 code | 61 blank | 130 comment | 28 complexity | 962109e1db8d43a192d1d8eeb76fe84e MD5 | raw file
Possible License(s): AGPL-1.0
  1. <?php
  2. /**
  3. *
  4. * This file is part of the phpBB Forum Software package.
  5. *
  6. * @copyright (c) phpBB Limited <https://www.phpbb.com>
  7. * @license GNU General Public License, version 2 (GPL-2.0)
  8. *
  9. * For full copyright and license information, please see
  10. * the docs/CREDITS.txt file.
  11. *
  12. */
  13. namespace phpbb\notification\type;
  14. /**
  15. * Post notifications class
  16. * This class handles notifications for replies to a topic
  17. */
  18. class post extends \phpbb\notification\type\base
  19. {
  20. /**
  21. * Get notification type name
  22. *
  23. * @return string
  24. */
  25. public function get_type()
  26. {
  27. return 'post';
  28. }
  29. /**
  30. * Language key used to output the text
  31. *
  32. * @var string
  33. */
  34. protected $language_key = 'NOTIFICATION_POST';
  35. /**
  36. * Inherit notification read status from post.
  37. *
  38. * @var bool
  39. */
  40. protected $inherit_read_status = true;
  41. /**
  42. * Notification option data (for outputting to the user)
  43. *
  44. * @var bool|array False if the service should use it's default data
  45. * Array of data (including keys 'id', 'lang', and 'group')
  46. */
  47. public static $notification_option = array(
  48. 'lang' => 'NOTIFICATION_TYPE_POST',
  49. 'group' => 'NOTIFICATION_GROUP_POSTING',
  50. );
  51. /**
  52. * Is available
  53. */
  54. public function is_available()
  55. {
  56. return $this->config['allow_topic_notify'];
  57. }
  58. /**
  59. * Get the id of the item
  60. *
  61. * @param array $post The data from the post
  62. */
  63. public static function get_item_id($post)
  64. {
  65. return (int) $post['post_id'];
  66. }
  67. /**
  68. * Get the id of the parent
  69. *
  70. * @param array $post The data from the post
  71. */
  72. public static function get_item_parent_id($post)
  73. {
  74. return (int) $post['topic_id'];
  75. }
  76. /**
  77. * Find the users who want to receive notifications
  78. *
  79. * @param array $post Data from
  80. *
  81. * @return array
  82. */
  83. public function find_users_for_notification($post, $options = array())
  84. {
  85. $options = array_merge(array(
  86. 'ignore_users' => array(),
  87. ), $options);
  88. $users = array();
  89. $sql = 'SELECT user_id
  90. FROM ' . TOPICS_WATCH_TABLE . '
  91. WHERE topic_id = ' . (int) $post['topic_id'] . '
  92. AND notify_status = ' . NOTIFY_YES . '
  93. AND user_id <> ' . (int) $post['poster_id'];
  94. $result = $this->db->sql_query($sql);
  95. while ($row = $this->db->sql_fetchrow($result))
  96. {
  97. $users[] = (int) $row['user_id'];
  98. }
  99. $this->db->sql_freeresult($result);
  100. $sql = 'SELECT user_id
  101. FROM ' . FORUMS_WATCH_TABLE . '
  102. WHERE forum_id = ' . (int) $post['forum_id'] . '
  103. AND notify_status = ' . NOTIFY_YES . '
  104. AND user_id <> ' . (int) $post['poster_id'];
  105. $result = $this->db->sql_query($sql);
  106. while ($row = $this->db->sql_fetchrow($result))
  107. {
  108. $users[] = (int) $row['user_id'];
  109. }
  110. $this->db->sql_freeresult($result);
  111. if (empty($users))
  112. {
  113. return array();
  114. }
  115. $users = array_unique($users);
  116. sort($users);
  117. $auth_read = $this->auth->acl_get_list($users, 'f_read', $post['forum_id']);
  118. if (empty($auth_read))
  119. {
  120. return array();
  121. }
  122. $notify_users = $this->check_user_notification_options($auth_read[$post['forum_id']]['f_read'], $options);
  123. // Try to find the users who already have been notified about replies and have not read the topic since and just update their notifications
  124. $update_notifications = array();
  125. $sql = 'SELECT n.*
  126. FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
  127. WHERE n.notification_type_id = ' . (int) $this->notification_type_id . '
  128. AND n.item_parent_id = ' . (int) self::get_item_parent_id($post) . '
  129. AND n.notification_read = 0
  130. AND nt.notification_type_id = n.notification_type_id
  131. AND nt.notification_type_enabled = 1';
  132. $result = $this->db->sql_query($sql);
  133. while ($row = $this->db->sql_fetchrow($result))
  134. {
  135. // Do not create a new notification
  136. unset($notify_users[$row['user_id']]);
  137. $notification = $this->notification_manager->get_item_type_class($this->get_type(), $row);
  138. $update_responders = $notification->add_responders($post);
  139. if (!empty($update_responders))
  140. {
  141. $sql = 'UPDATE ' . $this->notifications_table . '
  142. SET ' . $this->db->sql_build_array('UPDATE', $update_responders) . '
  143. WHERE notification_id = ' . $row['notification_id'];
  144. $this->db->sql_query($sql);
  145. }
  146. }
  147. $this->db->sql_freeresult($result);
  148. return $notify_users;
  149. }
  150. /**
  151. * Get the user's avatar
  152. */
  153. public function get_avatar()
  154. {
  155. return $this->user_loader->get_avatar($this->get_data('poster_id'));
  156. }
  157. /**
  158. * Get the HTML formatted title of this notification
  159. *
  160. * @return string
  161. */
  162. public function get_title()
  163. {
  164. $responders = $this->get_data('responders');
  165. $usernames = array();
  166. if (!is_array($responders))
  167. {
  168. $responders = array();
  169. }
  170. $responders = array_merge(array(array(
  171. 'poster_id' => $this->get_data('poster_id'),
  172. 'username' => $this->get_data('post_username'),
  173. )), $responders);
  174. $responders_cnt = sizeof($responders);
  175. $responders = $this->trim_user_ary($responders);
  176. $trimmed_responders_cnt = $responders_cnt - sizeof($responders);
  177. foreach ($responders as $responder)
  178. {
  179. if ($responder['username'])
  180. {
  181. $usernames[] = $responder['username'];
  182. }
  183. else
  184. {
  185. $usernames[] = $this->user_loader->get_username($responder['poster_id'], 'no_profile');
  186. }
  187. }
  188. if ($trimmed_responders_cnt > 20)
  189. {
  190. $usernames[] = $this->user->lang('NOTIFICATION_MANY_OTHERS');
  191. }
  192. else if ($trimmed_responders_cnt)
  193. {
  194. $usernames[] = $this->user->lang('NOTIFICATION_X_OTHERS', $trimmed_responders_cnt);
  195. }
  196. return $this->user->lang(
  197. $this->language_key,
  198. phpbb_generate_string_list($usernames, $this->user),
  199. censor_text($this->get_data('topic_title')),
  200. $responders_cnt
  201. );
  202. }
  203. /**
  204. * Get email template
  205. *
  206. * @return string|bool
  207. */
  208. public function get_email_template()
  209. {
  210. return 'topic_notify';
  211. }
  212. /**
  213. * Get email template variables
  214. *
  215. * @return array
  216. */
  217. public function get_email_template_variables()
  218. {
  219. if ($this->get_data('post_username'))
  220. {
  221. $username = $this->get_data('post_username');
  222. }
  223. else
  224. {
  225. $username = $this->user_loader->get_username($this->get_data('poster_id'), 'username');
  226. }
  227. return array(
  228. 'AUTHOR_NAME' => htmlspecialchars_decode($username),
  229. 'POST_SUBJECT' => htmlspecialchars_decode(censor_text($this->get_data('post_subject'))),
  230. 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($this->get_data('topic_title'))),
  231. 'U_VIEW_POST' => generate_board_url() . "/viewtopic.{$this->php_ext}?p={$this->item_id}#p{$this->item_id}",
  232. 'U_NEWEST_POST' => generate_board_url() . "/viewtopic.{$this->php_ext}?f={$this->get_data('forum_id')}&t={$this->item_parent_id}&e=1&view=unread#unread",
  233. 'U_TOPIC' => generate_board_url() . "/viewtopic.{$this->php_ext}?f={$this->get_data('forum_id')}&t={$this->item_parent_id}",
  234. 'U_VIEW_TOPIC' => generate_board_url() . "/viewtopic.{$this->php_ext}?f={$this->get_data('forum_id')}&t={$this->item_parent_id}",
  235. 'U_FORUM' => generate_board_url() . "/viewforum.{$this->php_ext}?f={$this->get_data('forum_id')}",
  236. 'U_STOP_WATCHING_TOPIC' => generate_board_url() . "/viewtopic.{$this->php_ext}?uid={$this->user_id}&f={$this->get_data('forum_id')}&t={$this->item_parent_id}&unwatch=topic",
  237. );
  238. }
  239. /**
  240. * Get the url to this item
  241. *
  242. * @return string URL
  243. */
  244. public function get_url()
  245. {
  246. return append_sid($this->phpbb_root_path . 'viewtopic.' . $this->php_ext, "p={$this->item_id}#p{$this->item_id}");
  247. }
  248. /**
  249. * {inheritDoc}
  250. */
  251. public function get_redirect_url()
  252. {
  253. return append_sid($this->phpbb_root_path . 'viewtopic.' . $this->php_ext, "t={$this->item_parent_id}&amp;view=unread#unread");
  254. }
  255. /**
  256. * Users needed to query before this notification can be displayed
  257. *
  258. * @return array Array of user_ids
  259. */
  260. public function users_to_query()
  261. {
  262. $responders = $this->get_data('responders');
  263. $users = array(
  264. $this->get_data('poster_id'),
  265. );
  266. if (is_array($responders))
  267. {
  268. foreach ($responders as $responder)
  269. {
  270. $users[] = $responder['poster_id'];
  271. }
  272. }
  273. return $this->trim_user_ary($users);
  274. }
  275. /**
  276. * Trim the user array passed down to 3 users if the array contains
  277. * more than 4 users.
  278. *
  279. * @param array $users Array of users
  280. * @return array Trimmed array of user_ids
  281. */
  282. public function trim_user_ary($users)
  283. {
  284. if (sizeof($users) > 4)
  285. {
  286. array_splice($users, 3);
  287. }
  288. return $users;
  289. }
  290. /**
  291. * Pre create insert array function
  292. * This allows you to perform certain actions, like run a query
  293. * and load data, before create_insert_array() is run. The data
  294. * returned from this function will be sent to create_insert_array().
  295. *
  296. * @param array $post Post data from submit_post
  297. * @param array $notify_users Notify users list
  298. * Formated from find_users_for_notification()
  299. * @return array Whatever you want to send to create_insert_array().
  300. */
  301. public function pre_create_insert_array($post, $notify_users)
  302. {
  303. if (!sizeof($notify_users) || !$this->inherit_read_status)
  304. {
  305. return array();
  306. }
  307. $tracking_data = array();
  308. $sql = 'SELECT user_id, mark_time FROM ' . TOPICS_TRACK_TABLE . '
  309. WHERE topic_id = ' . (int) $post['topic_id'] . '
  310. AND ' . $this->db->sql_in_set('user_id', array_keys($notify_users));
  311. $result = $this->db->sql_query($sql);
  312. while ($row = $this->db->sql_fetchrow($result))
  313. {
  314. $tracking_data[$row['user_id']] = $row['mark_time'];
  315. }
  316. return $tracking_data;
  317. }
  318. /**
  319. * Function for preparing the data for insertion in an SQL query
  320. * (The service handles insertion)
  321. *
  322. * @param array $post Data from submit_post
  323. * @param array $pre_create_data Data from pre_create_insert_array()
  324. *
  325. * @return array Array of data ready to be inserted into the database
  326. */
  327. public function create_insert_array($post, $pre_create_data = array())
  328. {
  329. $this->set_data('poster_id', $post['poster_id']);
  330. $this->set_data('topic_title', $post['topic_title']);
  331. $this->set_data('post_subject', $post['post_subject']);
  332. $this->set_data('post_username', (($post['poster_id'] == ANONYMOUS) ? $post['post_username'] : ''));
  333. $this->set_data('forum_id', $post['forum_id']);
  334. $this->set_data('forum_name', $post['forum_name']);
  335. $this->notification_time = $post['post_time'];
  336. // Topics can be "read" before they are public (while awaiting approval).
  337. // Make sure that if the user has read the topic, it's marked as read in the notification
  338. if ($this->inherit_read_status && isset($pre_create_data[$this->user_id]) && $pre_create_data[$this->user_id] >= $this->notification_time)
  339. {
  340. $this->notification_read = true;
  341. }
  342. return parent::create_insert_array($post, $pre_create_data);
  343. }
  344. /**
  345. * Add responders to the notification
  346. *
  347. * @param mixed $post
  348. */
  349. public function add_responders($post)
  350. {
  351. // Do not add them as a responder if they were the original poster that created the notification
  352. if ($this->get_data('poster_id') == $post['poster_id'])
  353. {
  354. return array();
  355. }
  356. $responders = $this->get_data('responders');
  357. $responders = ($responders === null) ? array() : $responders;
  358. // Do not add more than 25 responders,
  359. // we trim the username list to "a, b, c and x others" anyway
  360. // so there is no use to add all of them anyway.
  361. if (sizeof($responders) > 25)
  362. {
  363. return array();
  364. }
  365. foreach ($responders as $responder)
  366. {
  367. // Do not add them as a responder multiple times
  368. if ($responder['poster_id'] == $post['poster_id'])
  369. {
  370. return array();
  371. }
  372. }
  373. $responders[] = array(
  374. 'poster_id' => $post['poster_id'],
  375. 'username' => (($post['poster_id'] == ANONYMOUS) ? $post['post_username'] : ''),
  376. );
  377. $this->set_data('responders', $responders);
  378. $serialized_data = serialize($this->get_data(false));
  379. // If the data is longer then 4000 characters, it would cause a SQL error.
  380. // We don't add the username to the list if this is the case.
  381. if (utf8_strlen($serialized_data) >= 4000)
  382. {
  383. return array();
  384. }
  385. return array('notification_data' => $serialized_data);
  386. }
  387. }