Making WordPress.org

Ticket #762: site-themes.php

File site-themes.php, 5.2 KB (added by nacin, 10 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