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 | |
---|