Changeset 2022
- Timestamp:
- 11/01/2015 10:27:39 AM (11 years ago)
- Location:
- sites/trunk/wordpress.org/public_html/wp-content/plugins/trac-notifications
- Files:
-
- 1 added
- 2 edited
-
trac-components.php (modified) (15 diffs)
-
trac-notifications-db.php (added)
-
trac-notifications.php (modified) (17 diffs)
Legend:
- Unmodified
- Added
- Removed
-
sites/trunk/wordpress.org/public_html/wp-content/plugins/trac-notifications/trac-components.php
r1965 r2022 4 4 const last_x_days = 7; 5 5 6 function __construct() { 6 function __construct( $api ) { 7 $this->api = $api; 7 8 add_action( 'init', array( $this, 'init' ) ); 8 9 add_action( 'pre_get_posts', array( $this, 'pre_get_posts' ) ); … … 15 16 add_filter( 'manage_component_posts_columns', array( $this, 'manage_posts_columns' ) ); 16 17 add_action( 'manage_component_posts_custom_column', array( $this, 'manage_posts_custom_column' ), 10, 2 ); 17 $this->trac = $GLOBALS['wpdb'];18 18 } 19 19 … … 319 319 echo "<strong>Want to help? Start following this component!</strong> <a href='/core/notifications/'>Adjust your notifications here</a>. Feel free to dig into any ticket." . "\n\n"; 320 320 321 $followers = $this-> trac->get_col( $this->trac->prepare( "SELECT username FROM _notifications WHERE type = 'component' AND value = %s", $post->post_title ));321 $followers = $this->api->get_component_followers( $post->post_title ); 322 322 $followers = "'" . implode( "', '", esc_sql( $followers ) ) . "'"; 323 323 $followers = $wpdb->get_results( "SELECT user_login, user_nicename, user_email FROM $wpdb->users WHERE user_login IN ($followers)" ); … … 345 345 $rows = wp_cache_get( 'trac_tickets_by_component_type_milestone' ); 346 346 if ( ! $rows ) { 347 $rows = $this->trac->get_results( "SELECT component, type, milestone, count(*) as count FROM ticket 348 WHERE status <> 'closed' GROUP BY component, type, milestone ORDER BY component, type, milestone" ); 347 $rows = $this->api->get_tickets_by_component_type_milestone(); 349 348 wp_cache_add( 'trac_tickets_by_component_type_milestone', $rows, '', 300 ); 350 349 } … … 364 363 $component_unreplied = wp_cache_get( 'trac_tickets_by_component_unreplied' ); 365 364 if ( ! $component_unreplied ) { 366 $rows = $this->trac->get_results( "SELECT id, component FROM ticket t 367 WHERE id NOT IN (SELECT ticket FROM ticket_change WHERE ticket = t.id AND t.reporter <> author AND field = 'comment' AND newvalue <> '') 368 AND status <> 'closed'" ); 369 $component_unreplied = array(); 370 foreach ( $rows as $row ) { 371 $component_unreplied[ $row->component ][] = $row->id; 372 } 365 $component_unreplied = $this->api->get_unreplied_ticket_counts_by_component(); 373 366 wp_cache_add( 'trac_tickets_by_component_unreplied', $component_unreplied, '', 300 ); 374 367 } … … 399 392 } 400 393 401 $history = $this-> get_component_history( $component );394 $history = $this->api->get_component_history( $component ); 402 395 $direction = ''; 403 396 if ( $history['change'] > 0 ) { … … 451 444 452 445 function trac_content( $component ) { 453 $unreplied_tickets = $this->trac->get_results( $this->trac->prepare( 454 "SELECT id, summary, status, resolution, milestone, value as focuses 455 FROM ticket t LEFT JOIN ticket_custom c ON c.ticket = t.id AND c.name = 'focuses' 456 WHERE id NOT IN ( 457 SELECT ticket FROM ticket_change 458 WHERE ticket = t.id AND t.reporter <> author 459 AND field = 'comment' AND newvalue <> '' 460 ) AND status <> 'closed' AND component = %s", $component ) ); 446 $unreplied_tickets = $this->api->get_unreplied_tickets_by_component( $component ); 461 447 462 448 if ( $unreplied_tickets ) { … … 467 453 } 468 454 469 $next_milestone = $this-> trac->get_results( $this->trac->prepare( "SELECT id, summary, status, resolution, milestone, value as focuses FROM ticket t470 LEFT JOIN ticket_custom c ON c.ticket = t.id AND c.name = 'focuses' WHERE component = %s AND status <> 'closed' AND milestone LIKE '_._'", $component ) ); 455 $next_milestone = $this->api->get_tickets_in_next_milestone( $component ); 456 471 457 if ( $next_milestone ) { 472 458 $count = count( $next_milestone ); … … 476 462 } 477 463 478 return; // Ditch the rest for now. 479 480 $tickets_by_type = $this->trac->get_results( $this->trac->prepare( "SELECT type, COUNT(*) as count FROM ticket WHERE component = %s AND status <> 'closed' GROUP BY type", $component ), OBJECT_K ); 481 foreach ( $tickets_by_type as &$object ) { 482 $object = $object->count; 483 } 484 unset( $object ); 464 $tickets_by_type = $this->api->get_ticket_counts_for_component( $component ); 485 465 486 466 $count = array_sum( $tickets_by_type ); … … 490 470 echo "\n\n"; 491 471 492 if ( $enhancements = $this->trac->get_results( $this->trac->prepare( "SELECT id, summary, status, resolution, milestone FROM ticket WHERE component = %s AND status <> 'closed' AND type = %s", $component, 'enhancement' ) ) ) { 493 printf( '<h3>Open enhancements (%d)</h3>', count( $enhancements ) ); 494 echo $this->trac_query_link( 'View list on Trac', array( 'component' => $component, 'type' => 'enhancement' ) ); 495 $this->render_tickets( $enhancements ); 496 } 497 498 if ( $tasks = $this->trac->get_results( $this->trac->prepare( "SELECT id, summary, status, resolution, milestone FROM ticket WHERE component = %s AND status <> 'closed' AND type = %s", $component, 'task (blessed)' ) ) ) { 499 printf( '<h3>Open tasks (%d)</h3>', count( $tasks ) ); 500 echo $this->trac_query_link( 'View list on Trac', array( 'component' => $component, 'type' => 'task (blessed)' ) ); 501 $this->render_tickets( $tasks ); 502 } 503 504 if ( $feature_requests = $this->trac->get_results( $this->trac->prepare( "SELECT id, summary, status, resolution, milestone FROM ticket WHERE component = %s AND status <> 'closed' AND type = %s", $component, 'feature request' ) ) ) { 505 printf( '<h3>Open feature requests (%d)</h3>', count( $feature_requests ) ); 506 echo $this->trac_query_link( 'View list on Trac', array( 'component' => $component, 'type' => 'feature request' ) ); 507 $this->render_tickets( $feature_requests ); 472 return; 473 474 $types = array( 475 'enhancement' => 'Open enhancements', 476 'task (blessed)' => 'Open tasks', 477 'feature request' => 'Open feature requests', 478 ); 479 480 foreach ( $types as $type => $title ) { 481 $args = compact( 'component', 'type' ); 482 if ( $tickets = $this->api->get_tickets_by( $args ) ) { 483 printf( '<h3>%s (%d)</h3>', $title, count( $tickets ) ); 484 echo $this->trac_query_link( 'View list on Trac', $args ); 485 $this->render_tickets( $tickets ); 486 } 508 487 } 509 488 } … … 531 510 } 532 511 echo '</ul>'; 533 }534 535 function get_component_history( $component ) {536 $days_ago = ( time() - ( DAY_IN_SECONDS * self::last_x_days ) ) * 1000000;537 $closed_reopened = $this->trac->get_results( $this->trac->prepare( "SELECT newvalue, COUNT(DISTINCT ticket) as count538 FROM ticket_change tc INNER JOIN ticket t ON tc.ticket = t.id539 WHERE field = 'status' AND (newvalue = 'closed' OR newvalue = 'reopened')540 AND tc.time >= %s AND t.component = %s GROUP BY newvalue", $days_ago, $component ), OBJECT_K );541 $reopened = isset( $closed_reopened['reopened'] ) ? $closed_reopened['reopened']->count : 0;542 $closed = isset( $closed_reopened['closed'] ) ? $closed_reopened['closed']->count : 0;543 $opened = $this->trac->get_var( $this->trac->prepare( "SELECT COUNT(DISTINCT id) FROM ticket WHERE time >= %s AND component = %s", $days_ago, $component ) );544 $assigned_unassigned = $this->trac->get_results( $this->trac->prepare( "SELECT IF(newvalue = %s, 'assigned', 'unassigned') as direction,545 COUNT(*) as count FROM ticket_change WHERE field = 'component' AND ( oldvalue = %s OR newvalue = %s ) AND time >= %s GROUP BY direction",546 $component, $component, $component, $days_ago ), OBJECT_K );547 $assigned = isset( $assigned_unassigned['assigned'] ) ? $assigned_unassigned['assigned']->count : 0;548 $unassigned = isset( $assigned_unassigned['unassigned'] ) ? $assigned_unassigned['unassigned']->count : 0;549 550 $change = $opened + $reopened + $assigned - $closed - $unassigned;551 return compact( 'change', 'opened', 'reopened', 'closed', 'assigned', 'unassigned' );552 512 } 553 513 … … 584 544 } 585 545 if ( in_array( 'component', $topics ) ) { 586 $components = $this-> trac->get_col( "SELECT name FROM component");546 $components = $this->api->get_components(); 587 547 foreach ( $components as $component ) { 588 548 echo '<option value="component/' . esc_attr( str_replace( ' ', '+', $component ) ) . '">' . esc_html( $component ) . "</option>"; … … 602 562 $component = $post->post_title; 603 563 $this->generate_component_breakdowns(); 604 $history = $this-> get_component_history( $component );564 $history = $this->api->get_component_history( $component ); 605 565 606 566 $arrow = ''; … … 633 593 } 634 594 635 $maintainers = $this->get_ maintainers_by_post( $post->ID );595 $maintainers = $this->get_component_maintainers_by_post( $post->ID ); 636 596 echo '<td class="no-grav maintainers">'; 637 597 foreach ( $maintainers as $maintainer ) { … … 642 602 } 643 603 644 function get_ maintainers_by_post( $post_id ) {604 function get_component_maintainers_by_post( $post_id ) { 645 605 return array_filter( array_map( 'trim', explode( ',', get_post_meta( $post_id, '_active_maintainers', true ) ) ) ); 646 606 } 647 607 648 function get_ maintainers_by_component( $component ) {649 return $this->get_ maintainers_by_post( get_page_by_title( $component, OBJECT, 'component' )->ID );608 function get_component_maintainers( $component ) { 609 return $this->get_component_maintainers_by_post( get_page_by_title( $component, OBJECT, 'component' )->ID ); 650 610 } 651 611 } -
sites/trunk/wordpress.org/public_html/wp-content/plugins/trac-notifications/trac-notifications.php
r1979 r2022 8 8 class wporg_trac_notifications { 9 9 10 protected $trac _subdomain;10 protected $trac; 11 11 protected $components; 12 12 … … 23 23 $trac = $_GET['trac']; 24 24 } 25 $this->set_trac( $trac ); 26 add_filter( 'allowed_http_origins', array( $this, 'filter_allowed_http_origins' ) ); 27 add_action( 'template_redirect', array( $this, 'action_template_redirect' ) ); 28 add_shortcode( 'trac-notifications', array( $this, 'notification_settings_page' ) ); 29 if ( 'core' === $trac ) { 30 require __DIR__ . '/trac-components.php'; 31 $this->components = new Make_Core_Trac_Components; 32 } 33 } 34 35 function set_trac( $trac ) { 36 $this->trac_subdomain = $trac; 25 26 require __DIR__ . '/trac-notifications-db.php'; 27 37 28 if ( function_exists( 'add_db_table' ) ) { 38 29 $tables = array( 'ticket', '_ticket_subs', '_notifications', 'ticket_change', 'component', 'milestone', 'ticket_custom' ); … … 40 31 add_db_table( 'trac_' . $trac, $table ); 41 32 } 42 $this->trac = $GLOBALS['wpdb']; 43 } 33 } 34 $this->api = new Trac_Notifications_DB( $GLOBALS['wpdb'] ); 35 36 if ( 'core' === $trac ) { 37 require __DIR__ . '/trac-components.php'; 38 $this->components = new Make_Core_Trac_Components( $this->api ); 39 } 40 41 $this->trac = $trac; 42 43 add_filter( 'allowed_http_origins', array( $this, 'filter_allowed_http_origins' ) ); 44 add_action( 'template_redirect', array( $this, 'action_template_redirect' ) ); 45 add_shortcode( 'trac-notifications', array( $this, 'notification_settings_page' ) ); 44 46 } 45 47 46 48 function trac_url() { 47 return 'https://' . $this->trac _subdomain. '.trac.wordpress.org';49 return 'https://' . $this->trac . '.trac.wordpress.org'; 48 50 } 49 51 … … 76 78 exit; 77 79 } 78 }79 80 function get_trac_ticket( $ticket_id ) {81 return $this->trac->get_row( $this->trac->prepare( "SELECT * FROM ticket WHERE id = %d", $ticket_id ) );82 }83 84 function get_trac_ticket_focuses( $ticket_id ) {85 return $this->trac->get_var( $this->trac->prepare( "SELECT value FROM ticket_custom WHERE ticket = %d AND name = 'focuses'", $ticket_id ) );86 }87 88 function get_trac_ticket_participants( $ticket_id ) {89 // Make sure we suppress CC-only comments that still exist in the database.90 // Do this by suppressing any 'cc' changes and also any empty comments (used by Trac for comment numbering).91 // Empty comments are also used for other property changes made without comment, but those changes will still be returned by this query.92 $ignore_cc = "field <> 'cc' AND NOT (field = 'comment' AND newvalue = '') AND";93 return $this->trac->get_col( $this->trac->prepare( "SELECT DISTINCT author FROM ticket_change WHERE $ignore_cc ticket = %d", $ticket_id ) );94 }95 96 function get_trac_ticket_subscriptions( $ticket_id ) {97 $by_status = array( 'blocked' => array(), 'starred' => array() );98 $subscriptions = $this->trac->get_results( $this->trac->prepare( "SELECT username, status FROM _ticket_subs WHERE ticket = %s", $ticket_id ) );99 foreach ( $subscriptions as $subscription ) {100 $by_status[ $subscription->status ? 'starred' : 'blocked' ][] = $subscription->username;101 }102 return $by_status;103 80 } 104 81 … … 135 112 } 136 113 137 function get_trac_components() {138 return $this->trac->get_col( "SELECT name FROM component WHERE name <> 'WordPress.org site' ORDER BY name ASC" );139 }140 141 function get_trac_milestones() {142 // Only show 3.8+, when this feature was launched.143 return $this->trac->get_results( "SELECT name, completed FROM milestone144 WHERE name NOT IN ('WordPress.org', '3.5.3', '3.6.2', '3.7.2') AND (completed = 0 OR completed >= 1386864000000000)145 ORDER BY (completed = 0) DESC, name DESC", OBJECT_K );146 }147 148 function get_trac_notifications_for_user( $username ) {149 $rows = $this->trac->get_results( $this->trac->prepare( "SELECT type, value FROM _notifications WHERE username = %s ORDER BY type ASC, value ASC", $username ) );150 $notifications = array( 'component' => array(), 'milestone' => array(), 'focus' => array(), 'newticket' => array() );151 152 foreach ( $rows as $row ) {153 $notifications[ $row->type ][ $row->value ] = true;154 }155 $notifications['newticket'] = ! empty( $notifications['newticket']['1'] );156 157 return $notifications;158 }159 160 function get_trac_ticket_subscription_status_for_user( $ticket_id, $username ) {161 $status = $this->trac->get_var( $this->trac->prepare( "SELECT status FROM _ticket_subs WHERE username = %s AND ticket = %s", $username, $ticket_id ) );162 if ( null !== $status ) {163 $status = (int) $status;164 }165 return $status;166 }167 168 function get_trac_ticket_subscriptions_for_user( $username ) {169 return $this->trac->get_col( $this->trac->prepare( "SELECT ticket FROM _ticket_subs WHERE username = %s AND status = 1", $username ) );170 }171 172 114 function trac_notifications_box_actions() { 173 115 send_origin_headers(); … … 179 121 $username = wp_get_current_user()->user_login; 180 122 181 $ticket _id= absint( $_POST['trac-ticket-sub'] );182 if ( ! $ticket _id) {123 $ticket = absint( $_POST['trac-ticket-sub'] ); 124 if ( ! $ticket ) { 183 125 wp_send_json_error(); 184 126 } 185 127 186 $ticket = $this->get_trac_ticket( $ticket_id ); 187 if ( ! $ticket ) { 128 if ( ! $this->api->get_trac_ticket( $ticket ) ) { 188 129 wp_send_json_error(); 189 130 } … … 198 139 case 'block' : 199 140 $status = $action === 'subscribe' ? 1 : 0; 200 $this->trac->delete( '_ticket_subs', array( 'username' => $username, 'ticket' => $ticket_id ) ); 201 $result = $this->trac->insert( '_ticket_subs', array( 'username' => $username, 'ticket' => $ticket_id, 'status' => $status ) ); 141 $result = $this->api->update_subscription( $username, $ticket, $status ); 202 142 break; 203 143 … … 205 145 case 'unblock' : 206 146 $status = $action === 'unsubscribe' ? 1 : 0; 207 $result = $this-> trac->delete( '_ticket_subs', array( 'username' => $username, 'ticket' => $ticket_id, 'status' => $status ));147 $result = $this->api->delete_subscription( $username, $ticket, $status ); 208 148 break; 209 149 } … … 229 169 } 230 170 231 $subscribed_tickets = $this-> get_trac_ticket_subscriptions_for_user( $username );171 $subscribed_tickets = $this->api->get_trac_ticket_subscriptions_for_user( $username ); 232 172 if ( ! is_array( $subscribed_tickets ) ) { 233 173 wp_send_json_error(); … … 250 190 exit; 251 191 } 252 $ticket = $this-> get_trac_ticket( $ticket_id );192 $ticket = $this->api->get_trac_ticket( $ticket_id ); 253 193 if ( ! $ticket ) { 254 194 exit; 255 195 } 256 196 257 $focuses = explode( ', ', $this-> get_trac_ticket_focuses( $ticket_id ) );258 259 $notifications = $this-> get_trac_notifications_for_user( $username );260 261 $ticket_sub = $this-> get_trac_ticket_subscription_status_for_user( $ticket_id, $username );262 263 $ticket_subscriptions = $this-> get_trac_ticket_subscriptions( $ticket_id );197 $focuses = explode( ', ', $this->api->get_trac_ticket_focuses( $ticket_id ) ); 198 199 $notifications = $this->api->get_trac_notifications_for_user( $username ); 200 201 $ticket_sub = $this->api->get_trac_ticket_subscription_status_for_user( $ticket_id, $username ); 202 203 $ticket_subscriptions = $this->api->get_trac_ticket_subscriptions( $ticket_id ); 264 204 $stars = $ticket_subscriptions['starred']; 265 205 $star_count = count( $stars ); 266 206 267 $participants = $this-> get_trac_ticket_participants( $ticket_id );207 $participants = $this->api->get_trac_ticket_participants( $ticket_id ); 268 208 269 209 $unblocked_participants = array_diff( $participants, $ticket_subscriptions['blocked'] ); … … 368 308 $send = array( 'notifications-box' => ob_get_clean() ); 369 309 if ( isset( $this->components ) ) { 370 $send['maintainers'] = $this->components->get_ maintainers_by_component( $ticket->component );310 $send['maintainers'] = $this->components->get_component_maintainers( $ticket->component ); 371 311 } 372 312 wp_send_json_success( $send ); … … 379 319 } 380 320 381 $previous_tickets = $this->trac->get_results( $this->trac->prepare( "SELECT id, summary, type, status, resolution 382 FROM ticket WHERE reporter = %s AND id <= %d LIMIT 5", $ticket->reporter, $ticket->id ) ); 383 384 if ( count( $previous_tickets ) >= 5 ) { 321 $activity = $this->api->get_reporter_past_activity( $ticket->reporter, $ticket->id ); 322 323 if ( count( $activity['tickets'] ) >= 5 ) { 385 324 return; 386 325 } 387 326 388 if ( 1 == count( $previous_tickets ) ) { 389 $previous_comments = $this->trac->get_var( $this->trac->prepare( "SELECT ticket FROM ticket_change 390 WHERE field = 'comment' AND author = %s AND ticket <> %d LIMIT 1", $ticket->reporter, $ticket->id ) ); 391 327 if ( 1 == count( $activity['tickets'] ) ) { 392 328 $output = '<strong>Make sure ' . $ticket->reporter . ' receives a warm welcome.</strong><br/>'; 393 329 394 if ( $previous_comments) {330 if ( ! empty( $activity['comments'] ) ) { 395 331 $output .= 'They’ve commented before, but it᾿s their first ticket!'; 396 332 } else { … … 400 336 $mapping = array( 2 => 'second', 3 => 'third', 4 => 'fourth' ); 401 337 402 $output = '<strong>This is only ' . $ticket->reporter . '’s ' . $mapping[ count( $ previous_tickets) ] . ' ticket!</strong><br/>Previously:';403 404 foreach ( $ previous_ticketsas $t ) {338 $output = '<strong>This is only ' . $ticket->reporter . '’s ' . $mapping[ count( $activity['tickets'] ) ] . ' ticket!</strong><br/>Previously:'; 339 340 foreach ( $activity['tickets'] as $t ) { 405 341 if ( $t->id != $ticket->id ) { 406 342 $output .= ' ' . $this->ticket_link( $t ); … … 424 360 425 361 ob_start(); 426 $components = $this-> get_trac_components();427 $milestones = $this-> get_trac_milestones();362 $components = $this->api->get_components(); 363 $milestones = $this->api->get_milestones(); 428 364 $focuses = $this->get_trac_focuses(); 429 365 430 366 $username = wp_get_current_user()->user_login; 431 $notifications = $this-> get_trac_notifications_for_user( $username );367 $notifications = $this->api->get_trac_notifications_for_user( $username ); 432 368 433 369 if ( $_POST && isset( $_POST['trac-nonce'] ) ) { 434 370 check_admin_referer( 'save-trac-notifications', 'trac-nonce' ); 371 372 $changes = array(); 435 373 436 374 foreach ( array( 'milestone', 'component', 'focus' ) as $type ) { … … 438 376 foreach ( $_POST['notifications'][ $type ] as $value => $on ) { 439 377 if ( empty( $notifications[ $type ][ $value ] ) ) { 440 $ this->trac->insert( '_notifications', compact( 'username', 'type', 'value' ));378 $changes['insert'][] = compact( 'username', 'type', 'value' ); 441 379 $notifications[ $type ][ $value ] = true; 442 380 } … … 446 384 foreach ( $notifications[ $type ] as $value => $on ) { 447 385 if ( empty( $_POST['notifications'][ $type ][ $value ] ) ) { 448 $ this->trac->delete( '_notifications', compact( 'username', 'type', 'value' ));386 $changes['delete'][] = compact( 'username', 'type', 'value' ); 449 387 unset( $notifications[ $type ][ $value ] ); 450 388 } … … 452 390 } 453 391 if ( empty( $_POST['notifications']['newticket'] ) && ! empty( $notifications['newticket'] ) ) { 454 $ this->trac->delete( '_notifications', array( 'username' => $username, 'type' => 'newticket' ));392 $changes['delete'][] = array( 'username' => $username, 'type' => 'newticket' ); 455 393 $notifications[ 'newticket' ] = false; 456 394 } elseif ( ! empty( $_POST['notifications']['newticket'] ) && empty( $notifications['newticket'] ) ) { 457 $ this->trac->insert( '_notifications', array( 'username' => $username, 'type' => 'newticket', 'value' => '1' ));395 $changes['insert'][] = array( 'username' => $username, 'type' => 'newticket', 'value' => '1' ); 458 396 $notifications[ 'newticket' ] = true; 459 397 } 460 } 398 $this->api->update_notifications( $changes ); 399 } 400 461 401 ?> 462 402
Note: See TracChangeset
for help on using the changeset viewer.