| 1 | <?php
|
|---|
| 2 |
|
|---|
| 3 | class Dotorg_Theme_Review_Assigner {
|
|---|
| 4 |
|
|---|
| 5 | protected $trac;
|
|---|
| 6 |
|
|---|
| 7 | function __construct() {
|
|---|
| 8 | add_action( 'widgets_init', array( $this, 'widgets_init' ) );
|
|---|
| 9 | add_action( 'admin_post_assign_theme_review', array( $this, 'admin_post' ) );
|
|---|
| 10 | }
|
|---|
| 11 |
|
|---|
| 12 | function require_trac() {
|
|---|
| 13 | require_once ABSPATH . WPINC . '/class-IXR.php';
|
|---|
| 14 | require_once ABSPATH . WPINC . '/class-wp-http-ixr-client.php';
|
|---|
| 15 | require_once WPORGPATH . 'bb-theme/themes/lib/class-trac.php';
|
|---|
| 16 | $this->trac = new Trac( 'themetracbot', THEME_TRACBOT_PASSWORD, 'https://themes.trac.wordpress.org/login/xmlrpc' );
|
|---|
| 17 | }
|
|---|
| 18 |
|
|---|
| 19 | function widgets_init() {
|
|---|
| 20 | register_widget( 'Dotorg_Theme_Review_Widget' );
|
|---|
| 21 | }
|
|---|
| 22 |
|
|---|
| 23 | function admin_post() {
|
|---|
| 24 | check_admin_referer( 'assign-theme-review' );
|
|---|
| 25 |
|
|---|
| 26 | $this->require_trac();
|
|---|
| 27 |
|
|---|
| 28 | $assignments = $this->get_current_assignments();
|
|---|
| 29 | if ( is_wp_error( $assignments ) ) {
|
|---|
| 30 | $result = 'failed';
|
|---|
| 31 | } elseif ( $assignments ) {
|
|---|
| 32 | $result = 'existing';
|
|---|
| 33 | } else {
|
|---|
| 34 | $ticket = $this->assign_next_theme();
|
|---|
| 35 | if ( is_wp_error( $ticket ) ) {
|
|---|
| 36 | $result = 'failed';
|
|---|
| 37 | } elseif ( $ticket ) {
|
|---|
| 38 | $result = $ticket;
|
|---|
| 39 | } else {
|
|---|
| 40 | $result = 'none';
|
|---|
| 41 | }
|
|---|
| 42 | }
|
|---|
| 43 |
|
|---|
| 44 | if ( is_int( $result ) ) {
|
|---|
| 45 | wp_redirect( 'https://themes.trac.wordpress.org/ticket/' . $result );
|
|---|
| 46 | exit;
|
|---|
| 47 | }
|
|---|
| 48 |
|
|---|
| 49 | $redirect = add_query_arg( array( 'theme-assign' => $result, 'now' => time() ), wp_get_referer() );
|
|---|
| 50 | wp_safe_redirect( $redirect );
|
|---|
| 51 | exit;
|
|---|
| 52 | }
|
|---|
| 53 |
|
|---|
| 54 | function get_current_assignments() {
|
|---|
| 55 | $username = wp_get_current_user()->user_login;
|
|---|
| 56 | $assigned = $this->trac->ticket_query( sprintf( 'owner=%s&status=reviewing', $username ) );
|
|---|
| 57 | if ( $assigned ) {
|
|---|
| 58 | return $assigned;
|
|---|
| 59 | } elseif ( $assigned === array() ) {
|
|---|
| 60 | return false;
|
|---|
| 61 | } else {
|
|---|
| 62 | // RPC failure condition ($assigned is false here)
|
|---|
| 63 | return new WP_Error;
|
|---|
| 64 | }
|
|---|
| 65 | }
|
|---|
| 66 |
|
|---|
| 67 | function assign_next_theme() {
|
|---|
| 68 | $username = wp_get_current_user()->user_login;
|
|---|
| 69 | $assigned = false;
|
|---|
| 70 | $i = 0;
|
|---|
| 71 | do {
|
|---|
| 72 | if ( ++$i > 10 ) {
|
|---|
| 73 | // Safeguard.
|
|---|
| 74 | return new WP_Error;
|
|---|
| 75 | }
|
|---|
| 76 |
|
|---|
| 77 | $next_ticket = $this->trac->ticket_query( 'priority=new theme&priority=previously reviewed&status=new&keywords=!~buddypress&order=time&max=1&owner=' );
|
|---|
| 78 | if ( $next_ticket === array() ) {
|
|---|
| 79 | return false;
|
|---|
| 80 | } elseif ( $next_ticket === false ) {
|
|---|
| 81 | return new WP_Error;
|
|---|
| 82 | }
|
|---|
| 83 |
|
|---|
| 84 | $ticket = $this->trac->ticket_get( $next_ticket[0] );
|
|---|
| 85 | // Avoid race condition: Maybe someone was just assigned this one between query and get.
|
|---|
| 86 | if ( $ticket['owner'] || $ticket['status'] !== 'new' ) {
|
|---|
| 87 | continue;
|
|---|
| 88 | }
|
|---|
| 89 |
|
|---|
| 90 | // Assign the ticket using the proper workflow actions.
|
|---|
| 91 | $attributes = array( 'action' => 'review_other', 'action_review_other_reassign_owner' => $username );
|
|---|
| 92 |
|
|---|
| 93 | // Set _ts (changetime) so the update will fail if the ticket was updated since our fetch.
|
|---|
| 94 | $attributes['_ts'] = $ticket['_ts'];
|
|---|
| 95 |
|
|---|
| 96 | // No comment, yes notify. User is 'themetracbot'.
|
|---|
| 97 | $updated = $this->trac->ticket_update( $ticket['id'], '', $attributes, true );
|
|---|
| 98 | if ( ! $updated ) {
|
|---|
| 99 | // Update failed. Try another ticket.
|
|---|
| 100 | continue;
|
|---|
| 101 | }
|
|---|
| 102 |
|
|---|
| 103 | $assigned = (int) $ticket['id'];
|
|---|
| 104 | } while ( ! $assigned );
|
|---|
| 105 | return $assigned;
|
|---|
| 106 | }
|
|---|
| 107 | }
|
|---|
| 108 |
|
|---|
| 109 | // Hack so this can sit in a mu-plugin (included before widgets are)
|
|---|
| 110 | add_action( 'widgets_init', function() {
|
|---|
| 111 |
|
|---|
| 112 | class Dotorg_Theme_Review_Widget extends WP_Widget_Text {
|
|---|
| 113 | function __construct() {
|
|---|
| 114 | $widget_ops = array( 'classname' => 'dotorg_theme_review_widget', 'description' => 'Widget for theme reviewers to self-assign themselves themes.' );
|
|---|
| 115 | $control_ops = array( 'width' => 400, 'height' => 350 );
|
|---|
| 116 | WP_Widget::__construct('dotorg_theme_review', __('Theme Review Self-Assign'), $widget_ops, $control_ops );
|
|---|
| 117 | }
|
|---|
| 118 |
|
|---|
| 119 | function widget( $args, $instance ) {
|
|---|
| 120 | ob_start();
|
|---|
| 121 | echo '<style>
|
|---|
| 122 | .dotorg_theme_review_widget .textwidget { font-size: 14px; color: #333 }
|
|---|
| 123 | .dotorg_theme_review_widget .textwidget p { margin: 1em 0; }
|
|---|
| 124 | .dotorg_theme_review_widget button { font-size: 13px; }
|
|---|
| 125 | </style>';
|
|---|
| 126 | $action = isset( $_GET['theme-assign'] ) ? $_GET['theme-assign'] : false;
|
|---|
| 127 |
|
|---|
| 128 | if ( $action && $_GET['now'] < time() - 10 ) {
|
|---|
| 129 | // If the page was refreshed > 10 seconds later, ignore the action and show the button again.
|
|---|
| 130 | $action = false;
|
|---|
| 131 | }
|
|---|
| 132 |
|
|---|
| 133 | if ( 'existing' === $action ) {
|
|---|
| 134 | printf( '<p><strong>You have reviews <a href="%s">assigned to you</a> that you need to complete first.</strong></p>',
|
|---|
| 135 | esc_url( 'https://themes.trac.wordpress.org/query?status=!closed&owner=$USER' ) );
|
|---|
| 136 | } elseif ( 'none' === $action ) {
|
|---|
| 137 | echo '<p><strong>There are no themes in the review queue to assign right now. Check back soon.</strong></p>';
|
|---|
| 138 | } elseif ( 'failed' === $action ) {
|
|---|
| 139 | echo '<p><strong>Something went wrong; the system can᾿t assign you a review right now.</strong></p>';
|
|---|
| 140 | } elseif ( is_user_logged_in() ) {
|
|---|
| 141 | $url = add_query_arg( '_wp_get_referer', $_SERVER['REQUEST_URI'], admin_url( 'admin-post.php?action=assign_theme_review' ) );
|
|---|
| 142 | $url = wp_nonce_url( $url, 'assign-theme-review' );
|
|---|
| 143 | printf( '<p><form method="post" action="%s"><button>Request a theme to review</button></form></p>', esc_url( $url ) );
|
|---|
| 144 | } else {
|
|---|
| 145 | printf( '<p>Please <a href="%s">log in</a> first to review.</em></p>', esc_url( wp_login_url( $_SERVER['REQUEST_URI'] ) ) );
|
|---|
| 146 | }
|
|---|
| 147 | $instance['text'] .= ob_get_clean();
|
|---|
| 148 | parent::widget( $args, $instance );
|
|---|
| 149 | }
|
|---|
| 150 | }
|
|---|
| 151 |
|
|---|
| 152 | }, 9 );
|
|---|
| 153 |
|
|---|
| 154 | new Dotorg_Theme_Review_Assigner( $themes_trac );
|
|---|
| 155 |
|
|---|