<!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>[13541] sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events: Translate: Sync "Translation Events" from GitHub</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 { white-space: pre-line; 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/13541">13541</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/13541","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>amieiro</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2024-04-16 12:41:37 +0000 (Tue, 16 Apr 2024)</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'>Translate: Sync "Translation Events" from GitHub</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsassetscsstranslationeventscss">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/assets/css/translation-events.css</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsautoloadphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/autoload.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesattendeeattendeerepositoryphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/attendee/attendee-repository.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludeseventeventformhandlerphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/event/event-form-handler.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludeseventeventphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/event/event.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesrouteseventdetailsphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/routes/event/details.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesrouteseventeditphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/routes/event/edit.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesroutesuserattendeventphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/routes/user/attend-event.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesroutesuserhosteventphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/routes/user/host-event.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesupgradephp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/upgrade.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventstemplateseventphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/templates/event.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventstemplateseventsheaderphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/templates/events-header.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventstemplateseventsmyeventsphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/templates/events-my-events.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventswporggptranslationeventsphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/wporg-gp-translation-events.php</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li>sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/stats/</li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesstatsstatscalculatorphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/stats/stats-calculator.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesstatsstatsimporterphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/stats/stats-importer.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesstatsstatslistenerphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/stats/stats-listener.php</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesstatscalculatorphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/stats-calculator.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesstatslistenerphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/stats-listener.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsassetscsstranslationeventscss"></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/wporg-gp-translation-events/assets/css/translation-events.css</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/wporg-gp-translation-events/assets/css/translation-events.css    2024-04-16 06:26:45 UTC (rev 13540)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/assets/css/translation-events.css      2024-04-16 12:41:37 UTC (rev 13541)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -100,7 +100,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">        margin-bottom: 0;
</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">-span.event-creator, span.event-you {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+span.event-not-attending {
</ins><span class="cx" style="display: block; padding: 0 10px">         display: block;
</span><span class="cx" style="display: block; padding: 0 10px">        margin-left: 55px;
</span><span class="cx" style="display: block; padding: 0 10px">        margin-top: 1em;
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsautoloadphp"></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/wporg-gp-translation-events/autoload.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/wporg-gp-translation-events/autoload.php 2024-04-16 06:26:45 UTC (rev 13540)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/autoload.php   2024-04-16 12:41:37 UTC (rev 13541)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -18,6 +18,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> require_once __DIR__ . '/includes/event/event-repository.php';
</span><span class="cx" style="display: block; padding: 0 10px"> require_once __DIR__ . '/includes/event/event-repository-cached.php';
</span><span class="cx" style="display: block; padding: 0 10px"> require_once __DIR__ . '/includes/event/event-form-handler.php';
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-require_once __DIR__ . '/includes/stats-calculator.php';
-require_once __DIR__ . '/includes/stats-listener.php';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+require_once __DIR__ . '/includes/stats/stats-calculator.php';
+require_once __DIR__ . '/includes/stats/stats-importer.php';
+require_once __DIR__ . '/includes/stats/stats-listener.php';
</ins><span class="cx" style="display: block; padding: 0 10px"> require_once __DIR__ . '/includes/event-text-snippet.php';
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesattendeeattendeerepositoryphp"></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/wporg-gp-translation-events/includes/attendee/attendee-repository.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/wporg-gp-translation-events/includes/attendee/attendee-repository.php    2024-04-16 06:26:45 UTC (rev 13540)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/attendee/attendee-repository.php      2024-04-16 12:41:37 UTC (rev 13541)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -119,7 +119,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * Get the hosts' users for an event.
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @param int $event_id The id of the event.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-         * @return array[Attendee] The hosts of the event.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  *
+        * @return Attendee[] The hosts of the event.
+        * @throws Exception
</ins><span class="cx" style="display: block; padding: 0 10px">          */
</span><span class="cx" style="display: block; padding: 0 10px">        public function get_hosts( int $event_id ): array {
</span><span class="cx" style="display: block; padding: 0 10px">                global $wpdb, $gp_table_prefix;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -127,10 +129,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">                // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
</span><span class="cx" style="display: block; padding: 0 10px">                // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
</span><span class="cx" style="display: block; padding: 0 10px">                // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $host_ids = $wpdb->get_col(
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $rows = $wpdb->get_results(
</ins><span class="cx" style="display: block; padding: 0 10px">                         $wpdb->prepare(
</span><span class="cx" style="display: block; padding: 0 10px">                                "
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                select user_id
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         select event_id, user_id
</ins><span class="cx" style="display: block; padding: 0 10px">                                 from {$gp_table_prefix}event_attendees
</span><span class="cx" style="display: block; padding: 0 10px">                                where event_id = %d and is_host = 1
</span><span class="cx" style="display: block; padding: 0 10px">                        ",
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -142,8 +144,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">                // phpcs:enable
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $hosts = array();
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                foreach ( $host_ids as $host_id ) {
-                       $hosts[] = $this->get_attendee( $event_id, $host_id );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         foreach ( $rows as $row ) {
+                       $host = new Attendee( $row->event_id, $row->user_id );
+                       $host->mark_as_host();
+                       $hosts[] = $host;
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><span class="cx" style="display: block; padding: 0 10px">                return $hosts;
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludeseventeventformhandlerphp"></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/wporg-gp-translation-events/includes/event/event-form-handler.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/wporg-gp-translation-events/includes/event/event-form-handler.php        2024-04-16 06:26:45 UTC (rev 13540)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/event/event-form-handler.php  2024-04-16 12:41:37 UTC (rev 13541)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -9,7 +9,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> use WP_Error;
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Attendee\Attendee;
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Attendee\Attendee_Repository;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-use Wporg\TranslationEvents\Stats_Calculator;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use Wporg\TranslationEvents\Stats\Stats_Calculator;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> class Event_Form_Handler {
</span><span class="cx" style="display: block; padding: 0 10px">        private Event_Repository_Interface $event_repository;
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludeseventeventphp"></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/wporg-gp-translation-events/includes/event/event.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/wporg-gp-translation-events/includes/event/event.php     2024-04-16 06:26:45 UTC (rev 13540)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/event/event.php       2024-04-16 12:41:37 UTC (rev 13541)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2,6 +2,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> namespace Wporg\TranslationEvents\Event;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use DateTimeImmutable;
</ins><span class="cx" style="display: block; padding: 0 10px"> use DateTimeZone;
</span><span class="cx" style="display: block; padding: 0 10px"> use Exception;
</span><span class="cx" style="display: block; padding: 0 10px"> use Throwable;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -86,6 +87,15 @@
</span><span class="cx" style="display: block; padding: 0 10px">                return $this->end;
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        public function is_active(): bool {
+               $now = new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) );
+               return $now >= $this->start->utc() && $now < $this->end->utc();
+       }
+
+       public function is_past(): bool {
+               return $this->end->is_in_the_past();
+       }
+
</ins><span class="cx" style="display: block; padding: 0 10px">         public function timezone(): DateTimeZone {
</span><span class="cx" style="display: block; padding: 0 10px">                return $this->timezone;
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesrouteseventdetailsphp"></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/wporg-gp-translation-events/includes/routes/event/details.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/wporg-gp-translation-events/includes/routes/event/details.php    2024-04-16 06:26:45 UTC (rev 13540)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/routes/event/details.php      2024-04-16 12:41:37 UTC (rev 13541)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -8,7 +8,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Attendee\Attendee_Repository;
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Event\Event_Repository_Interface;
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Routes\Route;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-use Wporg\TranslationEvents\Stats_Calculator;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use Wporg\TranslationEvents\Stats\Stats_Calculator;
</ins><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Translation_Events;
</span><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_htmlwpcontentpluginswporggptranslationeventsincludesrouteseventeditphp"></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/wporg-gp-translation-events/includes/routes/event/edit.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/wporg-gp-translation-events/includes/routes/event/edit.php       2024-04-16 06:26:45 UTC (rev 13540)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/routes/event/edit.php 2024-04-16 12:41:37 UTC (rev 13541)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -6,7 +6,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Attendee\Attendee_Repository;
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Event\Event_Repository_Interface;
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Routes\Route;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-use Wporg\TranslationEvents\Stats_Calculator;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use Wporg\TranslationEvents\Stats\Stats_Calculator;
</ins><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Translation_Events;
</span><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_htmlwpcontentpluginswporggptranslationeventsincludesroutesuserattendeventphp"></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/wporg-gp-translation-events/includes/routes/user/attend-event.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/wporg-gp-translation-events/includes/routes/user/attend-event.php        2024-04-16 06:26:45 UTC (rev 13540)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/routes/user/attend-event.php  2024-04-16 12:41:37 UTC (rev 13541)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -6,6 +6,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Attendee\Attendee_Repository;
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Event\Event_Repository_Interface;
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Routes\Route;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use Wporg\TranslationEvents\Stats\Stats_Importer;
</ins><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Translation_Events;
</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">@@ -12,15 +13,20 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * Toggle whether the current user is attending an event.
</span><span class="cx" style="display: block; padding: 0 10px">  * If the user is not currently marked as attending, they will be marked as attending.
</span><span class="cx" style="display: block; padding: 0 10px">  * If the user is currently marked as attending, they will be marked as not attending.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ *
+ * If the user is marked as attending, and the event is active at that moment, stats for the translations the user
+ * created since the event started are imported.
</ins><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> class Attend_Event_Route extends Route {
</span><span class="cx" style="display: block; padding: 0 10px">        private Event_Repository_Interface $event_repository;
</span><span class="cx" style="display: block; padding: 0 10px">        private Attendee_Repository $attendee_repository;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        private Stats_Importer $stats_importer;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        public function __construct() {
</span><span class="cx" style="display: block; padding: 0 10px">                parent::__construct();
</span><span class="cx" style="display: block; padding: 0 10px">                $this->event_repository    = Translation_Events::get_event_repository();
</span><span class="cx" style="display: block; padding: 0 10px">                $this->attendee_repository = Translation_Events::get_attendee_repository();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $this->stats_importer      = new Stats_Importer();
</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">        public function handle( int $event_id ): void {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -28,6 +34,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                if ( ! $user ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->die_with_error( esc_html__( 'Only logged-in users can attend events', 'gp-translation-events' ), 403 );
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $user_id = $user->ID;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $event = $this->event_repository->get_event( $event_id );
</span><span class="cx" style="display: block; padding: 0 10px">                if ( ! $event ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -34,15 +41,22 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        $this->die_with_404();
</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">-                $attendee = $this->attendee_repository->get_attendee( $event->id(), $user->ID );
-               if ( $attendee instanceof Attendee && $attendee->is_host() && ( 1 === count( $this->attendee_repository->get_hosts( $event_id ) ) ) ) {
-                       $this->die_with_error( esc_html__( 'The event needs a host. Add a new host before stopping to attend the event.', 'gp-translation-events' ), 403 );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( $event->is_past() ) {
+                       $this->die_with_error( esc_html__( 'Cannot attend or un-attend a past event', 'gp-translation-events' ), 403 );
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               $attendee = $this->attendee_repository->get_attendee( $event->id(), $user_id );
</ins><span class="cx" style="display: block; padding: 0 10px">                 if ( $attendee instanceof Attendee ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $this->attendee_repository->remove_attendee( $event->id(), $user->ID );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $this->attendee_repository->remove_attendee( $event->id(), $user_id );
</ins><span class="cx" style="display: block; padding: 0 10px">                 } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $attendee = new Attendee( $event->id(), $user->ID );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 $attendee = new Attendee( $event->id(), $user_id );
</ins><span class="cx" style="display: block; padding: 0 10px">                         $this->attendee_repository->insert_attendee( $attendee );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+                       // If the event is active right now,
+                       // import stats for translations the user created since the event started.
+                       if ( $event->is_active() ) {
+                               $this->stats_importer->import_for_user_and_event( $user_id, $event );
+                       }
</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">                wp_safe_redirect( gp_url( "/events/{$event->slug()}" ) );
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesroutesuserhosteventphp"></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/wporg-gp-translation-events/includes/routes/user/host-event.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/wporg-gp-translation-events/includes/routes/user/host-event.php  2024-04-16 06:26:45 UTC (rev 13540)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/routes/user/host-event.php    2024-04-16 12:41:37 UTC (rev 13541)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -50,9 +50,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">                $affected_attendee = $this->attendee_repository->get_attendee( $event_id, $user_id );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( $affected_attendee instanceof Attendee && $affected_attendee->is_host() && ( 1 === count( $this->attendee_repository->get_hosts( $event_id ) ) ) ) {
-                       $this->die_with_error( esc_html__( 'The event needs a host. Add a new host before stopping to attend the event.', 'gp-translation-events' ), 403 );
-               }
</del><span class="cx" style="display: block; padding: 0 10px">                 // The user is attending to the event, so if I don't find the attendee, I won't create it.
</span><span class="cx" style="display: block; padding: 0 10px">                if ( $affected_attendee instanceof Attendee ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( $affected_attendee->is_host() ) {
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesstatsstatscalculatorphp"></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/wporg-gp-translation-events/includes/stats/stats-calculator.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/wporg-gp-translation-events/includes/stats/stats-calculator.php                          (rev 0)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/stats/stats-calculator.php    2024-04-16 12:41:37 UTC (rev 13541)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,339 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+namespace Wporg\TranslationEvents\Stats;
+
+use Exception;
+use WP_Post;
+use WP_User;
+use GP;
+use GP_Locale;
+use GP_Locales;
+use DateTimeImmutable;
+use DateTimeZone;
+
+class Stats_Row {
+       public int $created;
+       public int $reviewed;
+       public int $users;
+       public ?GP_Locale $language = null;
+
+       public function __construct( $created, $reviewed, $users, ?GP_Locale $language = null ) {
+               $this->created  = $created;
+               $this->reviewed = $reviewed;
+               $this->users    = $users;
+               $this->language = $language;
+       }
+}
+
+class Event_Stats {
+       /**
+        * Associative array of rows, with the locale as key.
+        *
+        * @var Stats_Row[]
+        */
+       private array $rows = array();
+
+       private Stats_Row $totals;
+
+       /**
+        * Add a stats row.
+        *
+        * @throws Exception When incorrect locale is passed.
+        */
+       public function add_row( string $locale, Stats_Row $row ) {
+               if ( ! $locale ) {
+                       throw new Exception( 'locale must not be empty' );
+               }
+               $this->rows[ $locale ] = $row;
+       }
+
+       public function set_totals( Stats_Row $totals ) {
+               $this->totals = $totals;
+       }
+
+       /**
+        * Get an associative array of rows, with the locale as key.
+        *
+        * @return Stats_Row[]
+        */
+       public function rows(): array {
+               uasort(
+                       $this->rows,
+                       function ( $a, $b ) {
+                               if ( ! $a->language && ! $b->language ) {
+                                       return 0;
+                               }
+                               if ( ! $a->language ) {
+                                       return -1;
+                               }
+                               if ( ! $b->language ) {
+                                       return 1;
+                               }
+
+                               return strcasecmp( $a->language->english_name, $b->language->english_name );
+                       }
+               );
+
+               return $this->rows;
+       }
+
+       public function totals(): Stats_Row {
+               return $this->totals;
+       }
+}
+
+class Stats_Calculator {
+       /**
+        * Get stats for an event.
+        *
+        * @throws Exception When stats calculation failed.
+        */
+       public function for_event( int $event_id ): Event_Stats {
+               $stats = new Event_Stats();
+               global $wpdb, $gp_table_prefix;
+
+               // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
+               // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
+               // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
+               // phpcs thinks we're doing a schema change but we aren't.
+               // phpcs:disable WordPress.DB.DirectDatabaseQuery.SchemaChange
+               $rows = $wpdb->get_results(
+                       $wpdb->prepare(
+                               "
+                               select locale,
+                                       sum(action = 'create') as created,
+                                       count(*) as total,
+                                       count(distinct user_id) as users
+                               from {$gp_table_prefix}event_actions
+                               where event_id = %d
+                               group by locale with rollup
+                       ",
+                               array(
+                                       $event_id,
+                               )
+                       )
+               );
+               // phpcs:enable
+
+               foreach ( $rows as $index => $row ) {
+                       $is_totals = null === $row->locale;
+                       if ( $is_totals && array_key_last( $rows ) !== $index ) {
+                               // If this is not the last row, something is wrong in the data in the database table
+                               // or there's a bug in the query above.
+                               throw new Exception(
+                                       'Only the last row should have no locale but we found a non-last row with no locale.'
+                               );
+                       }
+
+                       $lang = GP_Locales::by_slug( $row->locale );
+                       if ( ! $lang ) {
+                               $lang = null;
+                       }
+
+                       $stats_row = new Stats_Row(
+                               $row->created,
+                               $row->total - $row->created,
+                               $row->users,
+                               $lang
+                       );
+
+                       if ( ! $is_totals ) {
+                               $stats->add_row( $row->locale, $stats_row );
+                       } else {
+                               $stats->set_totals( $stats_row );
+                       }
+               }
+
+               return $stats;
+       }
+
+       /**
+        * Get contributors for an event.
+        */
+       public function get_contributors( int $event_id ): array {
+               global $wpdb, $gp_table_prefix;
+
+               // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
+               // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
+               // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
+               // phpcs thinks we're doing a schema change but we aren't.
+               // phpcs:disable WordPress.DB.DirectDatabaseQuery.SchemaChange
+               $rows = $wpdb->get_results(
+                       $wpdb->prepare(
+                               "
+                               select user_id, group_concat( distinct locale ) as locales
+                               from {$gp_table_prefix}event_actions
+                               where event_id = %d
+                               group by user_id
+                       ",
+                               array(
+                                       $event_id,
+                               )
+                       )
+               );
+               // phpcs:enable
+
+               $users = array();
+               foreach ( $rows as $row ) {
+                       $user          = new WP_User( $row->user_id );
+                       $user->locales = explode( ',', $row->locales );
+                       $users[]       = $user;
+               }
+
+               uasort(
+                       $users,
+                       function ( $a, $b ) {
+                               return strcasecmp( $a->display_name, $b->display_name );
+                       }
+               );
+
+               return $users;
+       }
+
+       /**
+        * Get attendees without contributions for an event.
+        */
+       public function get_attendees_not_contributing( int $event_id ): array {
+               global $wpdb, $gp_table_prefix;
+
+               // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
+               // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
+               // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
+               $all_attendees_ids = $wpdb->get_col(
+                       $wpdb->prepare(
+                               "
+                               select distinct user_id
+                               from {$gp_table_prefix}event_attendees
+                               where event_id = %d
+                       ",
+                               array(
+                                       $event_id,
+                               )
+                       ),
+               );
+
+               $contributing_ids = $wpdb->get_col(
+                       $wpdb->prepare(
+                               "
+                               select distinct user_id
+                               from {$gp_table_prefix}event_actions
+                               where event_id = %d
+                       ",
+                               array(
+                                       $event_id,
+                               )
+                       )
+               );
+
+               $attendees_not_contributing_ids = array_diff( $all_attendees_ids, $contributing_ids );
+
+               $attendees_not_contributing = array();
+               foreach ( $attendees_not_contributing_ids as $user_id ) {
+                       $attendees_not_contributing[] = new WP_User( $user_id );
+               }
+
+               return $attendees_not_contributing;
+       }
+
+       /**
+        * Get projects for an event.
+        */
+       public function get_projects( int $event_id ): array {
+               global $wpdb, $gp_table_prefix;
+
+               // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
+               // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
+               // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
+               // phpcs thinks we're doing a schema change but we aren't.
+               // phpcs:disable WordPress.DB.DirectDatabaseQuery.SchemaChange
+               $rows = $wpdb->get_results(
+                       $wpdb->prepare(
+                               "
+                               select
+                                       o.project_id as project,
+                                       group_concat( distinct e.locale ) as locales,
+                                       sum(action = 'create') as created,
+                                       count(*) as total,
+                                       count(distinct user_id) as users
+                               from {$gp_table_prefix}event_actions e, {$gp_table_prefix}originals o
+                               where e.event_id = %d and e.original_id = o.id
+                               group by o.project_id
+                       ",
+                               array(
+                                       $event_id,
+                               )
+                       )
+               );
+               // phpcs:enable
+
+               $projects = array();
+               foreach ( $rows as $row ) {
+                       $row->project      = GP::$project->get( $row->project );
+                       $project_name      = $row->project->name;
+                       $parent_project_id = $row->project->parent_project_id;
+                       while ( $parent_project_id ) {
+                               $parent_project    = GP::$project->get( $parent_project_id );
+                               $parent_project_id = $parent_project->parent_project_id;
+                               $project_name      = substr( htmlspecialchars_decode( $parent_project->name ), 0, 35 ) . ' - ' . $project_name;
+                       }
+                       $projects[ $project_name ] = $row;
+               }
+
+               ksort( $projects );
+
+               return $projects;
+       }
+
+       /**
+        * Check if an event has stats.
+        *
+        * @param int $event_id The id of the event to check.
+        *
+        * @return bool True if the event has stats, false otherwise.
+        */
+       public function event_has_stats( int $event_id ): bool {
+               try {
+                       $stats = $this->for_event( $event_id );
+               } catch ( Exception $e ) {
+                       return false;
+               }
+
+               return ! empty( $stats->rows() );
+       }
+
+       /**
+        * Check if a user is a first time contributor.
+        *
+        * @param Event_Start_Date $event_start The event start date.
+        * @param int              $user_id      The user ID.
+        *
+        * @return bool True if the user is a first time contributor, false otherwise.
+        */
+       public function is_first_time_contributor( $event_start, $user_id ) {
+               global $wpdb, $gp_table_prefix;
+
+               // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
+               // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
+               // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
+               // phpcs:disable WordPress.DB.DirectDatabaseQuery.SchemaChange
+               $users_first_translation_date = $wpdb->get_var(
+                       $wpdb->prepare(
+                               "
+                       select min(date_added) from {$gp_table_prefix}translations where user_id = %d
+               ",
+                               array(
+                                       $user_id,
+                               )
+                       )
+               );
+
+               if ( get_userdata( $user_id ) && ! $users_first_translation_date ) {
+                       return true;
+               }
+               $event_start_date_time  = new DateTimeImmutable( $event_start->__toString(), new DateTimeZone( 'UTC' ) );
+               $first_translation_date = new DateTimeImmutable( $users_first_translation_date, new DateTimeZone( 'UTC' ) );
+               // A first time contributor is someone whose first translation was made not earlier than 24 hours before the event.
+               $event_start_date_time = $event_start_date_time->modify( '-1 day' );
+               return $event_start_date_time <= $first_translation_date;
+       }
+}
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/stats/stats-calculator.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_htmlwpcontentpluginswporggptranslationeventsincludesstatsstatsimporterphp"></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/wporg-gp-translation-events/includes/stats/stats-importer.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/wporg-gp-translation-events/includes/stats/stats-importer.php                            (rev 0)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/stats/stats-importer.php      2024-04-16 12:41:37 UTC (rev 13541)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,41 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+namespace Wporg\TranslationEvents\Stats;
+
+use Wporg\TranslationEvents\Event\Event;
+
+class Stats_Importer {
+       /**
+        * Imports the contributions a user made while a given event was active.
+        */
+       public function import_for_user_and_event( int $user_id, Event $event ): void {
+               global $wpdb, $gp_table_prefix;
+
+               // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
+               // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
+               // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
+               $wpdb->query(
+                       $wpdb->prepare(
+                               "
+                               insert ignore into {$gp_table_prefix}event_actions
+                                   (event_id, user_id, original_id, locale, action, happened_at)
+                               select %d, t.user_id, t.original_id, ts.locale, %s, t.date_added
+                               from {$gp_table_prefix}translations t,
+                                    {$gp_table_prefix}translation_sets ts
+                               where t.user_id = %d
+                                 and t.translation_set_id = ts.id
+                                 and t.status in ( 'current', 'waiting', 'changesrequested', 'fuzzy' )
+                                 and date_added between %s and %s
+                               ",
+                               array(
+                                       'event_id'          => $event->id(),
+                                       'action'            => Stats_Listener::ACTION_CREATE,
+                                       'user_id'           => $user_id,
+                                       'date_added_after'  => $event->start()->utc()->format( 'Y-m-d H:i:s' ),
+                                       'date_added_before' => $event->end()->utc()->format( 'Y-m-d H:i:s' ),
+                               ),
+                       ),
+               );
+               // phpcs:enable
+       }
+}
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/stats/stats-importer.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_htmlwpcontentpluginswporggptranslationeventsincludesstatsstatslistenerphp"></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/wporg-gp-translation-events/includes/stats/stats-listener.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/wporg-gp-translation-events/includes/stats/stats-listener.php                            (rev 0)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/stats/stats-listener.php      2024-04-16 12:41:37 UTC (rev 13541)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,136 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+namespace Wporg\TranslationEvents\Stats;
+
+use DateTimeImmutable;
+use DateTimeZone;
+use Exception;
+use GP_Translation;
+use GP_Translation_Set;
+use Wporg\TranslationEvents\Attendee\Attendee_Repository;
+use Wporg\TranslationEvents\Event\Event;
+use Wporg\TranslationEvents\Event\Event_Repository_Interface;
+
+class Stats_Listener {
+       const ACTION_CREATE          = 'create';
+       const ACTION_APPROVE         = 'approve';
+       const ACTION_REJECT          = 'reject';
+       const ACTION_REQUEST_CHANGES = 'request_changes';
+
+       private Attendee_Repository $attendee_repository;
+       private Event_Repository_Interface $event_repository;
+
+       public function __construct(
+               Event_Repository_Interface $event_repository,
+               Attendee_Repository $attendee_repository
+       ) {
+               $this->event_repository    = $event_repository;
+               $this->attendee_repository = $attendee_repository;
+       }
+
+       public function start(): void {
+               add_action(
+                       'gp_translation_created',
+                       function ( $translation ) {
+                               $happened_at = DateTimeImmutable::createFromFormat( 'Y-m-d H:i:s', $translation->date_added, new DateTimeZone( 'UTC' ) );
+                               if ( ! $translation->user_id ) {
+                                       return;
+                               }
+                               $this->handle_action( $translation, $translation->user_id, self::ACTION_CREATE, $happened_at );
+                       },
+               );
+
+               add_action(
+                       'gp_translation_saved',
+                       function ( $translation, $translation_before ) {
+                               $user_id     = $translation->user_id_last_modified;
+                               $status      = $translation->status;
+                               $happened_at = DateTimeImmutable::createFromFormat( 'Y-m-d H:i:s', $translation->date_modified, new DateTimeZone( 'UTC' ) );
+
+                               if ( $translation_before->status === $status ) {
+                                       // Translation hasn't changed status, so there's nothing for us to track.
+                                       return;
+                               }
+
+                               $action = null;
+                               switch ( $status ) {
+                                       case 'current':
+                                               $action = self::ACTION_APPROVE;
+                                               break;
+                                       case 'rejected':
+                                               $action = self::ACTION_REJECT;
+                                               break;
+                                       case 'changesrequested':
+                                               $action = self::ACTION_REQUEST_CHANGES;
+                                               break;
+                               }
+
+                               if ( $action && $user_id ) {
+                                       $this->handle_action( $translation, $user_id, $action, $happened_at );
+                               }
+                       },
+                       10,
+                       2,
+               );
+       }
+
+       private function handle_action( GP_Translation $translation, int $user_id, string $action, DateTimeImmutable $happened_at ): void {
+               try {
+                       // Get events that are active when the action happened, for which the user is registered for.
+                       $active_events = $this->event_repository->get_current_events();
+                       $events        = $this->select_events_user_is_registered_for( $active_events->events, $user_id );
+
+                       // phpcs:ignore Generic.Commenting.DocComment.MissingShort
+                       /** @var GP_Translation_Set $translation_set Translation set */
+                       $translation_set = ( new GP_Translation_Set() )->find_one( array( 'id' => $translation->translation_set_id ) );
+                       global $wpdb, $gp_table_prefix;
+
+                       foreach ( $events as $event ) {
+                               // A given user can only do one action on a specific translation.
+                               // So we insert ignore, which will keep only the first action.
+                               // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
+                               // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
+                               // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
+                               $wpdb->query(
+                                       $wpdb->prepare(
+                                               "insert ignore into {$gp_table_prefix}event_actions (event_id, locale, user_id, original_id, action, happened_at) values (%d, %s, %d, %d, %s, %s)",
+                                               array(
+                                                       // Start unique key.
+                                                       'event_id'    => $event->id(),
+                                                       'locale'      => $translation_set->locale,
+                                                       'user_id'     => $user_id,
+                                                       'original_id' => $translation->original_id,
+                                                       // End unique key.
+                                                       'action'      => $action,
+                                                       'happened_at' => $happened_at->format( 'Y-m-d H:i:s' ),
+                                               ),
+                                       ),
+                               );
+                               // phpcs:enable
+                       }
+               } catch ( Exception $exception ) {
+                       // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
+                       error_log( $exception );
+               }
+       }
+
+       /**
+        * Filter an array of events so that it only includes events the given user is attending.
+        *
+        * @param Event[] $events Events.
+        *
+        * @return Event[]
+        */
+       // phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
+       // phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.Found
+       private function select_events_user_is_registered_for( array $events, int $user_id ): array {
+               $attending_event_ids = $this->attendee_repository->get_events_for_user( $user_id );
+               return array_filter(
+                       $events,
+                       function ( Event $event ) use ( $attending_event_ids ) {
+                               return in_array( $event->id(), $attending_event_ids, true );
+                       }
+               );
+       }
+       // phpcs:enable
+}
</ins><span class="cx" style="display: block; padding: 0 10px">Property changes on: sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/stats/stats-listener.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_htmlwpcontentpluginswporggptranslationeventsincludesstatscalculatorphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/stats-calculator.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/wporg-gp-translation-events/includes/stats-calculator.php        2024-04-16 06:26:45 UTC (rev 13540)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/stats-calculator.php  2024-04-16 12:41:37 UTC (rev 13541)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,339 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-
-namespace Wporg\TranslationEvents;
-
-use Exception;
-use WP_Post;
-use WP_User;
-use GP;
-use GP_Locale;
-use GP_Locales;
-use DateTimeImmutable;
-use DateTimeZone;
-
-class Stats_Row {
-       public int $created;
-       public int $reviewed;
-       public int $users;
-       public ?GP_Locale $language = null;
-
-       public function __construct( $created, $reviewed, $users, ?GP_Locale $language = null ) {
-               $this->created  = $created;
-               $this->reviewed = $reviewed;
-               $this->users    = $users;
-               $this->language = $language;
-       }
-}
-
-class Event_Stats {
-       /**
-        * Associative array of rows, with the locale as key.
-        *
-        * @var Stats_Row[]
-        */
-       private array $rows = array();
-
-       private Stats_Row $totals;
-
-       /**
-        * Add a stats row.
-        *
-        * @throws Exception When incorrect locale is passed.
-        */
-       public function add_row( string $locale, Stats_Row $row ) {
-               if ( ! $locale ) {
-                       throw new Exception( 'locale must not be empty' );
-               }
-               $this->rows[ $locale ] = $row;
-       }
-
-       public function set_totals( Stats_Row $totals ) {
-               $this->totals = $totals;
-       }
-
-       /**
-        * Get an associative array of rows, with the locale as key.
-        *
-        * @return Stats_Row[]
-        */
-       public function rows(): array {
-               uasort(
-                       $this->rows,
-                       function ( $a, $b ) {
-                               if ( ! $a->language && ! $b->language ) {
-                                       return 0;
-                               }
-                               if ( ! $a->language ) {
-                                       return -1;
-                               }
-                               if ( ! $b->language ) {
-                                       return 1;
-                               }
-
-                               return strcasecmp( $a->language->english_name, $b->language->english_name );
-                       }
-               );
-
-               return $this->rows;
-       }
-
-       public function totals(): Stats_Row {
-               return $this->totals;
-       }
-}
-
-class Stats_Calculator {
-       /**
-        * Get stats for an event.
-        *
-        * @throws Exception When stats calculation failed.
-        */
-       public function for_event( int $event_id ): Event_Stats {
-               $stats = new Event_Stats();
-               global $wpdb, $gp_table_prefix;
-
-               // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
-               // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
-               // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
-               // phpcs thinks we're doing a schema change but we aren't.
-               // phpcs:disable WordPress.DB.DirectDatabaseQuery.SchemaChange
-               $rows = $wpdb->get_results(
-                       $wpdb->prepare(
-                               "
-                               select locale,
-                                       sum(action = 'create') as created,
-                                       count(*) as total,
-                                       count(distinct user_id) as users
-                               from {$gp_table_prefix}event_actions
-                               where event_id = %d
-                               group by locale with rollup
-                       ",
-                               array(
-                                       $event_id,
-                               )
-                       )
-               );
-               // phpcs:enable
-
-               foreach ( $rows as $index => $row ) {
-                       $is_totals = null === $row->locale;
-                       if ( $is_totals && array_key_last( $rows ) !== $index ) {
-                               // If this is not the last row, something is wrong in the data in the database table
-                               // or there's a bug in the query above.
-                               throw new Exception(
-                                       'Only the last row should have no locale but we found a non-last row with no locale.'
-                               );
-                       }
-
-                       $lang = GP_Locales::by_slug( $row->locale );
-                       if ( ! $lang ) {
-                               $lang = null;
-                       }
-
-                       $stats_row = new Stats_Row(
-                               $row->created,
-                               $row->total - $row->created,
-                               $row->users,
-                               $lang
-                       );
-
-                       if ( ! $is_totals ) {
-                               $stats->add_row( $row->locale, $stats_row );
-                       } else {
-                               $stats->set_totals( $stats_row );
-                       }
-               }
-
-               return $stats;
-       }
-
-       /**
-        * Get contributors for an event.
-        */
-       public function get_contributors( int $event_id ): array {
-               global $wpdb, $gp_table_prefix;
-
-               // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
-               // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
-               // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
-               // phpcs thinks we're doing a schema change but we aren't.
-               // phpcs:disable WordPress.DB.DirectDatabaseQuery.SchemaChange
-               $rows = $wpdb->get_results(
-                       $wpdb->prepare(
-                               "
-                               select user_id, group_concat( distinct locale ) as locales
-                               from {$gp_table_prefix}event_actions
-                               where event_id = %d
-                               group by user_id
-                       ",
-                               array(
-                                       $event_id,
-                               )
-                       )
-               );
-               // phpcs:enable
-
-               $users = array();
-               foreach ( $rows as $row ) {
-                       $user          = new WP_User( $row->user_id );
-                       $user->locales = explode( ',', $row->locales );
-                       $users[]       = $user;
-               }
-
-               uasort(
-                       $users,
-                       function ( $a, $b ) {
-                               return strcasecmp( $a->display_name, $b->display_name );
-                       }
-               );
-
-               return $users;
-       }
-
-       /**
-        * Get attendees without contributions for an event.
-        */
-       public function get_attendees_not_contributing( int $event_id ): array {
-               global $wpdb, $gp_table_prefix;
-
-               // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
-               // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
-               // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
-               $all_attendees_ids = $wpdb->get_col(
-                       $wpdb->prepare(
-                               "
-                               select distinct user_id
-                               from {$gp_table_prefix}event_attendees
-                               where event_id = %d
-                       ",
-                               array(
-                                       $event_id,
-                               )
-                       ),
-               );
-
-               $contributing_ids = $wpdb->get_col(
-                       $wpdb->prepare(
-                               "
-                               select distinct user_id
-                               from {$gp_table_prefix}event_actions
-                               where event_id = %d
-                       ",
-                               array(
-                                       $event_id,
-                               )
-                       )
-               );
-
-               $attendees_not_contributing_ids = array_diff( $all_attendees_ids, $contributing_ids );
-
-               $attendees_not_contributing = array();
-               foreach ( $attendees_not_contributing_ids as $user_id ) {
-                       $attendees_not_contributing[] = new WP_User( $user_id );
-               }
-
-               return $attendees_not_contributing;
-       }
-
-       /**
-        * Get projects for an event.
-        */
-       public function get_projects( int $event_id ): array {
-               global $wpdb, $gp_table_prefix;
-
-               // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
-               // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
-               // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
-               // phpcs thinks we're doing a schema change but we aren't.
-               // phpcs:disable WordPress.DB.DirectDatabaseQuery.SchemaChange
-               $rows = $wpdb->get_results(
-                       $wpdb->prepare(
-                               "
-                               select
-                                       o.project_id as project,
-                                       group_concat( distinct e.locale ) as locales,
-                                       sum(action = 'create') as created,
-                                       count(*) as total,
-                                       count(distinct user_id) as users
-                               from {$gp_table_prefix}event_actions e, {$gp_table_prefix}originals o
-                               where e.event_id = %d and e.original_id = o.id
-                               group by o.project_id
-                       ",
-                               array(
-                                       $event_id,
-                               )
-                       )
-               );
-               // phpcs:enable
-
-               $projects = array();
-               foreach ( $rows as $row ) {
-                       $row->project      = GP::$project->get( $row->project );
-                       $project_name      = $row->project->name;
-                       $parent_project_id = $row->project->parent_project_id;
-                       while ( $parent_project_id ) {
-                               $parent_project    = GP::$project->get( $parent_project_id );
-                               $parent_project_id = $parent_project->parent_project_id;
-                               $project_name      = substr( htmlspecialchars_decode( $parent_project->name ), 0, 35 ) . ' - ' . $project_name;
-                       }
-                       $projects[ $project_name ] = $row;
-               }
-
-               ksort( $projects );
-
-               return $projects;
-       }
-
-       /**
-        * Check if an event has stats.
-        *
-        * @param int $event_id The id of the event to check.
-        *
-        * @return bool True if the event has stats, false otherwise.
-        */
-       public function event_has_stats( int $event_id ): bool {
-               try {
-                       $stats = $this->for_event( $event_id );
-               } catch ( Exception $e ) {
-                       return false;
-               }
-
-               return ! empty( $stats->rows() );
-       }
-
-       /**
-        * Check if a user is a first time contributor.
-        *
-        * @param Event_Start_Date $event_start The event start date.
-        * @param int              $user_id      The user ID.
-        *
-        * @return bool True if the user is a first time contributor, false otherwise.
-        */
-       public function is_first_time_contributor( $event_start, $user_id ) {
-               global $wpdb, $gp_table_prefix;
-
-               // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
-               // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
-               // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
-               // phpcs:disable WordPress.DB.DirectDatabaseQuery.SchemaChange
-               $users_first_translation_date = $wpdb->get_var(
-                       $wpdb->prepare(
-                               "
-                       select min(date_added) from {$gp_table_prefix}translations where user_id = %d
-               ",
-                               array(
-                                       $user_id,
-                               )
-                       )
-               );
-
-               if ( get_userdata( $user_id ) && ! $users_first_translation_date ) {
-                       return true;
-               }
-               $event_start_date_time  = new DateTimeImmutable( $event_start->__toString(), new DateTimeZone( 'UTC' ) );
-               $first_translation_date = new DateTimeImmutable( $users_first_translation_date, new DateTimeZone( 'UTC' ) );
-               // A first time contributor is someone whose first translation was made not earlier than 24 hours before the event.
-               $event_start_date_time = $event_start_date_time->modify( '-1 day' );
-               return $event_start_date_time <= $first_translation_date;
-       }
-}
</del></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesstatslistenerphp"></a>
<div class="delfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Deleted: sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/stats-listener.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/wporg-gp-translation-events/includes/stats-listener.php  2024-04-16 06:26:45 UTC (rev 13540)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/stats-listener.php    2024-04-16 12:41:37 UTC (rev 13541)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,136 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-
-namespace Wporg\TranslationEvents;
-
-use DateTimeImmutable;
-use DateTimeZone;
-use Exception;
-use GP_Translation;
-use GP_Translation_Set;
-use Wporg\TranslationEvents\Attendee\Attendee_Repository;
-use Wporg\TranslationEvents\Event\Event;
-use Wporg\TranslationEvents\Event\Event_Repository_Interface;
-
-class Stats_Listener {
-       const ACTION_CREATE          = 'create';
-       const ACTION_APPROVE         = 'approve';
-       const ACTION_REJECT          = 'reject';
-       const ACTION_REQUEST_CHANGES = 'request_changes';
-
-       private Attendee_Repository $attendee_repository;
-       private Event_Repository_Interface $event_repository;
-
-       public function __construct(
-               Event_Repository_Interface $event_repository,
-               Attendee_Repository $attendee_repository
-       ) {
-               $this->event_repository    = $event_repository;
-               $this->attendee_repository = $attendee_repository;
-       }
-
-       public function start(): void {
-               add_action(
-                       'gp_translation_created',
-                       function ( $translation ) {
-                               $happened_at = DateTimeImmutable::createFromFormat( 'Y-m-d H:i:s', $translation->date_added, new DateTimeZone( 'UTC' ) );
-                               if ( ! $translation->user_id ) {
-                                       return;
-                               }
-                               $this->handle_action( $translation, $translation->user_id, self::ACTION_CREATE, $happened_at );
-                       },
-               );
-
-               add_action(
-                       'gp_translation_saved',
-                       function ( $translation, $translation_before ) {
-                               $user_id     = $translation->user_id_last_modified;
-                               $status      = $translation->status;
-                               $happened_at = DateTimeImmutable::createFromFormat( 'Y-m-d H:i:s', $translation->date_modified, new DateTimeZone( 'UTC' ) );
-
-                               if ( $translation_before->status === $status ) {
-                                       // Translation hasn't changed status, so there's nothing for us to track.
-                                       return;
-                               }
-
-                               $action = null;
-                               switch ( $status ) {
-                                       case 'current':
-                                               $action = self::ACTION_APPROVE;
-                                               break;
-                                       case 'rejected':
-                                               $action = self::ACTION_REJECT;
-                                               break;
-                                       case 'changesrequested':
-                                               $action = self::ACTION_REQUEST_CHANGES;
-                                               break;
-                               }
-
-                               if ( $action && $user_id ) {
-                                       $this->handle_action( $translation, $user_id, $action, $happened_at );
-                               }
-                       },
-                       10,
-                       2,
-               );
-       }
-
-       private function handle_action( GP_Translation $translation, int $user_id, string $action, DateTimeImmutable $happened_at ): void {
-               try {
-                       // Get events that are active when the action happened, for which the user is registered for.
-                       $active_events = $this->event_repository->get_current_events();
-                       $events        = $this->select_events_user_is_registered_for( $active_events->events, $user_id );
-
-                       // phpcs:ignore Generic.Commenting.DocComment.MissingShort
-                       /** @var GP_Translation_Set $translation_set Translation set */
-                       $translation_set = ( new GP_Translation_Set() )->find_one( array( 'id' => $translation->translation_set_id ) );
-                       global $wpdb, $gp_table_prefix;
-
-                       foreach ( $events as $event ) {
-                               // A given user can only do one action on a specific translation.
-                               // So we insert ignore, which will keep only the first action.
-                               // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
-                               // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
-                               // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
-                               $wpdb->query(
-                                       $wpdb->prepare(
-                                               "insert ignore into {$gp_table_prefix}event_actions (event_id, locale, user_id, original_id, action, happened_at) values (%d, %s, %d, %d, %s, %s)",
-                                               array(
-                                                       // Start unique key.
-                                                       'event_id'    => $event->id(),
-                                                       'locale'      => $translation_set->locale,
-                                                       'user_id'     => $user_id,
-                                                       'original_id' => $translation->original_id,
-                                                       // End unique key.
-                                                       'action'      => $action,
-                                                       'happened_at' => $happened_at->format( 'Y-m-d H:i:s' ),
-                                               ),
-                                       ),
-                               );
-                               // phpcs:enable
-                       }
-               } catch ( Exception $exception ) {
-                       // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
-                       error_log( $exception );
-               }
-       }
-
-       /**
-        * Filter an array of events so that it only includes events the given user is attending.
-        *
-        * @param Event[] $events Events.
-        *
-        * @return Event[]
-        */
-       // phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
-       // phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.Found
-       private function select_events_user_is_registered_for( array $events, int $user_id ): array {
-               $attending_event_ids = $this->attendee_repository->get_events_for_user( $user_id );
-               return array_filter(
-                       $events,
-                       function ( Event $event ) use ( $attending_event_ids ) {
-                               return in_array( $event->id(), $attending_event_ids, true );
-                       }
-               );
-       }
-       // phpcs:enable
-}
</del></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesupgradephp"></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/wporg-gp-translation-events/includes/upgrade.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/wporg-gp-translation-events/includes/upgrade.php 2024-04-16 06:26:45 UTC (rev 13540)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/upgrade.php   2024-04-16 12:41:37 UTC (rev 13541)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -5,6 +5,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> use Exception;
</span><span class="cx" style="display: block; padding: 0 10px"> use WP_Query;
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Attendee\Attendee;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use Wporg\TranslationEvents\Stats\Stats_Calculator;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> class Upgrade {
</span><span class="cx" style="display: block; padding: 0 10px">        private const VERSION        = 2;
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventstemplateseventphp"></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/wporg-gp-translation-events/templates/event.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/wporg-gp-translation-events/templates/event.php  2024-04-16 06:26:45 UTC (rev 13540)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/templates/event.php    2024-04-16 12:41:37 UTC (rev 13541)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -11,6 +11,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Event\Event;
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Event\Event_End_Date;
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Event\Event_Start_Date;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use Wporg\TranslationEvents\Stats\Event_Stats;
+use Wporg\TranslationEvents\Stats\Stats_Row;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /** @var Attendee_Repository $attendee_repo */
</span><span class="cx" style="display: block; padding: 0 10px"> /** @var Attendee $attendee */
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -45,33 +47,25 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                <ul>
</span><span class="cx" style="display: block; padding: 0 10px">                                        <?php foreach ( $contributors as $contributor ) : ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                                <li class="event-contributor" title="<?php echo esc_html( implode( ', ', $contributor->locales ) ); ?>">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                        <a href="<?php echo esc_url( get_author_posts_url( $contributor->ID ) ); ?>"><?php echo get_avatar( $contributor->ID, 48 ); ?></a>
-                                                       <a href="<?php echo esc_url( get_author_posts_url( $contributor->ID ) ); ?>"><?php echo esc_html( get_the_author_meta( 'display_name', $contributor->ID ) ); ?></a>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                 <a href="<?php echo esc_url( get_author_posts_url( $contributor->ID ) ); ?>" class="avatar"><?php echo get_avatar( $contributor->ID, 48 ); ?></a>
+                                                       <a href="<?php echo esc_url( get_author_posts_url( $contributor->ID ) ); ?>" class="name"><?php echo esc_html( get_the_author_meta( 'display_name', $contributor->ID ) ); ?></a>
</ins><span class="cx" style="display: block; padding: 0 10px">                                                         <?php if ( $stats_calculator->is_first_time_contributor( $event_start, $contributor->ID ) ) : ?>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                                <span class="first-time-contributor-tada"></span>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                         <span class="first-time-contributor-tada" title="<?php esc_html_e( 'New Translation Contributor', 'gp-translation-events' ); ?>"></span>
</ins><span class="cx" style="display: block; padding: 0 10px">                                                         <?php endif; ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                                        <?php
</span><span class="cx" style="display: block; padding: 0 10px">                                                        if ( ! $event->end()->is_in_the_past() ) :
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                                if ( ( $attendee instanceof Attendee && $attendee->is_host() ) || current_user_can( 'manage_options' ) ) :
-                                                                       if ( $user->ID !== $contributor->ID ) :
-                                                                               $_attendee = $attendee_repo->get_attendee( $event_id, $contributor->ID );
-                                                                               if ( $_attendee instanceof Attendee ) :
-                                                                                       echo '<form class="add-remove-user-as-host" method="post" action="' . esc_url( gp_url( "/events/host/$event_id/$contributor->ID" ) ) . '">';
-                                                                                       if ( $_attendee->is_host() ) :
-                                                                                               if ( 1 === count( $attendee_repo->get_hosts( $event_id ) ) ) :
-                                                                                                       echo '<input type="submit" class="button is-primary remove-as-host" disabled value="Remove as host"/>';
-                                                                                               else :
-                                                                                                       echo '<input type="submit" class="button is-primary remove-as-host" value="Remove as host"/>';
-                                                                                               endif;
-                                                                                       else :
-                                                                                               echo '<input type="submit" class="button is-secondary convert-to-host" value="Make co-host"/>';
-                                                                                       endif;
-                                                                                       echo '</form>';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                         if ( ( $attendee instanceof Attendee && $attendee->is_host() ) || current_user_can( 'manage_options' ) || $user->ID === $event->author_id() ) :
+                                                                       $_attendee = $attendee_repo->get_attendee( $event_id, $contributor->ID );
+                                                                       if ( $_attendee instanceof Attendee ) :
+                                                                               echo '<form class="add-remove-user-as-host" method="post" action="' . esc_url( gp_url( "/events/host/$event_id/$contributor->ID" ) ) . '">';
+                                                                               if ( $_attendee->is_host() ) :
+                                                                                       echo '<input type="submit" class="button is-primary remove-as-host" value="Remove as host"/>';
+                                                                               else :
+                                                                                       echo '<input type="submit" class="button is-secondary convert-to-host" value="Make co-host"/>';
</ins><span class="cx" style="display: block; padding: 0 10px">                                                                                 endif;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                                        elseif ( ( $attendee instanceof Attendee && $attendee->is_host() ) ) :
-                                                                                       echo '<span class="event-you">' . esc_html__( 'You (host)', 'gp-translation-events' ) . '</span>';
-                                                                               else :
-                                                                                       echo '<span class="event-you">' . esc_html__( 'You (event creator)', 'gp-translation-events' ) . '</span>';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                                         echo '</form>';
+                                                                       else :
+                                                                               echo '<span class="event-not-attending">' . esc_html__( 'Not attending', 'gp-translation-events' ) . '</span>';
</ins><span class="cx" style="display: block; padding: 0 10px">                                                                         endif;
</span><span class="cx" style="display: block; padding: 0 10px">                                                                endif;
</span><span class="cx" style="display: block; padding: 0 10px">                                                        endif;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -81,39 +75,29 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                </ul>
</span><span class="cx" style="display: block; padding: 0 10px">                        </div>
</span><span class="cx" style="display: block; padding: 0 10px">                <?php endif; ?>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                <?php if ( ! empty( $attendees ) && ( ! $event->end()->is_in_the_past() || ( ( $attendee instanceof Attendee && $attendee->is_host() ) || current_user_can( 'manage_options' ) ) ) ) : ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         <?php if ( ! empty( $attendees ) && ( ! $event->end()->is_in_the_past() || ( ( $attendee instanceof Attendee && $attendee->is_host() ) || current_user_can( 'manage_options' ) || $user->ID === $event->author_id() ) ) ) : ?>
</ins><span class="cx" style="display: block; padding: 0 10px">                         <div class="event-attendees">
</span><span class="cx" style="display: block; padding: 0 10px">                                <h2><?php esc_html_e( 'Attendees', 'gp-translation-events' ); ?></h2>
</span><span class="cx" style="display: block; padding: 0 10px">                                <ul>
</span><span class="cx" style="display: block; padding: 0 10px">                                        <?php foreach ( $attendees as $_user ) : ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                                <li class="event-attendee">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                        <a href="<?php echo esc_url( get_author_posts_url( $_user->ID ) ); ?>"><?php echo get_avatar( $_user->ID, 48 ); ?></a>
-                                                       <a href="<?php echo esc_url( get_author_posts_url( $_user->ID ) ); ?>"><?php echo esc_html( get_the_author_meta( 'display_name', $_user->ID ) ); ?></a>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                 <a href="<?php echo esc_url( get_author_posts_url( $_user->ID ) ); ?>" class="avatar"><?php echo get_avatar( $_user->ID, 48 ); ?></a>
+                                                       <a href="<?php echo esc_url( get_author_posts_url( $_user->ID ) ); ?>" class="name"><?php echo esc_html( get_the_author_meta( 'display_name', $_user->ID ) ); ?></a>
</ins><span class="cx" style="display: block; padding: 0 10px">                                                         <?php if ( $stats_calculator->is_first_time_contributor( $event_start, $_user->ID ) ) : ?>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                                <span class="first-time-contributor-tada"></span>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                         <span class="first-time-contributor-tada" title="<?php esc_html_e( 'New Translation Contributor', 'gp-translation-events' ); ?>"></span>
</ins><span class="cx" style="display: block; padding: 0 10px">                                                         <?php endif; ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                                        <?php
</span><span class="cx" style="display: block; padding: 0 10px">                                                        if ( ! $event->end()->is_in_the_past() ) :
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                                if ( ( $attendee instanceof Attendee && $attendee->is_host() ) || current_user_can( 'manage_options' ) ) :
-                                                                       if ( $user->ID !== $_user->ID ) :
-                                                                               $_attendee = $attendee_repo->get_attendee( $event_id, $_user->ID );
-                                                                               if ( $_attendee instanceof Attendee ) :
-                                                                                       echo '<form class="add-remove-user-as-host" method="post" action="' . esc_url( gp_url( "/events/host/$event_id/$_user->ID" ) ) . '">';
-                                                                                       if ( $_attendee->is_host() ) :
-                                                                                               if ( 1 === count( $attendee_repo->get_hosts( $event_id ) ) ) :
-                                                                                                       echo '<input type="submit" class="button is-primary remove-as-host" disabled value="Remove as host"/>';
-                                                                                               else :
-                                                                                                       echo '<input type="submit" class="button is-primary remove-as-host" value="Remove as host"/>';
-                                                                                               endif;
-                                                                                       else :
-                                                                                               echo '<input type="submit" class="button is-secondary convert-to-host" value="Make co-host"/>';
-                                                                                       endif;
-                                                                                       echo '</form>';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                         if ( ( $attendee instanceof Attendee && $attendee->is_host() ) || current_user_can( 'manage_options' ) || $user->ID === $event->author_id() ) :
+                                                                       $_attendee = $attendee_repo->get_attendee( $event_id, $_user->ID );
+                                                                       if ( $_attendee instanceof Attendee ) :
+                                                                               echo '<form class="add-remove-user-as-host" method="post" action="' . esc_url( gp_url( "/events/host/$event_id/$_user->ID" ) ) . '">';
+                                                                               if ( $_attendee->is_host() ) :
+                                                                                       echo '<input type="submit" class="button is-primary remove-as-host" value="Remove as host"/>';
+                                                                               else :
+                                                                                       echo '<input type="submit" class="button is-secondary convert-to-host" value="Make co-host"/>';
</ins><span class="cx" style="display: block; padding: 0 10px">                                                                                 endif;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                                        elseif ( ( $attendee instanceof Attendee && $attendee->is_host() ) ) :
-                                                                                       echo '<span class="event-you">' . esc_html__( 'You (host)', 'gp-translation-events' ) . '</span>';
-                                                                               else :
-                                                                                       echo '<span class="event-you">' . esc_html__( 'You (event creator)', 'gp-translation-events' ) . '</span>';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                                         echo '</form>';
</ins><span class="cx" style="display: block; padding: 0 10px">                                                                         endif;
</span><span class="cx" style="display: block; padding: 0 10px">                                                                endif;
</span><span class="cx" style="display: block; padding: 0 10px">                                                        endif;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -214,7 +198,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                                                ', ',
</span><span class="cx" style="display: block; padding: 0 10px">                                                                array_map(
</span><span class="cx" style="display: block; padding: 0 10px">                                                                        function ( $contributor ) use ( $stats_calculator, $event_start ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                                                $append_tada = $stats_calculator->is_first_time_contributor( $event_start, $contributor->ID ) ? '<span class="first-time-contributor-tada"></span>' : '';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                                         $append_tada = '';
+                                                                               if ( $stats_calculator->is_first_time_contributor( $event_start, $contributor->ID ) ) {
+                                                                                       $append_tada = '<span class="first-time-contributor-tada" title="' . esc_html__( 'New Translation Contributor', 'gp-translation-events' ) . '"></span>';
+                                                                               }
</ins><span class="cx" style="display: block; padding: 0 10px">                                                                                 return '@' . $contributor->user_login . $append_tada;
</span><span class="cx" style="display: block; padding: 0 10px">                                                                        },
</span><span class="cx" style="display: block; padding: 0 10px">                                                                        $contributors
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -224,6 +211,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                                array(
</span><span class="cx" style="display: block; padding: 0 10px">                                                        'span' => array(
</span><span class="cx" style="display: block; padding: 0 10px">                                                                'class' => array(),
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                                                'title' => array(),
</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">@@ -257,11 +245,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        <?php else : ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                <form class="event-details-attend" method="post" action="<?php echo esc_url( gp_url( "/events/attend/$event_id" ) ); ?>">
</span><span class="cx" style="display: block; padding: 0 10px">                                        <?php if ( $attendee instanceof Attendee ) : ?>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                                <?php if ( $attendee->is_host() && ( 1 === count( $attendee_repo->get_hosts( $event_id ) ) ) ) : ?>
-                                                       <input type="submit" class="button is-secondary attending-btn" disabled value="You're attending" />
-                                               <?php else : ?>
-                                                       <input type="submit" class="button is-secondary attending-btn" value="You're attending" />
-                                               <?php endif; ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                         <input type="submit" class="button is-secondary attending-btn" value="You're attending" />
</ins><span class="cx" style="display: block; padding: 0 10px">                                         <?php else : ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                                <input type="submit" class="button is-primary attend-btn" value="Attend Event"/>
</span><span class="cx" style="display: block; padding: 0 10px">                                        <?php endif; ?>
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventstemplateseventsheaderphp"></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/wporg-gp-translation-events/templates/events-header.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/wporg-gp-translation-events/templates/events-header.php  2024-04-16 06:26:45 UTC (rev 13540)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/templates/events-header.php    2024-04-16 12:41:37 UTC (rev 13541)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -39,20 +39,28 @@
</span><span class="cx" style="display: block; padding: 0 10px">        <p class="event-sub-head">
</span><span class="cx" style="display: block; padding: 0 10px">                        <span class="event-host">
</span><span class="cx" style="display: block; padding: 0 10px">                                <?php
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                if ( 1 === count( $hosts ) ) :
-                                       esc_html_e( 'Host:', 'gp-translation-events' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         if ( count( $hosts ) > 0 ) :
+                                       if ( 1 === count( $hosts ) ) :
+                                               esc_html_e( 'Host:', 'gp-translation-events' );
+                                       else :
+                                               esc_html_e( 'Hosts:', 'gp-translation-events' );
+                                       endif;
</ins><span class="cx" style="display: block; padding: 0 10px">                                 else :
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        esc_html_e( 'Hosts:', 'gp-translation-events' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 esc_html_e( 'Created by:', 'gp-translation-events' );
+                                       ?>
+                                       &nbsp;<a href="<?php echo esc_attr( get_author_posts_url( $user->ID ) ); ?>"><?php echo esc_html( get_the_author_meta( 'display_name', $user->ID ) ); ?></a>
+                                       <?php
</ins><span class="cx" style="display: block; padding: 0 10px">                                 endif;
</span><span class="cx" style="display: block; padding: 0 10px">                                ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                <?php foreach ( $hosts as $host ) : ?>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        <?php $user = get_userdata( $host->user_id() ); ?>
-                                       &nbsp;<a href="<?php echo esc_attr( get_author_posts_url( $user->ID ) ); ?>"><?php echo esc_html( get_the_author_meta( 'display_name', $user->ID ) ); ?></a>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 &nbsp;<a href="<?php echo esc_attr( get_author_posts_url( $host->user_id() ) ); ?>"><?php echo esc_html( get_the_author_meta( 'display_name', $host->user_id() ) ); ?></a>
</ins><span class="cx" style="display: block; padding: 0 10px">                                         <?php if ( end( $hosts ) !== $host ) : ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                                ,
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                        <?php else : ?>
+                                               .
</ins><span class="cx" style="display: block; padding: 0 10px">                                         <?php endif; ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                <?php endforeach; ?>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        .</span>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 </span>
</ins><span class="cx" style="display: block; padding: 0 10px">                         <?php $show_edit_button = ( ( $attendee instanceof Attendee && $attendee->is_host() ) || current_user_can( 'edit_post', $event->id() ) ) && $is_editable_event; ?>
</span><span class="cx" style="display: block; padding: 0 10px">                        <?php if ( $show_edit_button ) : ?>
</span><span class="cx" style="display: block; padding: 0 10px">                                <a class="event-page-edit-link" href="<?php echo esc_url( gp_url( 'events/edit/' . $event->id() ) ); ?>"><span class="dashicons dashicons-edit"></span><?php esc_html_e( 'Edit event', 'gp-translation-events' ); ?></a>
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventstemplateseventsmyeventsphp"></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/wporg-gp-translation-events/templates/events-my-events.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/wporg-gp-translation-events/templates/events-my-events.php       2024-04-16 06:26:45 UTC (rev 13540)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/templates/events-my-events.php 2024-04-16 12:41:37 UTC (rev 13541)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -6,6 +6,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> namespace Wporg\TranslationEvents;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Event\Events_Query_Result;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use Wporg\TranslationEvents\Stats\Stats_Calculator;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /** @var Events_Query_Result $events_i_created_query */
</span><span class="cx" style="display: block; padding: 0 10px"> /** @var Events_Query_Result $events_i_host_query */
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventswporggptranslationeventsphp"></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/wporg-gp-translation-events/wporg-gp-translation-events.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/wporg-gp-translation-events/wporg-gp-translation-events.php      2024-04-16 06:26:45 UTC (rev 13540)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/wporg-gp-translation-events.php        2024-04-16 12:41:37 UTC (rev 13541)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -29,6 +29,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Event\Event_Form_Handler;
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Event\Event_Repository_Cached;
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Event\Event_Repository_Interface;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use Wporg\TranslationEvents\Stats\Stats_Listener;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> class Translation_Events {
</span><span class="cx" style="display: block; padding: 0 10px">        public const CPT = 'translation_event';
</span></span></pre>
</div>
</div>

</body>
</html>