Making WordPress.org

Changeset 11921


Ignore:
Timestamp:
06/21/2022 02:15:05 PM (3 years ago)
Author:
amieiro
Message:

Translate: Introduce notification on rejection and opt-in/opt-out in a thread

See:

props akirk, spiraltee

Location:
sites/trunk/wordpress.org/public_html/wp-content/plugins/gp-translation-helpers
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/gp-translation-helpers/helpers-assets/css/translation-discussion.css

    r11837 r11921  
    8383    text-align: start;
    8484}
    85 
    8685.alignright {
    8786    float: right;
    8887}
     88.optin-message-for-each-discussion {
     89    padding: 0.5rem 1rem;
     90}
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/gp-translation-helpers/helpers-assets/templates/translation-discussion-comments.php

    r11837 r11921  
    115115            $post_obj
    116116        );
     117        echo '<div class="optin-message-for-each-discussion">';
     118        echo wp_kses(
     119            GP_Notifications::optin_message_for_each_discussion( $original_id ),
     120            array(
     121                'a' => array(
     122                    'href'             => array(),
     123                    'class'            => array(),
     124                    'data-original-id' => array(),
     125                    'data-opt-type'    => array(),
     126                ),
     127            )
     128        );
     129        echo '</div>';
    117130    } else {
    118131        /* translators: Log in URL. */
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/gp-translation-helpers/helpers/helper-translation-discussion.php

    r11837 r11921  
    279279
    280280        // We can't do much if the comment was posted logged out.
    281         if ( empty( $commentdata['comment_author'] ) ) {
     281        if ( empty( $commentdata['user_id'] ) ) {
    282282            return $approved;
    283283        }
    284284
    285285        // If our user has already contributed translations, approve comment.
    286         $user_current_translations = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->gp_translations WHERE user_id = %s AND status = 'current'", $commentdata['comment_author'] ) );
     286        $user_current_translations = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->gp_translations WHERE user_id = %s AND status = 'current'", $commentdata['user_id'] ) );
    287287        if ( $user_current_translations ) {
    288288            $approved = true;
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/gp-translation-helpers/includes/class-gp-notifications.php

    r11837 r11921  
    1010class GP_Notifications {
    1111    /**
     12     * Stores the related comments to the first one when the validator makes a bulk rejection.
     13     *
     14     * @since 0.0.2
     15     * @var array
     16     */
     17    private static array $related_comments = array();
     18    /**
    1219     * Sends notifications when a new comment in the discussion is stored using the WP REST API.
    1320     *
     
    2734                if ( ( '0' !== $comment->comment_parent ) ) { // Notify to the thread only if the comment is in a thread.
    2835                    self::send_emails_to_thread_commenters( $comment, $comment_meta );
     36                }
     37                if ( ( '0' === $comment->comment_parent ) && array_key_exists( 'reject_reason', $comment_meta ) && ( ! empty( $comment_meta['reject_reason'] ) ) ) {  // Notify a rejection without parent comments.
     38                    self::send_rejection_email_to_translator( $comment, $comment_meta );
    2939                }
    3040                $root_comment      = self::get_root_comment_in_a_thread( $comment );
     
    94104
    95105    /**
     106     * Sends the reject notification to the translator.
     107     *
     108     * @since 0.0.2
     109     *
     110     * @param WP_Comment $comment      The comment object.
     111     * @param array      $comment_meta The meta values for the comment.
     112     *
     113     * @return void
     114     */
     115    public static function send_rejection_email_to_translator( WP_Comment $comment, array $comment_meta ) {
     116        $translation_id = $comment_meta['translation_id'];
     117        $translation    = GP::$translation->get( $translation_id );
     118        $translator     = get_user_by( 'id', $translation->user_id_last_modified );
     119        if ( false === $translator ) {
     120            $translator = get_user_by( 'id', $translation->user_id );
     121        }
     122        self::send_emails( $comment, $comment_meta, array( $translator->user_email ) );
     123    }
     124
     125    /**
    96126     * Sends an email to the GlotPress admins.
    97127     *
     
    119149     */
    120150    public static function send_emails_to_validators( WP_Comment $comment, array $comment_meta ) {
    121         $project = self::get_project_to_translate( $comment );
     151        $post    = get_post( $comment->comment_post_ID );
     152        $project = self::get_project_from_post( $post );
    122153
    123154        $email_addresses = self::get_validators_email_addresses( $project->path );
     
    171202     * @since 0.0.2
    172203     *
    173      * @param array  $comments        Array with the parent comments to the posted comment.
    174      * @param string $email_address_to_ignore Email from the posted comment.
     204     * @param array       $comments                Array with the parent comments to the posted comment.
     205     * @param string|null $email_address_to_ignore Email from the posted comment.
    175206     *
    176207     * @return array The emails to be notified from the thread comments.
     
    252283        }
    253284
    254         $admin_email_addresses = $wpdb->get_results(
    255             "SELECT user_email FROM {$wpdb->users}
     285        try {
     286            $admin_email_addresses = $wpdb->get_results(
     287                "SELECT user_email FROM {$wpdb->users}
    256288            INNER JOIN {$wpdb->gp_permissions}
    257289            ON {$wpdb->users}.ID = {$wpdb->gp_permissions}.user_id
    258290            WHERE action='admin'"
    259         );
    260 
     291            );
     292        } catch ( Exception $e ) {
     293            $admin_email_addresses = array();
     294        }
    261295        foreach ( $admin_email_addresses as $admin ) {
    262296            $email_addresses[] = $admin->user_email;
     
    295329            return false;
    296330        }
     331        $original        = self::get_original( $comment );
    297332        $email_addresses = self::remove_commenter_email_address( $comment, $email_addresses );
     333        $email_addresses = self::remove_optout_discussion_email_addresses( $original->id, $email_addresses );
    298334
    299335        $headers = array(
     
    328364     */
    329365    public static function get_email_body( WP_Comment $comment, array $comment_meta ): string {
    330         $project  = self::get_project_to_translate( $comment );
     366        $post     = get_post( $comment->comment_post_ID );
     367        $project  = self::get_project_from_post( $post );
    331368        $original = self::get_original( $comment );
    332369        $output   = '';
     
    351388            )
    352389        ) . '<br/>';
     390        if ( ! empty( self::$related_comments ) ) {
     391            $output .= wp_kses(
     392            /* translators: The number of different translations related with the comment. */
     393                sprintf( __( 'This comment affects to <strong>%1$d different translations</strong>.', 'glotpress' ), count( self::$related_comments ) + 1 ),
     394                array(
     395                    'a'      => array( 'href' => array() ),
     396                    'strong' => array(),
     397                )
     398            ) . '<br/>';
     399        }
    353400        $output .= '<br>';
    354401        $output .= esc_html__( 'It would be nice if you have some time to review this comment and reply to it if needed.', 'glotpress' );
    355402        $output .= '<br><br>';
    356         $output .= '- ' . wp_kses(
     403        if ( array_key_exists( 'locale', $comment_meta ) && ( ! empty( $comment_meta['locale'][0] ) ) ) {
     404            /* translators: The translation locale for the comment. */
     405            $output .= '- ' . wp_kses( sprintf( __( '<strong>Locale:</strong> %s', 'glotpress' ), $comment_meta['locale'][0] ), array( 'strong' => array() ) ) . '<br/>';
     406        }
     407        if ( empty( self::$related_comments ) ) { // Only show original and translation strings if we don't have related comments (bulk rejection).
     408            /* translators: The original string to translate. */
     409            $output .= '- ' . wp_kses( sprintf( __( '<strong>Original string:</strong> %s', 'glotpress' ), $original->singular ), array( 'strong' => array() ) ) . '<br/>';
     410            if ( array_key_exists( 'translation_id', $comment_meta ) && $comment_meta['translation_id'][0] ) {
     411                $translation_id = $comment_meta['translation_id'][0];
     412                $translation    = GP::$translation->get( $translation_id );
     413                // todo: add the plurals.
     414                if ( ! is_null( $translation ) ) {
     415                    /* translators: The translation string. */
     416                    $output .= '- ' . wp_kses( sprintf( __( '<strong>Translation string:</strong> %s', 'glotpress' ), $translation->translation_0 ), array( 'strong' => array() ) ) . '<br/>';
     417                }
     418            }
     419        }
     420        /* translators: The comment made. */
     421        $output .= '- ' . wp_kses( sprintf( __( '<strong>Comment:</strong> %s', 'glotpress' ), $comment->comment_content ), array( 'strong' => array() ) ) . '<br/>';
     422        if ( empty( self::$related_comments ) ) {
     423            $output .= '- ' . __( '<strong>Discussion URL:</strong>' ) . '<br/>';
     424        } else {
     425            $output .= '- ' . __( '<strong>Discussion URLs:</strong>' ) . '<br/>';
     426        }
     427        $output .= '&nbsp;&nbsp;&nbsp; - ' . wp_kses(
    357428            /* translators: The discussion URL where the user can find the comment. */
    358             sprintf( __( '<strong>Discussion URL:</strong> <a href="%1$s">%1$s</a>', 'glotpress' ), $url ),
     429            sprintf( __( '<a href="%1$s">%1$s</a>', 'glotpress' ), $url ),
    359430            array(
    360431                'strong' => array(),
     
    362433            )
    363434        ) . '<br/>';
    364         if ( array_key_exists( 'locale', $comment_meta ) && ( ! empty( $comment_meta['locale'][0] ) ) ) {
    365             /* translators: The translation locale for the comment. */
    366             $output .= '- ' . wp_kses( sprintf( __( '<strong>Locale:</strong> %s', 'glotpress' ), $comment_meta['locale'][0] ), array( 'strong' => array() ) ) . '<br/>';
    367         }
    368         /* translators: The original string to translate. */
    369         $output .= '- ' . wp_kses( sprintf( __( '<strong>Original string:</strong> %s', 'glotpress' ), $original->singular ), array( 'strong' => array() ) ) . '<br/>';
    370         if ( array_key_exists( 'translation_id', $comment_meta ) && $comment_meta['translation_id'][0] ) {
    371             $translation_id = $comment_meta['translation_id'][0];
    372             $translation    = GP::$translation->get( $translation_id );
    373             // todo: add the plurals.
    374             if ( ! is_null( $translation ) ) {
    375                 /* translators: The translation string. */
    376                 $output .= '- ' . wp_kses( sprintf( __( '<strong>Translation string:</strong> %s', 'glotpress' ), $translation->translation_0 ), array( 'strong' => array() ) ) . '<br/>';
    377             }
    378         }
    379         /* translators: The comment made. */
    380         $output .= '- ' . wp_kses( sprintf( __( '<strong>Comment:</strong> %s', 'glotpress' ), $comment->comment_content ), array( 'strong' => array() ) );
     435        foreach ( self::$related_comments as $related_comment ) {
     436            $original = self::get_original( $related_comment );
     437            $url      = GP_Route_Translation_Helpers::get_permalink( $project->path, $original->id );
     438            $output  .= '&nbsp;&nbsp;&nbsp; - ' . wp_kses(
     439                /* translators: The discussion URL where the user can find the comment. */
     440                sprintf( __( '<a href="%1$s">%1$s</a>', 'glotpress' ), $url ),
     441                array(
     442                    'strong' => array(),
     443                    'a'      => array( 'href' => array() ),
     444                )
     445            ) . '<br/>';
     446        }
    381447        $output .= '<br><br>';
    382448        $output .= esc_html__( 'Have a nice day!', 'glotpress' );
     
    434500
    435501    /**
     502     * Removes the opt-out emails in the current discussion.
     503     *
     504     * @since 0.0.2
     505     *
     506     * @param int   $original_id     The id of the original string used for the discussion.
     507     * @param array $email_addresses A list of emails.
     508     *
     509     * @return array
     510     */
     511    public static function remove_optout_discussion_email_addresses( int $original_id, array $email_addresses ): array {
     512        foreach ( $email_addresses as $email_address ) {
     513            $user            = get_user_by( 'email', $email_address );
     514            $is_user_opt_out = ! empty(
     515                get_users(
     516                    array(
     517                        'meta_key'   => 'gp_opt_out',
     518                        'meta_value' => $original_id,
     519                        'include'    => array( $user->ID ),
     520                    )
     521                )
     522            );
     523            if ( $is_user_opt_out ) {
     524                $index = array_search( $email_address, $email_addresses, true );
     525                unset( $email_addresses[ $index ] );
     526            }
     527        }
     528
     529        return array_values( $email_addresses );
     530    }
     531
     532    /**
    436533     * Gets the project that the translated string belongs to.
    437534     *
    438535     * @since 0.0.2
    439536     *
     537     * @param WP_Post $post The post object.
     538     *
     539     * @return GP_Project|bool The project that the translated string belongs to.
     540     */
     541    private static function get_project_from_post( WP_Post $post ) {
     542        $terms = wp_get_object_terms( $post->ID, Helper_Translation_Discussion::LINK_TAXONOMY, array( 'number' => 1 ) );
     543        if ( empty( $terms ) ) {
     544            return false;
     545        }
     546
     547        $original   = GP::$original->get( $terms[0]->slug );
     548        $project_id = $original->project_id;
     549        $project    = GP::$project->get( $project_id );
     550
     551        return $project;
     552    }
     553
     554    /**
     555     * Adds a related comment (to the first one) when the validator makes a bulk rejection.
     556     *
     557     * @since 0.0.2
     558     *
     559     * @param WP_Comment $comment The related comment to add.
     560     *
     561     * @return void
     562     */
     563    public static function add_related_comment( WP_Comment $comment ) {
     564        self::$related_comments[] = $comment;
     565    }
     566
     567    /**
     568     * Gets the project the original_id belongs to.
     569     *
     570     * @since 0.0.2
     571     *
     572     * @param int $original_id The id of the original string used for the discussion.
     573     *
     574     * @return GP_Project The project the original_id belongs to.
     575     */
     576    public static function get_project_from_original_id( int $original_id ): GP_Project {
     577        $original = GP::$original->get( $original_id );
     578        return GP::$project->get( $original->project_id );
     579    }
     580
     581    /**
     582     * Gets the original string that the translated string belongs to.
     583     *
     584     * @since 0.0.2
     585     *
    440586     * @param WP_Comment $comment The comment object.
    441587     *
    442      * @return GP_Project|bool The project that the translated string belongs to.
    443      */
    444     private static function get_project_to_translate( WP_Comment $comment ) {
     588     * @return GP_Thing|false The original string that the translated string belongs to.
     589     */
     590    public static function get_original( WP_Comment $comment ) {
    445591        $post_id = $comment->comment_post_ID;
    446592        $terms   = wp_get_object_terms( $post_id, Helper_Translation_Discussion::LINK_TAXONOMY, array( 'number' => 1 ) );
     
    449595        }
    450596
    451         $original   = GP::$original->get( $terms[0]->slug );
    452         $project_id = $original->project_id;
    453         $project    = GP::$project->get( $project_id );
    454 
    455         return $project;
    456     }
    457 
    458     /**
    459      * Gets the original string that the translated string belongs to.
    460      *
    461      * @since 0.0.2
    462      *
    463      * @param WP_Comment $comment The comment object.
    464      *
    465      * @return GP_Thing|false The original string that the translated string belongs to.
    466      */
    467     private static function get_original( WP_Comment $comment ) {
    468         $post_id = $comment->comment_post_ID;
    469         $terms   = wp_get_object_terms( $post_id, Helper_Translation_Discussion::LINK_TAXONOMY, array( 'number' => 1 ) );
    470         if ( empty( $terms ) ) {
     597        return GP::$original->get( $terms[0]->slug );
     598    }
     599
     600    /**
     601     * Gets the post_id for the discussion of an original_id.
     602     *
     603     * If the post doesn't exist, the result is 0.
     604     *
     605     * @param int $original_id The id of the original string used for the discussion.
     606     *
     607     * @return int The post_id for the discussion of an original_id.
     608     */
     609    public static function get_post_id( int $original_id ): int {
     610            $gp_posts = get_posts(
     611                array(
     612                    'tax_query'        => array(
     613                        array(
     614                            'taxonomy' => Helper_Translation_Discussion::LINK_TAXONOMY,
     615                            'terms'    => $original_id,
     616                            'field'    => 'slug',
     617                        ),
     618                    ),
     619                    'post_type'        => Helper_Translation_Discussion::POST_TYPE,
     620                    'posts_per_page'   => 1,
     621                    'post_status'      => Helper_Translation_Discussion::POST_STATUS,
     622                    'suppress_filters' => false,
     623                )
     624            );
     625
     626        return ! empty( $gp_posts ) ? $gp_posts[0]->ID : 0;
     627    }
     628
     629    /**
     630     * Returns if the given user is an GlotPress admin or not.
     631     *
     632     * @since 0.0.2
     633     *
     634     * @param WP_User $user A user object.
     635     *
     636     * @return bool
     637     */
     638    public static function is_user_an_gp_admin( WP_User $user ): bool {
     639        global $wpdb;
     640        try {
     641            $db_email_addresses = $wpdb->get_results(
     642                "
     643            SELECT user_email FROM {$wpdb->users}
     644            INNER JOIN {$wpdb->gp_permissions}
     645            ON {$wpdb->users}.ID = {$wpdb->gp_permissions}.user_id
     646            WHERE action='admin'",
     647                ARRAY_N
     648            );
     649            foreach ( $db_email_addresses as $email_address ) {
     650                $email_addresses[] = $email_address[0];
     651            }
     652        } catch ( Exception $e ) {
     653            $email_addresses = array();
     654        }
     655        if ( empty( $email_addresses ) || empty( array_intersect( array( $user->user_email ), $email_addresses ) ) ) {
    471656            return false;
    472657        }
    473 
    474         return GP::$original->get( $terms[0]->slug );
     658        return true;
     659    }
     660
     661    /**
     662     * Returns if the given user is an GlotPress validator for the post or not.
     663     *
     664     * @since 0.0.2
     665     *
     666     * @param WP_User $user        A user object.
     667     * @param int     $original_id The id of the original string used for the discussion.
     668     *
     669     * @return bool
     670     */
     671    public static function is_user_an_gp_validator( WP_User $user, int $original_id ): bool {
     672        $project         = self::get_project_from_original_id( $original_id );
     673        $email_addresses = self::get_validators_email_addresses( $project->path );
     674        if ( empty( $email_addresses ) || empty( array_intersect( array( $user->user_email ), $email_addresses ) ) ) {
     675            return false;
     676        }
     677        return true;
     678    }
     679
     680    /**
     681     * Indicates whether an e-mail address is opt-out in a discussion.
     682     *
     683     * @since 0.0.2
     684     *
     685     * @param int     $original_id The id of the original string used for the discussion.
     686     * @param WP_User $user        A user object.
     687     *
     688     * @return bool True if the user has opt-out, otherwise false.
     689     */
     690    public static function is_user_opt_out_in_discussion( int $original_id, WP_User $user ): bool {
     691        return ! empty(
     692            get_users(
     693                array(
     694                    'meta_key'   => 'gp_opt_out',
     695                    'meta_value' => $original_id,
     696                    'include'    => array( $user->ID ),
     697                )
     698            )
     699        );
     700    }
     701
     702    /**
     703     * Gets the opt-in/oup-out message to show at the bottom of the discussions.
     704     *
     705     * @since 0.0.2
     706     *
     707     * @param int $original_id The id of the original string used for the discussion.
     708     *
     709     * @return string The opt-in/oup-out message to show at the bottom of the discussions.
     710     */
     711    public static function optin_message_for_each_discussion( int $original_id ): string {
     712        $post_id = self::get_post_id( $original_id );
     713        /**
     714         * Filters the optin message that will be showed in each discussion.
     715         *
     716         * @since 0.0.2
     717         *
     718         * @param string $message     The opt-in/oup-out message to show at the bottom of the discussions.
     719         * @param int    $original_id The id of the original string used for the discussion.
     720         */
     721        $message = apply_filters( 'gp_get_optin_message_for_each_discussion', '', $original_id );
     722        if ( $message ) {
     723            return $message;
     724        }
     725        $user            = wp_get_current_user();
     726        $is_user_opt_out = self::is_user_opt_out_in_discussion( $original_id, $user );
     727        if ( ! $is_user_opt_out ) {
     728            $comments = get_comments(
     729                array(
     730                    'user_id'            => $user->ID,
     731                    'post_id'            => $post_id,
     732                    'status'             => 'approve',
     733                    'type'               => 'comment',
     734                    'include_unapproved' => array( $user->ID ),
     735                )
     736            );
     737        }
     738
     739        if ( $is_user_opt_out ) {  // Opt-out user.
     740            $output  = __( 'You will not receive notifications for this discussion because you have opt-out to get notifications for it. ' );
     741            $output .= ' <a href="#" class="opt-in-discussion" data-original-id="' . $original_id . '" data-opt-type="optin">' . __( 'Start receiving notifications for this discussion.' ) . '</a>';
     742            return $output;
     743        }
     744        if ( $comments && ( ! self::is_user_an_gp_admin( $user ) ) && ( ! self::is_user_an_gp_validator( $user, $original_id ) ) ) { // Regular user with comments.
     745            $output  = __( 'You are going to receive notifications for the threads where you have participated. ' );
     746            $output .= ' <a href="#" class="opt-out-discussion" data-original-id="' . $original_id . '" data-opt-type="optout">' . __( 'Stop receiving notifications for this discussion.' ) . '</a>';
     747            return $output;
     748        }
     749        if ( self::is_user_an_gp_admin( $user ) && self::is_user_an_gp_validator( $user, $original_id ) ) {  // Admin and validator user.
     750            $output  = __( 'You are going to receive notifications because you are a GlotPress administrator and a validator for this project and language. ' );
     751            $output .= __( 'You will not receive notifications if another administrator or another validator participate in a thread where you do not take part. ' );
     752            $output .= ' <a href="#" class="opt-out-discussion" data-original-id="' . $original_id . '" data-opt-type="optout">' . __( 'Stop receiving notifications for this discussion.' ) . '</a>';
     753            return $output;
     754        }
     755        if ( self::is_user_an_gp_admin( $user ) ) {   // Admin user.
     756            $output  = __( 'You are going to receive notifications because you are a GlotPress administrator. ' );
     757            $output .= __( 'You will not receive notifications if another administrator participate in a thread where you do not take part. ' );
     758            $output .= ' <a href="#" class="opt-out-discussion" data-original-id="' . $original_id . '" data-opt-type="optout">' . __( 'Stop receiving notifications for this discussion.' ) . '</a>';
     759            return $output;
     760        }
     761        if ( self::is_user_an_gp_validator( $user, $original_id ) ) { // Validator user.
     762            $output  = __( 'You are going to receive notifications because you are a GlotPress validator for this project and language. ' );
     763            $output .= __( 'You will not receive notifications if another validator participate in a thread where you do not take part. ' );
     764            $output .= ' <a href="#" class="opt-out-discussion" data-original-id="' . $original_id . '" data-opt-type="optout">' . __( 'Stop receiving notifications for this discussion.' ) . '</a>';
     765            return $output;
     766        }
     767        return __( 'You will not receive notifications for this discussion. We will send you notifications as soon as you get involved.' ); // Regular user without comments.
     768
    475769    }
    476770}
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/gp-translation-helpers/includes/class-gp-translation-helpers.php

    r11837 r11921  
    6363        add_action( 'gp_pre_tmpl_load', array( $this, 'register_reject_feedback_js' ), 10, 2 );
    6464        add_action( 'wp_ajax_reject_with_feedback', array( $this, 'reject_with_feedback' ) );
     65        add_action( 'wp_ajax_optout_discussion_notifications', array( $this, 'optout_discussion_notifications' ) );
    6566
    6667        add_thickbox();
     
    160161
    161162        $translation_helpers_settings = array(
    162             'th_url' => gp_url_project( $args['project'], gp_url_join( $args['locale_slug'], $args['translation_set_slug'], '-get-translation-helpers' ) ),
     163            'th_url'   => gp_url_project( $args['project'], gp_url_join( $args['locale_slug'], $args['translation_set_slug'], '-get-translation-helpers' ) ),
     164            'ajax_url' => admin_url( 'admin-ajax.php' ),
     165            'nonce'    => wp_create_nonce( 'gp_optin_optout' ),
    163166        );
    164167
     
    395398
    396399        // Post comment on discussion page for the first string
    397         $save_feedback = $this->insert_reject_comment( $reject_comment, $first_original_id, $reject_reason, $first_translation_id, $locale_slug, $_SERVER );
     400        $first_comment_id = $this->insert_reject_comment( $reject_comment, $first_original_id, $reject_reason, $first_translation_id, $locale_slug, $_SERVER );
    398401
    399402        if ( ! empty( $original_id_array ) && ! empty( $translation_id_array ) ) {
    400403            // For other strings post link to the comment.
    401             $reject_comment = get_comment_link( $save_feedback );
     404            $reject_comment = get_comment_link( $first_comment_id );
    402405            foreach ( $original_id_array as $index => $single_original_id ) {
    403                 $this->insert_reject_comment( $reject_comment, $single_original_id, $reject_reason, $translation_id_array[ $index ], $locale_slug, $_SERVER );
    404             }
     406                $comment_id = $this->insert_reject_comment( $reject_comment, $single_original_id, $reject_reason, $translation_id_array[ $index ], $locale_slug, $_SERVER );
     407                $comment    = get_comment( $comment_id );
     408                GP_Notifications::add_related_comment( $comment );
     409            }
     410        }
     411
     412        if ( $first_comment_id ) {
     413            $comment = get_comment( $first_comment_id );
     414            GP_Notifications::init( $comment, null, null );
    405415        }
    406416
    407417        wp_send_json_success();
     418    }
     419
     420    /**
     421     * Adds or removes metadata to a user, related with the opt-in/opt-out status in a discussion
     422     *
     423     * It receives thought Ajax this data:
     424     * - nonce.
     425     * - originalId. The id of the original string related with the discussion.
     426     * - optType:
     427     *   - optout. Add the metadata, to opt-out from the notifications.
     428     *   - optin. Removes the metadata, to opt-in from the notifications. Default status.
     429     *
     430     * @since 0.0.2
     431     *
     432     * @return void
     433     */
     434    public function optout_discussion_notifications() {
     435        $nonce = sanitize_text_field( $_POST['data']['nonce'] );
     436        if ( ! wp_verify_nonce( $nonce, 'gp_optin_optout' ) ) {
     437            wp_send_json_error( esc_html__( 'Invalid nonce.' ), 403 );
     438        } else {
     439            $user_id     = get_current_user_id();
     440            $original_id = sanitize_text_field( $_POST['data']['originalId'] );
     441            $opt_type    = sanitize_text_field( $_POST['data']['optType'] );
     442            if ( 'optout' === $opt_type ) {
     443                add_user_meta( $user_id, 'gp_opt_out', $original_id );
     444            } elseif ( 'optin' === $opt_type ) {
     445                delete_user_meta( $user_id, 'gp_opt_out', $original_id );
     446            }
     447             wp_send_json_success();
     448        }
    408449    }
    409450
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/gp-translation-helpers/includes/class-wporg-notifications.php

    r11909 r11921  
    3434                'gp_notification_admin_email_addresses',
    3535                function ( $email_addresses, $comment, $comment_meta ) {
    36                     return self::get_author_email_address( $comment, $comment_meta );
     36                    $original               = GP_Notifications::get_original( $comment );
     37                    $email_addresses        = self::get_author_email_address( $original->id );
     38                    $parent_comments        = GP_Notifications::get_parent_comments( $comment->comment_parent );
     39                    $emails_from_the_thread = GP_Notifications::get_commenters_email_addresses( $parent_comments );
     40                    // If one author has a comment in the thread, we don't need to inform to any author, because this author will be notified in the thread.
     41                    if ( ( ! empty( array_intersect( $email_addresses, $emails_from_the_thread ) ) ) || in_array( $comment->comment_author_email, $email_addresses, true ) ) {
     42                        return array();
     43                    }
     44                    return $email_addresses;
    3745                },
    3846                10,
     
    4250                'gp_notification_validator_email_addresses',
    4351                function ( $email_addresses, $comment, $comment_meta ) {
    44                     return self::get_validator_email_addresses( $comment, $comment_meta );
     52                    $email_addresses        = self::get_validator_email_addresses( $comment, $comment_meta );
     53                    $parent_comments        = GP_Notifications::get_parent_comments( $comment->comment_parent );
     54                    $emails_from_the_thread = GP_Notifications::get_commenters_email_addresses( $parent_comments );
     55                    // If one validator (GTE/PTE/CLPTE) has a comment in the thread, we don't need to inform to any validator, because this validator will be notified in the thread.
     56                    if ( ! empty( array_intersect( $email_addresses, $emails_from_the_thread ) ) || in_array( $comment->comment_author_email, $email_addresses, true ) ) {
     57                        return array();
     58                    }
     59                    return $email_addresses;
    4560                },
    4661                10,
     
    7287                }
    7388            );
     89            add_filter(
     90                'gp_get_optin_message_for_each_discussion',
     91                function ( $message, $original_id ) {
     92                    return self::optin_message_for_each_discussion( $original_id );
     93                },
     94                10,
     95                2
     96            );
    7497        }
    7598    }
     
    89112     */
    90113    public static function get_validator_email_addresses( WP_Comment $comment, array $comment_meta ): array {
    91         $locale                 = $comment_meta['locale'][0];
    92         $email_addresses        = self::get_gte_email_addresses( $locale );
    93         $email_addresses        = array_merge( $email_addresses, self::get_pte_email_addresses_by_project_and_locale( $comment, $locale ) );
    94         $email_addresses        = array_merge( $email_addresses, self::get_clpte_email_addresses_by_project( $comment ) );
    95         $parent_comments        = GP_Notifications::get_parent_comments( $comment->comment_parent );
    96         $emails_from_the_thread = GP_Notifications::get_commenters_email_addresses( $parent_comments );
    97         // Set the email addresses array as empty if one GTE/PTE/CLPTE has a comment in the thread.
    98         if ( ! empty( array_intersect( $email_addresses, $emails_from_the_thread ) ) || in_array( $comment->comment_author_email, $email_addresses, true ) ) {
    99             return array();
    100         }
    101         return $email_addresses;
     114        $locale          = $comment_meta['locale'][0];
     115        $email_addresses = self::get_gte_email_addresses( $locale );
     116        $original        = GP_Notifications::get_original( $comment );
     117        $email_addresses = array_merge( $email_addresses, self::get_pte_email_addresses_by_project_and_locale( $original->id, $locale ) );
     118        return array_merge( $email_addresses, self::get_clpte_email_addresses_by_project( $original->id ) );
    102119    }
    103120
     
    151168     * @since 0.0.2
    152169     *
    153      * @param WP_Comment $comment The comment object.
    154      * @param string     $locale  The locale. E.g. 'zh-tw'.
     170     * @param int    $original_id The id of the original string used for the discussion.
     171     * @param string $locale  The locale. E.g. 'zh-tw'.
    155172     *
    156173     * @return array The project translation editors (PTE) emails.
    157174     */
    158     public static function get_pte_email_addresses_by_project_and_locale( $comment, $locale ): array {
    159         return self::get_pte_clpte_email_addresses_by_project_and_locale( $comment, $locale );
     175    public static function get_pte_email_addresses_by_project_and_locale( int $original_id, string $locale ): array {
     176        return self::get_pte_clpte_email_addresses_by_project_and_locale( $original_id, $locale );
    160177    }
    161178
     
    165182     * @since 0.0.2
    166183     *
    167      * @param WP_Comment $comment The comment object.
     184     * @param int $original_id The id of the original string used for the discussion.
    168185     *
    169186     * @return array The cross language project translation editors (CLPTE) emails.
    170187     */
    171     public static function get_clpte_email_addresses_by_project( $comment ): array {
    172         return self::get_pte_clpte_email_addresses_by_project_and_locale( $comment, 'all-locales' );
     188    public static function get_clpte_email_addresses_by_project( int $original_id ): array {
     189        return self::get_pte_clpte_email_addresses_by_project_and_locale( $original_id, 'all-locales' );
    173190    }
    174191
     
    178195     * @since 0.0.2
    179196     *
    180      * @param WP_Comment $comment The comment object.
    181      * @param string     $locale  The locale. E.g. 'zh-tw'.
     197     * @param int    $original_id The id of the original string used for the discussion.
     198     * @param string $locale      The locale. E.g. 'zh-tw'.
    182199     *
    183200     * @return array The PTE/CLPTE emails for the project and locale.
    184201     */
    185     private static function get_pte_clpte_email_addresses_by_project_and_locale( WP_Comment $comment, string $locale ): array {
     202    private static function get_pte_clpte_email_addresses_by_project_and_locale( int $original_id, string $locale ): array {
    186203        global $wpdb;
    187204
     
    196213        }
    197214
    198         $project = self::get_project_to_translate( $comment );
    199 
     215        $project = self::get_project_from_original_id( $original_id );
    200216        // todo: remove the deleted users in the SQL query.
    201217        $translation_editors = $wpdb->get_results(
     
    226242     * Themes: only one email.
    227243     * Plugins: all the plugin authors.
    228      *
    229      * @param WP_Comment $comment      The comment object.
    230      * @param array      $comment_meta The meta values for the comment.
     244     * Other projects: the special users, available at $i18n_email.
     245     *
     246     * @param int $original_id The id of the original string used for the discussion.
    231247     *
    232248     * @return array The email addresses for the author of a theme or a plugin.
    233249     */
    234     public static function get_author_email_address( WP_Comment $comment, array $comment_meta ): array {
     250    public static function get_author_email_address( int $original_id ): array {
    235251        global $wpdb;
    236252
    237253        $email_addresses = array();
    238         $project         = self::get_project_to_translate( $comment );
     254        $project         = GP_Notifications::get_project_from_original_id( $original_id );
    239255        if ( 'wp-themes' === substr( $project->path, 0, 9 ) ) {
    240256            $author = $wpdb->get_row(
     
    268284            $email_addresses = self::$i18n_email;
    269285        }
    270         $parent_comments        = GP_Notifications::get_parent_comments( $comment->comment_parent );
    271         $emails_from_the_thread = GP_Notifications::get_commenters_email_addresses( $parent_comments );
    272         // If one author has a comment in the thread or if one validator is the commenter, we don't need to inform any other validator.
    273         if ( ( true !== empty( array_intersect( $email_addresses, $emails_from_the_thread ) ) ) || in_array( $comment->comment_author_email, $email_addresses, true ) ) {
    274             return array();
    275         }
    276286        return $email_addresses;
    277287    }
     
    288298     */
    289299    public static function get_email_body( WP_Comment $comment, ?array $comment_meta ): ?string {
    290         $project  = self::get_project_to_translate( $comment );
    291         $original = self::get_original( $comment );
     300        $project  = self::get_project_from_post_id( $comment->comment_post_ID );
     301        $original = self::get_original( $comment->comment_post_ID );
    292302        $output   = esc_html__( 'Hi:' );
    293303        $output  .= '<br><br>';
     
    325335     * @since 0.0.2
    326336     *
    327      * @param WP_Comment $comment The comment object.
    328      *
    329      * @return GP_Project The project the translated string belongs to.
    330      */
    331     private static function get_project_to_translate( WP_Comment $comment ): GP_Project {
    332         $post_id = $comment->comment_post_ID;
    333         $terms   = wp_get_object_terms( $post_id, Helper_Translation_Discussion::LINK_TAXONOMY, array( 'number' => 1 ) );
     337     * @param int $post_id The id of the shadow post used for the discussion.
     338     *
     339     * @return false|GP_Project The project the translated string belongs to.
     340     */
     341    private static function get_project_from_post_id( int $post_id ) {
     342        $terms = wp_get_object_terms( $post_id, Helper_Translation_Discussion::LINK_TAXONOMY, array( 'number' => 1 ) );
    334343        if ( empty( $terms ) ) {
    335344            return false;
     
    344353        // because we have 3 levels of projects. E.g. wp-plugins->akismet->stable and the PTE are
    345354        // assigned to the second level.
    346         if ( ( ! is_null( $project->parent_project_id ) ) && ( ! in_array( $project->parent_project_id, $main_projects, true ) ) ) {
     355        if ( ( ! is_null( $project->parent_project_id ) ) && ( ! in_array( $project->parent_project_id, $main_projects, false ) ) ) {
     356            $project = GP::$project->get( $project->parent_project_id );
     357        }
     358        return $project;
     359    }
     360
     361    /**
     362     * Gets the project the original_id belongs to.
     363     *
     364     * @since 0.0.2
     365     *
     366     * @param int $original_id The id of the original string used for the discussion.
     367     *
     368     * @return GP_Project The project the original_id belongs to.
     369     */
     370    public static function get_project_from_original_id( int $original_id ): GP_Project {
     371        $original      = GP::$original->get( $original_id );
     372        $project_id    = $original->project_id;
     373        $project       = GP::$project->get( $project_id );
     374        $main_projects = self::get_main_projects();
     375
     376        // If the parent project is not a main project, get the parent project. We need to do this
     377        // because we have 3 levels of projects. E.g. wp-plugins->akismet->stable and the PTE are
     378        // assigned to the second level.
     379        if ( ( ! is_null( $project->parent_project_id ) ) && ( ! in_array( $project->parent_project_id, $main_projects, false ) ) ) {
    347380            $project = GP::$project->get( $project->parent_project_id );
    348381        }
     
    360393        global $wpdb;
    361394
    362         $main_projects = $wpdb->get_col( "SELECT id FROM {$wpdb->gp_projects} WHERE parent_project_id IS NULL" );
    363 
    364         return $main_projects;
     395        return $wpdb->get_col( "SELECT id FROM {$wpdb->gp_projects} WHERE parent_project_id IS NULL" );
    365396    }
    366397
     
    370401     * @since 0.0.2
    371402     *
    372      * @param WP_Comment $comment The comment object.
     403     * @param int $post_id The id of the shadow post used for the discussion.
    373404     *
    374405     * @return GP_Thing|false The original string that the translated string belongs to.
    375406     */
    376     private static function get_original( WP_Comment $comment ) {
    377         $post_id = $comment->comment_post_ID;
    378         $terms   = wp_get_object_terms( $post_id, Helper_Translation_Discussion::LINK_TAXONOMY, array( 'number' => 1 ) );
     407    private static function get_original( int $post_id ) {
     408        $terms = wp_get_object_terms( $post_id, Helper_Translation_Discussion::LINK_TAXONOMY, array( 'number' => 1 ) );
    379409        if ( empty( $terms ) ) {
    380410            return false;
     
    395425    private static function get_opted_in_email_addresses( array $email_addresses ): array {
    396426        foreach ( $email_addresses as $email_address ) {
    397             $user            = get_user_by( 'email', $email_address );
    398             $gp_default_sort = get_user_option( 'gp_default_sort', $user->ID );
    399             if ( 'on' != gp_array_get( $gp_default_sort, 'notifications_optin', 'off' ) ) {
     427            if ( self::is_global_optout_email_address( $email_address ) ) {
    400428                $index = array_search( $email_address, $email_addresses, true );
    401429                if ( false !== $index ) {
     
    406434        return array_values( $email_addresses );
    407435    }
     436
     437    /**
     438     * Indicates whether a user is globally opt-out.
     439     *
     440     * @since 0.0.2
     441     *
     442     * @param string $email_address The user's email address.
     443     *
     444     * @return bool Whether a user wis globally opt-out.
     445     */
     446    private static function is_global_optout_email_address( string $email_address ): bool {
     447        $user            = get_user_by( 'email', $email_address );
     448        $gp_default_sort = get_user_option( 'gp_default_sort', $user->ID );
     449        if ( 'on' != gp_array_get( $gp_default_sort, 'notifications_optin', 'off' ) ) {
     450            return true;
     451        }
     452        return false;
     453    }
     454
     455    /**
     456     * Indicates if the given user is a GTE at translate.wordpress.org.
     457     *
     458     * @since 0.0.2
     459     *
     460     * @todo Cache the GTE email addresses, because getting it made a lot of queries, slowing down the load time.
     461     *
     462     * @param WP_User $user A user object.
     463     *
     464     * @return bool Whether the user is GTE for any of the languages to which the comments in the post belong.
     465     */
     466    public static function is_user_an_wporg_gte( WP_User $user ): bool {
     467        $locales             = GP_Locales::locales();
     468        $gte_email_addresses = array();
     469        foreach ( $locales as $locale ) {
     470            $gte_email_addresses = array_merge( $gte_email_addresses, self::get_gte_email_addresses( $locale->slug ) );
     471        }
     472        if ( empty( array_intersect( array( $user->user_email ), $gte_email_addresses ) ) ) {
     473            return false;
     474        }
     475        return true;
     476    }
     477
     478    /**
     479     * Indicates if the given user is PTE for the project and for any of the languages to which the comments in the post belong.
     480     *
     481     * @since 0.0.2
     482     *
     483     * @todo Cache the PTE email addresses for each project, because getting it made a lot of queries, slowing down the load time.
     484     *
     485     * @param int     $original_id The id of the original string used for the discussion.
     486     * @param WP_User $user        A user object.
     487     *
     488     * @return bool Whether the user is PTE for the project and for any of the languages to which the comments in the post belong.
     489     */
     490    public static function is_user_an_wporg_pte_for_the_project( int $original_id, WP_User $user ): bool {
     491        $locales             = GP_Locales::locales();
     492        $pte_email_addresses = array();
     493        foreach ( $locales as $locale ) {
     494            $pte_email_addresses = array_merge( $pte_email_addresses, self::get_pte_email_addresses_by_project_and_locale( $original_id, $locale->slug ) );
     495        }
     496        if ( empty( $pte_email_addresses ) || empty( array_intersect( array( $user->user_email ), $pte_email_addresses ) ) ) {
     497            return false;
     498        }
     499        return true;
     500    }
     501
     502    /**
     503     * Indicates if the given user is CLPTE for the project to which the post belong.
     504     *
     505     * @since 0.0.2
     506     *
     507     * @param int     $original_id The id of the original string used for the discussion.
     508     * @param WP_User $user        A user object.
     509     *
     510     * @return bool Whether the user is a CLPTE for the project to which the post belong.
     511     */
     512    public static function is_user_an_wporg_clpte_for_the_project( int $original_id, WP_User $user ): bool {
     513        $clpte_email_addresses = self::get_clpte_email_addresses_by_project( $original_id );
     514        if ( empty( $clpte_email_addresses ) || empty( array_intersect( array( $user->user_email ), $clpte_email_addresses ) ) ) {
     515            return false;
     516        }
     517        return true;
     518    }
     519
     520    /**
     521     * Indicates if the given user is the author for the project to which the post belong.
     522     *
     523     * Only works with plugins and themes.
     524     *
     525     * @since 0.0.2
     526     *
     527     * @param int     $original_id The id of the original string used for the discussion.
     528     * @param WP_User $user        A user object.
     529     *
     530     * @return bool Whether the user is the author for the project to which the post belong.
     531     */
     532    public static function is_user_an_author_of_the_project( int $original_id, WP_User $user ): bool {
     533        $author_email_addresses = self::get_author_email_address( $original_id );
     534        if ( empty( $author_email_addresses ) || empty( array_intersect( array( $user->user_email ), $author_email_addresses ) ) ) {
     535            return false;
     536        }
     537        return true;
     538    }
     539
     540    /**
     541     * Indicates if the given user is a special user for projects different that themes and plugins.
     542     *
     543     * @since 0.0.2
     544     *
     545     * @param int     $original_id The id of the original string used for the discussion.
     546     * @param WP_User $user        A user object.
     547     *
     548     * @return bool Whether the user is a special user or not for projects different than themes and plugins.
     549     */
     550    public static function is_an_special_user_in_a_special_project( int $original_id, WP_User $user ):bool {
     551        $project = self::get_project_from_original_id( $original_id );
     552        if ( 'wp-themes' !== substr( $project->path, 0, 9 ) && ( 'wp-plugins' !== substr( $project->path, 0, 10 ) ) ) {
     553            if ( empty( self::$i18n_email ) || empty( array_intersect( array( $user->user_email ), self::$i18n_email ) ) ) {
     554                return false;
     555            }
     556            return true;
     557        }
     558        return false;
     559    }
     560
     561    /**
     562     * Indicates if the given user has made a comment in the discussion.
     563     *
     564     * @since 0.0.2
     565     *
     566     * @param int     $original_id The id of the original string used for the discussion.
     567     * @param WP_User $user        A user object.
     568     *
     569     * @return bool Whether the user has made a comment in the discussion.
     570     */
     571    private static function is_user_a_commenter_in_the_discussion( int $original_id, WP_User $user ):bool {
     572        $post_id  = GP_Notifications::get_post_id( $original_id );
     573        $comments = get_comments(
     574            array(
     575                'post_id'            => $post_id,
     576                'user_id'            => $user->ID,
     577                'status'             => 'approve',
     578                'type'               => 'comment',
     579                'include_unapproved' => array( get_current_user_id() ),
     580            )
     581        );
     582        if ( empty( $comments ) ) {
     583            return false;
     584        }
     585        return true;
     586    }
     587
     588    /**
     589     * Gets the opt-in/oup-out message to show at the bottom of the discussions at translate.wordpress.org.
     590     *
     591     * @param int $original_id The id of the original string used for the discussion.
     592     *
     593     * @return string The message to show at the bottom of the discussions at translate.wordpress.org.
     594     */
     595    public static function optin_message_for_each_discussion( int $original_id ): string {
     596        $user = wp_get_current_user();
     597
     598        if ( self::is_global_optout_email_address( $user->user_email ) ) {
     599            $output  = __( 'You will not receive notifications because you have not yet opted-in. ' );
     600            $output .= ' <a href="https://translate.wordpress.org/settings/">' . __( 'Start receiving notifications.' ) . '</a>';
     601            return $output;
     602        }
     603        if ( GP_Notifications::is_user_opt_out_in_discussion( $original_id, $user ) ) {
     604            $output  = __( 'You will not receive notifications for this discussion because you have opt-out to get notifications for it. ' );
     605            $output .= ' <a href="#" class="opt-in-discussion" data-original-id="' . $original_id . '" data-opt-type="optin">' . __( 'Start receiving notifications for this discussion.' ) . '</a>';
     606            $output .= ' <a href="https://translate.wordpress.org/settings/">' . __( 'Stop receiving notifications.' ) . '</a>';
     607            return $output;
     608        }
     609        if ( self::is_user_an_wporg_gte( $user ) ) {
     610            $output  = __( 'You are going to receive notifications for the questions in your language because you are a GTE. ' );
     611            $output .= __( 'You will not receive notifications if another GTE or PTE for your language or CLPTE participates in a thread where you do not take part. ' );
     612            $output .= ' <a href="#" class="opt-out-discussion" data-original-id="' . $original_id . '" data-opt-type="optout">' . __( 'Stop receiving notifications for this discussion.' ) . '</a>';
     613            $output .= ' <a href="https://translate.wordpress.org/settings/">' . __( 'Stop receiving notifications.' ) . '</a>';
     614            return $output;
     615        }
     616        if ( self::is_user_an_wporg_pte_for_the_project( $original_id, $user ) ) {
     617            $output  = __( 'You are going to receive notifications for the questions in your language because you are a PTE. ' );
     618            $output .= __( 'You will not receive notifications if another GTE or PTE for your language or CLPTE participates in a thread where you do not take part. ' );
     619            $output .= ' <a href="#" class="opt-out-discussion" data-original-id="' . $original_id . '" data-opt-type="optout">' . __( 'Stop receiving notifications for this discussion.' ) . '</a>';
     620            $output .= ' <a href="https://translate.wordpress.org/settings/">' . __( 'Stop receiving notifications.' ) . '</a>';
     621            return $output;
     622        }
     623        if ( self::is_user_an_wporg_clpte_for_the_project( $original_id, $user ) ) {
     624            $output  = __( 'You are going to receive notifications for the questions because you are a CLPTE. ' );
     625            $output .= __( 'You will not receive notifications if another GTE or PTE for their language or CLPTE participates in a thread where you do not take part. ' );
     626            $output .= ' <a href="#" class="opt-out-discussion" data-original-id="' . $original_id . '" data-opt-type="optout">' . __( 'Stop receiving notifications for this discussion.' ) . '</a>';
     627            $output .= ' <a href="https://translate.wordpress.org/settings/">' . __( 'Stop receiving notifications.' ) . '</a>';
     628            return $output;
     629        }
     630        if ( self::is_an_special_user_in_a_special_project( $original_id, $user ) ) {
     631            $output  = __( 'You are going to receive notifications for some questions (typos and more context) because you are a special user. ' );
     632            $output .= __( 'You will not receive notifications if another special user participates in a thread where you do not take part. ' );
     633            $output .= ' <a href="#" class="opt-out-discussion" data-original-id="' . $original_id . '" data-opt-type="optout">' . __( 'Stop receiving notifications for this discussion.' ) . '</a>';
     634            $output .= ' <a href="https://translate.wordpress.org/settings/">' . __( 'Stop receiving notifications.' ) . '</a>';
     635            return $output;
     636        }
     637        if ( self::is_user_an_author_of_the_project( $original_id, $user ) ) {
     638            $output  = __( 'You are going to receive notifications for some questions (typos and more context) because you are an author. ' );
     639            $output .= __( 'You will not receive notifications if another author participates in a thread where you do not take part. ' );
     640            $output .= ' <a href="#" class="opt-out-discussion" data-original-id="' . $original_id . '" data-opt-type="optout">' . __( 'Stop receiving notifications for this discussion.' ) . '</a>';
     641            $output .= ' <a href="https://translate.wordpress.org/settings/">' . __( 'Stop receiving notifications.' ) . '</a>';
     642            return $output;
     643        }
     644        if ( self::is_user_a_commenter_in_the_discussion( $original_id, $user ) ) {
     645            $output  = __( 'You are going to receive notifications for some threads where you have taken part. ' );
     646            $output .= ' <a href="#" class="opt-out-discussion" data-original-id="' . $original_id . '" data-opt-type="optout">' . __( 'Stop receiving notifications for this discussion.' ) . '</a>';
     647            $output .= ' <a href="https://translate.wordpress.org/settings/">' . __( 'Stop receiving notifications.' ) . '</a>';
     648            return $output;
     649        }
     650        $output  = __( 'You will not receive notifications for this discussion. We will send you notifications as soon as you get involved.' );
     651        $output .= ' <a href="https://translate.wordpress.org/settings/">' . __( 'Stop receiving notifications.' ) . '</a>';
     652        return $output;
     653    }
     654
    408655}
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/gp-translation-helpers/js/translation-helpers.js

    r11837 r11921  
    1 /* global $gp, window */
     1/* global $gp, window, $gp_translation_helpers_settings */
    22$gp.translation_helpers = (
    33    function( $ ) {
     
    1414                    .on( 'beforeShow', '.editor', $gp.translation_helpers.hooks.initial_fetch )
    1515                    .on( 'click', '.helpers-tabs li', $gp.translation_helpers.hooks.tab_select )
    16                     .on( 'click', 'a.comment-reply-link', $gp.translation_helpers.hooks.reply_comment_form );
     16                    .on( 'click', 'a.comment-reply-link', $gp.translation_helpers.hooks.reply_comment_form )
     17                    .on( 'click', 'a.opt-out-discussion,a.opt-in-discussion', $gp.translation_helpers.hooks.optin_optout_discussion );
    1718            },
    1819            initial_fetch: function( $element ) {
     
    8182                }
    8283            },
     84            optin_optout_discussion: function( $link ) {
     85                var data = {
     86                    action: 'optout_discussion_notifications',
     87                    data: {
     88                        nonce: $gp_translation_helpers_settings.nonce,
     89                        originalId: $link.attr( 'data-original-id' ),
     90                        optType: $link.attr( 'data-opt-type' ),
     91                    },
     92                };
     93                $.ajax(
     94                    {
     95                        type: 'POST',
     96                        url: $gp_translation_helpers_settings.ajax_url,
     97                        data: data,
     98                    }
     99                ).done(
     100                    function() {
     101                        $gp.translation_helpers.fetch( 'discussion' );
     102                    }
     103                );
     104            },
    83105            hooks: {
    84106                initial_fetch: function() {
     
    93115                    event.preventDefault();
    94116                    $gp.translation_helpers.reply_comment_form( $( this ) );
     117                    return false;
     118                },
     119                optin_optout_discussion: function( event ) {
     120                    event.preventDefault();
     121                    $gp.translation_helpers.optin_optout_discussion( $( this ) );
    95122                    return false;
    96123                },
Note: See TracChangeset for help on using the changeset viewer.