Total Complexity | 77 |
Total Lines | 634 |
Duplicated Lines | 0 % |
Changes | 3 | ||
Bugs | 2 | Features | 0 |
Complex classes like Notify_Controller often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Notify_Controller, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
23 | class Notify_Controller extends Action_Controller |
||
24 | { |
||
25 | /** |
||
26 | * Pre Dispatch, called before other methods, used to load common needs. |
||
27 | */ |
||
28 | public function pre_dispatch() |
||
33 | } |
||
34 | |||
35 | /** |
||
36 | * Dispatch to the right action. |
||
37 | * |
||
38 | * @see Action_Controller::action_index() |
||
39 | */ |
||
40 | public function action_index() |
||
41 | { |
||
42 | // The number of choices is boggling, ok there are just 2 |
||
43 | $subActions = array( |
||
44 | 'notify' => array($this, 'action_notify'), |
||
45 | 'unsubscribe' => array($this, 'action_unsubscribe'), |
||
46 | ); |
||
47 | |||
48 | // We like action, so lets get ready for some |
||
49 | $action = new Action(''); |
||
50 | |||
51 | // Get the subAction, or just go to action_notify |
||
52 | $subAction = $action->initialize($subActions, 'notify'); |
||
53 | |||
54 | // forward to our respective method. |
||
55 | $action->dispatch($subAction); |
||
56 | } |
||
57 | |||
58 | /** |
||
59 | * Turn off/on notification for a particular topic. |
||
60 | * |
||
61 | * What it does: |
||
62 | * |
||
63 | * - Must be called with a topic specified in the URL. |
||
64 | * - The sub-action can be 'on', 'off', or nothing for what to do. |
||
65 | * - Requires the mark_any_notify permission. |
||
66 | * - Upon successful completion of action will direct user back to topic. |
||
67 | * - Accessed via ?action=notify. |
||
68 | * |
||
69 | * @uses Notify.template, main sub-template |
||
70 | */ |
||
71 | public function action_notify() |
||
72 | { |
||
73 | global $topic, $scripturl, $txt, $user_info, $context; |
||
74 | |||
75 | // Api ajax call? |
||
76 | if (isset($this->_req->query->api)) |
||
77 | { |
||
78 | $this->action_notify_api(); |
||
79 | return true; |
||
80 | } |
||
81 | |||
82 | // Make sure they aren't a guest or something - guests can't really receive notifications! |
||
83 | is_not_guest(); |
||
84 | isAllowedTo('mark_any_notify'); |
||
85 | |||
86 | // Make sure the topic has been specified. |
||
87 | if (empty($topic)) |
||
88 | throw new Elk_Exception('not_a_topic', false); |
||
89 | |||
90 | // What do we do? Better ask if they didn't say.. |
||
91 | if (empty($this->_req->query->sa)) |
||
92 | { |
||
93 | // Load the template, but only if it is needed. |
||
94 | loadTemplate('Notify'); |
||
95 | |||
96 | // Find out if they have notification set for this topic already. |
||
97 | $context['notification_set'] = hasTopicNotification($user_info['id'], $topic); |
||
98 | |||
99 | // Set the template variables... |
||
100 | $context['topic_href'] = $scripturl . '?topic=' . $topic . '.' . $this->_req->query->start; |
||
101 | $context['start'] = $this->_req->query->start; |
||
102 | $context['page_title'] = $txt['notifications']; |
||
103 | $context['sub_template'] = 'notification_settings'; |
||
104 | |||
105 | return true; |
||
106 | } |
||
107 | else |
||
108 | { |
||
109 | checkSession('get'); |
||
110 | |||
111 | $this->_toggle_topic_notification(); |
||
112 | } |
||
113 | |||
114 | // Send them back to the topic. |
||
115 | redirectexit('topic=' . $topic . '.' . $this->_req->query->start); |
||
116 | |||
117 | return true; |
||
118 | } |
||
119 | |||
120 | /** |
||
121 | * Turn off/on notifications for a particular topic |
||
122 | * |
||
123 | * - Intended for use in XML or JSON calls |
||
124 | */ |
||
125 | public function action_notify_api() |
||
126 | { |
||
127 | global $topic, $txt, $scripturl, $context, $user_info; |
||
128 | |||
129 | loadTemplate('Xml'); |
||
130 | |||
131 | Template_Layers::instance()->removeAll(); |
||
132 | $context['sub_template'] = 'generic_xml_buttons'; |
||
133 | |||
134 | // Even with Ajax, guests still can't do this |
||
135 | if ($user_info['is_guest']) |
||
136 | { |
||
137 | loadLanguage('Errors'); |
||
138 | $context['xml_data'] = array( |
||
139 | 'error' => 1, |
||
140 | 'text' => $txt['not_guests'] |
||
141 | ); |
||
142 | |||
143 | return; |
||
144 | } |
||
145 | |||
146 | // And members still need the right permissions |
||
147 | if (!allowedTo('mark_any_notify') || empty($topic) || empty($this->_req->query->sa)) |
||
148 | { |
||
149 | loadLanguage('Errors'); |
||
150 | $context['xml_data'] = array( |
||
151 | 'error' => 1, |
||
152 | 'text' => $txt['cannot_mark_any_notify'] |
||
153 | ); |
||
154 | |||
155 | return; |
||
156 | } |
||
157 | |||
158 | // And sessions still matter, so you better have a valid one |
||
159 | if (checkSession('get', '', false)) |
||
160 | { |
||
161 | loadLanguage('Errors'); |
||
162 | $context['xml_data'] = array( |
||
163 | 'error' => 1, |
||
164 | 'url' => $scripturl . '?action=notify;sa=' . ($this->_req->query->sa === 'on' ? 'on' : 'off') . ';topic=' . $topic . '.' . $this->_req->query->start . ';' . $context['session_var'] . '=' . $context['session_id'], |
||
165 | ); |
||
166 | return; |
||
167 | } |
||
168 | |||
169 | $this->_toggle_topic_notification(); |
||
170 | |||
171 | // Return the results so the UI can be updated properly |
||
172 | $context['xml_data'] = array( |
||
173 | 'text' => $this->_req->query->sa === 'on' ? $txt['unnotify'] : $txt['notify'], |
||
174 | 'url' => $scripturl . '?action=notify;sa=' . ($this->_req->query->sa === 'on' ? 'off' : 'on') . ';topic=' . $topic . '.' . $this->_req->query->start . ';' . $context['session_var'] . '=' . $context['session_id'] . ';api', |
||
175 | 'confirm' => $this->_req->query->sa === 'on' ? $txt['notification_disable_topic'] : $txt['notification_enable_topic'] |
||
176 | ); |
||
177 | } |
||
178 | |||
179 | /** |
||
180 | * Toggle a topic notification on/off |
||
181 | */ |
||
182 | private function _toggle_topic_notification() |
||
188 | } |
||
189 | |||
190 | /** |
||
191 | * Turn off/on notification for a particular board. |
||
192 | * |
||
193 | * What it does: |
||
194 | * |
||
195 | * - Must be called with a board specified in the URL. |
||
196 | * - Only uses the template if no sub action is used. (on/off) |
||
197 | * - Requires the mark_notify permission. |
||
198 | * - Redirects the user back to the board after it is done. |
||
199 | * - Accessed via ?action=notifyboard. |
||
200 | * |
||
201 | * @uses template_notify_board() sub-template in Notify.template |
||
202 | */ |
||
203 | public function action_notifyboard() |
||
204 | { |
||
205 | global $scripturl, $txt, $board, $user_info, $context; |
||
206 | |||
207 | // Permissions are an important part of anything ;). |
||
208 | is_not_guest(); |
||
209 | isAllowedTo('mark_notify'); |
||
210 | |||
211 | // You have to specify a board to turn notifications on! |
||
212 | if (empty($board)) |
||
213 | throw new Elk_Exception('no_board', false); |
||
214 | |||
215 | // No subaction: find out what to do. |
||
216 | if (empty($this->_req->query->sa)) |
||
217 | { |
||
218 | // We're gonna need the notify template... |
||
219 | loadTemplate('Notify'); |
||
220 | |||
221 | // Find out if they have notification set for this board already. |
||
222 | $context['notification_set'] = hasBoardNotification($user_info['id'], $board); |
||
223 | |||
224 | // Set the template variables... |
||
225 | $context['board_href'] = $scripturl . '?board=' . $board . '.' . $this->_req->query->start; |
||
226 | $context['start'] = $this->_req->query->start; |
||
227 | $context['page_title'] = $txt['notifications']; |
||
228 | $context['sub_template'] = 'notify_board'; |
||
229 | |||
230 | return; |
||
231 | } |
||
232 | // Turn the board level notification on/off? |
||
233 | else |
||
234 | { |
||
235 | checkSession('get'); |
||
236 | |||
237 | // Turn notification on/off for this board. |
||
238 | $this->_toggle_board_notification(); |
||
239 | } |
||
240 | |||
241 | // Back to the board! |
||
242 | redirectexit('board=' . $board . '.' . $this->_req->query->start); |
||
243 | } |
||
244 | |||
245 | /** |
||
246 | * Turn off/on notification for a particular board. |
||
247 | * |
||
248 | * - Intended for use in XML or JSON calls |
||
249 | * - Performs the same actions as action_notifyboard but provides ajax responses |
||
250 | */ |
||
251 | public function action_notifyboard_api() |
||
252 | { |
||
253 | global $scripturl, $txt, $board, $user_info, $context; |
||
254 | |||
255 | loadTemplate('Xml'); |
||
256 | |||
257 | Template_Layers::instance()->removeAll(); |
||
258 | $context['sub_template'] = 'generic_xml_buttons'; |
||
259 | |||
260 | // Permissions are an important part of anything ;). |
||
261 | if ($user_info['is_guest']) |
||
262 | { |
||
263 | loadLanguage('Errors'); |
||
264 | $context['xml_data'] = array( |
||
265 | 'error' => 1, |
||
266 | 'text' => $txt['not_guests'] |
||
267 | ); |
||
268 | |||
269 | return; |
||
270 | } |
||
271 | |||
272 | // Have to have provided the right information |
||
273 | if (!allowedTo('mark_notify') || empty($board) || empty($this->_req->query->sa)) |
||
274 | { |
||
275 | loadLanguage('Errors'); |
||
276 | $context['xml_data'] = array( |
||
277 | 'error' => 1, |
||
278 | 'text' => $txt['cannot_mark_notify'], |
||
279 | ); |
||
280 | |||
281 | return; |
||
282 | } |
||
283 | |||
284 | // Sessions are always verified |
||
285 | if (checkSession('get', '', false)) |
||
286 | { |
||
287 | loadLanguage('Errors'); |
||
288 | $context['xml_data'] = array( |
||
289 | 'error' => 1, |
||
290 | 'url' => $scripturl . '?action=notifyboard;sa=' . ($this->_req->query->sa === 'on' ? 'on' : 'off') . ';board=' . $board . '.' . $this->_req->query->start . ';' . $context['session_var'] . '=' . $context['session_id'], |
||
291 | ); |
||
292 | |||
293 | return; |
||
294 | } |
||
295 | |||
296 | $this->_toggle_board_notification(); |
||
297 | |||
298 | $context['xml_data'] = array( |
||
299 | 'text' => $this->_req->query->sa === 'on' ? $txt['unnotify'] : $txt['notify'], |
||
300 | 'url' => $scripturl . '?action=notifyboard;sa=' . ($this->_req->query->sa === 'on' ? 'off' : 'on') . ';board=' . $board . '.' . $this->_req->query->start . ';' . $context['session_var'] . '=' . $context['session_id'] . ';api' . (isset($_REQUEST['json']) ? ';json' : ''), |
||
301 | 'confirm' => $this->_req->query->sa === 'on' ? $txt['notification_disable_board'] : $txt['notification_enable_board'] |
||
302 | ); |
||
303 | } |
||
304 | |||
305 | /** |
||
306 | * Toggle a board notification on/off |
||
307 | */ |
||
308 | private function _toggle_board_notification() |
||
309 | { |
||
310 | global $user_info, $board; |
||
311 | |||
312 | // Our board functions are here |
||
313 | require_once(SUBSDIR . '/Boards.subs.php'); |
||
314 | |||
315 | // Turn notification on/off for this board. |
||
316 | setBoardNotification($user_info['id'], $board, $this->_req->query->sa === 'on'); |
||
317 | } |
||
318 | |||
319 | /** |
||
320 | * Turn off/on unread replies subscription for a topic |
||
321 | * |
||
322 | * What it does: |
||
323 | * |
||
324 | * - Must be called with a topic specified in the URL. |
||
325 | * - The sub-action can be 'on', 'off', or nothing for what to do. |
||
326 | * - Requires the mark_any_notify permission. |
||
327 | * - Upon successful completion of action will direct user back to topic. |
||
328 | * - Accessed via ?action=unwatchtopic. |
||
329 | */ |
||
330 | public function action_unwatchtopic() |
||
331 | { |
||
332 | global $user_info, $topic, $modSettings; |
||
333 | |||
334 | is_not_guest(); |
||
335 | |||
336 | // Let's do something only if the function is enabled |
||
337 | if (!$user_info['is_guest'] && !empty($modSettings['enable_unwatch'])) |
||
338 | { |
||
339 | checkSession('get'); |
||
340 | |||
341 | $this->_toggle_topic_watch(); |
||
342 | } |
||
343 | |||
344 | // Back to the topic. |
||
345 | redirectexit('topic=' . $topic . '.' . $this->_req->query->start); |
||
346 | } |
||
347 | |||
348 | /** |
||
349 | * Turn off/on unread replies subscription for a topic |
||
350 | * |
||
351 | * - Intended for use in XML or JSON calls |
||
352 | */ |
||
353 | public function action_unwatchtopic_api() |
||
354 | { |
||
355 | global $user_info, $topic, $modSettings, $txt, $context, $scripturl; |
||
356 | |||
357 | loadTemplate('Xml'); |
||
358 | |||
359 | Template_Layers::instance()->removeAll(); |
||
360 | $context['sub_template'] = 'generic_xml_buttons'; |
||
361 | |||
362 | // Sorry guests just can't do this |
||
363 | if ($user_info['is_guest']) |
||
364 | { |
||
365 | loadLanguage('Errors'); |
||
366 | $context['xml_data'] = array( |
||
367 | 'error' => 1, |
||
368 | 'text' => $txt['not_guests'] |
||
369 | ); |
||
370 | |||
371 | return; |
||
372 | } |
||
373 | |||
374 | // Let's do something only if the function is enabled |
||
375 | if (empty($modSettings['enable_unwatch'])) |
||
376 | { |
||
377 | loadLanguage('Errors'); |
||
378 | $context['xml_data'] = array( |
||
379 | 'error' => 1, |
||
380 | 'text' => $txt['feature_disabled'], |
||
381 | ); |
||
382 | |||
383 | return; |
||
384 | } |
||
385 | |||
386 | // Sessions need to be validated |
||
387 | if (checkSession('get', '', false)) |
||
388 | { |
||
389 | loadLanguage('Errors'); |
||
390 | $context['xml_data'] = array( |
||
391 | 'error' => 1, |
||
392 | 'url' => $scripturl . '?action=unwatchtopic;sa=' . ($this->_req->query->sa === 'on' ? 'on' : 'off') . ';topic=' . $topic . '.' . $this->_req->query->start . ';' . $context['session_var'] . '=' . $context['session_id'], |
||
393 | ); |
||
394 | |||
395 | return; |
||
396 | } |
||
397 | |||
398 | $this->_toggle_topic_watch(); |
||
399 | |||
400 | $context['xml_data'] = array( |
||
401 | 'text' => $this->_req->query->sa === 'on' ? $txt['watch'] : $txt['unwatch'], |
||
402 | 'url' => $scripturl . '?action=unwatchtopic;topic=' . $context['current_topic'] . '.' . $this->_req->query->start . ';sa=' . ($this->_req->query->sa === 'on' ? 'off' : 'on') . ';' . $context['session_var'] . '=' . $context['session_id'] . ';api' . (isset($_REQUEST['json']) ? ';json' : ''), |
||
403 | ); |
||
404 | } |
||
405 | |||
406 | /** |
||
407 | * Toggle a watch topic on/off |
||
408 | */ |
||
409 | private function _toggle_topic_watch() |
||
410 | { |
||
411 | global $user_info, $topic; |
||
412 | |||
413 | setTopicWatch($user_info['id'], $topic, $this->_req->query->sa === 'on'); |
||
414 | } |
||
415 | |||
416 | /** |
||
417 | * Accessed via the unsubscribe link provided in site emails. This will then |
||
418 | * unsubscribe the user from a board or a topic (depending on the link) without them |
||
419 | * having to login. |
||
420 | */ |
||
421 | public function action_unsubscribe() |
||
440 | } |
||
441 | |||
442 | /** |
||
443 | * Does the actual area unsubscribe toggle |
||
444 | * |
||
445 | * @param mixed[] $member Member info from getBasicMemberData |
||
446 | * @param string $area area they want to be removed from |
||
447 | * @param string $extra parameters needed for some areas |
||
448 | */ |
||
449 | private function _unsubscribeToggle($member, $area, $extra) |
||
450 | { |
||
451 | global $user_info, $board, $topic; |
||
452 | |||
453 | $baseAreas = array('topic', 'board', 'buddy', 'likemsg', 'mentionmem', 'quotedmem', 'rlikemsg'); |
||
454 | |||
455 | // Not a base method, so an addon will need to process this |
||
456 | if (!in_array($area, $baseAreas)) |
||
457 | { |
||
458 | return $this->_unsubscribeModuleToggle($member, $area, $extra); |
||
459 | } |
||
460 | |||
461 | // Look away while we stuff the old ballet box, power to the people! |
||
462 | $user_info['id'] = (int) $member['id_member']; |
||
463 | $this->_req->query->sa = 'off'; |
||
464 | |||
465 | switch ($area) |
||
466 | { |
||
467 | case 'topic': |
||
468 | $topic = $extra; |
||
469 | $this->_toggle_topic_notification(); |
||
470 | break; |
||
471 | case 'board': |
||
472 | $board = $extra; |
||
473 | $this->_toggle_board_notification(); |
||
474 | break; |
||
475 | case 'buddy': |
||
476 | case 'likemsg': |
||
477 | case 'mentionmem': |
||
478 | case 'quotedmem': |
||
479 | case 'rlikemsg': |
||
480 | $this->_setUserNotificationArea($member['id_member'], $area, 1); |
||
481 | break; |
||
482 | } |
||
483 | |||
484 | return true; |
||
485 | } |
||
486 | |||
487 | /** |
||
488 | * Pass unsubscribe information to the appropriate mention class/method |
||
489 | * |
||
490 | * @param mixed[] $member Member info from getBasicMemberData |
||
491 | * @param string $area area they want to be removed from |
||
492 | * @param string $extra parameters needed for some |
||
493 | * |
||
494 | * @return bool if the $unsubscribe method was called |
||
495 | */ |
||
496 | private function _unsubscribeModuleToggle($member, $area, $extra) |
||
497 | { |
||
498 | Elk_Autoloader::instance()->register(SUBSDIR . '/MentionType', '\\ElkArte\\sources\\subs\\MentionType'); |
||
499 | $class_name = '\\ElkArte\\sources\\subs\\MentionType\\' . ucwords($area) . '_Mention'; |
||
500 | |||
501 | if (method_exists($class_name, 'unsubscribe')) |
||
502 | { |
||
503 | $unsubscribe = new $class_name; |
||
504 | |||
505 | return $unsubscribe->unsubscribe($member, $area, $extra); |
||
506 | } |
||
507 | |||
508 | return false; |
||
509 | } |
||
510 | |||
511 | /** |
||
512 | * Validates a supplied token and extracts the needed bits |
||
513 | * |
||
514 | * What it does: |
||
515 | * - Checks token conforms to a known pattern |
||
516 | * - Checks token is for a known notification type |
||
517 | * - Checks the age of the token |
||
518 | * - Finds the member claimed in the token |
||
519 | * - Runs crypt on member data to validate it matches the supplied hash |
||
520 | * |
||
521 | * @param mixed[] $member Member info from getBasicMemberData |
||
522 | * @param string $area area they want to be removed from |
||
523 | * @param string $extra parameters needed for some areas |
||
524 | * @return bool |
||
525 | */ |
||
526 | private function _validateUnsubscribeToken(&$member, &$area, &$extra) |
||
571 | ); |
||
572 | } |
||
573 | |||
574 | /** |
||
575 | * Used to set a specific mention area to a new value while keeping other |
||
576 | * areas as they are. |
||
577 | * |
||
578 | * @param int $memID |
||
579 | * @param string $area buddy, likemsg, mentionmem, quotedmem, rlikemsg |
||
580 | * @param int $value 1=notify 2=immediate email 3=daily email 4=weekly email |
||
581 | */ |
||
582 | private function _setUserNotificationArea($memID, $area, $value) |
||
616 | } |
||
617 | |||
618 | /** |
||
619 | * Sets the unsubscribe string for template use |
||
620 | * |
||
621 | * @param string $area |
||
622 | * @param string $extra |
||
623 | * @throws \Elk_Exception |
||
624 | */ |
||
625 | private function _prepareTemplateMessage($area, $extra, $email) |
||
659 |