diff --git a/includes/Core/Email_Reporting/Email_Reporting.php b/includes/Core/Email_Reporting/Email_Reporting.php index 77bcbc3c1e7..bd7ea40b270 100644 --- a/includes/Core/Email_Reporting/Email_Reporting.php +++ b/includes/Core/Email_Reporting/Email_Reporting.php @@ -11,8 +11,9 @@ namespace Google\Site_Kit\Core\Email_Reporting; use Google\Site_Kit\Context; -use Google\Site_Kit\Core\Email\Email; use Google\Site_Kit\Core\Authentication\Authentication; +use Google\Site_Kit\Core\Email\Email; +use Google\Site_Kit\Core\Email_Reporting\Eligible_Subscribers_Query; use Google\Site_Kit\Core\Modules\Modules; use Google\Site_Kit\Core\Storage\Options; use Google\Site_Kit\Core\Storage\User_Options; @@ -195,18 +196,19 @@ public function __construct( $this->user_settings = new User_Email_Reporting_Settings( $this->user_options ); $this->was_analytics_4_connected = new Was_Analytics_4_Connected( $this->options ); - $frequency_planner = new Frequency_Planner(); - $subscribed_users_query = new Subscribed_Users_Query( $this->user_settings, $this->modules ); - $max_execution_limiter = new Max_Execution_Limiter( (int) ini_get( 'max_execution_time' ) ); - $batch_query = new Email_Log_Batch_Query(); - $email_sender = new Email(); - $section_builder = new Email_Report_Section_Builder( $this->context ); - $template_formatter = new Email_Template_Formatter( $this->context, $section_builder ); - $template_renderer_factory = new Email_Template_Renderer_Factory( $this->context ); - $report_sender = new Email_Report_Sender( $template_renderer_factory, $email_sender ); - $log_processor = new Email_Log_Processor( $batch_query, $this->data_requests, $template_formatter, $report_sender ); - - $this->rest_controller = new REST_Email_Reporting_Controller( $this->settings, $this->was_analytics_4_connected, $this->modules, $this->user_options, $this->user_settings ); + $frequency_planner = new Frequency_Planner(); + $subscribed_users_query = new Subscribed_Users_Query( $this->user_settings, $this->modules ); + $eligible_subscribers_query = new Eligible_Subscribers_Query( $this->modules, $this->user_options ); + $max_execution_limiter = new Max_Execution_Limiter( (int) ini_get( 'max_execution_time' ) ); + $batch_query = new Email_Log_Batch_Query(); + $email_sender = new Email(); + $section_builder = new Email_Report_Section_Builder( $this->context ); + $template_formatter = new Email_Template_Formatter( $this->context, $section_builder ); + $template_renderer_factory = new Email_Template_Renderer_Factory( $this->context ); + $report_sender = new Email_Report_Sender( $template_renderer_factory, $email_sender ); + $log_processor = new Email_Log_Processor( $batch_query, $this->data_requests, $template_formatter, $report_sender ); + + $this->rest_controller = new REST_Email_Reporting_Controller( $this->settings, $this->was_analytics_4_connected, $this->modules, $this->user_settings, $eligible_subscribers_query, $email_sender ); $this->email_log = new Email_Log( $this->context ); $this->scheduler = new Email_Reporting_Scheduler( $frequency_planner ); $this->initiator_task = new Initiator_Task( $this->scheduler, $subscribed_users_query ); diff --git a/includes/Core/Email_Reporting/REST_Email_Reporting_Controller.php b/includes/Core/Email_Reporting/REST_Email_Reporting_Controller.php index 6785d103aaf..471e0272c2e 100644 --- a/includes/Core/Email_Reporting/REST_Email_Reporting_Controller.php +++ b/includes/Core/Email_Reporting/REST_Email_Reporting_Controller.php @@ -10,16 +10,18 @@ namespace Google\Site_Kit\Core\Email_Reporting; +use Google\Site_Kit\Core\Email\Email; +use Google\Site_Kit\Core\Email_Reporting\Eligible_Subscribers_Query; use Google\Site_Kit\Core\Modules\Modules; use Google\Site_Kit\Core\Permissions\Permissions; use Google\Site_Kit\Core\REST_API\REST_Route; use Google\Site_Kit\Core\REST_API\REST_Routes; -use Google\Site_Kit\Core\Storage\User_Options; use Google\Site_Kit\Core\User\Email_Reporting_Settings as User_Email_Reporting_Settings; use WP_REST_Request; use WP_REST_Response; use WP_REST_Server; use WP_User; +use WP_Error; /** * Class for handling Email Reporting site settings via REST API. @@ -70,6 +72,14 @@ class REST_Email_Reporting_Controller { */ private $eligible_subscribers_query; + /** + * Email instance. + * + * @since n.e.x.t + * @var Email + */ + private $email; + /** * Constructor. * @@ -79,21 +89,24 @@ class REST_Email_Reporting_Controller { * @param Email_Reporting_Settings $settings Email_Reporting_Settings instance. * @param Was_Analytics_4_Connected $was_analytics_4_connected Was_Analytics_4_Connected instance. * @param Modules $modules Modules instance. - * @param User_Options $user_options User options instance. * @param User_Email_Reporting_Settings $user_email_reporting_settings User email reporting settings instance. + * @param Eligible_Subscribers_Query $eligible_subscribers_query Eligible subscribers query. + * @param Email $email Email sender instance. */ public function __construct( Email_Reporting_Settings $settings, Was_Analytics_4_Connected $was_analytics_4_connected, Modules $modules, - User_Options $user_options, - User_Email_Reporting_Settings $user_email_reporting_settings + User_Email_Reporting_Settings $user_email_reporting_settings, + Eligible_Subscribers_Query $eligible_subscribers_query, + Email $email ) { $this->settings = $settings; $this->modules = $modules; $this->was_analytics_4_connected = $was_analytics_4_connected; $this->user_email_reporting_settings = $user_email_reporting_settings; - $this->eligible_subscribers_query = new Eligible_Subscribers_Query( $this->modules, $user_options ); + $this->eligible_subscribers_query = $eligible_subscribers_query; + $this->email = $email; } /** @@ -203,6 +216,69 @@ function ( WP_User $user ) use ( $meta_key ) { ), ) ), + new REST_Route( + 'core/site/data/email-reporting-invite-user', + array( + array( + 'methods' => WP_REST_Server::EDITABLE, + 'callback' => function ( WP_REST_Request $request ) { + $user_id = (int) $request->get_param( 'userId' ); + + if ( $user_id <= 0 ) { + return new WP_Error( 'invalid_user', __( 'Invalid user ID.', 'google-site-kit' ), array( 'status' => 400 ) ); + } + + $target_user = get_user_by( 'id', $user_id ); + + if ( ! $target_user instanceof WP_User ) { + return new WP_Error( 'invalid_user', __( 'User not found.', 'google-site-kit' ), array( 'status' => 400 ) ); + } + + $eligible_users = $this->eligible_subscribers_query->get_eligible_users( get_current_user_id() ); + $eligible_ids = wp_list_pluck( $eligible_users, 'ID' ); + + if ( ! in_array( $user_id, $eligible_ids, true ) ) { + return new WP_Error( 'ineligible_user', __( 'User is not eligible for email reports.', 'google-site-kit' ), array( 'status' => 400 ) ); + } + + if ( $this->is_user_subscribed( $user_id ) ) { + return new WP_Error( 'already_subscribed', __( 'User is already subscribed to email reports.', 'google-site-kit' ), array( 'status' => 400 ) ); + } + + $rate_limit_key = $this->get_invite_rate_limit_key( $user_id ); + + if ( get_transient( $rate_limit_key ) ) { + return new WP_Error( 'rate_limited', __( 'An invitation was recently sent to this user.', 'google-site-kit' ), array( 'status' => 429 ) ); + } + + // @TODO - Implement proper email template when available (invoke method from renderer etc). + $invite = ''; + + if ( empty( $invite['subject'] ) || empty( $invite['content'] ) ) { + return new WP_Error( 'invite_render_failed', __( 'Failed to build invitation email.', 'google-site-kit' ), array( 'status' => 500 ) ); + } + + $headers = $this->email->build_headers( array( 'Content-Type: text/html; charset=UTF-8' ) ); + $result = $this->email->send( $target_user->user_email, $invite['subject'], $invite['content'], $headers ); + + if ( is_wp_error( $result ) ) { + return new WP_Error( 'invite_send_failed', $result->get_error_message(), array( 'status' => 500 ) ); + } + + set_transient( $rate_limit_key, 1, DAY_IN_SECONDS ); + + return new WP_REST_Response( array( 'success' => true ) ); + }, + 'permission_callback' => $can_manage, + 'args' => array( + 'userId' => array( + 'type' => 'integer', + 'required' => true, + ), + ), + ), + ) + ), new REST_Route( 'core/site/data/was-analytics-4-connected', array( @@ -218,6 +294,32 @@ function ( WP_User $user ) use ( $meta_key ) { ); } + /** + * Determines if a user is already subscribed. + * + * @since n.e.x.t + * + * @param int $user_id User ID. + * @return bool + */ + private function is_user_subscribed( $user_id ) { + $settings = get_user_meta( $user_id, $this->user_email_reporting_settings->get_meta_key(), true ); + + return is_array( $settings ) && ! empty( $settings['subscribed'] ); + } + + /** + * Gets the rate limit transient key for user invites. + * + * @since n.e.x.t + * + * @param int $user_id User ID. + * @return string + */ + private function get_invite_rate_limit_key( $user_id ) { + return 'googlesitekit_email_reporting_invite_' . (int) $user_id; + } + /** * Maps a user to the REST response shape. *