<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[2022] sites/trunk/wordpress.org/public_html/wp-content/plugins/trac-notifications: Trac Notifications: Abstract all queries into a separate class.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="http://meta.trac.wordpress.org/changeset/2022">2022</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"http://meta.trac.wordpress.org/changeset/2022","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>nacin</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2015-11-01 10:27:39 +0000 (Sun, 01 Nov 2015)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Trac Notifications: Abstract all queries into a separate class.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginstracnotificationstraccomponentsphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/trac-notifications/trac-components.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginstracnotificationstracnotificationsphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/trac-notifications/trac-notifications.php</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginstracnotificationstracnotificationsdbphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/trac-notifications/trac-notifications-db.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginstracnotificationstraccomponentsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordpress.org/public_html/wp-content/plugins/trac-notifications/trac-components.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordpress.org/public_html/wp-content/plugins/trac-notifications/trac-components.php   2015-10-30 17:17:20 UTC (rev 2021)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/trac-notifications/trac-components.php     2015-11-01 10:27:39 UTC (rev 2022)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -3,7 +3,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> class Make_Core_Trac_Components {
</span><span class="cx" style="display: block; padding: 0 10px">        const last_x_days = 7;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function __construct() {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ function __construct( $api ) {
+               $this->api = $api;
</ins><span class="cx" style="display: block; padding: 0 10px">                 add_action( 'init', array( $this, 'init' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                add_action( 'pre_get_posts', array( $this, 'pre_get_posts' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                add_action( 'admin_menu', array( $this, 'admin_menu' ) );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -14,7 +15,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">                add_action( 'component_table_row', array( $this, 'component_table_row' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                add_filter( 'manage_component_posts_columns', array( $this, 'manage_posts_columns' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                add_action( 'manage_component_posts_custom_column', array( $this, 'manage_posts_custom_column' ), 10, 2 );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $this->trac = $GLOBALS['wpdb'];
</del><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        function init() {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -318,7 +318,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                echo "\n" . "Many contributors help maintain one or more components. These maintainers are vital to keeping WordPress development running as smoothly as possible. They triage new tickets, look after existing ones, spearhead or mentor tasks, pitch new ideas, curate roadmaps, and provide feedback to other contributors. Longtime maintainers with a deep understanding of particular areas of core are always seeking to mentor others to impart their knowledge.\n\n";
</span><span class="cx" style="display: block; padding: 0 10px">                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";
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $followers = $this->trac->get_col( $this->trac->prepare( "SELECT username FROM _notifications WHERE type = 'component' AND value = %s", $post->post_title ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $followers = $this->api->get_component_followers( $post->post_title );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $followers = "'" . implode( "', '", esc_sql( $followers ) ) . "'";
</span><span class="cx" style="display: block; padding: 0 10px">                $followers = $wpdb->get_results( "SELECT user_login, user_nicename, user_email FROM $wpdb->users WHERE user_login IN ($followers)" );
</span><span class="cx" style="display: block; padding: 0 10px">                if ( $followers ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -344,8 +344,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $type_filled = array_fill_keys( array( 'defect (bug)', 'enhancement', 'feature request', 'task (blessed)' ), 0 );
</span><span class="cx" style="display: block; padding: 0 10px">                $rows = wp_cache_get( 'trac_tickets_by_component_type_milestone' );
</span><span class="cx" style="display: block; padding: 0 10px">                if ( ! $rows ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $rows = $this->trac->get_results( "SELECT component, type, milestone, count(*) as count FROM ticket
-                               WHERE status <> 'closed' GROUP BY component, type, milestone ORDER BY component, type, milestone" );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $rows = $this->api->get_tickets_by_component_type_milestone();
</ins><span class="cx" style="display: block; padding: 0 10px">                         wp_cache_add( 'trac_tickets_by_component_type_milestone', $rows, '', 300 );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -363,13 +362,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $component_unreplied = wp_cache_get( 'trac_tickets_by_component_unreplied' );
</span><span class="cx" style="display: block; padding: 0 10px">                if ( ! $component_unreplied ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $rows = $this->trac->get_results( "SELECT id, component FROM ticket t
-                               WHERE id NOT IN (SELECT ticket FROM ticket_change WHERE ticket = t.id AND t.reporter <> author AND field = 'comment' AND newvalue <> '')
-                               AND status <> 'closed'" );
-                       $component_unreplied = array();
-                       foreach ( $rows as $row ) {
-                               $component_unreplied[ $row->component ][] = $row->id;
-                       }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $component_unreplied = $this->api->get_unreplied_ticket_counts_by_component();
</ins><span class="cx" style="display: block; padding: 0 10px">                         wp_cache_add( 'trac_tickets_by_component_unreplied', $component_unreplied, '', 300 );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -398,7 +391,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        echo '<h3>' . sprintf( _n( '%s open ticket', '%s open tickets', $component_count ), $component_count ) . ' in the ' . $component . ' component</h3>';
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $history = $this->get_component_history( $component );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $history = $this->api->get_component_history( $component );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $direction = '';
</span><span class="cx" style="display: block; padding: 0 10px">                if ( $history['change'] > 0 ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $direction = ' growing';
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -450,14 +443,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        function trac_content( $component ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $unreplied_tickets = $this->trac->get_results( $this->trac->prepare(
-                       "SELECT id, summary, status, resolution, milestone, value as focuses
-                       FROM ticket t LEFT JOIN ticket_custom c ON c.ticket = t.id AND c.name = 'focuses'
-                       WHERE id NOT IN (
-                               SELECT ticket FROM ticket_change
-                               WHERE ticket = t.id AND t.reporter <> author
-                               AND field = 'comment' AND newvalue <> ''
-                       ) AND status <> 'closed' AND component = %s", $component ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $unreplied_tickets = $this->api->get_unreplied_tickets_by_component( $component );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                if ( $unreplied_tickets ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $count = count( $unreplied_tickets );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -466,8 +452,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->render_tickets( $unreplied_tickets );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $next_milestone = $this->trac->get_results( $this->trac->prepare( "SELECT id, summary, status, resolution, milestone, value as focuses FROM ticket t
-                       LEFT JOIN ticket_custom c ON c.ticket = t.id AND c.name = 'focuses' WHERE component = %s AND status <> 'closed' AND milestone LIKE '_._'", $component ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $next_milestone = $this->api->get_tickets_in_next_milestone( $component );
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( $next_milestone ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $count = count( $next_milestone );
</span><span class="cx" style="display: block; padding: 0 10px">                        echo '<h3>' . sprintf( _n( '%s ticket slated for ' . $next_milestone[0]->milestone, '%s tickets slated for ' . $next_milestone[0]->milestone, $count ), $count ) . '</h3>';
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -475,36 +461,29 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->render_tickets( $next_milestone );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                return; // Ditch the rest for now.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $tickets_by_type = $this->api->get_ticket_counts_for_component( $component );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $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 );
-               foreach ( $tickets_by_type as &$object ) {
-                       $object = $object->count;
-               }
-               unset( $object );
-
</del><span class="cx" style="display: block; padding: 0 10px">                 $count = array_sum( $tickets_by_type );
</span><span class="cx" style="display: block; padding: 0 10px">                echo '<h3>' . sprintf( _n( '%s open ticket', '%s open tickets', $count ), $count ) . '</h3>';
</span><span class="cx" style="display: block; padding: 0 10px">                echo "\n" . '<strong>Open bugs: ' . $tickets_by_type['defect (bug)'] . '</strong>. ';
</span><span class="cx" style="display: block; padding: 0 10px">                echo $this->trac_query_link( 'View list on Trac', array( 'component' => $component, 'type' => 'defect (bug)' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                echo "\n\n";
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                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' ) ) ) {
-                       printf( '<h3>Open enhancements (%d)</h3>', count( $enhancements ) );
-                       echo $this->trac_query_link( 'View list on Trac', array( 'component' => $component, 'type' => 'enhancement' ) );
-                       $this->render_tickets( $enhancements );
-               }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         return;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                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)' ) ) ) {
-                       printf( '<h3>Open tasks (%d)</h3>', count( $tasks ) );
-                       echo $this->trac_query_link( 'View list on Trac', array( 'component' => $component, 'type' => 'task (blessed)' ) );
-                       $this->render_tickets( $tasks );
-               }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $types = array(
+                       'enhancement'     => 'Open enhancements',
+                       'task (blessed)'  => 'Open tasks',
+                       'feature request' => 'Open feature requests',
+               );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                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' ) ) ) {
-                       printf( '<h3>Open feature requests (%d)</h3>', count( $feature_requests ) );
-                       echo $this->trac_query_link( 'View list on Trac', array( 'component' => $component, 'type' => 'feature request' ) );
-                       $this->render_tickets( $feature_requests );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         foreach ( $types as $type => $title ) {
+                       $args = compact( 'component', 'type' );
+                       if ( $tickets = $this->api->get_tickets_by( $args ) ) {
+                               printf( '<h3>%s (%d)</h3>', $title, count( $tickets ) );
+                               echo $this->trac_query_link( 'View list on Trac', $args );
+                               $this->render_tickets( $tickets );   
+                       }
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -532,25 +511,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">                echo '</ul>';
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function get_component_history( $component ) {
-               $days_ago = ( time() - ( DAY_IN_SECONDS * self::last_x_days ) ) * 1000000;
-               $closed_reopened = $this->trac->get_results( $this->trac->prepare( "SELECT newvalue, COUNT(DISTINCT ticket) as count
-                       FROM ticket_change tc INNER JOIN ticket t ON tc.ticket = t.id
-                       WHERE field = 'status' AND (newvalue = 'closed' OR newvalue = 'reopened')
-                       AND tc.time >= %s AND t.component = %s GROUP BY newvalue", $days_ago, $component ), OBJECT_K );
-               $reopened = isset( $closed_reopened['reopened'] ) ? $closed_reopened['reopened']->count : 0;
-               $closed = isset( $closed_reopened['closed'] ) ? $closed_reopened['closed']->count : 0;
-               $opened = $this->trac->get_var( $this->trac->prepare( "SELECT COUNT(DISTINCT id) FROM ticket WHERE time >= %s AND component = %s", $days_ago, $component ) );
-               $assigned_unassigned = $this->trac->get_results( $this->trac->prepare( "SELECT IF(newvalue = %s, 'assigned', 'unassigned') as direction,
-                       COUNT(*) as count FROM ticket_change WHERE field = 'component' AND ( oldvalue = %s OR newvalue = %s ) AND time >= %s GROUP BY direction",
-                       $component, $component, $component, $days_ago ), OBJECT_K );
-               $assigned = isset( $assigned_unassigned['assigned'] ) ? $assigned_unassigned['assigned']->count : 0;
-               $unassigned = isset( $assigned_unassigned['unassigned'] ) ? $assigned_unassigned['unassigned']->count : 0;
-
-               $change = $opened + $reopened + $assigned - $closed - $unassigned;
-               return compact( 'change', 'opened', 'reopened', 'closed', 'assigned', 'unassigned' );
-       }
-
</del><span class="cx" style="display: block; padding: 0 10px">         function shortcode_logged_in( $attr, $content, $tag ) {
</span><span class="cx" style="display: block; padding: 0 10px">                if ( is_user_logged_in() == ( $tag == 'logged-in' ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        return $content;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -583,7 +543,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        echo '<option></option>';
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px">                if ( in_array( 'component', $topics ) ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $components = $this->trac->get_col( "SELECT name FROM component" );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $components = $this->api->get_components();
</ins><span class="cx" style="display: block; padding: 0 10px">                         foreach ( $components as $component ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                echo '<option value="component/' . esc_attr( str_replace( ' ', '+', $component ) ) . '">' . esc_html( $component ) . "</option>";
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -601,7 +561,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $component = $post->post_title;
</span><span class="cx" style="display: block; padding: 0 10px">                $this->generate_component_breakdowns();
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $history = $this->get_component_history( $component );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $history = $this->api->get_component_history( $component );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $arrow = '';
</span><span class="cx" style="display: block; padding: 0 10px">                if ( $history['change'] ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -632,7 +592,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        echo '<td></td>';
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $maintainers = $this->get_maintainers_by_post( $post->ID );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $maintainers = $this->get_component_maintainers_by_post( $post->ID );
</ins><span class="cx" style="display: block; padding: 0 10px">                 echo '<td class="no-grav maintainers">';
</span><span class="cx" style="display: block; padding: 0 10px">                foreach ( $maintainers as $maintainer ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        echo '<a href="//profiles.wordpress.org/' . esc_attr( $maintainer ) . '" title="' . esc_attr( $maintainer ) . '">' . get_avatar( get_user_by( 'login', $maintainer )->user_email, 24 ) . "</a>";
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -641,11 +601,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">                echo '</tr>';
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function get_maintainers_by_post( $post_id ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ function get_component_maintainers_by_post( $post_id ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                 return array_filter( array_map( 'trim', explode( ',', get_post_meta( $post_id, '_active_maintainers', true ) ) ) );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function get_maintainers_by_component( $component ) {
-               return $this->get_maintainers_by_post( get_page_by_title( $component, OBJECT, 'component' )->ID );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ function get_component_maintainers( $component ) {
+               return $this->get_component_maintainers_by_post( get_page_by_title( $component, OBJECT, 'component' )->ID );
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginstracnotificationstracnotificationsdbphp"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: sites/trunk/wordpress.org/public_html/wp-content/plugins/trac-notifications/trac-notifications-db.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordpress.org/public_html/wp-content/plugins/trac-notifications/trac-notifications-db.php                             (rev 0)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/trac-notifications/trac-notifications-db.php       2015-11-01 10:27:39 UTC (rev 2022)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,176 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+/**
+ * This class must execute queries valid for both MySQL and SQLite3.
+ */
+class Trac_Notifications_DB {
+       function __construct( $db ) {
+               $this->db = $db;
+       }
+
+       function get_unreplied_ticket_counts_by_component() {
+               $rows = $this->db->get_results( "SELECT id, component FROM ticket t
+                       WHERE id NOT IN (SELECT ticket FROM ticket_change WHERE ticket = t.id AND t.reporter <> author AND field = 'comment' AND newvalue <> '')
+                       AND status <> 'closed'" );
+               $component_unreplied = array();
+               foreach ( $rows as $row ) {
+                       $component_unreplied[ $row->component ][] = $row->id;
+               }
+               return $component_unreplied;
+       }
+
+       function get_unreplied_tickets_by_component( $component ) {
+               return $this->db->get_results( $this->db->prepare(
+                       "SELECT id, summary, status, resolution, milestone, value as focuses
+                       FROM ticket t LEFT JOIN ticket_custom c ON c.ticket = t.id AND c.name = 'focuses'
+                       WHERE id NOT IN (
+                               SELECT ticket FROM ticket_change
+                               WHERE ticket = t.id AND t.reporter <> author
+                               AND field = 'comment' AND newvalue <> ''
+                       ) AND status <> 'closed' AND component = %s", $component ) );
+       }
+
+       function get_tickets_by_component_type_milestone() {
+               return $this->db->get_results( "SELECT component, type, milestone, count(*) as count FROM ticket
+                       WHERE status <> 'closed' GROUP BY component, type, milestone ORDER BY component, type, milestone" );
+       }
+
+       function get_ticket_counts_for_component( $component ) {
+               $tickets_by_type = $this->db->get_results( $this->db->prepare( "SELECT type, COUNT(*) as count FROM ticket WHERE component = %s AND status <> 'closed' GROUP BY type", $component ), OBJECT_K );
+               foreach ( $tickets_by_type as &$object ) {
+                       $object = $object->count;
+               }
+               unset( $object );
+               return $tickets_by_type;
+       }
+
+       function get_tickets_by( $args ) {
+               $where = 'AND ' . implode( ' = %s AND ', array_keys( $args ) ) . ' = %s';
+               if ( ! isset( $args['status'] ) ) {
+                       $where .= " AND status <> 'closed'";
+               }
+               return $this->db->get_results( $this->db->prepare( "SELECT id, summary, status, resolution, milestone FROM ticket WHERE 1=1 $where", array_values( $args ) ) );
+       }
+
+       function get_components() {
+               return $this->db->get_col( "SELECT name FROM component WHERE name <> 'WordPress.org site' ORDER BY name ASC" );
+       }
+
+       function get_component_followers() {
+               return $this->db->get_col( $this->db->prepare( "SELECT username FROM _notifications WHERE type = 'component' AND value = %s", $post->post_title ) );
+       }
+
+       function get_component_history( $component ) {
+               $days_ago = ( time() - ( 86400 * Make_Core_Trac_Components::last_x_days ) ) * 1000000;
+               $closed_reopened = $this->db->get_results( $this->db->prepare( "SELECT newvalue, COUNT(DISTINCT ticket) as count
+                       FROM ticket_change tc INNER JOIN ticket t ON tc.ticket = t.id
+                       WHERE field = 'status' AND (newvalue = 'closed' OR newvalue = 'reopened')
+                       AND tc.time >= %s AND t.component = %s GROUP BY newvalue", $days_ago, $component ), OBJECT_K );
+               $reopened = isset( $closed_reopened['reopened'] ) ? $closed_reopened['reopened']->count : 0;
+               $closed = isset( $closed_reopened['closed'] ) ? $closed_reopened['closed']->count : 0;
+               $opened = $this->db->get_var( $this->db->prepare( "SELECT COUNT(DISTINCT id) FROM ticket WHERE time >= %s AND component = %s", $days_ago, $component ) );
+               $assigned_unassigned = $this->db->get_results( $this->db->prepare(
+                       "SELECT CASE WHEN newvalue = %s THEN 'assigned' ELSE 'unassigned' END as direction,
+                       COUNT(*) as count FROM ticket_change WHERE field = 'component' AND ( oldvalue = %s OR newvalue = %s ) AND time >= %s GROUP BY direction",
+                       $component, $component, $component, $days_ago ), OBJECT_K );
+               $assigned = isset( $assigned_unassigned['assigned'] ) ? $assigned_unassigned['assigned']->count : 0;
+               $unassigned = isset( $assigned_unassigned['unassigned'] ) ? $assigned_unassigned['unassigned']->count : 0;
+
+               $change = $opened + $reopened + $assigned - $closed - $unassigned;
+               return compact( 'change', 'opened', 'reopened', 'closed', 'assigned', 'unassigned' );
+       }
+
+       function get_milestones() {
+               // Only show 3.8+, when this feature was launched.
+               return $this->db->get_results( "SELECT name, completed FROM milestone
+                       WHERE name <> 'WordPress.org' AND (completed = 0 OR completed >= 1386864000000000)
+                       ORDER BY (completed = 0) DESC, name DESC", OBJECT_K );
+       }
+
+       function get_tickets_in_next_milestone( $component ) {
+               return $this->db->get_results( $this->db->prepare( "SELECT id, summary, status, resolution, milestone, value as focuses FROM ticket t
+                       LEFT JOIN ticket_custom c ON c.ticket = t.id AND c.name = 'focuses' WHERE component = %s AND status <> 'closed' AND milestone LIKE '_._'", $component ) );
+       }
+
+       function get_trac_ticket( $ticket_id ) {
+               return $this->db->get_row( $this->db->prepare( "SELECT * FROM ticket WHERE id = %d", $ticket_id ) );
+       }
+
+       function get_trac_ticket_focuses( $ticket_id ) {
+               return $this->db->get_var( $this->db->prepare( "SELECT value FROM ticket_custom WHERE ticket = %d AND name = 'focuses'", $ticket_id ) );
+       }
+
+       function get_trac_ticket_participants( $ticket_id ) {
+               // Make sure we suppress CC-only comments that still exist in the database.
+               // Do this by suppressing any 'cc' changes and also any empty comments (used by Trac for comment numbering).
+               // Empty comments are also used for other property changes made without comment, but those changes will still be returned by this query.
+               $ignore_cc = "field <> 'cc' AND NOT (field = 'comment' AND newvalue = '') AND";
+               return $this->db->get_col( $this->db->prepare( "SELECT DISTINCT author FROM ticket_change WHERE $ignore_cc ticket = %d", $ticket_id ) );
+       }
+
+       function get_trac_ticket_subscriptions( $ticket_id ) {
+               $by_status = array( 'blocked' => array(), 'starred' => array() );
+               $subscriptions = $this->db->get_results( $this->db->prepare( "SELECT username, status FROM _ticket_subs WHERE ticket = %s", $ticket_id ) );
+               foreach ( $subscriptions as $subscription ) {
+                       $by_status[ $subscription->status ? 'starred' : 'blocked' ][] = $subscription->username;
+               }
+               return $by_status;
+       }
+
+       function get_trac_ticket_subscription_status_for_user( $ticket_id, $username ) {
+               $status = $this->db->get_var( $this->db->prepare( "SELECT status FROM _ticket_subs WHERE username = %s AND ticket = %s", $username, $ticket_id ) );
+               if ( null !== $status ) {
+                       $status = (int) $status;
+               }
+               return $status;
+       }
+
+       function get_trac_notifications_for_user( $username ) {
+               $rows = $this->db->get_results( $this->db->prepare( "SELECT type, value FROM _notifications WHERE username = %s ORDER BY type ASC, value ASC", $username ) );
+               $notifications = array( 'component' => array(), 'milestone' => array(), 'focus' => array(), 'newticket' => array() );
+
+               foreach ( $rows as $row ) {
+                       $notifications[ $row->type ][ $row->value ] = true;
+               }
+               $notifications['newticket'] = ! empty( $notifications['newticket']['1'] );
+
+               return $notifications;
+       }
+
+       function get_trac_ticket_subscriptions_for_user( $username ) {
+               return $this->db->get_col( $this->db->prepare( "SELECT ticket FROM _ticket_subs WHERE username = %s AND status = 1", $username ) );
+       }
+
+       function get_reporter_past_activity( $reporter, $ticket ) {
+               $activity = array();
+
+               $activity['tickets'] = $this->db->get_results( $this->db->prepare( "SELECT id, summary, type, status, resolution
+                       FROM ticket WHERE reporter = %s AND id <= %d LIMIT 5", $reporter, $ticket ) );
+
+               if ( count( $previous_tickets ) === 1 ) {
+                       $activity['comments'] = (bool) $this->db->get_var( $this->db->prepare(
+                               "SELECT ticket FROM ticket_change WHERE field = 'comment'
+                               AND author = %s AND ticket <> %d LIMIT 1",
+                               $reporter, $ticket
+                       ) );
+               }
+
+               return $activity;
+       }
+
+       function update_subscription( $username, $ticket, $status ) {
+               $this->db->delete( '_ticket_subs', compact( 'username', 'ticket' ) );
+               return $this->db->insert( '_ticket_subs', compact( 'username', 'ticket', 'status' ) );
+       }
+
+       function delete_subscription( $username, $ticket, $status ) {
+               return $this->db->delete( '_ticket_subs', compact( 'username', 'ticket', 'status' ) );
+       }
+
+       function update_notifications( $all_changes ) {
+               foreach ( $all_changes as $method => $changes ) {
+                       foreach ( $changes as $where ) {
+                               call_user_func( array( $this->db, $method ), '_notifications', $where );
+                       }
+               }
+       }
+}
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: sites/trunk/wordpress.org/public_html/wp-content/plugins/trac-notifications/trac-notifications-db.php
</span><span class="cx" style="display: block; padding: 0 10px">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Added: svn:eol-style</h4></div>
<ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+native
</ins><span class="cx" style="display: block; padding: 0 10px">\ No newline at end of property
</span><a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginstracnotificationstracnotificationsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordpress.org/public_html/wp-content/plugins/trac-notifications/trac-notifications.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordpress.org/public_html/wp-content/plugins/trac-notifications/trac-notifications.php        2015-10-30 17:17:20 UTC (rev 2021)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/trac-notifications/trac-notifications.php  2015-11-01 10:27:39 UTC (rev 2022)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -7,7 +7,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> class wporg_trac_notifications {
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        protected $trac_subdomain;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ protected $trac;
</ins><span class="cx" style="display: block; padding: 0 10px">         protected $components;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        protected $tracs_supported = array( 'core', 'meta', 'themes', 'plugins' );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -22,29 +22,31 @@
</span><span class="cx" style="display: block; padding: 0 10px">                if ( 'core' === $trac && isset( $_GET['trac'] ) && in_array( $_GET['trac'], $this->tracs_supported_extra ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $trac = $_GET['trac'];
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $this->set_trac( $trac );
-               add_filter( 'allowed_http_origins', array( $this, 'filter_allowed_http_origins' ) );
-               add_action( 'template_redirect', array( $this, 'action_template_redirect' ) );
-               add_shortcode( 'trac-notifications', array( $this, 'notification_settings_page' ) );
-               if ( 'core' === $trac ) {
-                       require __DIR__ . '/trac-components.php';
-                       $this->components = new Make_Core_Trac_Components;
-               }
-       }
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function set_trac( $trac ) {
-               $this->trac_subdomain = $trac;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         require __DIR__ . '/trac-notifications-db.php';
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( function_exists( 'add_db_table' ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $tables = array( 'ticket', '_ticket_subs', '_notifications', 'ticket_change', 'component', 'milestone', 'ticket_custom' );
</span><span class="cx" style="display: block; padding: 0 10px">                        foreach ( $tables as $table ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                add_db_table( 'trac_' . $trac, $table );
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $this->trac = $GLOBALS['wpdb'];
</del><span class="cx" style="display: block; padding: 0 10px">                 }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $this->api = new Trac_Notifications_DB( $GLOBALS['wpdb'] );
+
+               if ( 'core' === $trac ) {
+                       require __DIR__ . '/trac-components.php';
+                       $this->components = new Make_Core_Trac_Components( $this->api );
+               }
+
+               $this->trac = $trac;
+
+               add_filter( 'allowed_http_origins', array( $this, 'filter_allowed_http_origins' ) );
+               add_action( 'template_redirect', array( $this, 'action_template_redirect' ) );
+               add_shortcode( 'trac-notifications', array( $this, 'notification_settings_page' ) );
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        function trac_url() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                return 'https://' . $this->trac_subdomain . '.trac.wordpress.org';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         return 'https://' . $this->trac . '.trac.wordpress.org';
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        function filter_allowed_http_origins( $origins ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -77,31 +79,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function get_trac_ticket( $ticket_id ) {
-               return $this->trac->get_row( $this->trac->prepare( "SELECT * FROM ticket WHERE id = %d", $ticket_id ) );
-       }
-
-       function get_trac_ticket_focuses( $ticket_id ) {
-               return $this->trac->get_var( $this->trac->prepare( "SELECT value FROM ticket_custom WHERE ticket = %d AND name = 'focuses'", $ticket_id ) );
-       }
-
-       function get_trac_ticket_participants( $ticket_id ) {
-               // Make sure we suppress CC-only comments that still exist in the database.
-               // Do this by suppressing any 'cc' changes and also any empty comments (used by Trac for comment numbering).
-               // Empty comments are also used for other property changes made without comment, but those changes will still be returned by this query.
-               $ignore_cc = "field <> 'cc' AND NOT (field = 'comment' AND newvalue = '') AND";
-               return $this->trac->get_col( $this->trac->prepare( "SELECT DISTINCT author FROM ticket_change WHERE $ignore_cc ticket = %d", $ticket_id ) );
-       }
-
-       function get_trac_ticket_subscriptions( $ticket_id ) {
-               $by_status = array( 'blocked' => array(), 'starred' => array() );
-               $subscriptions = $this->trac->get_results( $this->trac->prepare( "SELECT username, status FROM _ticket_subs WHERE ticket = %s", $ticket_id ) );
-               foreach ( $subscriptions as $subscription ) {
-                       $by_status[ $subscription->status ? 'starred' : 'blocked' ][] = $subscription->username;
-               }
-               return $by_status;
-       }
-
</del><span class="cx" style="display: block; padding: 0 10px">         function get_trac_focuses() {
</span><span class="cx" style="display: block; padding: 0 10px">                return array( 'accessibility', 'administration', 'docs', 'javascript', 'multisite', 'performance', 'rtl', 'template', 'ui' );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -134,41 +111,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">                return $tree;
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function get_trac_components() {
-               return $this->trac->get_col( "SELECT name FROM component WHERE name <> 'WordPress.org site' ORDER BY name ASC" );
-       }
-
-       function get_trac_milestones() {
-               // Only show 3.8+, when this feature was launched.
-               return $this->trac->get_results( "SELECT name, completed FROM milestone
-                       WHERE name NOT IN ('WordPress.org', '3.5.3', '3.6.2', '3.7.2') AND (completed = 0 OR completed >= 1386864000000000)
-                       ORDER BY (completed = 0) DESC, name DESC", OBJECT_K );
-       }
-
-       function get_trac_notifications_for_user( $username ) {
-               $rows = $this->trac->get_results( $this->trac->prepare( "SELECT type, value FROM _notifications WHERE username = %s ORDER BY type ASC, value ASC", $username ) );
-               $notifications = array( 'component' => array(), 'milestone' => array(), 'focus' => array(), 'newticket' => array() );
-
-               foreach ( $rows as $row ) {
-                       $notifications[ $row->type ][ $row->value ] = true;
-               }
-               $notifications['newticket'] = ! empty( $notifications['newticket']['1'] );
-
-               return $notifications;
-       }
-
-       function get_trac_ticket_subscription_status_for_user( $ticket_id, $username ) {
-               $status = $this->trac->get_var( $this->trac->prepare( "SELECT status FROM _ticket_subs WHERE username = %s AND ticket = %s", $username, $ticket_id ) );
-               if ( null !== $status ) {
-                       $status = (int) $status;
-               }
-               return $status;
-       }
-
-       function get_trac_ticket_subscriptions_for_user( $username ) {
-               return $this->trac->get_col( $this->trac->prepare( "SELECT ticket FROM _ticket_subs WHERE username = %s AND status = 1", $username ) );
-       }
-
</del><span class="cx" style="display: block; padding: 0 10px">         function trac_notifications_box_actions() {
</span><span class="cx" style="display: block; padding: 0 10px">                send_origin_headers();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -178,13 +120,12 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $username = wp_get_current_user()->user_login;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $ticket_id = absint( $_POST['trac-ticket-sub'] );
-               if ( ! $ticket_id ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $ticket = absint( $_POST['trac-ticket-sub'] );
+               if ( ! $ticket ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                         wp_send_json_error();
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $ticket = $this->get_trac_ticket( $ticket_id );
-               if ( ! $ticket ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( ! $this->api->get_trac_ticket( $ticket ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                         wp_send_json_error();
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -197,14 +138,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        case 'subscribe' :
</span><span class="cx" style="display: block; padding: 0 10px">                        case 'block' :
</span><span class="cx" style="display: block; padding: 0 10px">                                $status = $action === 'subscribe' ? 1 : 0;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                $this->trac->delete( '_ticket_subs', array( 'username' => $username, 'ticket' => $ticket_id ) );
-                               $result = $this->trac->insert( '_ticket_subs', array( 'username' => $username, 'ticket' => $ticket_id, 'status' => $status ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         $result = $this->api->update_subscription( $username, $ticket, $status );
</ins><span class="cx" style="display: block; padding: 0 10px">                                 break;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        case 'unsubscribe' :
</span><span class="cx" style="display: block; padding: 0 10px">                        case 'unblock' :
</span><span class="cx" style="display: block; padding: 0 10px">                                $status = $action === 'unsubscribe' ? 1 : 0;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                $result = $this->trac->delete( '_ticket_subs', array( 'username' => $username, 'ticket' => $ticket_id, 'status' => $status ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         $result = $this->api->delete_subscription( $username, $ticket, $status );
</ins><span class="cx" style="display: block; padding: 0 10px">                                 break;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -228,7 +168,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        wp_send_json_error();
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $subscribed_tickets = $this->get_trac_ticket_subscriptions_for_user( $username );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $subscribed_tickets = $this->api->get_trac_ticket_subscriptions_for_user( $username );
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( ! is_array( $subscribed_tickets ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        wp_send_json_error();
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -249,22 +189,22 @@
</span><span class="cx" style="display: block; padding: 0 10px">                if ( ! $ticket_id ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        exit;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $ticket = $this->get_trac_ticket( $ticket_id );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $ticket = $this->api->get_trac_ticket( $ticket_id );
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( ! $ticket ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        exit;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $focuses = explode( ', ', $this->get_trac_ticket_focuses( $ticket_id ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $focuses = explode( ', ', $this->api->get_trac_ticket_focuses( $ticket_id ) );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $notifications = $this->get_trac_notifications_for_user( $username );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $notifications = $this->api->get_trac_notifications_for_user( $username );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $ticket_sub = $this->get_trac_ticket_subscription_status_for_user( $ticket_id, $username );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $ticket_sub = $this->api->get_trac_ticket_subscription_status_for_user( $ticket_id, $username );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $ticket_subscriptions = $this->get_trac_ticket_subscriptions( $ticket_id );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $ticket_subscriptions = $this->api->get_trac_ticket_subscriptions( $ticket_id );
</ins><span class="cx" style="display: block; padding: 0 10px">                 $stars = $ticket_subscriptions['starred'];
</span><span class="cx" style="display: block; padding: 0 10px">                $star_count = count( $stars );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $participants = $this->get_trac_ticket_participants( $ticket_id );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $participants = $this->api->get_trac_ticket_participants( $ticket_id );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $unblocked_participants = array_diff( $participants, $ticket_subscriptions['blocked'] );
</span><span class="cx" style="display: block; padding: 0 10px">                $all_receiving_notifications = array_unique( array_merge( $stars, $unblocked_participants ) );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -367,7 +307,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $this->ticket_notes( $ticket, $username );
</span><span class="cx" style="display: block; padding: 0 10px">                $send = array( 'notifications-box' => ob_get_clean() );
</span><span class="cx" style="display: block; padding: 0 10px">                if ( isset( $this->components ) ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $send['maintainers'] = $this->components->get_maintainers_by_component( $ticket->component );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $send['maintainers'] = $this->components->get_component_maintainers( $ticket->component );
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><span class="cx" style="display: block; padding: 0 10px">                wp_send_json_success( $send );
</span><span class="cx" style="display: block; padding: 0 10px">                exit;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -378,20 +318,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        return;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $previous_tickets = $this->trac->get_results( $this->trac->prepare( "SELECT id, summary, type, status, resolution
-                       FROM ticket WHERE reporter = %s AND id <= %d LIMIT 5", $ticket->reporter, $ticket->id ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $activity = $this->api->get_reporter_past_activity( $ticket->reporter, $ticket->id );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( count( $previous_tickets ) >= 5 ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( count( $activity['tickets'] ) >= 5 ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                         return;
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( 1 == count( $previous_tickets ) ) {
-                       $previous_comments = $this->trac->get_var( $this->trac->prepare( "SELECT ticket FROM ticket_change
-                               WHERE field = 'comment' AND author = %s AND ticket <> %d LIMIT 1", $ticket->reporter, $ticket->id ) );
-
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( 1 == count( $activity['tickets'] ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                         $output = '<strong>Make sure ' . $ticket->reporter . ' receives a warm welcome.</strong><br/>';
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        if ( $previous_comments ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 if ( ! empty( $activity['comments'] ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                                 $output .= 'They&#8217;ve commented before, but it&#8127;s their first ticket!';
</span><span class="cx" style="display: block; padding: 0 10px">                        } else {
</span><span class="cx" style="display: block; padding: 0 10px">                                $output .= 'It&#8127;s their first ticket!';
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -399,9 +335,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">                } else {
</span><span class="cx" style="display: block; padding: 0 10px">                        $mapping = array( 2 => 'second', 3 => 'third', 4 => 'fourth' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $output = '<strong>This is only ' . $ticket->reporter . '&#8217;s ' . $mapping[ count( $previous_tickets ) ] . ' ticket!</strong><br/>Previously:';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $output = '<strong>This is only ' . $ticket->reporter . '&#8217;s ' . $mapping[ count( $activity['tickets'] ) ] . ' ticket!</strong><br/>Previously:';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                foreach ( $previous_tickets as $t ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         foreach ( $activity['tickets'] as $t ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                                         if ( $t->id != $ticket->id ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                                $output .= ' ' . $this->ticket_link( $t );
</span><span class="cx" style="display: block; padding: 0 10px">                                        }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -423,21 +359,23 @@
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                ob_start();
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $components = $this->get_trac_components();
-               $milestones = $this->get_trac_milestones();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $components = $this->api->get_components();
+               $milestones = $this->api->get_milestones();
</ins><span class="cx" style="display: block; padding: 0 10px">                 $focuses = $this->get_trac_focuses();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $username = wp_get_current_user()->user_login;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $notifications = $this->get_trac_notifications_for_user( $username );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $notifications = $this->api->get_trac_notifications_for_user( $username );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                if ( $_POST && isset( $_POST['trac-nonce'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        check_admin_referer( 'save-trac-notifications', 'trac-nonce' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        $changes = array();
+
</ins><span class="cx" style="display: block; padding: 0 10px">                         foreach ( array( 'milestone', 'component', 'focus' ) as $type ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                if ( ! empty( $_POST['notifications'][ $type ] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                        foreach ( $_POST['notifications'][ $type ] as $value => $on ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                                if ( empty( $notifications[ $type ][ $value ] ) ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                        $this->trac->insert( '_notifications', compact( 'username', 'type', 'value' ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                 $changes['insert'][] = compact( 'username', 'type', 'value' );
</ins><span class="cx" style="display: block; padding: 0 10px">                                                         $notifications[ $type ][ $value ] = true;
</span><span class="cx" style="display: block; padding: 0 10px">                                                }
</span><span class="cx" style="display: block; padding: 0 10px">                                        }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -445,19 +383,21 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                foreach ( $notifications[ $type ] as $value => $on ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                        if ( empty( $_POST['notifications'][ $type ][ $value ] ) ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                $this->trac->delete( '_notifications', compact( 'username', 'type', 'value' ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                         $changes['delete'][] = compact( 'username', 'type', 'value' );
</ins><span class="cx" style="display: block; padding: 0 10px">                                                 unset( $notifications[ $type ][ $value ] );
</span><span class="cx" style="display: block; padding: 0 10px">                                        }
</span><span class="cx" style="display: block; padding: 0 10px">                                }
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( empty( $_POST['notifications']['newticket'] ) && ! empty( $notifications['newticket'] ) ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                $this->trac->delete( '_notifications', array( 'username' => $username, 'type' => 'newticket' ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         $changes['delete'][] = array( 'username' => $username, 'type' => 'newticket' );
</ins><span class="cx" style="display: block; padding: 0 10px">                                 $notifications[ 'newticket' ] = false;
</span><span class="cx" style="display: block; padding: 0 10px">                        } elseif ( ! empty( $_POST['notifications']['newticket'] ) && empty( $notifications['newticket'] ) ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                $this->trac->insert( '_notifications', array( 'username' => $username, 'type' => 'newticket', 'value' => '1' ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         $changes['insert'][] = array( 'username' => $username, 'type' => 'newticket', 'value' => '1' );
</ins><span class="cx" style="display: block; padding: 0 10px">                                 $notifications[ 'newticket' ] = true;
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        $this->api->update_notifications( $changes );
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">                 ?>
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                <style>
</span></span></pre>
</div>
</div>

</body>
</html>