/** * Responds to requests activated from the main emergency alert button. * * @link https://developer.wordpress.org/reference/hooks/wp_ajax__requestaction/ * * @global $_POST * * @uses WP_Buoy_Plugin::$prefix * @uses check_ajax_referer() * @uses get_current_user_id() * @uses WP_Buoy_User_Settings::get() * @uses sanitize_text_field() * @uses stripslashes_deep() * @uses WP_Buoy_Alert::set() * @uses WP_Buoy_Alert::save() * @uses WP_Buoy_Alert::get_hash() * @uses wp_send_json_error() * @uses wp_send_json_success() * @uses wp_safe_redirect() * * @return void */ public static function handleNewAlert() { check_ajax_referer(self::$prefix . '_new_alert', self::$prefix . '_nonce'); $postarr = array(); $meta_input = array(); // Collect info from the browser via Ajax request $alert_position = empty($_POST['pos']) ? false : $_POST['pos']; // TODO: array_map and sanitize this? if ($alert_position) { $meta_input['geo_latitude'] = $alert_position['latitude']; $meta_input['geo_longitude'] = $alert_position['longitude']; } if (isset($_POST[self::$prefix . '_teams']) && is_array($_POST[self::$prefix . '_teams'])) { $my_teams = array_map('absint', $_POST[self::$prefix . '_teams']); $valid_teams = array(); foreach ($my_teams as $team_id) { $team = new WP_Buoy_Team($team_id); if (get_current_user_id() == $team->wp_post->post_author) { $valid_teams[] = $team_id; } } $meta_input[self::$prefix . '_teams'] = $valid_teams; } // Create and publish the new alert. $buoy_user = new WP_Buoy_User(get_current_user_id()); $postarr['post_title'] = empty($_POST['msg']) ? $buoy_user->get_crisis_message() : sanitize_text_field(stripslashes_deep($_POST['msg'])); if (!empty($meta_input)) { $postarr['meta_input'] = $meta_input; } $err = new WP_Error(); if (isset($_POST['scheduled-datetime-utc'])) { // TODO: Scheduled alerts should be their own function? $old_timezone = date_default_timezone_get(); date_default_timezone_set('UTC'); $when_utc = strtotime(stripslashes_deep($_POST['scheduled-datetime-utc'])); if (!$when_utc) { $err->add('scheduled-datetime-utc', __('Buoy could not understand the date and time you entered.', 'buoy')); } else { $dt = new DateTime("@{$when_utc}"); // TODO: This fails to offset the UTC time back to server-local time // correctly if the WP site is manually offset by a 30 minute // offset instead of an hourly offset. $dt->setTimeZone(new DateTimeZone(wp_get_timezone_string())); $postarr['post_date'] = $dt->format('Y-m-d H:i:s'); $postarr['post_date_gmt'] = gmdate('Y-m-d H:i:s', $when_utc); $postarr['post_status'] = 'future'; } date_default_timezone_set($old_timezone); } $buoy_alert = new self(); $post_id = $buoy_alert->set($postarr)->save(); if (is_wp_error($post_id)) { wp_send_json_error($post_id); } else { if (!empty($err->errors)) { wp_send_json_error($err); } else { if (isset($_POST['scheduled-datetime-utc']) && empty($err->errors)) { wp_send_json_success(array('id' => $post_id, 'message' => __('Your timed alert has been scheduled. Schedule another?', 'buoy'))); } else { // Construct the redirect URL to the alerter's chat room $next_url = wp_nonce_url(admin_url('?page=' . self::$prefix . '_chat' . '&' . self::$prefix . '_hash=' . $buoy_alert->get_hash()), self::$prefix . '_chat', self::$prefix . '_nonce'); if (isset($_SERVER['HTTP_ACCEPT'])) { $accepts = explode(',', $_SERVER['HTTP_ACCEPT']); } if ($accepts && 'application/json' === array_shift($accepts)) { wp_send_json_success($next_url); } else { wp_safe_redirect(html_entity_decode($next_url)); exit; } } } } }
/** * Checks to ensure a user doesn't leave themselves without any * responders. * * Teams are only "active" is they are in the "publish" status. * This checks a team transition and if the action leaves a user * without any responders, it will re-set the team's status. * * @link https://developer.wordpress.org/reference/hooks/post_updated/ * * @uses WP_Buoy_User::has_responder() * @uses WP_Buoy_Team::is_default() * @uses WP_Buoy_Team::make_default() * * @param int $post_id * @param WP_Post $post_after * @param WP_Post $post_before * * @return void */ public static function postUpdated($post_id, $post_after, $post_before) { if (self::$prefix . '_team' !== $post_after->post_type) { return; } $buoy_user = new WP_Buoy_User($post_before->post_author); // Prevent the user from trashing their last responder team. if ('publish' === $post_before->post_status && 'publish' !== $post_after->post_status) { if (!$buoy_user->has_responder()) { wp_update_post(array('ID' => $post_id, 'post_status' => 'publish')); } } // Re-set the default team if the default team is trashed. $team = new WP_Buoy_Team($post_id); if ('trash' === $post_after->post_status && $team->is_default()) { $teams = $buoy_user->get_teams(); $next_team = new WP_Buoy_Team(array_pop($teams)); $next_team->make_default(); } }
/** * Loads plugin componentry and calls that component's register() * method. Called at the WordPress `init` hook. * * @uses WP_Buoy_Settings::register() * @uses WP_Buoy_Team::register() * @uses WP_Buoy_Notification::register() * @uses WP_Buoy_User::register() * @uses WP_Buoy_Alert::register() * * @return void */ public static function initialize() { require_once 'class-buoy-settings.php'; require_once 'class-buoy-user-settings.php'; require_once 'class-buoy-team.php'; require_once 'class-buoy-notification.php'; require_once 'class-buoy-user.php'; require_once 'class-buoy-alert.php'; require_once 'includes/class-wp-screen-help-loader.php'; WP_Buoy_Settings::register(); WP_Buoy_Team::register(); WP_Buoy_Notification::register(); WP_Buoy_User::register(); WP_Buoy_Alert::register(); }
/** * Runs whenever an alert is published. Sends notifications to an * alerter's response team informing them of the alert. * * @param int $post_id * @param WP_Post $post * * @return void */ public static function publishAlert($post_id, $post) { $alert = new WP_Buoy_Alert($post_id); $responder_link = admin_url('?page=' . self::$prefix . '_review_alert' . '&' . self::$prefix . '_hash=' . $alert->get_hash()); $responder_short_link = home_url('?' . self::$prefix . '_alert=' . substr($alert->get_hash(), 0, 8)); $subject = $post->post_title; $alerter = get_userdata($post->post_author); $headers = array("From: \"{$alerter->display_name}\" <{$alerter->user_email}>"); foreach ($alert->get_teams() as $team_id) { $team = new WP_Buoy_Team($team_id); foreach ($team->get_confirmed_members() as $user_id) { $responder = new WP_Buoy_User($user_id); // TODO: Write a more descriptive message. wp_mail($responder->wp_user->user_email, $subject, $responder_link, $headers); $smsemail = $responder->get_sms_email(); if (!empty($smsemail)) { $sms_max_length = 160; // We need to ensure that SMS notifications fit within the 160 character // limit of SMS transmissions. Since we're using email-to-SMS gateways, // a subject will be wrapped inside of parentheses, making it two chars // longer than whatever its original contents are. Then a space is // inserted between the subject and the message body. The total length // of strlen($subject) + 2 + 1 + strlen($message) must be less than 160. $extra_length = 3; // two parenthesis and a space // but in practice, there seems to be another 7 chars eaten up somewhere? $extra_length += 7; $url_length = strlen($responder_short_link); $full_length = strlen($subject) + $extra_length + $url_length; if ($full_length > $sms_max_length) { // truncate the $subject since the link must be fully included $subject = substr($subject, 0, $sms_max_length - $url_length - $extra_length); } wp_mail($smsemail, $subject, $responder_short_link, $headers); } } } }
/** * Loads plugin componentry and calls that component's register() * method. Called at the WordPress `init` hook. * * @uses WP_Buoy_Settings::register() * @uses WP_Buoy_Team::register() * @uses WP_Buoy_Notification::register() * @uses WP_Buoy_User::register() * @uses WP_Buoy_Alert::register() * * @return void */ public static function initialize() { require_once 'class-buoy-settings.php'; require_once 'class-buoy-user-settings.php'; require_once 'class-buoy-team.php'; require_once 'class-buoy-notification.php'; require_once 'class-buoy-user.php'; require_once 'class-buoy-alert.php'; if (!class_exists('WP_Screen_Help_Loader')) { require_once 'includes/vendor/wp-screen-help-loader/class-wp-screen-help-loader.php'; } WP_Buoy_Settings::register(); WP_Buoy_Team::register(); WP_Buoy_Notification::register(); WP_Buoy_User::register(); WP_Buoy_Alert::register(); }