Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
77.08% |
111 / 144 |
|
42.11% |
8 / 19 |
CRAP | |
0.00% |
0 / 1 |
post | |
77.08% |
111 / 144 |
|
42.11% |
8 / 19 |
71.47 | |
0.00% |
0 / 1 |
get_type | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
set_config | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
set_user_loader | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
is_available | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
get_item_id | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
get_item_parent_id | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
find_users_for_notification | |
100.00% |
31 / 31 |
|
100.00% |
1 / 1 |
5 | |||
get_avatar | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
get_title | |
95.83% |
23 / 24 |
|
0.00% |
0 / 1 |
6 | |||
get_reference | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
get_email_template | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
get_email_template_variables | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
6 | |||
get_url | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
get_redirect_url | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
users_to_query | |
75.00% |
6 / 8 |
|
0.00% |
0 / 1 |
3.14 | |||
trim_user_ary | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
pre_create_insert_array | |
81.82% |
9 / 11 |
|
0.00% |
0 / 1 |
4.10 | |||
create_insert_array | |
90.00% |
9 / 10 |
|
0.00% |
0 / 1 |
5.03 | |||
add_responders | |
82.76% |
24 / 29 |
|
0.00% |
0 / 1 |
8.33 |
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 | |
14 | namespace phpbb\notification\type; |
15 | |
16 | /** |
17 | * Post notifications class |
18 | * This class handles notifications for replies to a topic |
19 | */ |
20 | |
21 | class post extends \phpbb\notification\type\base |
22 | { |
23 | /** |
24 | * Get notification type name |
25 | * |
26 | * @return string |
27 | */ |
28 | public function get_type() |
29 | { |
30 | return 'notification.type.post'; |
31 | } |
32 | |
33 | /** |
34 | * Language key used to output the text |
35 | * |
36 | * @var string |
37 | */ |
38 | protected $language_key = 'NOTIFICATION_POST'; |
39 | |
40 | /** |
41 | * Inherit notification read status from post. |
42 | * |
43 | * @var bool |
44 | */ |
45 | protected $inherit_read_status = true; |
46 | |
47 | /** |
48 | * Notification option data (for outputting to the user) |
49 | * |
50 | * @var bool|array False if the service should use it's default data |
51 | * Array of data (including keys 'id', 'lang', and 'group') |
52 | */ |
53 | public static $notification_option = array( |
54 | 'lang' => 'NOTIFICATION_TYPE_POST', |
55 | 'group' => 'NOTIFICATION_GROUP_POSTING', |
56 | ); |
57 | |
58 | /** @var \phpbb\user_loader */ |
59 | protected $user_loader; |
60 | |
61 | /** @var \phpbb\config\config */ |
62 | protected $config; |
63 | |
64 | public function set_config(\phpbb\config\config $config) |
65 | { |
66 | $this->config = $config; |
67 | } |
68 | |
69 | public function set_user_loader(\phpbb\user_loader $user_loader) |
70 | { |
71 | $this->user_loader = $user_loader; |
72 | } |
73 | |
74 | /** |
75 | * Is available |
76 | */ |
77 | public function is_available() |
78 | { |
79 | return (bool) $this->config['allow_topic_notify']; |
80 | } |
81 | |
82 | /** |
83 | * Get the id of the item |
84 | * |
85 | * @param array $type_data The data from the post |
86 | * |
87 | * @return int The post id |
88 | */ |
89 | public static function get_item_id($type_data) |
90 | { |
91 | return (int) $type_data['post_id']; |
92 | } |
93 | |
94 | /** |
95 | * Get the id of the parent |
96 | * |
97 | * @param array $type_data The data from the post |
98 | * |
99 | * @return int The topic id |
100 | */ |
101 | public static function get_item_parent_id($type_data) |
102 | { |
103 | return (int) $type_data['topic_id']; |
104 | } |
105 | |
106 | /** |
107 | * Find the users who want to receive notifications |
108 | * |
109 | * @param array $type_data Data from submit_post |
110 | * @param array $options Options for finding users for notification |
111 | * |
112 | * @return array |
113 | */ |
114 | public function find_users_for_notification($type_data, $options = array()) |
115 | { |
116 | $options = array_merge(array( |
117 | 'ignore_users' => array(), |
118 | ), $options); |
119 | |
120 | $users = array(); |
121 | |
122 | $sql = 'SELECT user_id |
123 | FROM ' . TOPICS_WATCH_TABLE . ' |
124 | WHERE topic_id = ' . (int) $type_data['topic_id'] . ' |
125 | AND notify_status = ' . NOTIFY_YES . ' |
126 | AND user_id <> ' . (int) $type_data['poster_id']; |
127 | $result = $this->db->sql_query($sql); |
128 | while ($row = $this->db->sql_fetchrow($result)) |
129 | { |
130 | $users[] = (int) $row['user_id']; |
131 | } |
132 | $this->db->sql_freeresult($result); |
133 | |
134 | $notify_users = $this->get_authorised_recipients($users, $type_data['forum_id'], $options, true); |
135 | |
136 | if (empty($notify_users)) |
137 | { |
138 | return array(); |
139 | } |
140 | |
141 | // Try to find the users who already have been notified about replies and have not read the topic since and just update their notifications |
142 | $notified_users = $this->notification_manager->get_notified_users($this->get_type(), array( |
143 | 'item_parent_id' => static::get_item_parent_id($type_data), |
144 | 'read' => 0, |
145 | )); |
146 | |
147 | foreach ($notified_users as $user => $notification_data) |
148 | { |
149 | unset($notify_users[$user]); |
150 | |
151 | /** @var post $notification */ |
152 | $notification = $this->notification_manager->get_item_type_class($this->get_type(), $notification_data); |
153 | $update_responders = $notification->add_responders($type_data); |
154 | if (!empty($update_responders)) |
155 | { |
156 | $this->notification_manager->update_notification($notification, $update_responders, array( |
157 | 'item_parent_id' => self::get_item_parent_id($type_data), |
158 | 'read' => 0, |
159 | 'user_id' => $user, |
160 | )); |
161 | } |
162 | } |
163 | |
164 | return $notify_users; |
165 | } |
166 | |
167 | /** |
168 | * Get the user's avatar |
169 | */ |
170 | public function get_avatar() |
171 | { |
172 | return $this->user_loader->get_avatar($this->get_data('poster_id'), false, true); |
173 | } |
174 | |
175 | /** |
176 | * Get the HTML formatted title of this notification |
177 | * |
178 | * @return string |
179 | */ |
180 | public function get_title() |
181 | { |
182 | $responders = $this->get_data('responders'); |
183 | $usernames = array(); |
184 | |
185 | if (!is_array($responders)) |
186 | { |
187 | $responders = array(); |
188 | } |
189 | |
190 | $responders = array_merge(array(array( |
191 | 'poster_id' => $this->get_data('poster_id'), |
192 | 'username' => $this->get_data('post_username'), |
193 | )), $responders); |
194 | |
195 | $responders_cnt = count($responders); |
196 | $responders = $this->trim_user_ary($responders); |
197 | $trimmed_responders_cnt = $responders_cnt - count($responders); |
198 | |
199 | foreach ($responders as $responder) |
200 | { |
201 | if ($responder['username']) |
202 | { |
203 | $usernames[] = $responder['username']; |
204 | } |
205 | else |
206 | { |
207 | $usernames[] = $this->user_loader->get_username($responder['poster_id'], 'no_profile'); |
208 | } |
209 | } |
210 | |
211 | if ($trimmed_responders_cnt > 20) |
212 | { |
213 | $usernames[] = $this->language->lang('NOTIFICATION_MANY_OTHERS'); |
214 | } |
215 | else if ($trimmed_responders_cnt) |
216 | { |
217 | $usernames[] = $this->language->lang('NOTIFICATION_X_OTHERS', $trimmed_responders_cnt); |
218 | } |
219 | |
220 | return $this->language->lang( |
221 | $this->language_key, |
222 | phpbb_generate_string_list($usernames, $this->user), |
223 | $responders_cnt |
224 | ); |
225 | } |
226 | |
227 | /** |
228 | * Get the HTML formatted reference of the notification |
229 | * |
230 | * @return string |
231 | */ |
232 | public function get_reference() |
233 | { |
234 | return $this->language->lang( |
235 | 'NOTIFICATION_REFERENCE', |
236 | censor_text($this->get_data('topic_title')) |
237 | ); |
238 | } |
239 | |
240 | /** |
241 | * {@inheritdoc} |
242 | */ |
243 | public function get_email_template() |
244 | { |
245 | return 'topic_notify'; |
246 | } |
247 | |
248 | /** |
249 | * Get email template variables |
250 | * |
251 | * @return array |
252 | */ |
253 | public function get_email_template_variables() |
254 | { |
255 | if ($this->get_data('post_username')) |
256 | { |
257 | $username = $this->get_data('post_username'); |
258 | } |
259 | else |
260 | { |
261 | $username = $this->user_loader->get_username($this->get_data('poster_id'), 'username'); |
262 | } |
263 | |
264 | return array( |
265 | 'AUTHOR_NAME' => html_entity_decode($username, ENT_COMPAT), |
266 | 'POST_SUBJECT' => html_entity_decode(censor_text($this->get_data('post_subject')), ENT_COMPAT), |
267 | 'TOPIC_TITLE' => html_entity_decode(censor_text($this->get_data('topic_title')), ENT_COMPAT), |
268 | |
269 | 'U_VIEW_POST' => generate_board_url() . "/viewtopic.{$this->php_ext}?p={$this->item_id}#p{$this->item_id}", |
270 | 'U_NEWEST_POST' => generate_board_url() . "/viewtopic.{$this->php_ext}?t={$this->item_parent_id}&e=1&view=unread#unread", |
271 | 'U_TOPIC' => generate_board_url() . "/viewtopic.{$this->php_ext}?t={$this->item_parent_id}", |
272 | 'U_VIEW_TOPIC' => generate_board_url() . "/viewtopic.{$this->php_ext}?t={$this->item_parent_id}", |
273 | 'U_FORUM' => generate_board_url() . "/viewforum.{$this->php_ext}?f={$this->get_data('forum_id')}", |
274 | 'U_STOP_WATCHING_TOPIC' => generate_board_url() . "/viewtopic.{$this->php_ext}?uid={$this->user_id}&t={$this->item_parent_id}&unwatch=topic", |
275 | ); |
276 | } |
277 | |
278 | /** |
279 | * Get the url to this item |
280 | * |
281 | * @return string URL |
282 | */ |
283 | public function get_url() |
284 | { |
285 | return append_sid($this->phpbb_root_path . 'viewtopic.' . $this->php_ext, "p={$this->item_id}#p{$this->item_id}"); |
286 | } |
287 | |
288 | /** |
289 | * {inheritDoc} |
290 | */ |
291 | public function get_redirect_url() |
292 | { |
293 | return append_sid($this->phpbb_root_path . 'viewtopic.' . $this->php_ext, "t={$this->item_parent_id}&view=unread#unread"); |
294 | } |
295 | |
296 | /** |
297 | * Users needed to query before this notification can be displayed |
298 | * |
299 | * @return array Array of user_ids |
300 | */ |
301 | public function users_to_query() |
302 | { |
303 | $responders = $this->get_data('responders'); |
304 | $users = array( |
305 | $this->get_data('poster_id'), |
306 | ); |
307 | |
308 | if (is_array($responders)) |
309 | { |
310 | foreach ($responders as $responder) |
311 | { |
312 | $users[] = $responder['poster_id']; |
313 | } |
314 | } |
315 | |
316 | return $this->trim_user_ary($users); |
317 | } |
318 | |
319 | /** |
320 | * Trim the user array passed down to 3 users if the array contains |
321 | * more than 4 users. |
322 | * |
323 | * @param array $users Array of users |
324 | * @return array Trimmed array of user_ids |
325 | */ |
326 | public function trim_user_ary($users) |
327 | { |
328 | if (count($users) > 4) |
329 | { |
330 | array_splice($users, 3); |
331 | } |
332 | return $users; |
333 | } |
334 | |
335 | /** |
336 | * Pre create insert array function |
337 | * This allows you to perform certain actions, like run a query |
338 | * and load data, before create_insert_array() is run. The data |
339 | * returned from this function will be sent to create_insert_array(). |
340 | * |
341 | * @param array $type_data Post data from submit_post |
342 | * @param array $notify_users Notify users list |
343 | * Formatted from find_users_for_notification() |
344 | * |
345 | * @return array Whatever you want to send to create_insert_array(). |
346 | */ |
347 | public function pre_create_insert_array($type_data, $notify_users) |
348 | { |
349 | if (!count($notify_users) || !$this->inherit_read_status) |
350 | { |
351 | return array(); |
352 | } |
353 | |
354 | $tracking_data = array(); |
355 | $sql = 'SELECT user_id, mark_time FROM ' . TOPICS_TRACK_TABLE . ' |
356 | WHERE topic_id = ' . (int) $type_data['topic_id'] . ' |
357 | AND ' . $this->db->sql_in_set('user_id', array_keys($notify_users)); |
358 | $result = $this->db->sql_query($sql); |
359 | while ($row = $this->db->sql_fetchrow($result)) |
360 | { |
361 | $tracking_data[$row['user_id']] = $row['mark_time']; |
362 | } |
363 | $this->db->sql_freeresult($result); |
364 | |
365 | return $tracking_data; |
366 | } |
367 | |
368 | /** |
369 | * {@inheritdoc} |
370 | */ |
371 | public function create_insert_array($type_data, $pre_create_data = array()) |
372 | { |
373 | $this->set_data('poster_id', $type_data['poster_id']); |
374 | |
375 | $this->set_data('topic_title', $type_data['topic_title']); |
376 | |
377 | $this->set_data('post_subject', $type_data['post_subject']); |
378 | |
379 | $this->set_data('post_username', (($type_data['poster_id'] == ANONYMOUS) ? $type_data['post_username'] : '')); |
380 | |
381 | $this->set_data('forum_id', $type_data['forum_id']); |
382 | |
383 | $this->set_data('forum_name', $type_data['forum_name']); |
384 | |
385 | $this->notification_time = $type_data['post_time']; |
386 | |
387 | // Topics can be "read" before they are public (while awaiting approval). |
388 | // Make sure that if the user has read the topic, it's marked as read in the notification |
389 | if ($this->inherit_read_status && isset($pre_create_data[$this->user_id]) && $pre_create_data[$this->user_id] >= $this->notification_time) |
390 | { |
391 | $this->notification_read = true; |
392 | } |
393 | |
394 | parent::create_insert_array($type_data, $pre_create_data); |
395 | } |
396 | |
397 | /** |
398 | * Add responders to the notification |
399 | * |
400 | * @param mixed $post |
401 | * @return array Array of responder data |
402 | */ |
403 | public function add_responders($post) |
404 | { |
405 | // Do not add them as a responder if they were the original poster that created the notification |
406 | if ($this->get_data('poster_id') == $post['poster_id']) |
407 | { |
408 | return array(); |
409 | } |
410 | |
411 | $responders = $this->get_data('responders'); |
412 | |
413 | $responders = ($responders === null) ? array() : $responders; |
414 | |
415 | // Do not add more than 25 responders, |
416 | // we trim the username list to "a, b, c and x others" anyway |
417 | // so there is no use to add all of them anyway. |
418 | if (count($responders) > 25) |
419 | { |
420 | return array(); |
421 | } |
422 | |
423 | foreach ($responders as $responder) |
424 | { |
425 | // Do not add them as a responder multiple times |
426 | if ($responder['poster_id'] == $post['poster_id']) |
427 | { |
428 | return array(); |
429 | } |
430 | } |
431 | |
432 | $responders[] = array( |
433 | 'poster_id' => $post['poster_id'], |
434 | 'username' => (($post['poster_id'] == ANONYMOUS) ? $post['post_username'] : ''), |
435 | ); |
436 | |
437 | $this->set_data('responders', $responders); |
438 | |
439 | $serialized_data = serialize($this->get_data(false)); |
440 | |
441 | // If the data is longer then 4000 characters, it would cause a SQL error. |
442 | // We don't add the username to the list if this is the case. |
443 | if (utf8_strlen($serialized_data) >= 4000) |
444 | { |
445 | return array(); |
446 | } |
447 | |
448 | $data_array = array_merge(array( |
449 | 'poster_id' => $post['poster_id'], |
450 | 'topic_title' => $post['topic_title'], |
451 | 'post_subject' => $post['post_subject'], |
452 | 'post_username' => $post['post_username'], |
453 | 'forum_id' => $post['forum_id'], |
454 | 'forum_name' => $post['forum_name'], |
455 | 'post_time' => $post['post_time'], |
456 | 'post_id' => $post['post_id'], |
457 | 'topic_id' => $post['topic_id'] |
458 | ), $this->get_data(false)); |
459 | |
460 | return $data_array; |
461 | } |
462 | } |