email working - remove clients - preview polish
This commit is contained in:
1 parent
2b1424d127
commit
da83beaec3
19 files changed
+1342
-1060
No files matched your search
@@ -35,17 +35,42 @@ class HSSM_Notifications {
|
||||
public static function get_settings() {
|
||||
$defaults = array(
|
||||
'editor_emails' => '',
|
||||
'itc_emails' => ''
|
||||
'itc_emails' => '',
|
||||
);
|
||||
|
||||
$settings = get_option( 'hssm_notification_settings', $defaults );
|
||||
|
||||
// Ensure we have an array and it contains our expected keys
|
||||
|
||||
$settings = get_option( 'hssm_notification_settings', false );
|
||||
if ( ! is_array( $settings ) ) {
|
||||
return $defaults;
|
||||
$settings = $defaults;
|
||||
} else {
|
||||
$settings = wp_parse_args( $settings, $defaults );
|
||||
}
|
||||
|
||||
return wp_parse_args( $settings, $defaults );
|
||||
|
||||
$has_current = '' !== trim( (string) $settings['editor_emails'] ) || '' !== trim( (string) $settings['itc_emails'] );
|
||||
if ( $has_current ) {
|
||||
return $settings;
|
||||
}
|
||||
|
||||
$legacy = get_option( 'hssm_notification_emails', array() );
|
||||
if ( empty( $legacy ) ) {
|
||||
return $settings;
|
||||
}
|
||||
|
||||
if ( is_array( $legacy ) ) {
|
||||
$legacy_emails = array_filter( array_map( 'sanitize_email', $legacy ) );
|
||||
$legacy_string = implode( ',', $legacy_emails );
|
||||
} else {
|
||||
$legacy_string = sanitize_text_field( (string) $legacy );
|
||||
}
|
||||
|
||||
if ( '' === $legacy_string ) {
|
||||
return $settings;
|
||||
}
|
||||
|
||||
$settings['editor_emails'] = $legacy_string;
|
||||
update_option( 'hssm_notification_settings', $settings );
|
||||
delete_option( 'hssm_notification_emails' );
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,6 +114,215 @@ class HSSM_Notifications {
|
||||
return array_unique( $clean_emails );
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirmation token for ITC live emails (does not depend on a logged-in session).
|
||||
*
|
||||
* @since 1.1.3
|
||||
* @param int $slide_id Slide ID.
|
||||
* @return string
|
||||
*/
|
||||
public static function get_confirm_token( $slide_id ) {
|
||||
return hash( 'sha256', absint( $slide_id ) . '|' . wp_salt( 'auth' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a confirmation token is valid.
|
||||
*
|
||||
* @since 1.1.3
|
||||
* @param int $slide_id Slide ID.
|
||||
* @param string $token Token from the email link.
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_valid_confirm_token( $slide_id, $token ) {
|
||||
return is_string( $token ) && hash_equals( self::get_confirm_token( $slide_id ), $token );
|
||||
}
|
||||
|
||||
/**
|
||||
* Preview page URL for a slide.
|
||||
*
|
||||
* @since 1.1.3
|
||||
* @param int $slide_id Slide ID.
|
||||
* @return string
|
||||
*/
|
||||
private function get_preview_link( $slide_id ) {
|
||||
$start_date = get_post_meta( $slide_id, '_hssm_start_date', true );
|
||||
if ( $start_date && preg_match( '/^(\d{4}-\d{2}-\d{2})/', $start_date, $matches ) ) {
|
||||
$date = $matches[1];
|
||||
} else {
|
||||
$date = current_time( 'Y-m-d' );
|
||||
}
|
||||
|
||||
$sites = wp_get_post_terms( $slide_id, 'hssm_site', array( 'fields' => 'slugs' ) );
|
||||
$first_site = ( ! is_wp_error( $sites ) && ! empty( $sites ) ) ? $sites[0] : '';
|
||||
|
||||
return add_query_arg(
|
||||
array(
|
||||
'hssm_date' => $date,
|
||||
'hssm_site' => $first_site,
|
||||
'hssm_preview' => $slide_id,
|
||||
),
|
||||
hssm_get_page_url_by_template( 'page-slide-preview.php', '/slide-preview/' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* ITC confirmation page URL.
|
||||
*
|
||||
* @since 1.1.3
|
||||
* @param int $slide_id Slide ID.
|
||||
* @return string
|
||||
*/
|
||||
private function get_confirmation_link( $slide_id ) {
|
||||
return add_query_arg(
|
||||
array(
|
||||
'slide_id' => $slide_id,
|
||||
'hssm_token' => self::get_confirm_token( $slide_id ),
|
||||
),
|
||||
hssm_get_page_url_by_template( 'page-slide-confirmation.php', '/slide-confirmation/' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Front dashboard URL.
|
||||
*
|
||||
* @since 1.1.3
|
||||
* @return string
|
||||
*/
|
||||
private function get_dashboard_link( $slide_id = 0 ) {
|
||||
$url = hssm_get_page_url_by_template( 'page-slide-dashboard.php', '/slide-dashboard/' );
|
||||
if ( $slide_id ) {
|
||||
$url = add_query_arg( 'hssm_focus', absint( $slide_id ), $url );
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the slide is currently visible on companion sites.
|
||||
*
|
||||
* @since 1.1.3
|
||||
* @param int $slide_id Slide ID.
|
||||
* @return bool
|
||||
*/
|
||||
private function is_slide_currently_live( $slide_id ) {
|
||||
$post = get_post( $slide_id );
|
||||
if ( ! $post || 'publish' !== $post->post_status ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$now = current_time( 'timestamp' );
|
||||
$start = get_post_meta( $slide_id, '_hssm_start_date', true );
|
||||
if ( $start ) {
|
||||
$start_ts = strtotime( $start );
|
||||
if ( false !== $start_ts && $start_ts > $now ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$end = get_post_meta( $slide_id, '_hssm_end_date', true );
|
||||
if ( $end ) {
|
||||
$end_ts = strtotime( $end );
|
||||
if ( false !== $end_ts && $end_ts < $now ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Human-readable site list, with URLs when configured.
|
||||
*
|
||||
* @since 1.1.3
|
||||
* @param int $slide_id Slide ID.
|
||||
* @return string
|
||||
*/
|
||||
private function format_site_lines( $slide_id ) {
|
||||
$terms = wp_get_post_terms( $slide_id, 'hssm_site' );
|
||||
if ( is_wp_error( $terms ) || empty( $terms ) ) {
|
||||
return 'None';
|
||||
}
|
||||
|
||||
$catalog = array();
|
||||
if ( class_exists( 'HSSM_Main' ) ) {
|
||||
foreach ( HSSM_Main::get_companion_sites() as $site ) {
|
||||
$catalog[ $site['slug'] ] = $site;
|
||||
}
|
||||
}
|
||||
|
||||
$lines = array();
|
||||
foreach ( $terms as $term ) {
|
||||
$line = $term->name . ' (' . $term->slug . ')';
|
||||
if ( ! empty( $catalog[ $term->slug ]['url'] ) ) {
|
||||
$line .= ' - ' . $catalog[ $term->slug ]['url'];
|
||||
}
|
||||
$lines[] = $line;
|
||||
}
|
||||
|
||||
return implode( "\n", $lines );
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a one-time notification as sent.
|
||||
*
|
||||
* @since 1.1.3
|
||||
* @param int $slide_id Slide ID.
|
||||
* @param string $key Meta key.
|
||||
* @return bool True if this is the first send.
|
||||
*/
|
||||
private function mark_sent_once( $slide_id, $key ) {
|
||||
if ( get_post_meta( $slide_id, $key, true ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
update_post_meta( $slide_id, $key, current_time( 'mysql' ) );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send ITC the go-live email when a slide first reaches publish.
|
||||
*
|
||||
* @since 1.1.3
|
||||
* @param string $new_status New status.
|
||||
* @param string $old_status Previous status.
|
||||
* @param WP_Post $post Post object.
|
||||
*/
|
||||
public function on_slide_status_change( $new_status, $old_status, $post ) {
|
||||
if ( ! $post instanceof WP_Post || 'hssm_slide' !== $post->post_type ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 'publish' !== $new_status || 'publish' === $old_status ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->notify_itc_slide_live( $post->ID );
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify ITC of already-published slides whose start date just arrived.
|
||||
*
|
||||
* @since 1.1.3
|
||||
*/
|
||||
public function notify_due_live_slides() {
|
||||
$slides = get_posts(
|
||||
array(
|
||||
'post_type' => 'hssm_slide',
|
||||
'post_status' => 'publish',
|
||||
'posts_per_page' => 50,
|
||||
'meta_query' => array(
|
||||
array(
|
||||
'key' => '_hssm_itc_live_sent',
|
||||
'compare' => 'NOT EXISTS',
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
foreach ( $slides as $slide ) {
|
||||
$this->notify_itc_slide_live( $slide->ID );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send notification to Editor when slide is Scheduled or Published Immediately
|
||||
*
|
||||
@@ -105,47 +339,23 @@ class HSSM_Notifications {
|
||||
}
|
||||
|
||||
$slide = get_post( $slide_id );
|
||||
if ( ! $slide ) return;
|
||||
|
||||
$target_sites = wp_get_post_terms( $slide_id, 'hssm_site', array( 'fields' => 'slugs' ) );
|
||||
$site_slugs = ! empty( $target_sites ) ? implode( ',', $target_sites ) : '';
|
||||
|
||||
// Determine publish date
|
||||
$publish_date = ( $status === 'scheduled' )
|
||||
? get_post_meta( $slide_id, '_hssm_start_date', true )
|
||||
: current_time( 'Y-m-d' );
|
||||
|
||||
// Construct preview link
|
||||
// page-slide-preview.php logic usually takes 'date' and 'site' params
|
||||
// We'll link to the preview page. Assuming there is a page with the template, or we use a custom URL structure if defined.
|
||||
// The instructions mentioned: "generated link to the slide-preview page with params containing the slide-title, the publish-date... and the site slugs"
|
||||
|
||||
$preview_page_url = home_url( '/slide-preview/' ); // Basic assumption, adjust if needed based on setup
|
||||
// Better: find the page using the template
|
||||
$pages = get_pages(array(
|
||||
'meta_key' => '_wp_page_template',
|
||||
'meta_value' => 'page-slide-preview.php'
|
||||
));
|
||||
|
||||
if ( ! empty( $pages ) ) {
|
||||
$preview_page_url = get_permalink( $pages[0]->ID );
|
||||
if ( ! $slide ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$preview_link = add_query_arg( array(
|
||||
'preview_title' => urlencode( $slide->post_title ),
|
||||
'date' => $publish_date,
|
||||
'sites' => $site_slugs,
|
||||
'preview_mode' => 'editor_check'
|
||||
), $preview_page_url );
|
||||
$start_date = get_post_meta( $slide_id, '_hssm_start_date', true );
|
||||
$publish_date = $start_date ? $start_date : current_time( 'Y-m-d' );
|
||||
$status_label = ( 'scheduled' === $status ) ? 'Scheduled' : 'Published Immediately';
|
||||
|
||||
$subject = sprintf( 'New Slide %s: "%s"', ucfirst( $status ), $slide->post_title );
|
||||
|
||||
$message = "A new slide has been " . ( $status === 'scheduled' ? 'Scheduled' : 'Published Immediately' ) . ".\n\n";
|
||||
$message .= "Title: " . $slide->post_title . "\n";
|
||||
$message .= "Target Date: " . $publish_date . "\n";
|
||||
$message .= "Target Sites: " . implode( ', ', $target_sites ) . "\n\n";
|
||||
$message .= "Preview Link: " . $preview_link . "\n\n";
|
||||
$message .= "Please review the slide.";
|
||||
$subject = sprintf( 'New Slide %s: "%s"', $status_label, $slide->post_title );
|
||||
|
||||
$message = "A new slide has been {$status_label}.\n\n";
|
||||
$message .= 'Title: ' . $slide->post_title . "\n";
|
||||
$message .= 'Target Date: ' . $publish_date . "\n";
|
||||
$message .= "Target Sites:\n" . $this->format_site_lines( $slide_id ) . "\n\n";
|
||||
$message .= 'Preview: ' . $this->get_preview_link( $slide_id ) . "\n";
|
||||
$message .= 'Dashboard: ' . $this->get_dashboard_link( $slide_id ) . "\n\n";
|
||||
$message .= 'Please review the slide.';
|
||||
|
||||
foreach ( $emails as $email ) {
|
||||
wp_mail( $email, $subject, $message );
|
||||
@@ -159,80 +369,102 @@ class HSSM_Notifications {
|
||||
*/
|
||||
public function notify_creator_slide_approved( $slide_id ) {
|
||||
$slide = get_post( $slide_id );
|
||||
if ( ! $slide ) return;
|
||||
if ( ! $slide ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$author_email = get_the_author_meta( 'user_email', $slide->post_author );
|
||||
|
||||
if ( ! is_email( $author_email ) ) return;
|
||||
if ( ! is_email( $author_email ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$subject = 'Your Slide Has Been Approved: "' . $slide->post_title . '"';
|
||||
|
||||
$message = "Good news! Your slide has been approved.\n\n";
|
||||
$message .= "Title: " . $slide->post_title . "\n";
|
||||
$message .= "It is now scheduled/published according to your settings.";
|
||||
|
||||
$message = "Good news! Your slide has been approved.\n\n";
|
||||
$message .= 'Title: ' . $slide->post_title . "\n";
|
||||
$message .= "Target Sites:\n" . $this->format_site_lines( $slide_id ) . "\n\n";
|
||||
$message .= 'Preview: ' . $this->get_preview_link( $slide_id ) . "\n";
|
||||
$message .= 'Dashboard: ' . $this->get_dashboard_link( $slide_id ) . "\n\n";
|
||||
$message .= 'It is now scheduled or published according to your settings.';
|
||||
|
||||
wp_mail( $author_email, $subject, $message );
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify ITC to review date range after approval.
|
||||
*
|
||||
* @since 1.1.3
|
||||
* @param int $slide_id Slide ID.
|
||||
*/
|
||||
public function notify_itc_slide_approved( $slide_id ) {
|
||||
if ( ! $this->mark_sent_once( $slide_id, '_hssm_itc_approved_sent' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$settings = self::get_settings();
|
||||
$emails = $this->get_emails_array( $settings['itc_emails'] );
|
||||
if ( empty( $emails ) ) {
|
||||
hssm_debug_log( 'No ITC emails configured for approval notification.' );
|
||||
return;
|
||||
}
|
||||
|
||||
$slide = get_post( $slide_id );
|
||||
if ( ! $slide ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$start_date = get_post_meta( $slide_id, '_hssm_start_date', true );
|
||||
$end_date = get_post_meta( $slide_id, '_hssm_end_date', true );
|
||||
|
||||
$subject = 'Slide Approved for Review: "' . $slide->post_title . '"';
|
||||
|
||||
$message = "A slide has been approved. Please review the date range and preview before it goes live.\n\n";
|
||||
$message .= 'Title: ' . $slide->post_title . "\n";
|
||||
$message .= 'Start Date: ' . ( $start_date ? $start_date : 'Immediate' ) . "\n";
|
||||
$message .= 'End Date: ' . ( $end_date ? $end_date : 'None' ) . "\n";
|
||||
$message .= "Target Sites:\n" . $this->format_site_lines( $slide_id ) . "\n\n";
|
||||
$message .= 'Preview: ' . $this->get_preview_link( $slide_id ) . "\n";
|
||||
$message .= 'Dashboard: ' . $this->get_dashboard_link( $slide_id );
|
||||
|
||||
foreach ( $emails as $email ) {
|
||||
wp_mail( $email, $subject, $message );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send notification to ITCGuys when slide goes LIVE
|
||||
*
|
||||
* @param int $slide_id Slide ID
|
||||
*/
|
||||
public function notify_itc_slide_live( $slide_id ) {
|
||||
if ( ! $this->is_slide_currently_live( $slide_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! $this->mark_sent_once( $slide_id, '_hssm_itc_live_sent' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$settings = self::get_settings();
|
||||
$emails = $this->get_emails_array( $settings['itc_emails'] );
|
||||
|
||||
if ( empty( $emails ) ) return;
|
||||
$emails = $this->get_emails_array( $settings['itc_emails'] );
|
||||
if ( empty( $emails ) ) {
|
||||
hssm_debug_log( 'No ITC emails configured for live notification.' );
|
||||
return;
|
||||
}
|
||||
|
||||
$slide = get_post( $slide_id );
|
||||
if ( ! $slide ) return;
|
||||
if ( ! $slide ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate Confirmation Link
|
||||
// This link needs to trigger the "Slide is Live" confirmation page
|
||||
// We probably need a specialized page or endpoint for this.
|
||||
// Let's assume we use the Dashboard page with a specific action param or a separate page.
|
||||
// User requested: "We need a page 'Slide is Live' ... with a green confirmation button"
|
||||
// Let's use the preview page or dashboard page with a specific query arg to show this UI.
|
||||
// Or better, a dedicated endpoint. For now, let's point to the dashboard with a "confirm_live" param.
|
||||
|
||||
$confirm_url = home_url( '/slide-live-confirmation/' ); // Ideally we create this page or rewrite rule
|
||||
// For now, let's use the dashboard url with arguments, and we'll handle the UI there or create a rewrite.
|
||||
// Actually, creating a specific page 'Slide is Live' was requested.
|
||||
// I'll create a new template `page-slide-confirmation.php` later.
|
||||
|
||||
// Find confirmation page if exists, or construct URL
|
||||
$pages = get_pages(array(
|
||||
'meta_key' => '_wp_page_template',
|
||||
'meta_value' => 'page-slide-confirmation.php'
|
||||
));
|
||||
$confirmation_page_url = !empty($pages) ? get_permalink($pages[0]->ID) : home_url('/?hssm_action=confirm_live');
|
||||
|
||||
$confirm_link = add_query_arg( array(
|
||||
'slide_id' => $slide_id,
|
||||
'token' => wp_create_nonce( 'hssm_confirm_live_' . $slide_id ) // Note: Nonces depend on user session, might be tricky for email links if user isn't logged in.
|
||||
// Better to use a hash that doesn't expire or relies on a shared secret if ITC guys are not logged in.
|
||||
// Assuming ITC guys are logged in users for now or we just use a hash.
|
||||
), $confirmation_page_url );
|
||||
|
||||
// Since email links are clicked outside sessions often, maybe just a hash of slide ID + secret salt.
|
||||
$token = hash( 'sha256', $slide_id . 'hssm_secret_salt' );
|
||||
$confirm_link = add_query_arg( array(
|
||||
'slide_id' => $slide_id,
|
||||
'hssm_token' => $token
|
||||
), $confirmation_page_url );
|
||||
|
||||
|
||||
$target_sites = wp_get_post_terms( $slide_id, 'hssm_site', array( 'fields' => 'slugs' ) );
|
||||
|
||||
$subject = 'ACTION REQUIRED: Slide is LIVE - "' . $slide->post_title . '"';
|
||||
|
||||
$message = "A slide has just gone LIVE.\n\n";
|
||||
$message .= "Title: " . $slide->post_title . "\n";
|
||||
$message .= "Sites: " . implode( ', ', $target_sites ) . "\n\n";
|
||||
|
||||
$message = "A slide has just gone LIVE.\n\n";
|
||||
$message .= 'Title: ' . $slide->post_title . "\n";
|
||||
$message .= "Sites:\n" . $this->format_site_lines( $slide_id ) . "\n\n";
|
||||
$message .= "Please check the sites to ensure it is displaying correctly.\n";
|
||||
$message .= "Once verified, click the link below to confirm to the Editor and Author:\n\n";
|
||||
$message .= $confirm_link;
|
||||
$message .= "Once verified, click the confirmation link to notify the Editor and Author:\n\n";
|
||||
$message .= $this->get_confirmation_link( $slide_id );
|
||||
|
||||
foreach ( $emails as $email ) {
|
||||
wp_mail( $email, $subject, $message );
|
||||
@@ -243,32 +475,43 @@ class HSSM_Notifications {
|
||||
* Send FINAL notification to Editor and Author (triggered by ITC confirmation)
|
||||
*
|
||||
* @param int $slide_id Slide ID
|
||||
* @return bool True if the confirmation email was sent.
|
||||
*/
|
||||
public function notify_all_confirmed_live( $slide_id ) {
|
||||
$slide = get_post( $slide_id );
|
||||
if ( ! $slide ) return;
|
||||
if ( ! $slide ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Editor Emails
|
||||
$settings = self::get_settings();
|
||||
if ( ! $this->mark_sent_once( $slide_id, '_hssm_live_confirmed' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$settings = self::get_settings();
|
||||
$editor_emails = $this->get_emails_array( $settings['editor_emails'] );
|
||||
|
||||
// Author Email
|
||||
$author_email = get_the_author_meta( 'user_email', $slide->post_author );
|
||||
|
||||
$recipients = array_merge( $editor_emails, array( $author_email ) );
|
||||
$recipients = array_unique( array_filter( $recipients ) );
|
||||
$author_email = get_the_author_meta( 'user_email', $slide->post_author );
|
||||
$recipients = array_unique( array_filter( array_merge( $editor_emails, array( $author_email ) ) ) );
|
||||
|
||||
if ( empty( $recipients ) ) return;
|
||||
if ( empty( $recipients ) ) {
|
||||
hssm_debug_log( 'No recipients for live confirmation email.' );
|
||||
return true;
|
||||
}
|
||||
|
||||
$subject = 'CONFIRMED: Slide is Live and Verified - "' . $slide->post_title . '"';
|
||||
|
||||
$message = "The slide has been verified as LIVE by the ITC team.\n\n";
|
||||
$message .= "Title: " . $slide->post_title . "\n";
|
||||
$message .= "Status: Live & Verified\n\n";
|
||||
$message .= "You can view the slide on the live sites.";
|
||||
|
||||
$message = "The slide has been verified as LIVE by the ITC team.\n\n";
|
||||
$message .= 'Title: ' . $slide->post_title . "\n";
|
||||
$message .= "Status: Live & Verified\n";
|
||||
$message .= "Sites:\n" . $this->format_site_lines( $slide_id ) . "\n\n";
|
||||
$message .= 'Dashboard: ' . $this->get_dashboard_link( $slide_id ) . "\n";
|
||||
$message .= 'Preview: ' . $this->get_preview_link( $slide_id );
|
||||
|
||||
foreach ( $recipients as $email ) {
|
||||
wp_mail( $email, $subject, $message );
|
||||
if ( is_email( $email ) ) {
|
||||
wp_mail( $email, $subject, $message );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user