Changeset 11921 for sites/trunk/wordpress.org/public_html/wp-content/plugins/gp-translation-helpers/includes/class-gp-notifications.php
- Timestamp:
- 06/21/2022 02:15:05 PM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
sites/trunk/wordpress.org/public_html/wp-content/plugins/gp-translation-helpers/includes/class-gp-notifications.php
r11837 r11921 10 10 class GP_Notifications { 11 11 /** 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 /** 12 19 * Sends notifications when a new comment in the discussion is stored using the WP REST API. 13 20 * … … 27 34 if ( ( '0' !== $comment->comment_parent ) ) { // Notify to the thread only if the comment is in a thread. 28 35 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 ); 29 39 } 30 40 $root_comment = self::get_root_comment_in_a_thread( $comment ); … … 94 104 95 105 /** 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 /** 96 126 * Sends an email to the GlotPress admins. 97 127 * … … 119 149 */ 120 150 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 ); 122 153 123 154 $email_addresses = self::get_validators_email_addresses( $project->path ); … … 171 202 * @since 0.0.2 172 203 * 173 * @param array $commentsArray 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. 175 206 * 176 207 * @return array The emails to be notified from the thread comments. … … 252 283 } 253 284 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} 256 288 INNER JOIN {$wpdb->gp_permissions} 257 289 ON {$wpdb->users}.ID = {$wpdb->gp_permissions}.user_id 258 290 WHERE action='admin'" 259 ); 260 291 ); 292 } catch ( Exception $e ) { 293 $admin_email_addresses = array(); 294 } 261 295 foreach ( $admin_email_addresses as $admin ) { 262 296 $email_addresses[] = $admin->user_email; … … 295 329 return false; 296 330 } 331 $original = self::get_original( $comment ); 297 332 $email_addresses = self::remove_commenter_email_address( $comment, $email_addresses ); 333 $email_addresses = self::remove_optout_discussion_email_addresses( $original->id, $email_addresses ); 298 334 299 335 $headers = array( … … 328 364 */ 329 365 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 ); 331 368 $original = self::get_original( $comment ); 332 369 $output = ''; … … 351 388 ) 352 389 ) . '<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 } 353 400 $output .= '<br>'; 354 401 $output .= esc_html__( 'It would be nice if you have some time to review this comment and reply to it if needed.', 'glotpress' ); 355 402 $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 .= ' - ' . wp_kses( 357 428 /* 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 ), 359 430 array( 360 431 'strong' => array(), … … 362 433 ) 363 434 ) . '<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 .= ' - ' . 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 } 381 447 $output .= '<br><br>'; 382 448 $output .= esc_html__( 'Have a nice day!', 'glotpress' ); … … 434 500 435 501 /** 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 /** 436 533 * Gets the project that the translated string belongs to. 437 534 * 438 535 * @since 0.0.2 439 536 * 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 * 440 586 * @param WP_Comment $comment The comment object. 441 587 * 442 * @return GP_ Project|bool The projectthat the translated string belongs to.443 */ 444 p rivate 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 ) { 445 591 $post_id = $comment->comment_post_ID; 446 592 $terms = wp_get_object_terms( $post_id, Helper_Translation_Discussion::LINK_TAXONOMY, array( 'number' => 1 ) ); … … 449 595 } 450 596 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 ) ) ) { 471 656 return false; 472 657 } 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 475 769 } 476 770 }
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)