Making WordPress.org

Ticket #762: site-themes.php

File site-themes.php, 5.2 KB (added by nacin, 12 years ago)
Line 
1<?php
2
3class 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)
110add_action( 'widgets_init', function() {
111
112class 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&#8127;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
154new Dotorg_Theme_Review_Assigner( $themes_trac );
155