PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.6.1
Defender Security – Malware Scanner, Login Security & Firewall v5.6.1
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / src / controller / class-notification.php

class-notification.php in Defender Security – Malware Scanner, Login Security & Firewall 5.6.1, at src/controller/class-notification.php

926 lines 25.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles notification operations.
4 *
5 * @package WP_Defender\Controller
6 */
7
8 namespace WP_Defender\Controller;
9
10 use Exception;
11 use WP_Defender\Event;
12 use Calotes\Helper\HTTP;
13 use WP_Defender\Traits\User;
14 use Calotes\Component\Request;
15 use WP_Defender\Traits\Formats;
16 use Calotes\Component\Response;
17 use WP_Defender\Model\Notification\Malware_Report;
18 use WP_Defender\Component\Config\Config_Hub_Helper;
19 use WP_Defender\Model\Notification as Model_Notification;
20
21 /**
22 * Methods for handling notifications.
23 */
24 class Notification extends Event {
25
26 use User;
27 use Formats;
28
29 /**
30 * Slug identifier for subscribe page.
31 *
32 * @var string
33 */
34 public const SLUG_SUBSCRIBE = 'defender_listen_user_subscribe';
35
36 /**
37 * Slug identifier for unsubscribe page.
38 *
39 * @var string
40 */
41 public const SLUG_UNSUBSCRIBE = 'defender_listen_user_unsubscribe';
42 /**
43 * The slug identifier for this controller.
44 *
45 * @var string
46 */
47 public $slug = 'wdf-notification';
48
49 /**
50 * Service for handling logic.
51 *
52 * @var \WP_Defender\Component\Notification
53 */
54 protected $service;
55
56 /**
57 * Initializes the model and service, registers routes, and sets up scheduled events if the model is active.
58 */
59 public function __construct() {
60 $this->register_page(
61 esc_html__( 'Notifications', 'defender-security' ),
62 $this->slug,
63 array( $this, 'main_view' ),
64 $this->parent_slug
65 );
66 $this->register_routes();
67 $this->service = wd_di()->get( \WP_Defender\Component\Notification::class );
68 add_action( 'defender_enqueue_assets', array( $this, 'enqueue_assets' ) );
69 // We use custom ajax endpoint here as the nonce would fail with other user.
70 add_action( 'wp_ajax_' . self::SLUG_SUBSCRIBE, array( $this, 'verify_subscriber' ) );
71 add_action( 'wp_ajax_nopriv_' . self::SLUG_SUBSCRIBE, array( $this, 'verify_subscriber' ) );
72 add_action( 'wp_ajax_' . self::SLUG_UNSUBSCRIBE, array( $this, 'unsubscribe_and_send_email' ) );
73 add_action( 'wp_ajax_nopriv_' . self::SLUG_UNSUBSCRIBE, array( $this, 'unsubscribe_and_send_email' ) );
74 add_action( 'defender_notify', array( $this, 'send_notify' ), 10, 2 );
75 // We will schedule the time to send reports.
76 if ( ! wp_next_scheduled( 'wdf_maybe_send_report' ) ) {
77 $timestamp = gmmktime( wp_date( 'H' ), 0, 0 );
78 wp_schedule_event( $timestamp, 'thirty_minutes', 'wdf_maybe_send_report' );
79 }
80 add_action( 'wdf_maybe_send_report', array( $this, 'report_sender' ) );
81 add_action( 'admin_notices', array( $this, 'show_actions_with_subscription' ) );
82 }
83
84 /**
85 * For users who have subscribed or unsubscribed confirmation.
86 *
87 * @return null|void
88 */
89 public function show_actions_with_subscription() {
90 if ( ! defined( 'IS_PROFILE_PAGE' ) || false === constant( 'IS_PROFILE_PAGE' ) ) {
91 return null;
92 }
93 $slug = defender_get_data_from_request( 'slug', 'g' );
94 if ( empty( $slug ) ) {
95 return null;
96 }
97 $m = $this->service->find_module_by_slug( $slug );
98 if ( ! is_object( $m ) ) {
99 return null;
100 }
101 $context = defender_get_data_from_request( 'context', 'g' );
102 if ( 'subscribed' === $context ) {
103 $unsubscribe_link = $this->service->create_unsubscribe_url( $m->slug, $this->get_current_user_email() );
104 $strings = sprintf(
105 /* translators: 1. Module title. 2. Unsubscribed link. */
106 esc_html__(
107 'You are now subscribed to receive %1$s. Made a mistake? %2$s',
108 'defender-security'
109 ),
110 '<strong>' . $m->title . '</strong>',
111 '<a href="' . esc_url_raw( $unsubscribe_link ) . '" style="text-decoration: none">' . esc_html__( 'Unsubscribe', 'defender-security' ) . '</a>'
112 );
113 } elseif ( 'unsubscribe' === $context ) {
114 $strings = sprintf(
115 /* translators: %s: Module title. */
116 esc_html__( 'You are now unsubscribed from %s.', 'defender-security' ),
117 '<strong>' . $m->title . '</strong>'
118 );
119 } else {
120 return null;
121 }
122 ?>
123 <div class="notice notice-success" style="position:relative;">
124 <p><?php echo wp_kses_post( $strings ); ?></p>
125 <a href="<?php echo esc_url_raw( get_edit_profile_url() ); ?>" class="notice-dismiss"
126 style="text-decoration: none">
127 <span class="screen-reader-text"><?php esc_attr_e( 'Dismiss this notice.', 'defender-security' ); ?></span>
128 </a>
129 </div>
130 <?php
131 }
132
133 /**
134 * Trigger report check signals.
135 */
136 public function report_sender() {
137 $this->service->maybe_dispatch_report();
138 }
139
140 /**
141 * Renders the main view for this page.
142 */
143 public function main_view() {
144 $this->render( 'main' );
145 }
146
147 /**
148 * Dispatch notification.
149 *
150 * @param string $slug Module slug to identify the notification handler.
151 * @param object $args The arguments to pass to the notification.
152 */
153 public function send_notify( $slug, $args ) {
154 $this->service->dispatch_notification( $slug, $args );
155 }
156
157 /**
158 * Validates an email address provided in the request data.
159 *
160 * @param Request $request The request object .The request object containing the data to validate.
161 *
162 * @return Response The response object indicating the validation result.
163 * @defender_route
164 */
165 public function validate_email( Request $request ): Response {
166 $data = $request->get_data(
167 array(
168 'email' => array(
169 'type' => 'string',
170 'sanitize' => 'sanitize_text_field',
171 ),
172 )
173 );
174 $email = $data['email'] ?? false;
175 if ( filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
176 return new Response(
177 true,
178 array(
179 'error' => false,
180 'avatar' => get_avatar_url( $data['email'] ),
181 )
182 );
183 } else {
184 return new Response( false, array( 'error' => esc_html__( 'Invalid email address.', 'defender-security' ) ) );
185 }
186 }
187
188 /**
189 * Unsubscribe process.
190 */
191 public function unsubscribe_and_send_email() {
192 $slug = HTTP::get( 'slug', '' );
193 $hash = HTTP::get( 'hash', '' );
194 $slug = sanitize_text_field( $slug );
195 if ( empty( $slug ) || empty( $hash ) ) {
196 wp_die( esc_html__( 'You shall not pass.', 'defender-security' ) );
197 }
198 $m = $this->service->find_module_by_slug( $slug );
199 if ( ! is_object( $m ) ) {
200 wp_die( esc_html__( 'You shall not pass.', 'defender-security' ) );
201 }
202 $inhouse = false;
203 foreach ( $m->in_house_recipients as &$recipient ) {
204 $email = $recipient['email'];
205 if ( hash_equals( $hash, hash( 'sha256', $email . AUTH_SALT ) ) ) {
206 // We skip even an un-logged user, because the admin can change the user's access without notice.
207 if ( is_user_logged_in() ) {
208 if ( $email !== $this->get_current_user_email() ) {
209 wp_die( esc_html__( 'Invalid request.', 'defender-security' ) );
210 }
211 $inhouse = true;
212 }
213 $recipient['status'] = Model_Notification::USER_SUBSCRIBE_CANCELED;
214 $m->save();
215 // Send email.
216 $this->service->send_unsubscribe_email( $m, $email, $inhouse, $recipient['name'] );
217 break;
218 }
219 }
220
221 if ( false === $inhouse ) {
222 // No match on in-house, check the outhouse list.
223 foreach ( $m->out_house_recipients as &$recipient ) {
224 $email = $recipient['email'];
225 if ( hash_equals( $hash, hash( 'sha256', $email . AUTH_SALT ) ) ) {
226 $recipient['status'] = Model_Notification::USER_SUBSCRIBE_CANCELED;
227 $m->save();
228 $this->service->send_unsubscribe_email( $m, $email, $inhouse, $recipient['name'] );
229 }
230 }
231 }
232 if ( $inhouse ) {
233 wp_safe_redirect(
234 add_query_arg(
235 array(
236 'slug' => $slug,
237 'context' => 'unsubscribe',
238 ),
239 get_edit_profile_url()
240 )
241 );
242 } else {
243 wp_safe_redirect( get_home_url() );
244 }
245 exit;
246 }
247
248 /**
249 * An endpoint for saving single config from frontend.
250 *
251 * @param Request $request The request object .The request object containing the data to save.
252 *
253 * @defender_route
254 * @return Response
255 * @throws Exception Emits Exception in case of an error.
256 */
257 public function save( Request $request ): Response {
258 $raw_data = $request->get_data();
259 if ( empty( $raw_data['slug'] ) ) {
260 return new Response( false, array( 'message' => esc_html__( 'Invalid data.', 'defender-security' ) ) );
261 }
262 $slug = sanitize_textarea_field( $raw_data['slug'] );
263 $model = $this->service->find_module_by_slug( $slug );
264
265 if ( ! is_object( $model ) ) {
266 return new Response( false, array( 'message' => esc_html__( 'Invalid data.', 'defender-security' ) ) );
267 }
268 $data = $request->get_data_by_model( $model );
269 // Check config-values.
270 $data['configs'] = $model->type_casting( $data['configs'] );
271
272 $model->import( $data );
273 $model->status = Model_Notification::STATUS_ACTIVE;
274 if ( $model->validate() ) {
275 if ( 0 === $model->last_sent ) {
276 // This means that the notification or report never sent, we will use the moment that it get activate.
277 $model->last_sent = time();
278 }
279 $model->save();
280 $this->service->send_subscription_confirm_email( $model );
281 Config_Hub_Helper::set_clear_active_flag();
282 // Track.
283 if ( $this->is_tracking_active() ) {
284 $track_data = array( 'Notification type' => $raw_data['title'] );
285 // For reports. Separated check for 'Security Recommendations - Notification'.
286 if ( 'report' === $raw_data['type'] ) {
287 $track_data['Notification schedule'] = ucfirst( $data['frequency'] );
288 } elseif ( 'tweak-reminder' === $raw_data['slug'] ) {
289 $track_data['Notification schedule'] = ucfirst( $data['configs']['reminder'] );
290 }
291 $this->track_feature( 'def_notification_activated', $track_data );
292 }
293
294 return new Response(
295 true,
296 array_merge(
297 array(
298 'message' => esc_html__(
299 'You have activated the notification successfully. Note, recipients will need to confirm their subscriptions to begin receiving notifications.',
300 'defender-security'
301 ),
302 ),
303 $this->data_frontend()
304 )
305 );
306 }
307
308 return new Response( false, array( 'message' => $model->get_formatted_errors() ) );
309 }
310
311 /**
312 * Bulk update and save changes.
313 *
314 * @param Request $request The request object.
315 *
316 * @defender_route
317 * @return Response
318 */
319 public function save_bulk( Request $request ): Response {
320 $data = $request->get_data(
321 array(
322 'reports' => array(
323 'type' => 'array',
324 'sanitize' => 'sanitize_textarea_field',
325 ),
326 'notifications' => array(
327 'type' => 'array',
328 'sanitize' => 'sanitize_textarea_field',
329 ),
330 )
331 );
332 $this->save_reports( $data['reports'] );
333 $this->save_notifications( $data['notifications'] );
334 Config_Hub_Helper::set_clear_active_flag();
335
336 return new Response(
337 true,
338 array_merge(
339 $this->data_frontend(),
340 array(
341 'message' => esc_html__(
342 'Your settings have been updated successfully. Any new recipients will receive an email to confirm their subscription.',
343 'defender-security'
344 ),
345 )
346 )
347 );
348 }
349
350 /**
351 * Process bulk reports saving.
352 *
353 * @param array $data Data to save.
354 *
355 * @throws Exception Emits Exception in case of an error.
356 */
357 private function save_reports( $data ) {
358 foreach ( $data['configs'] as $datum ) {
359 $slug = $datum['slug'];
360 $model = $this->service->find_module_by_slug( $slug );
361 if ( ! is_object( $model ) ) {
362 continue;
363 }
364
365 $import = array(
366 // Saving after Bulk-Update must always change the status to Active.
367 'status' => Model_Notification::STATUS_ACTIVE,
368 'configs' => $model->type_casting( $datum ),
369 'in_house_recipients' => $data['in_house_recipients'],
370 'out_house_recipients' => $data['out_house_recipients'],
371 );
372 // since 2.7.0.
373 if ( Malware_Report::SLUG !== $slug ) {
374 $import['frequency'] = $data['frequency'];
375 $import['day_n'] = (int) $data['day_n'];
376 $import['day'] = $data['day'];
377 $import['time'] = $data['time'];
378 }
379 foreach ( $import['out_house_recipients'] as $key => $val ) {
380 if ( ! filter_var( $val['email'], FILTER_VALIDATE_EMAIL ) ) {
381 unset( $import['out_house_recipients'][ $key ] );
382 }
383 }
384 $model->import( $import );
385 if ( $model->validate() ) {
386 if ( 0 === $model->last_sent ) {
387 $model->last_sent = time();
388 }
389 $model->save();
390 $this->service->send_subscription_confirm_email( $model );
391 // Track.
392 if ( $this->is_tracking_active() ) {
393 $track_data = array(
394 'Notification type' => $model->title,
395 'Notification schedule' => 'tweak-reminder' === $slug
396 ? ucfirst( $data['configs']['reminder'] )
397 : ucfirst( $data['frequency'] ),
398 );
399 $this->track_feature( 'def_notification_activated', $track_data );
400 }
401 }
402 }
403 }
404
405 /**
406 * Saves the notifications based on the provided data.
407 *
408 * @param array $data The data containing the configurations for the notifications.
409 *
410 * @return void
411 * @throws Exception Emits Exception in case of an error.
412 */
413 private function save_notifications( $data ) {
414 foreach ( $data['configs'] as $datum ) {
415 $slug = $datum['slug'];
416 $model = $this->service->find_module_by_slug( $slug );
417 if ( ! is_object( $model ) ) {
418 continue;
419 }
420 $import = array(
421 // Saving after Bulk-Update must always change the status to Active.
422 'status' => Model_Notification::STATUS_ACTIVE,
423 'configs' => $model->type_casting( $datum ),
424 'in_house_recipients' => $data['in_house_recipients'],
425 'out_house_recipients' => $data['out_house_recipients'],
426 );
427 foreach ( $import['out_house_recipients'] as $key => $val ) {
428 if ( ! filter_var( $val['email'], FILTER_VALIDATE_EMAIL ) ) {
429 unset( $import['out_house_recipients'][ $key ] );
430 }
431 }
432 $model->import( $import );
433 if ( $model->validate() ) {
434 if ( 0 === $model->last_sent ) {
435 $model->last_sent = time();
436 }
437 $model->save();
438 $this->service->send_subscription_confirm_email( $model );
439 // Track.
440 if ( $this->is_tracking_active() ) {
441 $this->track_feature( 'def_notification_activated', array( 'Notification type' => $model->title ) );
442 }
443 }
444 }
445 }
446
447 /**
448 * Bulk activate.
449 *
450 * @param Request $request The request object.
451 *
452 * @defender_route
453 * @return Response
454 * @throws Exception Emits Exception in case of an error.
455 */
456 public function bulk_activate( Request $request ): Response {
457 $data = $request->get_data(
458 array(
459 'slugs' => array(
460 'type' => 'array',
461 'sanitize' => 'sanitize_text_field',
462 ),
463 )
464 );
465 $slugs = $data['slugs'];
466 if ( empty( $slugs ) ) {
467 return new Response( false, array() );
468 }
469
470 foreach ( $slugs as $slug ) {
471 $model = $this->service->find_module_by_slug( $slug );
472 if ( is_object( $model ) ) {
473 $model->status = Model_Notification::STATUS_ACTIVE;
474 if ( 0 === $model->last_sent ) {
475 // This means that the notification or report never sent, we will use the moment that it get activate.
476 $model->last_sent = time();
477 }
478 $model->save();
479 }
480 }
481
482 return new Response(
483 true,
484 array_merge(
485 array(
486 'message' => 'You have activated the notification successfully. Note, recipients will need to confirm their subscriptions to begin receiving notifications.',
487 ),
488 $this->data_frontend()
489 )
490 );
491 }
492
493 /**
494 * Bulk deactivate.
495 *
496 * @param Request $request The request object.
497 *
498 * @defender_route
499 * @return Response
500 */
501 public function bulk_deactivate( Request $request ): Response {
502 $data = $request->get_data(
503 array(
504 'slugs' => array(
505 'type' => 'array',
506 'sanitize' => 'sanitize_text_field',
507 ),
508 )
509 );
510 $slugs = $data['slugs'];
511 if ( empty( $slugs ) ) {
512 return new Response( false, array() );
513 }
514
515 foreach ( $slugs as $slug ) {
516 $model = $this->service->find_module_by_slug( $slug );
517 if ( is_object( $model ) ) {
518 $model->status = Model_Notification::STATUS_DISABLED;
519 $model->save();
520 }
521 }
522
523 return new Response(
524 true,
525 array_merge(
526 array( 'message' => esc_html__( 'You have deactivated the notifications successfully.', 'defender-security' ) ),
527 $this->data_frontend()
528 )
529 );
530 }
531
532 /**
533 * Disable a notification module.
534 *
535 * @param Request $request The request object .The request object containing the data to disable the module.
536 *
537 * @defender_route
538 * @return Response The response object indicating the success or failure of the operation.
539 */
540 public function disable( Request $request ): Response {
541 $data = $request->get_data(
542 array(
543 'slug' => array(
544 'type' => 'string',
545 'sanitize' => 'sanitize_text_field',
546 ),
547 )
548 );
549
550 $slug = $data['slug'];
551 $model = $this->service->find_module_by_slug( $slug );
552 if ( ! is_object( $model ) ) {
553 return new Response( false, array( 'message' => esc_html__( 'Invalid data.', 'defender-security' ) ) );
554 }
555
556 $model->status = Model_Notification::STATUS_DISABLED;
557 $model->save();
558
559 return new Response(
560 true,
561 array_merge(
562 $this->data_frontend(),
563 array(
564 'message' => esc_html__( 'You have deactivated the notification successfully.', 'defender-security' ),
565 )
566 )
567 );
568 }
569
570 /**
571 * This is a receiver to process subscribe confirmation from email.
572 */
573 public function verify_subscriber() {
574 $hash = HTTP::get( 'hash', '' );
575 $slug = HTTP::get( 'uid', '' );
576 $inhouse = HTTP::get( 'inhouse', 0 );
577 if ( $inhouse && ! is_user_logged_in() ) {
578 // This is in-house, so we need to redirect.
579 auth_redirect();
580 }
581 if ( empty( $hash ) || empty( $slug ) ) {
582 wp_die( esc_html__( 'You shall not pass.', 'defender-security' ) );
583 }
584 $m = $this->service->find_module_by_slug( $slug );
585 if ( ! is_object( $m ) ) {
586 wp_die( esc_html__( 'You shall not pass.', 'defender-security' ) );
587 }
588 if ( $inhouse ) {
589 $processed = false;
590 foreach ( $m->in_house_recipients as &$recipient ) {
591 if ( Model_Notification::USER_SUBSCRIBED === $recipient['status'] ) {
592 continue;
593 }
594
595 $email = $recipient['email'];
596 $name = $recipient['name'];
597 if ( hash_equals( $hash, hash( 'sha256', $email . AUTH_SALT ) )
598 && $email === $this->get_current_user_email() ) {
599 $recipient['status'] = Model_Notification::USER_SUBSCRIBED;
600 $this->service->send_subscribed_email( $email, $m, $name );
601 $processed = true;
602 }
603 }
604 } else {
605 foreach ( $m->out_house_recipients as &$recipient ) {
606 if ( Model_Notification::USER_SUBSCRIBED === $recipient['status'] ) {
607 continue;
608 }
609
610 $email = $recipient['email'];
611 $name = $recipient['name'];
612 if ( hash_equals( $hash, hash( 'sha256', $email . AUTH_SALT ) ) ) {
613 $recipient['status'] = Model_Notification::USER_SUBSCRIBED;
614 $this->service->send_subscribed_email( $email, $m, $name );
615 }
616 }
617 }
618 $m->save();
619 if ( $inhouse ) {
620 if ( $processed ) {
621 wp_safe_redirect(
622 add_query_arg(
623 array(
624 'slug' => $m->slug,
625 'context' => 'subscribed',
626 ),
627 get_edit_profile_url()
628 )
629 );
630 } else {
631 wp_safe_redirect( home_url() );
632 }
633 } else {
634 wp_safe_redirect( home_url() );
635 }
636 exit;
637 }
638
639 /**
640 * Enqueues scripts and styles for this page.
641 * Only enqueues assets if the page is active.
642 */
643 public function enqueue_assets() {
644 if ( ! $this->is_page_active() ) {
645 return;
646 }
647 wp_localize_script(
648 'def-notification',
649 'notification',
650 array_merge( $this->data_frontend(), $this->dump_routes_and_nonces() )
651 );
652 wp_enqueue_script( 'def-notification' );
653 $this->enqueue_main_assets();
654 wp_enqueue_style(
655 'def-select2',
656 defender_asset_url( '/assets/css/select2.min.css' ),
657 array(),
658 DEFENDER_VERSION,
659 true
660 );
661 }
662
663 /**
664 * An endpoint for fetching users pool.
665 *
666 * @param Request $request The request object .Request data.
667 *
668 * @defender_route
669 */
670 public function get_users( Request $request ) {
671 $data = $request->get_data(
672 array(
673 'paged' => array(
674 'type' => 'int',
675 'sanitize' => 'sanitize_text_field',
676 ),
677 'search' => array(
678 'type' => 'string',
679 'sanitize' => 'sanitize_text_field',
680 ),
681 'exclude' => array(
682 'type' => 'array',
683 ),
684 'module' => array(
685 'type' => 'string',
686 'sanitize' => 'sanitize_text_field',
687 ),
688 'user_role_filter' => array(
689 'type' => 'string',
690 'sanitize' => 'sanitize_text_field',
691 ),
692 'user_sort' => array(
693 'type' => 'string',
694 'sanitize' => 'sanitize_text_field',
695 ),
696 )
697 );
698 $paged = 1;
699 $exclude = $data['exclude'] ?? array();
700 $username = $data['search'] ?? '';
701 $slug = $data['module'] ?? null;
702 $role = '';
703
704 if (
705 isset( $data['user_role_filter'] ) &&
706 'all' !== $data['user_role_filter']
707 ) {
708 $role = $data['user_role_filter'];
709 }
710
711 $order_by = 'ID';
712 $order = 'DESC';
713 if ( isset( $data['user_sort'] ) ) {
714 switch ( $data['user_sort'] ) {
715 case 'recent':
716 $order_by = 'registered';
717 $order = 'DESC';
718 break;
719 case 'alpha_asc':
720 $order_by = 'display_name';
721 $order = 'ASC';
722 break;
723 case 'alpha_desc':
724 default:
725 $order_by = 'display_name';
726 $order = 'DESC';
727 break;
728 }
729 }
730
731 if ( strlen( $username ) ) {
732 $username = "*$username*";
733 }
734
735 $users = $this->service->get_users_pool(
736 $exclude,
737 $role,
738 $username,
739 $order_by,
740 $order,
741 10,
742 $paged
743 );
744
745 if ( ! is_null( $slug ) ) {
746 $notification = $this->service->find_module_by_slug( $slug );
747 if ( is_object( $notification ) ) {
748 foreach ( $notification->in_house_recipients as $recipient ) {
749 foreach ( $users as &$user ) {
750 if ( $user['email'] === $recipient['email'] ) {
751 $user['status'] = $recipient['status'];
752 }
753 }
754 }
755 }
756 }
757
758 wp_send_json_success( $users );
759 }
760
761 /**
762 * Removes settings for all submodules.
763 */
764 public function remove_settings() {
765 foreach ( $this->service->get_modules_as_objects() as $module ) {
766 $module->delete();
767 }
768 }
769
770 /**
771 * Delete all the data & the cache.
772 */
773 public function remove_data() {
774 }
775
776 /**
777 * Converts the current object state to an array.
778 *
779 * @return array The array representation of the object.
780 */
781 public function to_array(): array {
782 return array();
783 }
784
785 /**
786 * Provides data for the frontend.
787 *
788 * @return array An array of data for the frontend.
789 */
790 public function data_frontend(): array {
791 return array(
792 'notifications' => $this->service->get_modules(),
793 'inactive_notifications' => $this->service->get_inactive_modules(),
794 'active_count' => $this->service->count_active(),
795 'next_run' => $this->service->get_next_run(),
796 'misc' => array(
797 'days_of_week' => $this->get_days_of_week(),
798 'times_of_day' => $this->get_times(),
799 'timezone_text' => sprintf(
800 /* translators: 1. Timezone. 2. Time. */
801 esc_html__(
802 'Your timezone is set to %1$s, so your current time is %2$s.',
803 'defender-security'
804 ),
805 '<strong>' . wp_timezone_string() . '</strong>',
806 '<strong>' . wp_date( 'H:i', time() ) . '</strong>'
807 ),
808 'default_recipient' => $this->get_default_recipient(),
809 ),
810 );
811 }
812
813 /**
814 * Imports data into the model.
815 *
816 * @param array $data Data to be imported into the model.
817 */
818 public function import_data( array $data ) {
819 }
820
821 /**
822 * Exports strings.
823 *
824 * @return array An array of strings.
825 */
826 public function export_strings(): array {
827 $modules = wd_di()->get( self::class )->service->get_modules_as_objects();
828 $strings = array();
829 foreach ( $modules as $module ) {
830 /* translators: %s - module title, %s - module status */
831 $string = esc_html__( '%1$s: %2$s', 'defender-security' );
832 if ( 'notification' === $module->type ) {
833 $string = sprintf(
834 $string,
835 $module->title,
836 Model_Notification::STATUS_ACTIVE === $module->status ? esc_html__(
837 'Enabled',
838 'defender-security'
839 ) : esc_html__( 'Disabled', 'defender-security' )
840 );
841 } else {
842 $string = sprintf(
843 $string,
844 $module->title,
845 Model_Notification::STATUS_ACTIVE === $module->status ? $module->to_string() : esc_html__(
846 'Disabled',
847 'defender-security'
848 )
849 );
850 }
851 $strings[] = $string;
852 }
853
854 return $strings;
855 }
856
857 /**
858 * Resend invite email.
859 *
860 * @param Request $request The request object.
861 *
862 * @defender_route
863 * @return Response
864 */
865 public function resend_invite_email( Request $request ): Response {
866 $data = $request->get_data(
867 array(
868 'slug' => array(
869 'type' => 'string',
870 'sanitize' => 'sanitize_textarea_field',
871 ),
872 'email' => array(
873 'type' => 'string',
874 'sanitize' => 'sanitize_text_field',
875 ),
876 'id' => array(
877 'type' => 'integer',
878 ),
879 'name' => array(
880 'type' => 'string',
881 'sanitize' => 'sanitize_text_field',
882 ),
883 )
884 );
885
886 $model = $this->service->find_module_by_slug( $data['slug'] );
887
888 if ( ! is_object( $model ) ) {
889 return new Response( false, array( 'message' => esc_html__( 'Module not found.', 'defender-security' ) ) );
890 }
891
892 $subscriber = array(
893 'email' => $data['email'],
894 'name' => $data['name'],
895 );
896
897 if ( ! empty( $data['id'] ) ) {
898 $subscriber['id'] = $data['id'];
899 }
900 // Resend invite email now.
901 $sent = $this->service->send_email( $subscriber, $model );
902
903 if ( $sent ) {
904 return new Response( true, array( 'message' => esc_html__( 'Invitation sent successfully.', 'defender-security' ) ) );
905 }
906
907 return new Response(
908 false,
909 array(
910 'message' => esc_html__( 'Sorry! We could not send the invitation, Please try again later.', 'defender-security' ),
911 )
912 );
913 }
914
915 /**
916 * Get user roles with count.
917 *
918 * @defender_route
919 */
920 public function get_user_roles() {
921 $user_roles = $this->service->get_user_roles();
922
923 wp_send_json_success( $user_roles );
924 }
925 }
926