AnonSec Shell
Server IP : 172.67.157.199  /  Your IP : 3.15.208.156   [ Reverse IP ]
Web Server : Apache
System : Linux b70eb322-3aee-0c53-7c82-0db91281f2c6.secureserver.net 6.1.90-1.el9.elrepo.x86_64 #1 SMP PREEMPT_DYNAMIC Thu May 2 12:09:22 EDT 2024 x86_64
User : root ( 0)
PHP Version : 8.0.30.2
Disable Function : NONE
Domains : 0 Domains
MySQL : ON  |  cURL : ON  |  WGET : ON  |  Perl : OFF  |  Python : OFF  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /var/www/wp-content/plugins/defender-security/src/controller/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ HOME ]     [ BACKUP SHELL ]     [ JUMPING ]     [ MASS DEFACE ]     [ SCAN ROOT ]     [ SYMLINK ]     

Current File : /var/www/wp-content/plugins/defender-security/src/controller/class-notification.php
<?php
/**
 * Handles notification operations.
 *
 * @package WP_Defender\Controller
 */

namespace WP_Defender\Controller;

use Exception;
use WP_Defender\Event;
use Calotes\Helper\HTTP;
use WP_Defender\Traits\User;
use Calotes\Component\Request;
use WP_Defender\Traits\Formats;
use Calotes\Component\Response;
use WP_Defender\Model\Notification\Malware_Report;
use WP_Defender\Component\Config\Config_Hub_Helper;
use WP_Defender\Model\Notification as Model_Notification;

/**
 * Methods for handling notifications.
 */
class Notification extends Event {

	use User;
	use Formats;

	/**
	 * Slug identifier for subscribe page.
	 *
	 * @var string
	 */
	public const SLUG_SUBSCRIBE = 'defender_listen_user_subscribe';

	/**
	 * Slug identifier for unsubscribe page.
	 *
	 * @var string
	 */
	public const SLUG_UNSUBSCRIBE = 'defender_listen_user_unsubscribe';
	/**
	 * The slug identifier for this controller.
	 *
	 * @var string
	 */
	public $slug = 'wdf-notification';

	/**
	 * Service for handling logic.
	 *
	 * @var \WP_Defender\Component\Notification
	 */
	protected $service;

	/**
	 * Initializes the model and service, registers routes, and sets up scheduled events if the model is active.
	 */
	public function __construct() {
		$this->register_page(
			esc_html__( 'Notifications', 'defender-security' ),
			$this->slug,
			array(
				&$this,
				'main_view',
			),
			$this->parent_slug
		);
		$this->register_routes();
		$this->service = wd_di()->get( \WP_Defender\Component\Notification::class );
		add_action( 'defender_enqueue_assets', array( &$this, 'enqueue_assets' ) );
		// We use custom ajax endpoint here as the nonce would fail with other user.
		add_action( 'wp_ajax_' . self::SLUG_SUBSCRIBE, array( &$this, 'verify_subscriber' ) );
		add_action( 'wp_ajax_nopriv_' . self::SLUG_SUBSCRIBE, array( &$this, 'verify_subscriber' ) );
		add_action( 'wp_ajax_' . self::SLUG_UNSUBSCRIBE, array( &$this, 'unsubscribe_and_send_email' ) );
		add_action( 'wp_ajax_nopriv_' . self::SLUG_UNSUBSCRIBE, array( &$this, 'unsubscribe_and_send_email' ) );
		add_action( 'defender_notify', array( &$this, 'send_notify' ), 10, 2 );
		// We will schedule the time to send reports.
		if ( ! wp_next_scheduled( 'wdf_maybe_send_report' ) ) {
			$timestamp = gmmktime( wp_date( 'H' ), 0, 0 );
			wp_schedule_event( $timestamp, 'thirty_minutes', 'wdf_maybe_send_report' );
		}
		add_action( 'wdf_maybe_send_report', array( &$this, 'report_sender' ) );
		add_action( 'admin_notices', array( &$this, 'show_actions_with_subscription' ) );
	}

	/**
	 * For users who have subscribed or unsubscribed confirmation.
	 *
	 * @return null|void
	 */
	public function show_actions_with_subscription() {
		if ( ! defined( 'IS_PROFILE_PAGE' ) || false === constant( 'IS_PROFILE_PAGE' ) ) {
			return null;
		}
		$slug = defender_get_data_from_request( 'slug', 'g' );
		if ( empty( $slug ) ) {
			return null;
		}
		$m = $this->service->find_module_by_slug( $slug );
		if ( ! is_object( $m ) ) {
			return null;
		}
		$context = defender_get_data_from_request( 'context', 'g' );
		if ( 'subscribed' === $context ) {
			$unsubscribe_link = $this->service->create_unsubscribe_url( $m->slug, $this->get_current_user_email() );
			$strings          = sprintf(
			/* translators: 1. Module title. 2. Unsubscribed link. */
				esc_html__(
					'You are now subscribed to receive %1$s. Made a mistake? %2$s',
					'defender-security'
				),
				'<strong>' . $m->title . '</strong>',
				'<a href="' . esc_url_raw( $unsubscribe_link ) . '" style="text-decoration: none">' . esc_html__( 'Unsubscribe', 'defender-security' ) . '</a>'
			);
		} elseif ( 'unsubscribe' === $context ) {
			$strings = sprintf(
			/* translators: %s: Module title. */
				esc_html__( 'You are now unsubscribed from %s.', 'defender-security' ),
				'<strong>' . $m->title . '</strong>'
			);
		} else {
			return null;
		}
		?>
		<div class="notice notice-success" style="position:relative;">
			<p><?php echo wp_kses_post( $strings ); ?></p>
			<a href="<?php echo esc_url_raw( get_edit_profile_url() ); ?>" class="notice-dismiss"
				style="text-decoration: none">
				<span class="screen-reader-text"><?php esc_attr_e( 'Dismiss this notice.', 'defender-security' ); ?></span>
			</a>
		</div>
		<?php
	}

	/**
	 * Trigger report check signals.
	 */
	public function report_sender() {
		$this->service->maybe_dispatch_report();
	}

	/**
	 * Renders the main view for this page.
	 */
	public function main_view() {
		$this->render( 'main' );
	}

	/**
	 * Dispatch notification.
	 *
	 * @param  string $slug  Module slug to identify the notification handler.
	 * @param  object $args  The arguments to pass to the notification.
	 */
	public function send_notify( $slug, $args ) {
		$this->service->dispatch_notification( $slug, $args );
	}

	/**
	 * Validates an email address provided in the request data.
	 *
	 * @param  Request $request  The request object .The request object containing the data to validate.
	 *
	 * @return Response The response object indicating the validation result.
	 * @defender_route
	 */
	public function validate_email( Request $request ): Response {
		$data  = $request->get_data(
			array(
				'email' => array(
					'type'     => 'string',
					'sanitize' => 'sanitize_text_field',
				),
			)
		);
		$email = $data['email'] ?? false;
		if ( filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
			return new Response(
				true,
				array(
					'error'  => false,
					'avatar' => get_avatar_url( $data['email'] ),
				)
			);
		} else {
			return new Response( false, array( 'error' => esc_html__( 'Invalid email address.', 'defender-security' ) ) );
		}
	}

	/**
	 * Unsubscribe process.
	 */
	public function unsubscribe_and_send_email() {
		$slug = HTTP::get( 'slug', '' );
		$hash = HTTP::get( 'hash', '' );
		$slug = sanitize_text_field( $slug );
		if ( empty( $slug ) || empty( $hash ) ) {
			wp_die( esc_html__( 'You shall not pass.', 'defender-security' ) );
		}
		$m = $this->service->find_module_by_slug( $slug );
		if ( ! is_object( $m ) ) {
			wp_die( esc_html__( 'You shall not pass.', 'defender-security' ) );
		}
		$inhouse = false;
		foreach ( $m->in_house_recipients as &$recipient ) {
			$email = $recipient['email'];
			if ( hash_equals( $hash, hash( 'sha256', $email . AUTH_SALT ) ) ) {
				// We skip even an un-logged user, because the admin can change the user's access without notice.
				if ( is_user_logged_in() ) {
					if ( $email !== $this->get_current_user_email() ) {
						wp_die( esc_html__( 'Invalid request.', 'defender-security' ) );
					}
					$inhouse = true;
				}
				$recipient['status'] = Model_Notification::USER_SUBSCRIBE_CANCELED;
				$m->save();
				// Send email.
				$this->service->send_unsubscribe_email( $m, $email, $inhouse, $recipient['name'] );
				break;
			}
		}

		if ( false === $inhouse ) {
			// No match on in-house, check the outhouse list.
			foreach ( $m->out_house_recipients as &$recipient ) {
				$email = $recipient['email'];
				if ( hash_equals( $hash, hash( 'sha256', $email . AUTH_SALT ) ) ) {
					$recipient['status'] = Model_Notification::USER_SUBSCRIBE_CANCELED;
					$m->save();
					$this->service->send_unsubscribe_email( $m, $email, $inhouse, $recipient['name'] );
				}
			}
		}
		if ( $inhouse ) {
			wp_safe_redirect(
				add_query_arg(
					array(
						'slug'    => $slug,
						'context' => 'unsubscribe',
					),
					get_edit_profile_url()
				)
			);
		} else {
			wp_safe_redirect( get_home_url() );
		}
		exit;
	}

	/**
	 * An endpoint for saving single config from frontend.
	 *
	 * @param  Request $request  The request object .The request object containing the data to save.
	 *
	 * @defender_route
	 * @return Response
	 * @throws Exception Emits Exception in case of an error.
	 */
	public function save( Request $request ): Response {
		$raw_data = $request->get_data();
		if ( empty( $raw_data['slug'] ) ) {
			return new Response( false, array( 'message' => esc_html__( 'Invalid data.', 'defender-security' ) ) );
		}
		$slug  = sanitize_textarea_field( $raw_data['slug'] );
		$model = $this->service->find_module_by_slug( $slug );

		if ( ! is_object( $model ) ) {
			return new Response( false, array( 'message' => esc_html__( 'Invalid data.', 'defender-security' ) ) );
		}
		$data = $request->get_data_by_model( $model );
		// Check config-values.
		$data['configs'] = $model->type_casting( $data['configs'] );

		$model->import( $data );
		$model->status = Model_Notification::STATUS_ACTIVE;
		if ( $model->validate() ) {
			if ( 0 === $model->last_sent ) {
				// This means that the notification or report never sent, we will use the moment that it get activate.
				$model->last_sent = time();
			}
			$model->save();
			$this->service->send_subscription_confirm_email( $model );
			Config_Hub_Helper::set_clear_active_flag();
			// Track.
			if ( $this->is_tracking_active() ) {
				$track_data = array( 'Notification type' => $raw_data['title'] );
				// For reports. Separated check for 'Security Recommendations - Notification'.
				if ( 'report' === $raw_data['type'] ) {
					$track_data['Notification schedule'] = ucfirst( $data['frequency'] );
				} elseif ( 'tweak-reminder' === $raw_data['slug'] ) {
					$track_data['Notification schedule'] = ucfirst( $data['configs']['reminder'] );
				}
				$this->track_feature( 'def_notification_activated', $track_data );
			}

			return new Response(
				true,
				array_merge(
					array(
						'message' => esc_html__(
							'You have activated the notification successfully. Note, recipients will need to confirm their subscriptions to begin receiving notifications.',
							'defender-security'
						),
					),
					$this->data_frontend()
				)
			);
		}

		return new Response( false, array( 'message' => $model->get_formatted_errors() ) );
	}

	/**
	 * Bulk update and save changes.
	 *
	 * @param  Request $request  The request object.
	 *
	 * @defender_route
	 * @return Response
	 */
	public function save_bulk( Request $request ): Response {
		$data = $request->get_data(
			array(
				'reports'       => array(
					'type'     => 'array',
					'sanitize' => 'sanitize_textarea_field',
				),
				'notifications' => array(
					'type'     => 'array',
					'sanitize' => 'sanitize_textarea_field',
				),
			)
		);
		$this->save_reports( $data['reports'] );
		$this->save_notifications( $data['notifications'] );
		Config_Hub_Helper::set_clear_active_flag();

		return new Response(
			true,
			array_merge(
				$this->data_frontend(),
				array(
					'message' => esc_html__(
						'Your settings have been updated successfully. Any new recipients will receive an email to confirm their subscription.',
						'defender-security'
					),
				)
			)
		);
	}

	/**
	 * Process bulk reports saving.
	 *
	 * @param  array $data  Data to save.
	 *
	 * @throws Exception Emits Exception in case of an error.
	 */
	private function save_reports( $data ) {
		foreach ( $data['configs'] as $datum ) {
			$slug  = $datum['slug'];
			$model = $this->service->find_module_by_slug( $slug );
			if ( ! is_object( $model ) ) {
				continue;
			}

			$import = array(
				// Saving after Bulk-Update must always change the status to Active.
				'status'               => Model_Notification::STATUS_ACTIVE,
				'configs'              => $model->type_casting( $datum ),
				'in_house_recipients'  => $data['in_house_recipients'],
				'out_house_recipients' => $data['out_house_recipients'],
			);
			// since 2.7.0.
			if ( Malware_Report::SLUG !== $slug ) {
				$import['frequency'] = $data['frequency'];
				$import['day_n']     = $data['day_n'];
				$import['day']       = $data['day'];
				$import['time']      = $data['time'];
			}
			foreach ( $import['out_house_recipients'] as $key => $val ) {
				if ( ! filter_var( $val['email'], FILTER_VALIDATE_EMAIL ) ) {
					unset( $import['out_house_recipients'][ $key ] );
				}
			}
			$model->import( $import );
			if ( $model->validate() ) {
				if ( 0 === $model->last_sent ) {
					$model->last_sent = time();
				}
				$model->save();
				$this->service->send_subscription_confirm_email( $model );
				// Track.
				if ( $this->is_tracking_active() ) {
					$track_data = array(
						'Notification type'     => $model->title,
						'Notification schedule' => 'tweak-reminder' === $slug
							? ucfirst( $data['configs']['reminder'] )
							: ucfirst( $data['frequency'] ),
					);
					$this->track_feature( 'def_notification_activated', $track_data );
				}
			}
		}
	}

	/**
	 * Saves the notifications based on the provided data.
	 *
	 * @param  array $data  The data containing the configurations for the notifications.
	 *
	 * @return void
	 * @throws Exception Emits Exception in case of an error.
	 */
	private function save_notifications( $data ) {
		foreach ( $data['configs'] as $datum ) {
			$slug  = $datum['slug'];
			$model = $this->service->find_module_by_slug( $slug );
			if ( ! is_object( $model ) ) {
				continue;
			}
			$import = array(
				// Saving after Bulk-Update must always change the status to Active.
				'status'               => Model_Notification::STATUS_ACTIVE,
				'configs'              => $model->type_casting( $datum ),
				'in_house_recipients'  => $data['in_house_recipients'],
				'out_house_recipients' => $data['out_house_recipients'],
			);
			foreach ( $import['out_house_recipients'] as $key => $val ) {
				if ( ! filter_var( $val['email'], FILTER_VALIDATE_EMAIL ) ) {
					unset( $import['out_house_recipients'][ $key ] );
				}
			}
			$model->import( $import );
			if ( $model->validate() ) {
				if ( 0 === $model->last_sent ) {
					$model->last_sent = time();
				}
				$model->save();
				$this->service->send_subscription_confirm_email( $model );
				// Track.
				if ( $this->is_tracking_active() ) {
					$this->track_feature( 'def_notification_activated', array( 'Notification type' => $model->title ) );
				}
			}
		}
	}

	/**
	 * Bulk activate.
	 *
	 * @param  Request $request  The request object.
	 *
	 * @defender_route
	 * @return Response
	 * @throws Exception Emits Exception in case of an error.
	 */
	public function bulk_activate( Request $request ): Response {
		$data  = $request->get_data(
			array(
				'slugs' => array(
					'type'     => 'array',
					'sanitize' => 'sanitize_text_field',
				),
			)
		);
		$slugs = $data['slugs'];
		if ( empty( $slugs ) ) {
			return new Response( false, array() );
		}

		foreach ( $slugs as $slug ) {
			$model = $this->service->find_module_by_slug( $slug );
			if ( is_object( $model ) ) {
				$model->status = Model_Notification::STATUS_ACTIVE;
				if ( 0 === $model->last_sent ) {
					// This means that the notification or report never sent, we will use the moment that it get activate.
					$model->last_sent = time();
				}
				$model->save();
			}
		}

		return new Response(
			true,
			array_merge(
				array(
					'message' => 'You have activated the notification successfully. Note, recipients will need to confirm their subscriptions to begin receiving notifications.',
				),
				$this->data_frontend()
			)
		);
	}

	/**
	 * Bulk deactivate.
	 *
	 * @param  Request $request  The request object.
	 *
	 * @defender_route
	 * @return Response
	 */
	public function bulk_deactivate( Request $request ): Response {
		$data  = $request->get_data(
			array(
				'slugs' => array(
					'type'     => 'array',
					'sanitize' => 'sanitize_text_field',
				),
			)
		);
		$slugs = $data['slugs'];
		if ( empty( $slugs ) ) {
			return new Response( false, array() );
		}

		foreach ( $slugs as $slug ) {
			$model = $this->service->find_module_by_slug( $slug );
			if ( is_object( $model ) ) {
				$model->status = Model_Notification::STATUS_DISABLED;
				$model->save();
			}
		}

		return new Response(
			true,
			array_merge(
				array( 'message' => esc_html__( 'You have deactivated the notifications successfully.', 'defender-security' ) ),
				$this->data_frontend()
			)
		);
	}

	/**
	 * Disable a notification module.
	 *
	 * @param  Request $request  The request object .The request object containing the data to disable the module.
	 *
	 * @defender_route
	 * @return Response The response object indicating the success or failure of the operation.
	 */
	public function disable( Request $request ): Response {
		$data = $request->get_data(
			array(
				'slug' => array(
					'type'     => 'string',
					'sanitize' => 'sanitize_text_field',
				),
			)
		);

		$slug  = $data['slug'];
		$model = $this->service->find_module_by_slug( $slug );
		if ( ! is_object( $model ) ) {
			return new Response( false, array( 'message' => esc_html__( 'Invalid data.', 'defender-security' ) ) );
		}

		$model->status = Model_Notification::STATUS_DISABLED;
		$model->save();

		return new Response(
			true,
			array_merge(
				$this->data_frontend(),
				array(
					'message' => esc_html__( 'You have deactivated the notification successfully.', 'defender-security' ),
				)
			)
		);
	}

	/**
	 * This is a receiver to process subscribe confirmation from email.
	 */
	public function verify_subscriber() {
		$hash    = HTTP::get( 'hash', '' );
		$slug    = HTTP::get( 'uid', '' );
		$inhouse = HTTP::get( 'inhouse', 0 );
		if ( $inhouse && ! is_user_logged_in() ) {
			// This is in-house, so we need to redirect.
			auth_redirect();
		}
		if ( empty( $hash ) || empty( $slug ) ) {
			wp_die( esc_html__( 'You shall not pass.', 'defender-security' ) );
		}
		$m = $this->service->find_module_by_slug( $slug );
		if ( ! is_object( $m ) ) {
			wp_die( esc_html__( 'You shall not pass.', 'defender-security' ) );
		}
		if ( $inhouse ) {
			$processed = false;
			foreach ( $m->in_house_recipients as &$recipient ) {
				if ( Model_Notification::USER_SUBSCRIBED === $recipient['status'] ) {
					continue;
				}

				$email = $recipient['email'];
				$name  = $recipient['name'];
				if ( hash_equals( $hash, hash( 'sha256', $email . AUTH_SALT ) )
					&& $email === $this->get_current_user_email() ) {
					$recipient['status'] = Model_Notification::USER_SUBSCRIBED;
					$this->service->send_subscribed_email( $email, $m, $name );
					$processed = true;
				}
			}
		} else {
			foreach ( $m->out_house_recipients as &$recipient ) {
				if ( Model_Notification::USER_SUBSCRIBED === $recipient['status'] ) {
					continue;
				}

				$email = $recipient['email'];
				$name  = $recipient['name'];
				if ( hash_equals( $hash, hash( 'sha256', $email . AUTH_SALT ) ) ) {
					$recipient['status'] = Model_Notification::USER_SUBSCRIBED;
					$this->service->send_subscribed_email( $email, $m, $name );
				}
			}
		}
		$m->save();
		if ( $inhouse ) {
			if ( $processed ) {
				wp_safe_redirect(
					add_query_arg(
						array(
							'slug'    => $m->slug,
							'context' => 'subscribed',
						),
						get_edit_profile_url()
					)
				);
			} else {
				wp_safe_redirect( home_url() );
			}
		} else {
			wp_safe_redirect( home_url() );
		}
		exit;
	}

	/**
	 * Enqueues scripts and styles for this page.
	 * Only enqueues assets if the page is active.
	 */
	public function enqueue_assets() {
		if ( ! $this->is_page_active() ) {
			return;
		}
		wp_localize_script(
			'def-notification',
			'notification',
			array_merge( $this->data_frontend(), $this->dump_routes_and_nonces() )
		);
		wp_enqueue_script( 'def-momentjs', defender_asset_url( '/assets/js/vendor/moment/moment.min.js' ), array(), DEFENDER_VERSION, true );
		wp_enqueue_script( 'def-notification' );
		$this->enqueue_main_assets();
		wp_enqueue_style(
			'def-select2',
			defender_asset_url( '/assets/css/select2.min.css' ),
			array(),
			DEFENDER_VERSION,
			true
		);
	}

	/**
	 * An endpoint for fetching users pool.
	 *
	 * @param  Request $request  The request object .Request data.
	 *
	 * @defender_route
	 */
	public function get_users( Request $request ) {
		$data     = $request->get_data(
			array(
				'paged'            => array(
					'type'     => 'int',
					'sanitize' => 'sanitize_text_field',
				),
				'search'           => array(
					'type'     => 'string',
					'sanitize' => 'sanitize_text_field',
				),
				'exclude'          => array(
					'type' => 'array',
				),
				'module'           => array(
					'type'     => 'string',
					'sanitize' => 'sanitize_text_field',
				),
				'user_role_filter' => array(
					'type'     => 'string',
					'sanitize' => 'sanitize_text_field',
				),
				'user_sort'        => array(
					'type'     => 'string',
					'sanitize' => 'sanitize_text_field',
				),
			)
		);
		$paged    = 1;
		$exclude  = $data['exclude'] ?? array();
		$username = $data['search'] ?? '';
		$slug     = $data['module'] ?? null;
		$role     = '';

		if (
			isset( $data['user_role_filter'] ) &&
			'all' !== $data['user_role_filter']
		) {
			$role = $data['user_role_filter'];
		}

		$order_by = 'ID';
		$order    = 'DESC';
		if ( isset( $data['user_sort'] ) ) {
			switch ( $data['user_sort'] ) {
				case 'recent':
					$order_by = 'registered';
					$order    = 'DESC';
					break;
				case 'alpha_asc':
					$order_by = 'display_name';
					$order    = 'ASC';
					break;
				case 'alpha_desc':
				default:
					$order_by = 'display_name';
					$order    = 'DESC';
					break;
			}
		}

		if ( strlen( $username ) ) {
			$username = "*$username*";
		}

		$users = $this->service->get_users_pool(
			$exclude,
			$role,
			$username,
			$order_by,
			$order,
			10,
			$paged
		);

		if ( ! is_null( $slug ) ) {
			$notification = $this->service->find_module_by_slug( $slug );
			if ( is_object( $notification ) ) {
				foreach ( $notification->in_house_recipients as $recipient ) {
					foreach ( $users as &$user ) {
						if ( $user['email'] === $recipient['email'] ) {
							$user['status'] = $recipient['status'];
						}
					}
				}
			}
		}

		wp_send_json_success( $users );
	}

	/**
	 * Removes settings for all submodules.
	 */
	public function remove_settings() {
		foreach ( $this->service->get_modules_as_objects() as $module ) {
			$module->delete();
		}
	}

	/**
	 * Delete all the data & the cache.
	 */
	public function remove_data() {
	}

	/**
	 * Converts the current object state to an array.
	 *
	 * @return array The array representation of the object.
	 */
	public function to_array(): array {
		return array();
	}

	/**
	 * Provides data for the frontend.
	 *
	 * @return array An array of data for the frontend.
	 */
	public function data_frontend(): array {
		return array(
			'notifications'          => $this->service->get_modules(),
			'inactive_notifications' => $this->service->get_inactive_modules(),
			'active_count'           => $this->service->count_active(),
			'next_run'               => $this->service->get_next_run(),
			'misc'                   => array(
				'days_of_week'      => $this->get_days_of_week(),
				'times_of_day'      => $this->get_times(),
				'timezone_text'     => sprintf(
				/* translators: 1. Timezone. 2. Time. */
					esc_html__(
						'Your timezone is set to %1$s, so your current time is %2$s.',
						'defender-security'
					),
					'<strong>' . wp_timezone_string() . '</strong>',
					'<strong>' . wp_date( 'H:i', time() ) . '</strong>'
				),
				'default_recipient' => $this->get_default_recipient(),
			),
		);
	}

	/**
	 * Imports data into the model.
	 *
	 * @param  array $data  Data to be imported into the model.
	 */
	public function import_data( array $data ) {
	}

	/**
	 * Exports strings.
	 *
	 * @return array An array of strings.
	 */
	public function export_strings(): array {
		$modules = wd_di()->get( self::class )->service->get_modules_as_objects();
		$strings = array();
		foreach ( $modules as $module ) {
			/* translators: %s - module title, %s - module status */
			$string = esc_html__( '%1$s: %2$s', 'defender-security' );
			if ( 'notification' === $module->type ) {
				$string = sprintf(
					$string,
					$module->title,
					Model_Notification::STATUS_ACTIVE === $module->status ? esc_html__(
						'Enabled',
						'defender-security'
					) : esc_html__( 'Disabled', 'defender-security' )
				);
			} else {
				$string = sprintf(
					$string,
					$module->title,
					Model_Notification::STATUS_ACTIVE === $module->status ? $module->to_string() : esc_html__(
						'Disabled',
						'defender-security'
					)
				);
			}
			$strings[] = $string;
		}

		return $strings;
	}

	/**
	 * Resend invite email.
	 *
	 * @param  Request $request  The request object.
	 *
	 * @defender_route
	 * @return Response
	 */
	public function resend_invite_email( Request $request ): Response {
		$data = $request->get_data(
			array(
				'slug'  => array(
					'type'     => 'string',
					'sanitize' => 'sanitize_textarea_field',
				),
				'email' => array(
					'type'     => 'string',
					'sanitize' => 'sanitize_text_field',
				),
				'id'    => array(
					'type' => 'integer',
				),
				'name'  => array(
					'type'     => 'string',
					'sanitize' => 'sanitize_text_field',
				),
			)
		);

		$model = $this->service->find_module_by_slug( $data['slug'] );

		if ( ! is_object( $model ) ) {
			return new Response( false, array( 'message' => esc_html__( 'Module not found.', 'defender-security' ) ) );
		}

		$subscriber = array(
			'email' => $data['email'],
			'name'  => $data['name'],
		);

		if ( ! empty( $data['id'] ) ) {
			$subscriber['id'] = $data['id'];
		}
		// Resend invite email now.
		$sent = $this->service->send_email( $subscriber, $model );

		if ( $sent ) {
			return new Response( true, array( 'message' => esc_html__( 'Invitation sent successfully.', 'defender-security' ) ) );
		}

		return new Response(
			false,
			array(
				'message' => esc_html__( 'Sorry! We could not send the invitation, Please try again later.', 'defender-security' ),
			)
		);
	}

	/**
	 * Get user roles with count.
	 *
	 * @defender_route
	 */
	public function get_user_roles() {
		$user_roles = $this->service->get_user_roles();

		wp_send_json_success( $user_roles );
	}
}

Anon7 - 2022
AnonSec Team