<!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>[13529] 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/13529">13529</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/13529","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-15 13:37:55 +0000 (Mon, 15 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_htmlwpcontentpluginswporggptranslationeventsassetsjstranslationeventsjs">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/assets/js/translation-events.js</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesrouteseventcreatephp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/routes/event/create.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_htmlwpcontentpluginswporggptranslationeventsincludesrouteseventlistphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/routes/event/list.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_htmlwpcontentpluginswporggptranslationeventsincludesroutesusermyeventsphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/routes/user/my-events.php</a></li>
<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>
<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_htmlwpcontentpluginswporggptranslationeventstemplateseventsformphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/templates/events-form.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_htmlwpcontentpluginswporggptranslationeventstemplateseventslistphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/templates/events-list.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><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsautoloadphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/autoload.php</a></li>
<li>sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/attendee/</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_htmlwpcontentpluginswporggptranslationeventsincludesattendeeattendeephp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/attendee/attendee.php</a></li>
<li>sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/event/</li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludeseventeventdatephp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/event/event-date.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_htmlwpcontentpluginswporggptranslationeventsincludeseventeventrepositorycachedphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/event/event-repository-cached.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludeseventeventrepositoryinterfacephp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/event/event-repository-interface.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludeseventeventrepositoryphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/event/event-repository.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_htmlwpcontentpluginswporggptranslationeventsincludeseventtextsnippetphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/event-text-snippet.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>
</ul>
<h3>Removed Paths</h3>
<ul>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesactiveeventscachephp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/active-events-cache.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludeseventphp">sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/event.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-15 08:28:54 UTC (rev 13528)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/assets/css/translation-events.css 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -3,17 +3,21 @@
</span><span class="cx" style="display: block; padding: 0 10px"> width: 140px;
</span><span class="cx" style="display: block; padding: 0 10px"> vertical-align: top;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .translation-event-form #event-title,
</span><span class="cx" style="display: block; padding: 0 10px"> .translation-event-form #event-description {
</span><span class="cx" style="display: block; padding: 0 10px"> width: 30%;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .translation-event-form input[type="text"],
</span><span class="cx" style="display: block; padding: 0 10px"> .translation-event-form input[type="date"] {
</span><span class="cx" style="display: block; padding: 0 10px"> width: 13%;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .translation-event-form div {
</span><span class="cx" style="display: block; padding: 0 10px"> margin-top: 1em;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .translation-event-form #submit-event {
</span><span class="cx" style="display: block; padding: 0 10px"> margin-left: 10%;
</span><span class="cx" style="display: block; padding: 0 10px"> width: 30%;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -20,15 +24,13 @@
</span><span class="cx" style="display: block; padding: 0 10px"> margin-top: 1em;
</span><span class="cx" style="display: block; padding: 0 10px"> display: block;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-.event-page-title {
- border-bottom: #d9d8d8 thin solid;
- padding-bottom: .5em;
-}
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-details-page {
</span><span class="cx" style="display: block; padding: 0 10px"> border-bottom: #cfd4d4 thin solid;
</span><span class="cx" style="display: block; padding: 0 10px"> width: 60%;
</span><span class="cx" style="display: block; padding: 0 10px"> margin: 0 auto;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-details-left {
</span><span class="cx" style="display: block; padding: 0 10px"> width: 77%;
</span><span class="cx" style="display: block; padding: 0 10px"> float: left;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -36,39 +38,52 @@
</span><span class="cx" style="display: block; padding: 0 10px"> margin-right: 1%;
</span><span class="cx" style="display: block; padding: 0 10px"> padding-right: 1em;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-details-right {
</span><span class="cx" style="display: block; padding: 0 10px"> width: 22%;
</span><span class="cx" style="display: block; padding: 0 10px"> float: right;
</span><span class="cx" style="display: block; padding: 0 10px"> padding-top: 1em;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-details-stats {
</span><span class="cx" style="display: block; padding: 0 10px"> clear: both;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- margin: 1em;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ margin: 0;
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-details-stats table {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ margin: 1rem;
+}
+.event-details-stats table {
</ins><span class="cx" style="display: block; padding: 0 10px"> width: 100%;
</span><span class="cx" style="display: block; padding: 0 10px"> table-layout: fixed;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-.event-details-stats table th, .event-details-stats table td {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+.event-details-stats table th,
+.event-details-stats table td {
</ins><span class="cx" style="display: block; padding: 0 10px"> padding: 1em;
</span><span class="cx" style="display: block; padding: 0 10px"> text-align: center;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-details-stats table td:first-child {
</span><span class="cx" style="display: block; padding: 0 10px"> text-align: left;
</span><span class="cx" style="display: block; padding: 0 10px"> word-break: break-all;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-details-stats table tr {
</span><span class="cx" style="display: block; padding: 0 10px"> border-bottom: thin solid #f0f0f0;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-details-stats table th {
</span><span class="cx" style="display: block; padding: 0 10px"> background-color: #e9e9e9;
</span><span class="cx" style="display: block; padding: 0 10px"> /* allow breaking the word anywhere so that it doesn't overflow */
</span><span class="cx" style="display: block; padding: 0 10px"> word-break: break-all;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-details-stats-totals td {
</span><span class="cx" style="display: block; padding: 0 10px"> font-weight: bold;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-.event-contributors li {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+.event-contributors li, .event-attendees li {
</ins><span class="cx" style="display: block; padding: 0 10px"> display: inline-block;
</span><span class="cx" style="display: block; padding: 0 10px"> list-style-type: none;
</span><span class="cx" style="display: block; padding: 0 10px"> margin-right: 1em;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -75,21 +90,36 @@
</span><span class="cx" style="display: block; padding: 0 10px"> margin-bottom: .5em;
</span><span class="cx" style="display: block; padding: 0 10px"> width: 15em;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-.event-contributors li .avatar {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+.event-contributors li .avatar, .event-attendees li .avatar {
</ins><span class="cx" style="display: block; padding: 0 10px"> border-radius: 50%;
</span><span class="cx" style="display: block; padding: 0 10px"> vertical-align: middle;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+.event-attendees h2 {
+ margin-bottom: 0;
+}
+
+span.event-creator, span.event-you {
+ display: block;
+ margin-left: 55px;
+ margin-top: 1em;
+ font-size: smaller;
+}
</ins><span class="cx" style="display: block; padding: 0 10px"> .hide-event-url {
</span><span class="cx" style="display: block; padding: 0 10px"> display: none;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .translation-event-form button.save-draft {
</span><span class="cx" style="display: block; padding: 0 10px"> background: #fff;
</span><span class="cx" style="display: block; padding: 0 10px"> color: var(--gp-color-btn-primary-bg);
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> #event-url span {
</span><span class="cx" style="display: block; padding: 0 10px"> width: 10%;
</span><span class="cx" style="display: block; padding: 0 10px"> display: inline-block;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> span.event-list-date {
</span><span class="cx" style="display: block; padding: 0 10px"> display: block;
</span><span class="cx" style="display: block; padding: 0 10px"> color: #939393;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -96,72 +126,94 @@
</span><span class="cx" style="display: block; padding: 0 10px"> font-size: .8em;
</span><span class="cx" style="display: block; padding: 0 10px"> font-weight: normal;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> span.event-list-date.events-i-am-attending {
</span><span class="cx" style="display: block; padding: 0 10px"> font-size: .8em;
</span><span class="cx" style="display: block; padding: 0 10px"> font-weight: normal;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-.event-list-item a{
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+.event-list-item a {
</ins><span class="cx" style="display: block; padding: 0 10px"> font-weight: bold;
</span><span class="cx" style="display: block; padding: 0 10px"> font-size: 1.2em;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> li.event-list-item {
</span><span class="cx" style="display: block; padding: 0 10px"> list-style-type: none;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ margin-bottom: .5em;
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> li.event-list-item p {
</span><span class="cx" style="display: block; padding: 0 10px"> margin-top: 0;
</span><span class="cx" style="display: block; padding: 0 10px"> color: #5a5a5a;
</span><span class="cx" style="display: block; padding: 0 10px"> font-size: .95em;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> h2.event_page_title {
</span><span class="cx" style="display: block; padding: 0 10px"> border-bottom: #e0e0e0 thin solid;
</span><span class="cx" style="display: block; padding: 0 10px"> padding-bottom: 0.5em;
</span><span class="cx" style="display: block; padding: 0 10px"> font-weight: bold;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-list-top-bar {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- display: block;
</del><span class="cx" style="display: block; padding: 0 10px"> width: 80%;
</span><span class="cx" style="display: block; padding: 0 10px"> margin: 0 auto;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- text-align: right;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ display: grid;
+ grid-template-columns: 1fr auto;
+ align-items: center;
+ border-bottom: #d9d8d8 thin solid;
+ padding-bottom: .5em;
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-list-nav li {
</span><span class="cx" style="display: block; padding: 0 10px"> display: inline;
</span><span class="cx" style="display: block; padding: 0 10px"> margin: 0 0.1rem;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-list-nav li a {
</span><span class="cx" style="display: block; padding: 0 10px"> text-decoration: none;
</span><span class="cx" style="display: block; padding: 0 10px"> font-weight: bold;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-list-nav li:not(:first-child):not(:last-child):before {
</span><span class="cx" style="display: block; padding: 0 10px"> content: " | ";
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-left-col {
</span><span class="cx" style="display: block; padding: 0 10px"> width: 75%;
</span><span class="cx" style="display: block; padding: 0 10px"> float: left;
</span><span class="cx" style="display: block; padding: 0 10px"> border-right: var(--gp-color-secondary-400) thin solid;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-right-col {
</span><span class="cx" style="display: block; padding: 0 10px"> width: 25%;
</span><span class="cx" style="display: block; padding: 0 10px"> float: left;
</span><span class="cx" style="display: block; padding: 0 10px"> padding-left: 1em;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-attending-list {
</span><span class="cx" style="display: block; padding: 0 10px"> list-style-type: none;
</span><span class="cx" style="display: block; padding: 0 10px"> padding: 0;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-attending-list li {
</span><span class="cx" style="display: block; padding: 0 10px"> margin-bottom: 1em;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-list-nav li a.button {
</span><span class="cx" style="display: block; padding: 0 10px"> background-color: var(--gp-color-btn-primary-bg) !important;
</span><span class="cx" style="display: block; padding: 0 10px"> color: #fff !important;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> a.event-link-draft {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- color:#80807f;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ color: #80807f;
</ins><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-label-draft, span.event-details-join-expired, span.active-events-before-translation-table {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+span.event-label-draft,
+span.event-details-join-expired,
+span.active-events-before-translation-table {
</ins><span class="cx" style="display: block; padding: 0 10px"> font-weight: 500;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- color: var( --gp-color-bubble-inactive-project-text );
- border: 1px solid var( --gp-color-bubble-inactive-project-text );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ color: var(--gp-color-bubble-inactive-project-text);
+ border: 1px solid var(--gp-color-bubble-inactive-project-text);
</ins><span class="cx" style="display: block; padding: 0 10px"> font-size: .7em;
</span><span class="cx" style="display: block; padding: 0 10px"> margin-right: 0.3em;
</span><span class="cx" style="display: block; padding: 0 10px"> width: 6em;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -170,28 +222,37 @@
</span><span class="cx" style="display: block; padding: 0 10px"> border-radius: 1em;
</span><span class="cx" style="display: block; padding: 0 10px"> text-transform: capitalize;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> span.active-events-before-translation-table a {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- color: var( --gp-color-bubble-inactive-project-text );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ color: var(--gp-color-bubble-inactive-project-text);
</ins><span class="cx" style="display: block; padding: 0 10px"> text-decoration: none;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .active-events-before-translation-table {
</span><span class="cx" style="display: block; padding: 0 10px"> width: 100%;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- border: 1px solid var( --gp-color-border-default );
- background: var( --gp-color-status-waiting-subtle );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ border: 1px solid var(--gp-color-border-default);
+ background: var(--gp-color-status-waiting-subtle);
</ins><span class="cx" style="display: block; padding: 0 10px"> margin: 1rem 0;
</span><span class="cx" style="display: block; padding: 0 10px"> padding: 0.3rem 0.8rem;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-page-wrapper {
</span><span class="cx" style="display: block; padding: 0 10px"> margin: 0 auto;
</span><span class="cx" style="display: block; padding: 0 10px"> width: 80%;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-list {
</span><span class="cx" style="display: block; padding: 0 10px"> margin: 0;
</span><span class="cx" style="display: block; padding: 0 10px"> padding: 0;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-.event-details-head {
- border-bottom: var(--gp-color-secondary-400) thin solid;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+input[type="submit"].remove-as-host, input[type="submit"].convert-to-host {
+ text-align: center;
+ display: inline;
+ margin-top: 1em;
+ font-weight: bold;
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> input[type="submit"].attend-btn {
</span><span class="cx" style="display: block; padding: 0 10px"> width: 100%;
</span><span class="cx" style="display: block; padding: 0 10px"> text-align: center;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -199,27 +260,36 @@
</span><span class="cx" style="display: block; padding: 0 10px"> margin-top: 1em;
</span><span class="cx" style="display: block; padding: 0 10px"> font-weight: bold;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-input[type="submit"].attending-btn, a.button.is-primary.attend-btn {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+input[type="submit"].attending-btn,
+a.button.is-primary.attend-btn {
</ins><span class="cx" style="display: block; padding: 0 10px"> width: 100%;
</span><span class="cx" style="display: block; padding: 0 10px"> text-align: center;
</span><span class="cx" style="display: block; padding: 0 10px"> display: block;
</span><span class="cx" style="display: block; padding: 0 10px"> margin-top: 1em;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-details-date {
</span><span class="cx" style="display: block; padding: 0 10px"> background: #f4f4f4;
</span><span class="cx" style="display: block; padding: 0 10px"> color: #606161;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- padding: .5em;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ padding: 0.1em .5em;
</ins><span class="cx" style="display: block; padding: 0 10px"> font-size: .9em;
</span><span class="cx" style="display: block; padding: 0 10px"> line-height: 1.8em;
</span><span class="cx" style="display: block; padding: 0 10px"> font-weight: 500;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ margin-bottom: 1em;
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-page-edit-link {
</span><span class="cx" style="display: block; padding: 0 10px"> float: right;
</span><span class="cx" style="display: block; padding: 0 10px"> text-decoration: none;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ justify-self: end;
+ grid-column: 2;
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-stats-summary {
</span><span class="cx" style="display: block; padding: 0 10px"> margin-top: 1em;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-stats-summary summary {
</span><span class="cx" style="display: block; padding: 0 10px"> background: #f8f8f8;
</span><span class="cx" style="display: block; padding: 0 10px"> padding: 0.4em;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -228,6 +298,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> font-weight: 500;
</span><span class="cx" style="display: block; padding: 0 10px"> font-size: .9em;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-stats-summary p.event-stats-text {
</span><span class="cx" style="display: block; padding: 0 10px"> margin: 0;
</span><span class="cx" style="display: block; padding: 0 10px"> background: #f8f8f8;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -235,15 +306,23 @@
</span><span class="cx" style="display: block; padding: 0 10px"> font-size: .9em;
</span><span class="cx" style="display: block; padding: 0 10px"> border-top: thin solid #e0e0e0;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-time.event-utc-time {
- display: block;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+.event-details-date time {
</ins><span class="cx" style="display: block; padding: 0 10px"> font-size: .95em;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ font-weight: normal;
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-.event-utc-time:first-of-type{
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+.event-details-date time:last-child {
+ margin-bottom: 0;
+}
+
+.event-details-date time.full-time {
+ display: block;
</ins><span class="cx" style="display: block; padding: 0 10px"> border-bottom: #cdcdcd thin solid;
</span><span class="cx" style="display: block; padding: 0 10px"> padding-bottom: 0.5em;
</span><span class="cx" style="display: block; padding: 0 10px"> margin-bottom: 0.5em;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> span.event-details-date-label {
</span><span class="cx" style="display: block; padding: 0 10px"> font-weight: bold;
</span><span class="cx" style="display: block; padding: 0 10px"> color: #5a5a5a;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -250,19 +329,46 @@
</span><span class="cx" style="display: block; padding: 0 10px"> display: block;
</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">+.event-host {
+ display: flex;
+ grid-column: 1;
+}
+
+p.event-sub-head {
+ grid-column: 1 / -1;
+ margin-top: 0;
+}
+
+a.event-page-edit-link {
+ font-size: .9em;
+ text-decoration: none;
+}
+
+a.event-page-edit-link:hover {
+ border-bottom: var(--gp-color-btn-primary-bg) thin solid;
+ text-decoration: none;
+}
+ul.text-snippets {
+ padding: 0;
+ margin-left: 160px;
+}
+.first-time-contributor-tada::after {
+ content: ' 🎉';
+}
+
</ins><span class="cx" style="display: block; padding: 0 10px"> /* show the event-details-right below instead of on the right on mobile */
</span><span class="cx" style="display: block; padding: 0 10px"> @media (max-width: 768px) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- .event-page-wrapper, .event-details-right, .event-details-left {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+ .event-page-wrapper,
+ .event-details-right,
+ .event-details-left {
</ins><span class="cx" style="display: block; padding: 0 10px"> width: 100%;
</span><span class="cx" style="display: block; padding: 0 10px"> float: none;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> .event-details-left {
</span><span class="cx" style="display: block; padding: 0 10px"> border-right: none;
</span><span class="cx" style="display: block; padding: 0 10px"> margin: 0;
</span><span class="cx" style="display: block; padding: 0 10px"> padding: 0;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
- .event-details-stats {
- margin: 0;
- }
</del><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsassetsjstranslationeventsjs"></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/js/translation-events.js</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/js/translation-events.js 2024-04-15 08:28:54 UTC (rev 13528)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/assets/js/translation-events.js 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -9,6 +9,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> validateEventDates();
</span><span class="cx" style="display: block; padding: 0 10px"> convertToUserLocalTime();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ setInterval( convertToUserLocalTime, 10000 );
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> $( '.submit-event' ).on(
</span><span class="cx" style="display: block; padding: 0 10px"> 'click',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -27,6 +28,16 @@
</span><span class="cx" style="display: block; padding: 0 10px"> handleDelete()
</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">+
+ $( '.text-snippet' ).on(
+ 'click',
+ function ( e ) {
+ e.preventDefault();
+ var textArea = $( this ).closest( 'div' ).find( 'textarea' );
+ var textAreaContent = textArea.val();
+ textArea.val( textAreaContent + $( this ).data( 'snippet' ) );
+ }
+ );
</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">@@ -37,6 +48,15 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * @param isDraft Whether the current event status is a draft or not
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> function handleSubmit( eventStatus, isDraft ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ const $form = $( '.translation-event-form' );
+ if ( ! $form[0].reportValidity() ) {
+ return;
+ }
+
+ if ( '' === $( '#event-title' ).val() ) {
+ $gp.notices.error( 'Event title must be set.' );
+ return;
+ }
</ins><span class="cx" style="display: block; padding: 0 10px"> if ( '' === $( '#event-start' ).val() ) {
</span><span class="cx" style="display: block; padding: 0 10px"> $gp.notices.error( 'Event start date and time must be set.' );
</span><span class="cx" style="display: block; padding: 0 10px"> return;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -56,7 +76,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"> $( '#event-form-action' ).val( eventStatus );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- const $form = $( '.translation-event-form' );
</del><span class="cx" style="display: block; padding: 0 10px"> const $is_creation = $( '#form-name' ).val() === 'create_event';
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> $.ajax(
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -148,12 +167,73 @@
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> timeElements.forEach(
</span><span class="cx" style="display: block; padding: 0 10px"> function ( timeEl ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- const eventDateObj = new Date( timeEl.getAttribute( 'datetime' ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ const datetime = timeEl.getAttribute( 'datetime' );
+ if ( ! datetime ) {
+ return;
+ }
+ const eventDateObj = new Date( datetime );
+ timeEl.title = eventDateObj.toUTCString();
+
</ins><span class="cx" style="display: block; padding: 0 10px"> const userTimezoneOffset = new Date().getTimezoneOffset();
</span><span class="cx" style="display: block; padding: 0 10px"> const userTimezoneOffsetMs = userTimezoneOffset * 60 * 1000;
</span><span class="cx" style="display: block; padding: 0 10px"> const userLocalDateTime = new Date( eventDateObj.getTime() - userTimezoneOffsetMs );
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- const options = {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( timeEl.classList.contains( 'relative' ) ) {
+ // Display the relative time.
+ const now = new Date();
+ let diff = userLocalDateTime - now;
+ let in_text = 'in ';
+ let ago_text = '';
+ if ( diff < 0 ) {
+ if ( timeEl.classList.contains( 'future' ) ) {
+ // If an event transitions from future to past, reload the page to move it from active to past events and vice versa.
+ location.reload();
+ }
+ in_text = '';
+ ago_text = ' ago';
+ diff = - diff;
+ }
+
+ const seconds = Math.floor( diff / 1000 );
+ const minutes = Math.floor( seconds / 60 );
+ const hours = Math.floor( minutes / 60 );
+ const days = Math.floor( hours / 24 );
+ const weeks = Math.floor( days / 7 );
+ const months = Math.floor( days / 30 );
+ const years = Math.floor( days / 365.25 );
+ let relativeTime = '';
+ if ( years > 1 ) {
+ if ( ! timeEl.classList.contains( 'hide-if-too-far' ) ) {
+ relativeTime = years + ' year' + ( years > 1 ? 's' : '' );
+ } else {
+ in_text = '';
+ }
+ } else if ( months > 1 ) {
+ if ( ! timeEl.classList.contains( 'hide-if-too-far' ) ) {
+ relativeTime = months + ' month' + ( months > 1 ? 's' : '' );
+ } else {
+ in_text = '';
+ }
+ } else if ( weeks > 1 ) {
+ if ( ! timeEl.classList.contains( 'hide-if-too-far' ) || weeks < 3 ) {
+ relativeTime = weeks + ' week' + ( weeks > 1 ? 's' : '' );
+ } else {
+ in_text = '';
+ }
+ } else if ( days > 0 ) {
+ relativeTime = days + ' day' + ( days > 1 ? 's' : '' );
+ } else if ( hours > 0 ) {
+ relativeTime = hours + ' hour' + ( hours > 1 ? 's' : '' );
+ } else if ( minutes > 0 ) {
+ relativeTime = minutes + ' minute' + ( minutes > 1 ? 's' : '' );
+ } else {
+ relativeTime = 'less than a minute';
+ }
+ timeEl.textContent = in_text + relativeTime + ago_text;
+ return;
+ }
+
+ const options = {
</ins><span class="cx" style="display: block; padding: 0 10px"> weekday: 'short',
</span><span class="cx" style="display: block; padding: 0 10px"> year: 'numeric',
</span><span class="cx" style="display: block; padding: 0 10px"> month: 'short',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -162,6 +242,18 @@
</span><span class="cx" style="display: block; padding: 0 10px"> minute: 'numeric',
</span><span class="cx" style="display: block; padding: 0 10px"> timeZoneName: 'short'
</span><span class="cx" style="display: block; padding: 0 10px"> };
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( timeEl.dataset.format ) {
+ if ( timeEl.dataset.format.includes( 'l' ) ) {
+ options.weekday = 'long';
+ } else if ( ! timeEl.dataset.format.includes( 'D' ) ) {
+ delete options.weekday;
+ }
+ if ( timeEl.dataset.format.includes( 'F' ) ) {
+ options.month = 'long';
+ } else if ( timeEl.dataset.format.includes( 'm' ) || timeEl.dataset.format.includes( 'n' ) ) {
+ options.month = 'numeric';
+ }
+ }
</ins><span class="cx" style="display: block; padding: 0 10px"> timeEl.textContent = userLocalDateTime.toLocaleTimeString( navigator.language, options );
</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_htmlwpcontentpluginswporggptranslationeventsautoloadphp"></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/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 (rev 0)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/autoload.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,23 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+require_once __DIR__ . '/includes/upgrade.php';
+require_once __DIR__ . '/templates/helper-functions.php';
+require_once __DIR__ . '/includes/routes/route.php';
+require_once __DIR__ . '/includes/routes/event/create.php';
+require_once __DIR__ . '/includes/routes/event/details.php';
+require_once __DIR__ . '/includes/routes/event/edit.php';
+require_once __DIR__ . '/includes/routes/event/list.php';
+require_once __DIR__ . '/includes/routes/user/attend-event.php';
+require_once __DIR__ . '/includes/routes/user/host-event.php';
+require_once __DIR__ . '/includes/routes/user/my-events.php';
+require_once __DIR__ . '/includes/attendee/attendee.php';
+require_once __DIR__ . '/includes/attendee/attendee-repository.php';
+require_once __DIR__ . '/includes/event/event-date.php';
+require_once __DIR__ . '/includes/event/event.php';
+require_once __DIR__ . '/includes/event/event-repository-interface.php';
+require_once __DIR__ . '/includes/event/event-repository.php';
+require_once __DIR__ . '/includes/event/event-repository-cached.php';
+require_once __DIR__ . '/includes/event/event-form-handler.php';
+require_once __DIR__ . '/includes/stats-calculator.php';
+require_once __DIR__ . '/includes/stats-listener.php';
+require_once __DIR__ . '/includes/event-text-snippet.php';
</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/autoload.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_htmlwpcontentpluginswporggptranslationeventsincludesactiveeventscachephp"></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/active-events-cache.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/active-events-cache.php 2024-04-15 08:28:54 UTC (rev 13528)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/active-events-cache.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,53 +0,0 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<?php
-
-namespace Wporg\TranslationEvents;
-
-use Exception;
-
-class Active_Events_Cache {
- public const CACHE_DURATION = 60 * 60 * 24; // 24 hours.
- private const KEY = 'translation-events-active-events';
-
- /**
- * Cache active events.
- *
- * @param Event[] $events Events to cache.
- *
- * @throws Exception When it fails to cache events.
- */
- public function cache( array $events ): void {
- if ( ! wp_cache_set( self::KEY, $events, '', self::CACHE_DURATION ) ) {
- throw new Exception( 'Failed to cache active events' );
- }
- }
-
- /**
- * Returns the cached events, or null if nothing is cached.
- *
- * @return Event[]|null
- * @throws Exception When it fails to retrieve cached events.
- */
- public function get(): ?array {
- $result = wp_cache_get( self::KEY, '', false, $found );
- if ( ! $found ) {
- return null;
- }
-
- if ( ! is_array( $result ) ) {
- throw new Exception( 'Cached events is not an array, something is wrong' );
- }
-
- return $result;
- }
-
- /**
- * Invalidates the active events cache.
- *
- * @throws Exception When it fails to invalidate the cache.
- */
- public static function invalidate(): void {
- if ( ! wp_cache_delete( self::KEY ) ) {
- throw new Exception( 'Failed to invalidate cached events' );
- }
- }
-}
</del></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesattendeeattendeerepositoryphp"></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/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 (rev 0)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/attendee/attendee-repository.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,187 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+namespace Wporg\TranslationEvents\Attendee;
+
+use Exception;
+use WP_User;
+
+class Attendee_Repository {
+ /**
+ * @throws Exception
+ */
+ public function insert_attendee( Attendee $attendee ): 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_attendees (event_id, user_id, is_host) values (%d, %d, %d)",
+ array(
+ 'event_id' => $attendee->event_id(),
+ 'user_id' => $attendee->user_id(),
+ 'is_host' => $attendee->is_host() ? 1 : 0,
+ ),
+ ),
+ );
+ // phpcs:enable
+ }
+
+ /**
+ * Update an attendee.
+ *
+ * @param Attendee $attendee The attendee to update.
+ * @return void
+ */
+ public function update_attendee( Attendee $attendee ): void {
+ global $wpdb, $gp_table_prefix;
+
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
+ $wpdb->update(
+ "{$gp_table_prefix}event_attendees",
+ array( 'is_host' => $attendee->is_host() ? 1 : 0 ),
+ array(
+ 'event_id' => $attendee->event_id(),
+ 'user_id' => $attendee->user_id(),
+ )
+ );
+ // phpcs:enable
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function remove_attendee( int $event_id, int $user_id ): void {
+ global $wpdb, $gp_table_prefix;
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
+ $wpdb->delete(
+ "{$gp_table_prefix}event_attendees",
+ array(
+ 'event_id' => $event_id,
+ 'user_id' => $user_id,
+ ),
+ array(
+ '%d',
+ '%d',
+ ),
+ );
+ // phpcs:enable
+ }
+
+ /**
+ * @throws Exception
+ */
+ public function get_attendee( int $event_id, int $user_id ): ?Attendee {
+ global $wpdb, $gp_table_prefix;
+
+ // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
+ $row = $wpdb->get_row(
+ $wpdb->prepare(
+ "
+ select *
+ from {$gp_table_prefix}event_attendees
+ where event_id = %d
+ and user_id = %d
+ ",
+ array(
+ $event_id,
+ $user_id,
+ ),
+ )
+ );
+ // phpcs:enable
+
+ if ( ! $row ) {
+ return null;
+ }
+
+ $attendee = new Attendee( $row->event_id, $row->user_id );
+ if ( '1' === $row->is_host ) {
+ $attendee->mark_as_host();
+ }
+
+ return $attendee;
+ }
+
+ /**
+ * @return Attendee[] Attendees of the event.
+ */
+ public function get_attendees( int $event_id ): array { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
+ // TODO.
+ return array();
+ }
+
+ /**
+ * Get the hosts' users for an event.
+ *
+ * @param int $event_id The id of the event.
+ * @return array[Attendee] The hosts of the event.
+ */
+ public function get_hosts( 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
+ $host_ids = $wpdb->get_col(
+ $wpdb->prepare(
+ "
+ select user_id
+ from {$gp_table_prefix}event_attendees
+ where event_id = %d and is_host = 1
+ ",
+ array(
+ $event_id,
+ )
+ )
+ );
+ // phpcs:enable
+
+ $hosts = array();
+ foreach ( $host_ids as $host_id ) {
+ $hosts[] = $this->get_attendee( $event_id, $host_id );
+ }
+ return $hosts;
+ }
+
+ /**
+ * @deprecated
+ * TODO: This method should be moved out of this class because it's not about attendance,
+ * it returns events that match a condition (have a user as attendee), so it belongs in an event repository.
+ * However, since we don't have an event repository yet, the method is placed here for now.
+ * When the method is moved to an event repository, it should return Event instances instead of event ids.
+ *
+ * @return int[] Event ids.
+ */
+ public function get_events_for_user( int $user_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
+ $rows = $wpdb->get_results(
+ $wpdb->prepare(
+ "
+ select event_id
+ from {$gp_table_prefix}event_attendees
+ where user_id = %d
+ ",
+ array(
+ $user_id,
+ )
+ )
+ );
+ // phpcs:enable
+
+ return array_map(
+ function ( object $row ) {
+ return intval( $row->event_id );
+ },
+ $rows
+ );
+ }
+}
</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/attendee/attendee-repository.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_htmlwpcontentpluginswporggptranslationeventsincludesattendeeattendeephp"></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/attendee/attendee.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.php (rev 0)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/attendee/attendee.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,47 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+namespace Wporg\TranslationEvents\Attendee;
+
+use Exception;
+
+class Attendee {
+ private int $event_id;
+ private int $user_id;
+ private bool $is_host;
+
+ /**
+ * @throws Exception
+ */
+ public function __construct( int $event_id, int $user_id ) {
+ if ( $event_id < 1 ) {
+ throw new Exception( 'invalid event id' );
+ }
+ if ( $user_id < 1 ) {
+ throw new Exception( 'invalid user id' );
+ }
+
+ $this->event_id = $event_id;
+ $this->user_id = $user_id;
+ $this->is_host = false;
+ }
+
+ public function event_id(): int {
+ return $this->event_id;
+ }
+
+ public function user_id(): int {
+ return $this->user_id;
+ }
+
+ public function is_host(): bool {
+ return $this->is_host;
+ }
+
+ public function mark_as_host(): void {
+ $this->is_host = true;
+ }
+
+ public function mark_as_non_host(): void {
+ $this->is_host = false;
+ }
+}
</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/attendee/attendee.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_htmlwpcontentpluginswporggptranslationeventsincludeseventeventdatephp"></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/event/event-date.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-date.php (rev 0)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/event/event-date.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,173 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+namespace Wporg\TranslationEvents\Event;
+
+use DateTime;
+use DateTimeImmutable;
+use DateTimeZone;
+use Exception;
+
+/**
+ * Event_Date
+ *
+ * The event date is in local time, get the UTC time via the utc() method.
+ *
+ * @package Wporg\TranslationEvents
+ */
+abstract class Event_Date extends DateTimeImmutable {
+ protected $event_timezone;
+ public function __construct( string $date, DateTimeZone $timezone = null ) {
+ if ( ! $timezone ) {
+ $timezone = new DateTimeZone( 'UTC' );
+ }
+
+ try {
+ $utc_date = new DateTime( $date, new DateTimeZone( 'UTC' ) );
+ $utc_date->setTimezone( $timezone );
+ } catch ( Exception $e ) {
+ $utc_date = new DateTime( 'now', new DateTimeZone( 'UTC' ) );
+ }
+
+ parent::__construct( $utc_date->format( 'Y-m-d H:i:s' ), $timezone );
+ $this->event_timezone = $timezone;
+ }
+
+ public function timezone() {
+ return $this->event_timezone;
+ }
+
+ /**
+ * Get the standard formatted text for the date in UTC.
+ *
+ * @return string The date text.
+ */
+ public function __toString(): string {
+ return $this->utc()->format( 'Y-m-d H:i:s' );
+ }
+ /**
+ * Get the local formatted text for the date in UTC.
+ *
+ * @return DateTimeImmutable The date text.
+ */
+ public function utc(): DateTimeImmutable {
+ return $this->setTimeZone( new DateTimeZone( 'UTC' ) );
+ }
+
+ public function is_in_the_past() {
+ $current_date_time = new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) );
+ return $this->utc() < $current_date_time;
+ }
+
+ public function print_relative_time_html( $format = false ) {
+ echo wp_kses(
+ '<time
+ class="event-utc-time relative' . ( $this->is_in_the_past() ? '' : ' future' ) . '"
+ datetime="' . esc_attr( $this ) . '">' . esc_html( $format ? $this->format( $format ) : $this->get_variable_text() ) . '</time>',
+ array(
+ 'time' => array(
+ 'class' => array(),
+ 'datetime' => array(),
+ ),
+ )
+ );
+ }
+
+ public function print_time_html( $format = 'D, F j, Y H:i T' ) {
+ echo wp_kses(
+ '<time
+ class="event-utc-time full-time"
+ data-format="' . esc_attr( $format ) . '"
+ datetime="' . esc_attr( $this ) . '">' . esc_html( $this->format( $format ) ) . '</time>',
+ array(
+ 'time' => array(
+ 'class' => array(),
+ 'datetime' => array(),
+ 'data-format' => array(),
+ ),
+ )
+ );
+ }
+
+ /**
+ * Generate variable text depending on when the event starts or ends.
+ *
+ * @return string The end date text.
+ */
+ abstract public function get_variable_text(): string;
+}
+
+class Event_Start_Date extends Event_Date {
+ public function get_variable_text(): string {
+ $interval = $this->diff( new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) ) );
+ $hours_left = ( $interval->d * 24 ) + $interval->h;
+ $hours_in_a_day = 24;
+
+ if ( $this->is_in_the_past() ) {
+ if ( 0 === $hours_left ) {
+ /* translators: %s: Number of minutes left. */
+ return sprintf( _n( 'started %s minute ago', 'started %s minutes ago', $interval->i ), $interval->i );
+ }
+
+ if ( $hours_left >= $hours_in_a_day ) {
+ /* translators: %s: Number of hours left. */
+ return sprintf( _n( 'started %s hour ago', 'started %s hours ago', $hours_left ), $hours_left );
+ }
+
+ // translators: %s: A date.
+ return sprintf( __( 'started %s', 'gp-translation-events' ), $this->format( 'D, F j, Y H:i T' ) );
+ }
+
+ if ( 0 === $hours_left ) {
+ if ( ! $interval->i ) {
+ return __( 'starts in less than a minute', 'gp-translation-events' );
+ }
+ /* translators: %s: Number of minutes left. */
+ return sprintf( _n( 'starts in %s minute', 'starts in %s minutes', $interval->i, 'gp-translation-events' ), $interval->i );
+ }
+
+ if ( $hours_left <= $hours_in_a_day ) {
+ /* translators: %s: Number of hours left. */
+ $out = sprintf( _n( 'starts in %s hour', 'starts in %s hours', $hours_left, 'gp-translation-events' ), $hours_left );
+ if ( $interval->i ) {
+ /* translators: %s: Number of minutes left. */
+ $out .= sprintf( _n( ' and %s minute', ' and %s minutes', $interval->i, 'gp-translation-events' ), $interval->i );
+ }
+ return $out;
+ }
+
+ // translators: %s: A date.
+ return sprintf( __( 'started %s', 'gp-translation-events' ), $this->format( 'D, F j, Y H:i T' ) );
+ }
+}
+
+class Event_End_Date extends Event_Date {
+ public function get_variable_text(): string {
+ if ( $this->is_in_the_past() ) {
+ return sprintf( 'ended %s', $this->format( 'l, F j, Y' ) );
+ }
+
+ $interval = $this->diff( new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) ) );
+ $hours_left = ( $interval->d * 24 ) + $interval->h;
+ $hours_in_a_day = 24;
+
+ if ( 0 === $hours_left ) {
+ if ( ! $interval->i ) {
+ return __( 'ends in less than a minute', 'gp-translation-events' );
+ }
+ /* translators: %s: Number of minutes left. */
+ return sprintf( _n( 'ends in %s minute', 'ends in %s minutes', $interval->i, 'gp-translation-events' ), $interval->i );
+ }
+
+ if ( $hours_left <= $hours_in_a_day ) {
+ /* translators: %s: Number of hours left. */
+ $out = sprintf( _n( 'ends in %s hour', 'ends in %s hours', $hours_left, 'gp-translation-events' ), $hours_left );
+ if ( $interval->i ) {
+ /* translators: %s: Number of minutes left. */
+ $out .= sprintf( _n( ' and %s minute', ' and %s minutes', $interval->i, 'gp-translation-events' ), $interval->i );
+ }
+ return $out;
+ }
+
+ return sprintf( 'until %s', $this->format( 'l, F j, Y H:i' ) );
+ }
+}
</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/event/event-date.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_htmlwpcontentpluginswporggptranslationeventsincludeseventeventformhandlerphp"></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/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 (rev 0)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/event/event-form-handler.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,237 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+namespace Wporg\TranslationEvents\Event;
+
+use DateTime;
+use DateTimeZone;
+use Exception;
+use GP;
+use WP_Error;
+use Wporg\TranslationEvents\Attendee\Attendee;
+use Wporg\TranslationEvents\Attendee\Attendee_Repository;
+use Wporg\TranslationEvents\Stats_Calculator;
+
+class Event_Form_Handler {
+ private Event_Repository_Interface $event_repository;
+ private Attendee_Repository $attendee_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 handle( array $form_data ): void {
+ if ( ! is_user_logged_in() ) {
+ wp_send_json_error( esc_html__( 'The user must be logged in.', 'gp-translation-events' ), 403 );
+ }
+ $action = isset( $form_data['form_name'] ) ? sanitize_text_field( wp_unslash( $form_data['form_name'] ) ) : '';
+ $response_message = '';
+ $is_nonce_valid = false;
+ $nonce_name = '_event_nonce';
+ if ( ! in_array( $action, array( 'create_event', 'edit_event', 'delete_event' ), true ) ) {
+ wp_send_json_error( esc_html__( 'Invalid form name.', 'gp-translation-events' ), 403 );
+ }
+ /**
+ * Filter the ability to create, edit, or delete an event.
+ *
+ * @param bool $can_crud_event Whether the user can create, edit, or delete an event.
+ */
+ $can_crud_event = apply_filters( 'gp_translation_events_can_crud_event', GP::$permission->current_user_can( 'admin' ) );
+ if ( 'create_event' === $action && ( ! $can_crud_event ) ) {
+ wp_send_json_error( esc_html__( 'The user does not have permission to create an event.', 'gp-translation-events' ), 403 );
+ }
+ if ( 'edit_event' === $action ) {
+ $event_id = isset( $form_data['event_id'] ) ? sanitize_text_field( wp_unslash( $form_data['event_id'] ) ) : '';
+ $event = $this->event_repository->get_event( $event_id );
+ $attendee = $this->attendee_repository->get_attendee( $event->id(), get_current_user_id() );
+ if ( ! ( $can_crud_event || ( $attendee instanceof Attendee && $attendee->is_host() ) || current_user_can( 'edit_post', $event_id ) || $event->author_id() === get_current_user_id() ) ) {
+ wp_send_json_error( esc_html__( 'The user does not have permission to edit or delete the event.', 'gp-translation-events' ), 403 );
+ }
+ }
+ if ( 'delete_event' === $action ) {
+ $event_id = isset( $form_data['event_id'] ) ? sanitize_text_field( wp_unslash( $form_data['event_id'] ) ) : '';
+ $event = $this->event_repository->get_event( $event_id );
+ $attendee = $this->attendee_repository->get_attendee( $event->id(), get_current_user_id() );
+ $stats_calculator = new Stats_Calculator();
+ if ( $stats_calculator->event_has_stats( $event->id() ) ) {
+ wp_send_json_error( esc_html__( 'The event has stats so it cannot be deleted.', 'gp-translation-events' ), 422 );
+ }
+ if ( ! ( $can_crud_event || ( $attendee instanceof Attendee && $attendee->is_host() ) || current_user_can( 'delete_post', $event_id ) || get_current_user_id() === $event->author_id() ) ) {
+ wp_send_json_error( esc_html__( 'You do not have permission to delete this event.', 'gp-translation-events' ), 403 );
+ }
+ }
+ if ( isset( $form_data[ $nonce_name ] ) ) {
+ $nonce_value = sanitize_text_field( wp_unslash( $form_data[ $nonce_name ] ) );
+ if ( wp_verify_nonce( $nonce_value, $nonce_name ) ) {
+ $is_nonce_valid = true;
+ }
+ }
+ if ( ! $is_nonce_valid ) {
+ wp_send_json_error( esc_html__( 'Nonce verification failed.', 'gp-translation-events' ), 403 );
+ }
+
+ if ( 'delete_event' === $action ) {
+ // Delete event.
+ $event_id = intval( sanitize_text_field( wp_unslash( $form_data['event_id'] ) ) );
+ $event = $this->event_repository->get_event( $event_id );
+ if ( ! $event ) {
+ wp_send_json_error( esc_html__( 'Event does not exist.', 'gp-translation-events' ), 404 );
+ }
+
+ $stats_calculator = new Stats_Calculator();
+ try {
+ $event_stats = $stats_calculator->for_event( $event->id() );
+ } catch ( Exception $e ) {
+ wp_send_json_error( esc_html__( 'Failed to calculate event stats.', 'gp-translation-events' ), 500 );
+ }
+ if ( ! empty( $event_stats->rows() ) ) {
+ wp_send_json_error( esc_html__( 'Event has stats so it cannot be deleted.', 'gp-translation-events' ), 422 );
+ }
+
+ if ( false === $this->event_repository->delete_event( $event ) ) {
+ $response_message = esc_html__( 'Failed to delete event.', 'gp-translation-events' );
+ $event_status = $event->status();
+ } else {
+ $response_message = esc_html__( 'Event deleted successfully.', 'gp-translation-events' );
+ $event_status = 'deleted';
+ }
+ } else {
+ // Create or update event.
+
+ try {
+ $new_event = $this->parse_form_data( $form_data );
+ } catch ( InvalidTimeZone $e ) {
+ wp_send_json_error( esc_html__( 'Invalid time zone.', 'gp-translation-events' ), 422 );
+ return;
+ } catch ( InvalidStart $e ) {
+ wp_send_json_error( esc_html__( 'Invalid start date.', 'gp-translation-events' ), 422 );
+ return;
+ } catch ( InvalidEnd $e ) {
+ wp_send_json_error( esc_html__( 'Invalid end date.', 'gp-translation-events' ), 422 );
+ return;
+ } catch ( InvalidStatus $e ) {
+ wp_send_json_error( esc_html__( 'Invalid status.', 'gp-translation-events' ), 422 );
+ return;
+ } catch ( InvalidTitle $e ) {
+ wp_send_json_error( esc_html__( 'Invalid title.', 'gp-translation-events' ), 422 );
+ return;
+ }
+ if ( $new_event->end() < new DateTime( 'now', new DateTimeZone( 'UTC' ) ) ) {
+ wp_send_json_error( esc_html__( 'Past events cannot be created or edited.', 'gp-translation-events' ), 422 );
+ return;
+ }
+
+ // This is a list of slugs that are not allowed, as they conflict with the event URLs.
+ $invalid_slugs = array( 'new', 'edit', 'attend', 'my-events' );
+ if ( in_array( sanitize_title( $new_event->title() ), $invalid_slugs, true ) ) {
+ wp_send_json_error( esc_html__( 'Invalid slug.', 'gp-translation-events' ), 422 );
+ }
+
+ if ( 'create_event' === $action ) {
+ $result = $this->event_repository->insert_event( $new_event );
+ if ( $result instanceof WP_Error ) {
+ wp_send_json_error( esc_html__( 'Failed to create event.', 'gp-translation-events' ), 422 );
+ return;
+ }
+ $response_message = esc_html__( 'Event created successfully.', 'gp-translation-events' );
+ }
+ if ( 'edit_event' === $action ) {
+ $event = $this->event_repository->get_event( $new_event->id() );
+ if ( ! $event ) {
+ wp_send_json_error( esc_html__( 'Event does not exist.', 'gp-translation-events' ), 404 );
+ }
+
+ try {
+ $event->set_status( $new_event->status() );
+ $event->set_title( $new_event->title() );
+ $event->set_description( $new_event->description() );
+ $event->set_timezone( $new_event->timezone() );
+ $event->set_times( $new_event->start(), $new_event->end() );
+ } catch ( Exception $e ) {
+ wp_send_json_error( esc_html__( 'Failed to update event.', 'gp-translation-events' ), 422 );
+ return;
+ }
+
+ $result = $this->event_repository->update_event( $event );
+ if ( $result instanceof WP_Error ) {
+ wp_send_json_error( esc_html__( 'Failed to update event.', 'gp-translation-events' ), 422 );
+ return;
+ }
+ $response_message = esc_html__( 'Event updated successfully', 'gp-translation-events' );
+ }
+
+ $event_id = $new_event->id();
+ $event_status = $new_event->status();
+ }
+
+ list( $permalink, $post_name ) = get_sample_permalink( $event_id );
+ $permalink = str_replace( '%pagename%', $post_name, $permalink );
+ wp_send_json_success(
+ array(
+ 'message' => $response_message,
+ 'eventId' => $event_id,
+ 'eventUrl' => str_replace( '%pagename%', $post_name, $permalink ),
+ 'eventStatus' => $event_status,
+ 'eventEditUrl' => esc_url( gp_url( '/events/edit/' . $event_id ) ),
+ 'eventDeleteUrl' => esc_url( gp_url( '/events/my-events/' ) ),
+ )
+ );
+ }
+
+ // PHPCS erroneously thinks there should be only two throw tags.
+ // phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber
+ /**
+ * @throws InvalidStart
+ * @throws InvalidEnd
+ * @throws InvalidTimeZone
+ * @throws InvalidTitle
+ * @throws InvalidStatus
+ */
+ // phpcs:enable
+ private function parse_form_data( array $data ): Event {
+ $event_id = isset( $data['event_id'] ) ? sanitize_text_field( wp_unslash( $data['event_id'] ) ) : 0;
+ $title = isset( $data['event_title'] ) ? sanitize_text_field( wp_unslash( $data['event_title'] ) ) : '';
+
+ // This will be sanitized by sanitize_post which is called in wp_insert_post.
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
+ $description = isset( $data['event_description'] ) ? force_balance_tags( wp_unslash( $data['event_description'] ) ) : '';
+ $event_start = isset( $data['event_start'] ) ? sanitize_text_field( wp_unslash( $data['event_start'] ) ) : '';
+ $event_end = isset( $data['event_end'] ) ? sanitize_text_field( wp_unslash( $data['event_end'] ) ) : '';
+ $event_timezone = isset( $data['event_timezone'] ) ? sanitize_text_field( wp_unslash( $data['event_timezone'] ) ) : '';
+
+ $event_status = '';
+ if ( isset( $data['event_form_action'] ) && in_array( $data['event_form_action'], array( 'draft', 'publish', 'delete' ), true ) ) {
+ $event_status = sanitize_text_field( wp_unslash( $data['event_form_action'] ) );
+ }
+
+ try {
+ $timezone = new DateTimeZone( $event_timezone );
+ } catch ( Exception $e ) {
+ throw new InvalidTimeZone();
+ }
+
+ try {
+ $start = new Event_Start_Date( $event_start, $timezone );
+ } catch ( Exception $e ) {
+ throw new InvalidStart();
+ }
+
+ try {
+ $end = new Event_End_Date( $event_end, $timezone );
+ } catch ( Exception $e ) {
+ throw new InvalidEnd();
+ }
+
+ $event = new Event(
+ get_current_user_id(),
+ $start->setTimezone( new DateTimeZone( 'UTC' ) ),
+ $end->setTimezone( new DateTimeZone( 'UTC' ) ),
+ $timezone,
+ $event_status,
+ $title,
+ $description,
+ );
+ $event->set_id( intval( $event_id ) );
+ return $event;
+ }
+}
</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/event/event-form-handler.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_htmlwpcontentpluginswporggptranslationeventsincludeseventeventrepositorycachedphp"></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/event/event-repository-cached.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-repository-cached.php (rev 0)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/event/event-repository-cached.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,95 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+namespace Wporg\TranslationEvents\Event;
+
+use DateTimeImmutable;
+use DateTimeZone;
+use Exception;
+use WP_Error;
+
+class Event_Repository_Cached extends Event_Repository {
+ private const CACHE_DURATION = DAY_IN_SECONDS;
+ private const ACTIVE_EVENTS_KEY = 'translation-events-active-events';
+
+ public function insert_event( Event $event ) {
+ $event_id_or_error = parent::insert_event( $event );
+ if ( $event_id_or_error instanceof WP_Error ) {
+ return $event_id_or_error;
+ }
+
+ $this->invalidate_cache();
+ return $event_id_or_error;
+ }
+
+ public function update_event( Event $event ) {
+ $event_id_or_error = parent::update_event( $event );
+ if ( $event_id_or_error instanceof WP_Error ) {
+ return $event_id_or_error;
+ }
+
+ $this->invalidate_cache();
+ return $event_id_or_error;
+ }
+
+ public function delete_event( Event $event ) {
+ parent::delete_event( $event );
+ $this->invalidate_cache();
+ }
+
+ public function get_current_events( int $page = -1, int $page_size = -1 ): Events_Query_Result {
+ $this->assert_pagination_arguments( $page, $page_size );
+
+ $cache_duration = self::CACHE_DURATION;
+ $now = new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) );
+ $boundary_start = $now;
+ $boundary_end = $now->modify( "+$cache_duration seconds" );
+
+ $events = wp_cache_get( self::ACTIVE_EVENTS_KEY, '', false, $found );
+ if ( ! $found ) {
+ $events = $this->get_events_active_between( $boundary_start, $boundary_end )->events;
+ wp_cache_set( self::ACTIVE_EVENTS_KEY, $events, '', self::CACHE_DURATION );
+ } elseif ( ! is_array( $events ) ) {
+ throw new Exception( 'Cached events is not an array, something is wrong' );
+ }
+
+ // Filter out events that aren't actually active at $at.
+ $events = array_values(
+ array_filter(
+ $events,
+ function ( $event ) use ( $now ) {
+ return $event->start() <= $now && $now <= $event->end();
+ }
+ )
+ );
+
+ if ( empty( $events ) ) {
+ return new Events_Query_Result( $events, $page, 0 );
+ }
+
+ // Split the list of all current events into pages.
+ // If no pagination parameters were supplied, we return the full list of events as a single page.
+
+ if ( $page >= 1 ) {
+ // Pagination parameters were supplied.
+ // Convert from 1-indexed to 0-indexed.
+ --$page;
+ } else {
+ // No pagination parameters were supplied.
+ $page = 0;
+ $page_size = count( $events );
+ }
+
+ $pages = array_chunk( $events, $page_size );
+ if ( ! empty( $pages ) && isset( $pages[ $page ] ) ) {
+ $events = $pages[ $page ];
+ } else {
+ $events = array();
+ }
+
+ return new Events_Query_Result( $events, $page, count( $pages ) );
+ }
+
+ private function invalidate_cache(): void {
+ wp_cache_delete( self::ACTIVE_EVENTS_KEY );
+ }
+}
</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/event/event-repository-cached.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_htmlwpcontentpluginswporggptranslationeventsincludeseventeventrepositoryinterfacephp"></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/event/event-repository-interface.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-repository-interface.php (rev 0)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/event/event-repository-interface.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,151 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+namespace Wporg\TranslationEvents\Event;
+
+use Exception;
+use WP_Error;
+
+interface Event_Repository_Interface {
+ /**
+ * Insert a new Event.
+ *
+ * @param Event $event Event to insert.
+ *
+ * @return int|WP_Error The id of the inserted event, or an error.
+ */
+ public function insert_event( Event $event );
+
+ /**
+ * Update an Event.
+ *
+ * @param Event $event Event to update.
+ *
+ * @return int|WP_Error The id of the updated event, or an error.
+ */
+ public function update_event( Event $event );
+
+ /**
+ * Delete an Event.
+ *
+ * @param Event $event Event to delete.
+ *
+ * @return Event|false Deleted event or false on error.
+ */
+ public function delete_event( Event $event );
+
+ /**
+ * Get an Event.
+ *
+ * @param int $id Event id.
+ *
+ * @return Event|null
+ */
+ public function get_event( int $id ): ?Event;
+
+ /**
+ * @throws Exception
+ */
+
+ /**
+ * Get events that are currently active.
+ *
+ * @param int $page Index of the page to return.
+ * @param int $page_size Page size.
+ *
+ * @return Events_Query_Result
+ * @throws Exception
+ */
+ public function get_current_events( int $page = -1, int $page_size = -1 ): Events_Query_Result;
+
+ /**
+ * Get events that will be active in the future.
+ *
+ * @param int $page Index of the page to return.
+ * @param int $page_size Page size.
+ *
+ * @return Events_Query_Result
+ * @throws Exception
+ */
+ public function get_upcoming_events( int $page = -1, int $page_size = -1 ): Events_Query_Result;
+
+ /**
+ * Get events that were active in the past.
+ *
+ * @param int $page Index of the page to return.
+ * @param int $page_size Page size.
+ *
+ * @return Events_Query_Result
+ * @throws Exception
+ */
+ public function get_past_events( int $page = -1, int $page_size = -1 ): Events_Query_Result;
+
+ /**
+ * Get events that are currently active for a given user.
+ *
+ * @param int $user_id Id of the user.
+ * @param int $page Index of the page to return.
+ * @param int $page_size Page size.
+ *
+ * @return Events_Query_Result
+ * @throws Exception
+ */
+ public function get_current_and_upcoming_events_for_user( int $user_id, int $page = -1, int $page_size = -1 ): Events_Query_Result;
+
+ /**
+ * Get events that are no longer active for a given user.
+ *
+ * @param int $user_id Id of the user.
+ * @param int $page Index of the page to return.
+ * @param int $page_size Page size.
+ *
+ * @return Events_Query_Result
+ * @throws Exception
+ */
+ public function get_past_events_for_user( int $user_id, int $page = -1, int $page_size = -1 ): Events_Query_Result;
+
+ /**
+ * Get events created by a given user.
+ *
+ * @param int $user_id Id of the user.
+ * @param int $page Index of the page to return.
+ * @param int $page_size Page size.
+ *
+ * @return Events_Query_Result
+ * @throws Exception
+ */
+ public function get_events_created_by_user( int $user_id, int $page = -1, int $page_size = -1 ): Events_Query_Result;
+
+ /**
+ * Get events hosted by a given user.
+ *
+ * @param int $user_id Id of the user.
+ * @param int $page Index of the page to return.
+ * @param int $page_size Page size.
+ *
+ * @return Events_Query_Result
+ * @throws Exception
+ */
+ public function get_events_hosted_by_user( int $user_id, int $page = -1, int $page_size = -1 ): Events_Query_Result;
+}
+
+class Events_Query_Result {
+ /**
+ * @var Event[]
+ */
+ public array $events;
+
+ public int $page_count;
+
+ /**
+ * @var int The current page (starts at 1).
+ */
+ public int $current_page;
+
+ public function __construct( array $events, int $current_page, int $page_count ) {
+ $this->events = $events;
+
+ // The call to intval() is required because WP_Query::max_num_pages is sometimes a float, despite being type-hinted as int.
+ $this->page_count = intval( $page_count );
+ $this->current_page = intval( $current_page );
+ }
+}
</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/event/event-repository-interface.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_htmlwpcontentpluginswporggptranslationeventsincludeseventeventrepositoryphp"></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/event/event-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/event/event-repository.php (rev 0)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/event/event-repository.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,420 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+namespace Wporg\TranslationEvents\Event;
+
+use DateTimeImmutable;
+use DateTimeZone;
+use Exception;
+use WP_Error;
+use WP_Post;
+use WP_Query;
+use Wporg\TranslationEvents\Attendee\Attendee_Repository;
+use Wporg\TranslationEvents\Translation_Events;
+
+class Event_Repository implements Event_Repository_Interface {
+ private const POST_TYPE = Translation_Events::CPT;
+
+ private Attendee_Repository $attendee_repository;
+
+ public function __construct( Attendee_Repository $attendee_repository ) {
+ $this->attendee_repository = $attendee_repository;
+ }
+
+ public function insert_event( Event $event ) {
+ $event_id_or_error = wp_insert_post(
+ array(
+ 'post_type' => self::POST_TYPE,
+ 'post_name' => $event->slug(),
+ 'post_title' => $event->title(),
+ 'post_content' => $event->description(),
+ 'post_status' => $event->status(),
+ )
+ );
+ if ( $event_id_or_error instanceof WP_Error ) {
+ return $event_id_or_error;
+ }
+
+ $event->set_id( $event_id_or_error );
+ $this->update_event_meta( $event );
+ return $event->id();
+ }
+
+ public function update_event( Event $event ) {
+ $event_id_or_error = wp_update_post(
+ array(
+ 'ID' => $event->id(),
+ 'post_name' => $event->slug(),
+ 'post_title' => $event->title(),
+ 'post_content' => $event->description(),
+ 'post_status' => $event->status(),
+ )
+ );
+ if ( $event_id_or_error instanceof WP_Error ) {
+ return $event_id_or_error;
+ }
+
+ $this->update_event_meta( $event );
+ return $event->id();
+ }
+
+ public function delete_event( Event $event ) {
+ $result = wp_trash_post( $event->id() );
+ if ( ! $result ) {
+ return false;
+ }
+ return $event;
+ }
+
+ public function get_event( int $id ): ?Event {
+ $post = $this->get_event_post( $id );
+ if ( ! $post ) {
+ return null;
+ }
+
+ try {
+ $meta = $this->get_event_meta( $id );
+ $event = new Event(
+ intval( $post->post_author ),
+ $meta['start'],
+ $meta['end'],
+ $meta['timezone'],
+ $post->post_status,
+ $post->post_title,
+ $post->post_content,
+ );
+ $event->set_id( $post->ID );
+ $event->set_slug( $post->post_name );
+ return $event;
+ } catch ( Exception $e ) {
+ // This should not be possible as it means data in the database is invalid.
+ // So we consider an invalid event to be not found.
+ return null;
+ }
+ }
+
+ public function get_current_events( int $page = -1, int $page_size = -1 ): Events_Query_Result {
+ $now = new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) );
+
+ return $this->get_events_active_between(
+ $now,
+ $now,
+ array(),
+ $page,
+ $page_size
+ );
+ }
+
+ public function get_upcoming_events( int $page = - 1, int $page_size = - 1 ): Events_Query_Result {
+ $now = new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) );
+
+ // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_query
+ // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_key
+ return $this->execute_events_query(
+ $page,
+ $page_size,
+ array(
+ 'meta_query' => array(
+ array(
+ 'key' => '_event_start',
+ 'value' => $now->format( 'Y-m-d H:i:s' ),
+ 'compare' => '>=',
+ 'type' => 'DATETIME',
+ ),
+ ),
+ 'orderby' => array( 'meta_value', 'ID' ),
+ 'order' => 'ASC',
+ )
+ );
+ // phpcs:enable
+ }
+
+ public function get_past_events( int $page = - 1, int $page_size = - 1 ): Events_Query_Result {
+ $now = new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) );
+
+ // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_query
+ // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_key
+ return $this->execute_events_query(
+ $page,
+ $page_size,
+ array(
+ 'meta_query' => array(
+ array(
+ 'key' => '_event_end',
+ 'value' => $now->format( 'Y-m-d H:i:s' ),
+ 'compare' => '<',
+ 'type' => 'DATETIME',
+ ),
+ ),
+ 'orderby' => array( 'meta_value', 'ID' ),
+ 'order' => 'DESC',
+ )
+ );
+ // phpcs:enable
+ }
+
+ public function get_current_and_upcoming_events_for_user( int $user_id, int $page = -1, int $page_size = -1 ): Events_Query_Result {
+ $now = new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) );
+
+ // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_query
+ // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_key
+ return $this->execute_events_query(
+ $page,
+ $page_size,
+ array(
+ 'meta_query' => array(
+ array(
+ 'key' => '_event_end',
+ 'value' => $now->format( 'Y-m-d H:i:s' ),
+ 'compare' => '>',
+ 'type' => 'DATETIME',
+ ),
+ ),
+ 'meta_key' => '_event_start',
+ 'orderby' => 'meta_value',
+ 'order' => 'ASC',
+ ),
+ $this->attendee_repository->get_events_for_user( $user_id ),
+ );
+ // phpcs:enable
+ }
+
+ public function get_past_events_for_user( int $user_id, int $page = -1, int $page_size = -1 ): Events_Query_Result {
+ $now = new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) );
+
+ $user_events = $this->attendee_repository->get_events_for_user( $user_id );
+ if ( empty( $user_events ) ) {
+ return new Events_Query_Result( array(), 1, 1 );
+ }
+
+ // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_query
+ // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_key
+ return $this->execute_events_query(
+ $page,
+ $page_size,
+ array(
+ 'meta_query' => array(
+ array(
+ 'key' => '_event_end',
+ 'value' => $now->format( 'Y-m-d H:i:s' ),
+ 'compare' => '<',
+ 'type' => 'DATETIME',
+ ),
+ ),
+ 'meta_key' => '_event_start',
+ 'meta_type' => 'DATETIME',
+ 'orderby' => 'meta_value',
+ 'order' => 'DESC',
+ ),
+ $user_events
+ );
+ // phpcs:enable
+ }
+
+ public function get_events_created_by_user( int $user_id, int $page = -1, int $page_size = -1 ): Events_Query_Result {
+ // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_query
+ // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_key
+ return $this->execute_events_query(
+ $page,
+ $page_size,
+ array(
+ 'post_status' => array( 'publish', 'draft' ),
+ 'author' => $user_id,
+ 'meta_key' => '_event_start',
+ 'orderby' => 'meta_value',
+ 'order' => 'DESC',
+ )
+ );
+ // phpcs:enable
+ }
+
+ public function get_events_hosted_by_user( int $user_id, int $page = -1, int $page_size = -1 ): Events_Query_Result {
+ global $wpdb, $gp_table_prefix;
+
+ // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
+ $events_user_is_hosting_ids = $wpdb->get_col(
+ $wpdb->prepare(
+ "
+ select distinct event_id
+ from {$gp_table_prefix}event_attendees
+ where user_id = %d
+ and is_host = 1
+ ",
+ array(
+ $user_id,
+ )
+ ),
+ );
+
+ if ( empty( $events_user_is_hosting_ids ) ) {
+ return new Events_Query_Result( array(), 1, 1 );
+ }
+
+ // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_query
+ // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_key
+ return $this->execute_events_query(
+ $page,
+ $page_size,
+ array(
+ 'post_status' => array( 'publish', 'draft' ),
+ 'meta_key' => '_event_start',
+ 'orderby' => 'meta_value',
+ 'order' => 'DESC',
+ ),
+ $events_user_is_hosting_ids
+ );
+ // phpcs:enable
+ }
+
+ /**
+ * @throws Exception
+ */
+ protected function get_events_active_between(
+ DateTimeImmutable $boundary_start,
+ DateTimeImmutable $boundary_end,
+ array $filter_by_ids = array(),
+ int $page = -1,
+ int $page_size = -1
+ ): Events_Query_Result {
+ if ( $boundary_end < $boundary_start ) {
+ throw new Exception( 'boundary end must not be before boundary start' );
+ }
+
+ // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_query
+ // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_key
+ $query_args = array(
+ 'meta_query' => array(
+ array(
+ 'key' => '_event_start',
+ 'value' => $boundary_end->format( 'Y-m-d H:i:s' ),
+ 'compare' => '<',
+ 'type' => 'DATETIME',
+ ),
+ array(
+ 'key' => '_event_end',
+ 'value' => $boundary_start->format( 'Y-m-d H:i:s' ),
+ 'compare' => '>',
+ 'type' => 'DATETIME',
+ ),
+ ),
+ 'meta_key' => '_event_start',
+ 'meta_type' => 'DATETIME',
+ 'orderby' => array( 'meta_value', 'ID' ),
+ );
+ // phpcs:enable
+
+ return $this->execute_events_query( $page, $page_size, $query_args, $filter_by_ids );
+ }
+
+ /**
+ * @throws Exception
+ */
+ protected function assert_pagination_arguments( int $page, int $page_size ) {
+ if ( -1 !== $page && $page <= 0 ) {
+ throw new Exception( 'page must be greater than 0' );
+ }
+ if ( -1 !== $page_size && $page_size <= 0 ) {
+ throw new Exception( 'page size must be greater than 0' );
+ }
+ if ( $page > 0 && -1 === $page_size ) {
+ throw new Exception( 'if page is specified, page size must also be' );
+ }
+ if ( $page_size > 0 && -1 === $page ) {
+ throw new Exception( 'if page size is specified, page must also be' );
+ }
+ }
+
+ /**
+ * @throws InvalidStart
+ * @throws InvalidEnd
+ * @throws InvalidTitle
+ * @throws InvalidStatus
+ * @throws Exception
+ */
+ private function execute_events_query( int $page, int $page_size, array $args, array $filter_by_ids = array() ): Events_Query_Result {
+ $this->assert_pagination_arguments( $page, $page_size );
+
+ $args = array_replace_recursive(
+ $args,
+ array(
+ 'post_type' => self::POST_TYPE,
+ 'paged' => $page,
+ 'posts_per_page' => $page_size,
+ ),
+ );
+
+ if ( ! isset( $args['post_status'] ) ) {
+ $args['post_status'] = 'publish';
+ }
+
+ if ( ! empty( $filter_by_ids ) ) {
+ $args['post__in'] = $filter_by_ids;
+ }
+
+ $query = new WP_Query( $args );
+ $posts = $query->get_posts();
+ $events = array();
+
+ foreach ( $posts as $post ) {
+ $meta = $this->get_event_meta( $post->ID );
+
+ $title = $post->post_title;
+ if ( empty( $title ) ) {
+ // Previously, it was possible for events to not have a title, so there can be events in the database
+ // that do not have a title. To work around that, we set the title of those events to a single space.
+ $title = ' ';
+ }
+
+ $event = new Event(
+ intval( $post->post_author ),
+ $meta['start'],
+ $meta['end'],
+ $meta['timezone'],
+ $post->post_status,
+ $title,
+ $post->post_content,
+ );
+ $event->set_id( $post->ID );
+ $event->set_slug( $post->post_name );
+ $events[] = $event;
+ }
+
+ return new Events_Query_Result( $events, $page, $query->max_num_pages );
+ }
+
+ private function get_event_post( int $event_id ): ?WP_Post {
+ if ( 0 === $event_id ) {
+ return null;
+ }
+ $post = get_post( $event_id );
+ if ( ! ( $post instanceof WP_Post ) ) {
+ return null;
+ }
+ if ( self::POST_TYPE !== $post->post_type ) {
+ return null;
+ }
+
+ return $post;
+ }
+
+ /**
+ * @throws Exception
+ */
+ private function get_event_meta( int $event_id ): array {
+ $meta = get_post_meta( $event_id );
+ $utc = new DateTimeZone( 'UTC' );
+
+ return array(
+ 'start' => new Event_Start_Date( $meta['_event_start'][0], $utc ),
+ 'end' => new Event_End_Date( $meta['_event_end'][0], $utc ),
+ 'timezone' => new DateTimeZone( $meta['_event_timezone'][0] ),
+ );
+ }
+
+ private function update_event_meta( Event $event ) {
+ update_post_meta( $event->id(), '_event_start', $event->start()->utc()->format( 'Y-m-d H:i:s' ) );
+ update_post_meta( $event->id(), '_event_end', $event->end()->utc()->format( 'Y-m-d H:i:s' ) );
+ update_post_meta( $event->id(), '_event_timezone', $event->timezone()->getName() );
+ }
+}
</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/event/event-repository.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_htmlwpcontentpluginswporggptranslationeventsincludeseventeventphp"></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/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 (rev 0)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/event/event.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,169 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+namespace Wporg\TranslationEvents\Event;
+
+use DateTimeZone;
+use Exception;
+use Throwable;
+
+class InvalidTimeZone extends Exception {
+ public function __construct( Throwable $previous = null ) {
+ parent::__construct( 'Event time zone is invalid', 0, $previous );
+ }
+}
+
+class InvalidStart extends Exception {
+ public function __construct( Throwable $previous = null ) {
+ parent::__construct( 'Event start is invalid', 0, $previous );
+ }
+}
+
+class InvalidEnd extends Exception {
+ public function __construct( Throwable $previous = null ) {
+ parent::__construct( 'Event end is invalid', 0, $previous );
+ }
+}
+
+class InvalidTitle extends Exception {
+ public function __construct( Throwable $previous = null ) {
+ parent::__construct( 'Event title is invalid', 0, $previous );
+ }
+}
+
+class InvalidStatus extends Exception {
+ public function __construct( Throwable $previous = null ) {
+ parent::__construct( 'Event status is invalid', 0, $previous );
+ }
+}
+
+class Event {
+ private int $id = 0;
+ private int $author_id;
+ private Event_Start_Date $start;
+ private Event_End_Date $end;
+ private DateTimeZone $timezone;
+ private string $slug = '';
+ private string $status;
+ private string $title;
+ private string $description;
+
+ /**
+ * @throws InvalidStart
+ * @throws InvalidEnd
+ * @throws InvalidStatus
+ * @throws InvalidTitle
+ */
+ public function __construct(
+ int $author_id,
+ Event_Start_Date $start,
+ Event_End_Date $end,
+ DateTimeZone $timezone,
+ string $status,
+ string $title,
+ string $description
+ ) {
+ $this->author_id = $author_id;
+ $this->set_times( $start, $end );
+ $this->set_timezone( $timezone );
+ $this->set_status( $status );
+ $this->set_title( $title );
+ $this->set_description( $description );
+ }
+
+ public function id(): int {
+ return $this->id;
+ }
+
+ public function author_id(): int {
+ return $this->author_id;
+ }
+
+ public function start(): Event_Start_Date {
+ return $this->start;
+ }
+
+ public function end(): Event_End_Date {
+ return $this->end;
+ }
+
+ public function timezone(): DateTimeZone {
+ return $this->timezone;
+ }
+
+ public function slug(): string {
+ return $this->slug;
+ }
+
+ public function status(): string {
+ return $this->status;
+ }
+
+ public function title(): string {
+ return $this->title;
+ }
+
+ public function description(): string {
+ return $this->description;
+ }
+
+ public function set_id( int $id ): void {
+ $this->id = $id;
+ }
+
+ public function set_slug( string $slug ): void {
+ $this->slug = $slug;
+ }
+
+ /**
+ * @throws InvalidStart|InvalidEnd
+ */
+ public function set_times( Event_Start_Date $start, Event_End_Date $end ): void {
+ $this->validate_times( $start, $end );
+ $this->start = $start;
+ $this->end = $end;
+ }
+
+ public function set_timezone( DateTimeZone $timezone ): void {
+ $this->timezone = $timezone;
+ }
+
+ /**
+ * @throws InvalidStatus
+ */
+ public function set_status( string $status ): void {
+ if ( ! in_array( $status, array( 'draft', 'publish' ), true ) ) {
+ throw new InvalidStatus();
+ }
+ $this->status = $status;
+ }
+
+ /**
+ * @throws InvalidTitle
+ */
+ public function set_title( string $title ): void {
+ if ( ! $title ) {
+ throw new InvalidTitle();
+ }
+ $this->title = $title;
+ }
+
+ public function set_description( string $description ): void {
+ $this->description = $description;
+ }
+
+ /**
+ * @throws InvalidStart
+ * @throws InvalidEnd
+ */
+ private function validate_times( Event_Start_Date $start, Event_End_Date $end ) {
+ if ( $end <= $start ) {
+ throw new InvalidEnd();
+ }
+ if ( ! $start->getTimezone() || 'UTC' !== $start->getTimezone()->getName() ) {
+ throw new InvalidStart();
+ }
+ if ( ! $end->getTimezone() || 'UTC' !== $end->getTimezone()->getName() ) {
+ throw new InvalidEnd();
+ }
+ }
+}
</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/event/event.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_htmlwpcontentpluginswporggptranslationeventsincludeseventtextsnippetphp"></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/event-text-snippet.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-text-snippet.php (rev 0)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/event-text-snippet.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,21 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+namespace Wporg\TranslationEvents;
+
+class Event_Text_Snippet {
+
+ /**
+ * Generate links for text snippets.
+ *
+ * @return string The snippet links in a list.
+ */
+ public static function get_snippet_links(): string {
+ $snippets = apply_filters( 'wporg_translation_events_snippets', array() );
+ $snippets_link_list = '<ul class="text-snippets">';
+ foreach ( $snippets as $snippet ) {
+ $snippets_link_list .= sprintf( '<li><a href="#" class="text-snippet" data-snippet="%s">%s</a></li>', esc_html( $snippet['snippet'] ), esc_html( $snippet['title'] ) );
+ }
+ $snippets_link_list .= '</ul>';
+ return $snippets_link_list;
+ }
+}
</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/event-text-snippet.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_htmlwpcontentpluginswporggptranslationeventsincludeseventphp"></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/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.php 2024-04-15 08:28:54 UTC (rev 13528)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/event.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,80 +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;
-
-class Event {
- private int $id;
- private DateTimeImmutable $start;
- private DateTimeImmutable $end;
- private DateTimeZone $timezone;
-
- /**
- * Make an Event from post meta.
- *
- * @throws Exception When dates are invalid.
- */
- public static function from_post_meta( int $id, array $meta ): Event {
- if ( ! isset( $meta['_event_start'][0] ) || ! isset( $meta['_event_end'][0] ) || ! isset( $meta['_event_timezone'][0] ) ) {
- throw new Exception( 'Invalid event meta' );
- }
-
- return new Event(
- $id,
- DateTimeImmutable::createFromFormat( 'Y-m-d H:i:s', $meta['_event_start'][0], new DateTimeZone( 'UTC' ) ),
- DateTimeImmutable::createFromFormat( 'Y-m-d H:i:s', $meta['_event_end'][0], new DateTimeZone( 'UTC' ) ),
- new DateTimeZone( $meta['_event_timezone'][0] ),
- );
- }
-
- private function __construct( int $id, DateTimeImmutable $start, DateTimeImmutable $end, DateTimeZone $timezone ) {
- $this->id = $id;
- $this->start = $start;
- $this->end = $end;
- $this->timezone = $timezone;
- }
-
- public function id(): int {
- return $this->id;
- }
-
- public function start(): DateTimeImmutable {
- return $this->start;
- }
-
- public function end(): DateTimeImmutable {
- return $this->end;
- }
-
- public function timezone(): DateTimeZone {
- return $this->timezone;
- }
-
- /**
- * Generate text for the end date.
- *
- * @param string $event_end The end date.
- *
- * @return string The end date text.
- */
- public static function get_end_date_text( string $event_end ): string {
- $end_date_time = new DateTimeImmutable( $event_end );
- $current_date_time = new DateTimeImmutable( 'now', new DateTimeZone( 'UTC' ) );
-
- $interval = $end_date_time->diff( $current_date_time );
- $hours_left = ( $interval->d * 24 ) + $interval->h;
- $hours_in_a_day = 24;
-
- if ( 0 === $hours_left ) {
- /* translators: %s: Number of minutes left. */
- return sprintf( _n( 'ends in %s minute', 'ends in %s minutes', $interval->i ), $interval->i );
- } elseif ( $hours_left <= $hours_in_a_day ) {
- /* translators: %s: Number of hours left. */
- return sprintf( _n( 'ends in %s hour', 'ends in %s hours', $hours_left ), $hours_left );
- }
- return sprintf( 'until %s', $end_date_time->format( 'M j, Y' ) );
- }
-}
</del></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesrouteseventcreatephp"></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/create.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/create.php 2024-04-15 08:28:54 UTC (rev 13528)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/routes/event/create.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2,6 +2,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> namespace Wporg\TranslationEvents\Routes\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 Wporg\TranslationEvents\Event\Event_End_Date;
+use Wporg\TranslationEvents\Event\Event_Start_Date;
</ins><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Routes\Route;
</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">@@ -14,18 +16,18 @@
</span><span class="cx" style="display: block; padding: 0 10px"> wp_safe_redirect( wp_login_url( home_url( $wp->request ) ) );
</span><span class="cx" style="display: block; padding: 0 10px"> exit;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $event_form_title = 'Create Event';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $event_page_title = 'Create Event';
</ins><span class="cx" style="display: block; padding: 0 10px"> $event_form_name = 'create_event';
</span><span class="cx" style="display: block; padding: 0 10px"> $css_show_url = 'hide-event-url';
</span><span class="cx" style="display: block; padding: 0 10px"> $event_id = null;
</span><span class="cx" style="display: block; padding: 0 10px"> $event_title = '';
</span><span class="cx" style="display: block; padding: 0 10px"> $event_description = '';
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $event_timezone = '';
- $event_start = '';
- $event_end = '';
</del><span class="cx" style="display: block; padding: 0 10px"> $event_url = '';
</span><span class="cx" style="display: block; padding: 0 10px"> $create_delete_button = true;
</span><span class="cx" style="display: block; padding: 0 10px"> $visibility_delete_button = 'none';
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $event_timezone = null;
+ $event_start = new Event_Start_Date( date_i18n( 'Y - m - d H:i' ) );
+ $event_end = new Event_End_Date( date_i18n( 'Y - m - d H:i' ) );
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> $this->tmpl( 'events-form', get_defined_vars() );
</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-15 08:28:54 UTC (rev 13528)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/routes/event/details.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -4,6 +4,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> use Exception;
</span><span class="cx" style="display: block; padding: 0 10px"> use GP;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use Wporg\TranslationEvents\Attendee\Attendee;
+use Wporg\TranslationEvents\Attendee\Attendee_Repository;
+use Wporg\TranslationEvents\Event\Event_Repository_Interface;
</ins><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Routes\Route;
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Stats_Calculator;
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Translation_Events;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -12,6 +15,15 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * Displays the event details page.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> class Details_Route extends Route {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ private Event_Repository_Interface $event_repository;
+ private Attendee_Repository $attendee_repository;
+
+ public function __construct() {
+ parent::__construct();
+ $this->event_repository = Translation_Events::get_event_repository();
+ $this->attendee_repository = Translation_Events::get_attendee_repository();
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> public function handle( string $event_slug ): void {
</span><span class="cx" style="display: block; padding: 0 10px"> $user = wp_get_current_user();
</span><span class="cx" style="display: block; padding: 0 10px"> $event = get_page_by_path( $event_slug, OBJECT, Translation_Events::CPT );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -18,6 +30,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> if ( ! $event ) {
</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><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $event = $this->event_repository->get_event( $event->ID );
+ if ( ! $event ) {
+ $this->die_with_404();
+ }
</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"> * Filter the ability to create, edit, or delete an event.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -25,22 +41,27 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * @param bool $can_crud_event Whether the user can create, edit, or delete an event.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> $can_crud_event = apply_filters( 'gp_translation_events_can_crud_event', GP::$permission->current_user_can( 'admin' ) );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- if ( 'publish' !== $event->post_status && ! $can_crud_event ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( 'publish' !== $event->status() && ! $can_crud_event ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> $this->die_with_error( esc_html__( 'You are not authorized to view this page.', 'gp-translation-events' ), 403 );
</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">- $event_id = $event->ID;
- $event_title = $event->post_title;
- $event_description = $event->post_content;
- $event_start = get_post_meta( $event->ID, '_event_start', true ) ?: '';
- $event_end = get_post_meta( $event->ID, '_event_end', true ) ?: '';
- $attending_event_ids = get_user_meta( $user->ID, Translation_Events::USER_META_KEY_ATTENDING, true ) ?: array();
- $user_is_attending = isset( $attending_event_ids[ $event_id ] );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $event_id = $event->id();
+ $event_title = $event->title();
+ $event_description = $event->description();
+ $event_start = $event->start();
+ $event_end = $event->end();
</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 );
+ $user_is_attending = $attendee instanceof Attendee;
+
</ins><span class="cx" style="display: block; padding: 0 10px"> $stats_calculator = new Stats_Calculator();
</span><span class="cx" style="display: block; padding: 0 10px"> try {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $event_stats = $stats_calculator->for_event( $event );
- $contributors = $stats_calculator->get_contributors( $event );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $event_stats = $stats_calculator->for_event( $event->id() );
+ $contributors = $stats_calculator->get_contributors( $event->id() );
+ $attendees = $stats_calculator->get_attendees_not_contributing( $event->id() );
+ $attendee_repo = $this->attendee_repository;
+ $hosts = $this->attendee_repository->get_hosts( $event->id() );
+ $projects = $stats_calculator->get_projects( $event->id() );
</ins><span class="cx" style="display: block; padding: 0 10px"> } catch ( Exception $e ) {
</span><span class="cx" style="display: block; padding: 0 10px"> // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
</span><span class="cx" style="display: block; padding: 0 10px"> error_log( $e );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -47,6 +68,11 @@
</span><span class="cx" style="display: block; padding: 0 10px"> $this->die_with_error( esc_html__( 'Failed to calculate event stats', 'gp-translation-events' ) );
</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">+ $is_editable_event = true;
+ if ( $event_end->is_in_the_past() || $stats_calculator->event_has_stats( $event->id() ) ) {
+ $is_editable_event = false;
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> $this->tmpl( 'event', get_defined_vars() );
</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-15 08:28:54 UTC (rev 13528)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/routes/event/edit.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2,9 +2,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> namespace Wporg\TranslationEvents\Routes\Event;
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-use DateTime;
-use DateTimeZone;
-use Exception;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use Wporg\TranslationEvents\Attendee\Attendee;
+use Wporg\TranslationEvents\Attendee\Attendee_Repository;
+use Wporg\TranslationEvents\Event\Event_Repository_Interface;
</ins><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Routes\Route;
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Stats_Calculator;
</span><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Translation_Events;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -13,6 +13,15 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * Displays the event edit page.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> class Edit_Route extends Route {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ private Event_Repository_Interface $event_repository;
+ private Attendee_Repository $attendee_repository;
+
+ public function __construct() {
+ parent::__construct();
+ $this->event_repository = Translation_Events::get_event_repository();
+ $this->attendee_repository = Translation_Events::get_attendee_repository();
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> public function handle( int $event_id ): void {
</span><span class="cx" style="display: block; padding: 0 10px"> global $wp;
</span><span class="cx" style="display: block; padding: 0 10px"> if ( ! is_user_logged_in() ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -19,58 +28,49 @@
</span><span class="cx" style="display: block; padding: 0 10px"> wp_safe_redirect( wp_login_url( home_url( $wp->request ) ) );
</span><span class="cx" style="display: block; padding: 0 10px"> exit;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $event = get_post( $event_id );
- if ( ! $event || Translation_Events::CPT !== $event->post_type || ! ( current_user_can( 'edit_post', $event->ID ) || intval( $event->post_author ) === get_current_user_id() ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $event = $this->event_repository->get_event( $event_id );
+ $attendee = $this->attendee_repository->get_attendee( $event->id(), get_current_user_id() );
+
+ if ( ! $event || ! ( ( $attendee instanceof Attendee && $attendee->is_host() ) || current_user_can( 'edit_post', $event->id() ) || $event->author_id() === get_current_user_id() ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> $this->die_with_error( esc_html__( 'Event does not exist, or you do not have permission to edit it.', 'gp-translation-events' ), 403 );
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- if ( 'trash' === $event->post_status ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( 'trash' === $event->status() ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> $this->die_with_error( esc_html__( 'You cannot edit a trashed event', 'gp-translation-events' ), 403 );
</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"> include ABSPATH . 'wp-admin/includes/post.php';
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $event_form_title = 'Edit Event';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $event_page_title = 'Edit Event';
</ins><span class="cx" style="display: block; padding: 0 10px"> $event_form_name = 'edit_event';
</span><span class="cx" style="display: block; padding: 0 10px"> $css_show_url = '';
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $event_title = $event->post_title;
- $event_description = $event->post_content;
- $event_status = $event->post_status;
- list( $permalink, $post_name ) = get_sample_permalink( $event_id );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $event_title = $event->title();
+ $event_description = $event->description();
+ $event_status = $event->status();
+ list( $permalink, $post_name ) = get_sample_permalink( $event->id() );
</ins><span class="cx" style="display: block; padding: 0 10px"> $permalink = str_replace( '%pagename%', $post_name, $permalink );
</span><span class="cx" style="display: block; padding: 0 10px"> $event_url = get_site_url() . gp_url( wp_make_link_relative( $permalink ) );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $event_timezone = get_post_meta( $event_id, '_event_timezone', true ) ?: '';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $event_timezone = $event->timezone();
+ $event_start = $event->start();
+ $event_end = $event->end();
</ins><span class="cx" style="display: block; padding: 0 10px"> $create_delete_button = false;
</span><span class="cx" style="display: block; padding: 0 10px"> $visibility_delete_button = 'inline-flex';
</span><span class="cx" style="display: block; padding: 0 10px">
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( $event->end()->is_in_the_past() ) {
+ $this->die_with_error( esc_html__( 'You cannot edit a past event.', 'gp-translation-events' ), 403 );
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> $stats_calculator = new Stats_Calculator();
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- if ( ! $stats_calculator->event_has_stats( $event ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+ if ( $stats_calculator->event_has_stats( $event->id() ) ) {
+ $this->die_with_error( esc_html__( 'You cannot edit an event with translations.', 'gp-translation-events' ), 403 );
+ }
+
+ if ( ! $stats_calculator->event_has_stats( $event->id() ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> $current_user = wp_get_current_user();
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- if ( $current_user->ID === $event->post_author || current_user_can( 'manage_options' ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( ( $current_user->ID === $event->author_id() || ( $attendee instanceof Attendee && $attendee->is_host() ) || current_user_can( 'manage_options' ) ) && ! $event->end()->is_in_the_past() ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> $create_delete_button = true;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- try {
- $event_start = self::convertToTimezone( get_post_meta( $event_id, '_event_start', true ), $event_timezone );
- $event_end = self::convertToTimezone( get_post_meta( $event_id, '_event_end', true ), $event_timezone );
- } catch ( Exception $e ) {
- // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
- error_log( $e );
- $this->die_with_error( esc_html__( 'Something is wrong.', 'gp-translation-events' ) );
- }
-
</del><span class="cx" style="display: block; padding: 0 10px"> $this->tmpl( 'events-form', get_defined_vars() );
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
- /**
- * Convert date time stored in UTC to a date time in a time zone.
- *
- * @param string $date_time The date time in UTC.
- * @param string $time_zone The time zone.
- *
- * @return string The date time in the time zone.
- * @throws Exception When date is invalid.
- */
- private static function convertToTimezone( string $date_time, string $time_zone ): string {
- return ( new DateTime( $date_time, new DateTimeZone( 'UTC' ) ) )->setTimezone( new DateTimeZone( $time_zone ) )->format( 'Y-m-d H:i:s' );
- }
</del><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesrouteseventlistphp"></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/list.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/list.php 2024-04-15 08:28:54 UTC (rev 13528)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/routes/event/list.php 2024-04-15 13:37:55 UTC (rev 13529)
</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 DateTimeZone;
</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><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use Wporg\TranslationEvents\Event\Event_Repository_Interface;
</ins><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Routes\Route;
</span><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="lines" style="display: block; padding: 0 10px; color: #888">@@ -13,6 +14,13 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * Displays the event list page.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> class List_Route extends Route {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ private Event_Repository_Interface $event_repository;
+
+ public function __construct() {
+ parent::__construct();
+ $this->event_repository = Translation_Events::get_event_repository();
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> public function handle(): void {
</span><span class="cx" style="display: block; padding: 0 10px"> $current_datetime_utc = null;
</span><span class="cx" style="display: block; padding: 0 10px"> try {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -55,92 +63,11 @@
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> // phpcs:enable
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $current_events_args = array(
- 'post_type' => Translation_Events::CPT,
- 'posts_per_page' => 10,
- 'paged' => $_current_events_paged,
- 'post_status' => 'publish',
- // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
- 'meta_query' => array(
- array(
- 'key' => '_event_start',
- 'value' => $current_datetime_utc,
- 'compare' => '<=',
- 'type' => 'DATETIME',
- ),
- array(
- 'key' => '_event_end',
- 'value' => $current_datetime_utc,
- 'compare' => '>=',
- 'type' => 'DATETIME',
- ),
- ),
- 'orderby' => 'meta_value',
- 'order' => 'ASC',
- );
- $current_events_query = new WP_Query( $current_events_args );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $current_events_query = $this->event_repository->get_current_events( $_current_events_paged, 10 );
+ $upcoming_events_query = $this->event_repository->get_upcoming_events( $_upcoming_events_paged, 10 );
+ $past_events_query = $this->event_repository->get_past_events( $_past_events_paged, 10 );
+ $user_attending_events_query = $this->event_repository->get_current_and_upcoming_events_for_user( get_current_user_id(), $_user_attending_events_paged, 10 );
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $upcoming_events_args = array(
- 'post_type' => Translation_Events::CPT,
- 'posts_per_page' => 10,
- 'paged' => $_upcoming_events_paged,
- 'post_status' => 'publish',
- // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
- 'meta_query' => array(
- array(
- 'key' => '_event_start',
- 'value' => $current_datetime_utc,
- 'compare' => '>=',
- 'type' => 'DATETIME',
- ),
- ),
- 'orderby' => 'meta_value',
- 'order' => 'ASC',
- );
- $upcoming_events_query = new WP_Query( $upcoming_events_args );
-
- $past_events_args = array(
- 'post_type' => Translation_Events::CPT,
- 'posts_per_page' => 10,
- 'paged' => $_past_events_paged,
- 'post_status' => 'publish',
- // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
- 'meta_query' => array(
- array(
- 'key' => '_event_end',
- 'value' => $current_datetime_utc,
- 'compare' => '<',
- 'type' => 'DATETIME',
- ),
- ),
- 'orderby' => 'meta_value',
- 'order' => 'ASC',
- );
- $past_events_query = new WP_Query( $past_events_args );
-
- $user_attending_events = get_user_meta( get_current_user_id(), Translation_Events::USER_META_KEY_ATTENDING, true ) ?: array( 0 );
- $user_attending_events_args = array(
- 'post_type' => Translation_Events::CPT,
- 'post__in' => array_keys( $user_attending_events ),
- 'posts_per_page' => 10,
- 'paged' => $_user_attending_events_paged,
- 'post_status' => 'publish',
- // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
- 'meta_query' => array(
- array(
- 'key' => '_event_end',
- 'value' => $current_datetime_utc,
- 'compare' => '>',
- 'type' => 'DATETIME',
- ),
- ),
- // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
- 'meta_key' => '_event_start',
- 'orderby' => 'meta_value',
- 'order' => 'ASC',
- );
- $user_attending_events_query = new WP_Query( $user_attending_events_args );
-
</del><span class="cx" style="display: block; padding: 0 10px"> $this->tmpl( 'events-list', get_defined_vars() );
</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-15 08:28:54 UTC (rev 13528)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/routes/user/attend-event.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2,6 +2,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> namespace Wporg\TranslationEvents\Routes\User;
</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 Wporg\TranslationEvents\Attendee\Attendee;
+use Wporg\TranslationEvents\Attendee\Attendee_Repository;
+use Wporg\TranslationEvents\Event\Event_Repository_Interface;
</ins><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Routes\Route;
</span><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="lines" style="display: block; padding: 0 10px; color: #888">@@ -11,6 +14,15 @@
</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><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><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ private Event_Repository_Interface $event_repository;
+ private Attendee_Repository $attendee_repository;
+
+ public function __construct() {
+ parent::__construct();
+ $this->event_repository = Translation_Events::get_event_repository();
+ $this->attendee_repository = Translation_Events::get_attendee_repository();
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> public function handle( int $event_id ): void {
</span><span class="cx" style="display: block; padding: 0 10px"> $user = wp_get_current_user();
</span><span class="cx" style="display: block; padding: 0 10px"> if ( ! $user ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -17,28 +29,23 @@
</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><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $event = get_post( $event_id );
-
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $event = $this->event_repository->get_event( $event_id );
</ins><span class="cx" style="display: block; padding: 0 10px"> if ( ! $event ) {
</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">- $event_ids = get_user_meta( $user->ID, Translation_Events::USER_META_KEY_ATTENDING, true ) ?? array();
- if ( ! $event_ids ) {
- $event_ids = array();
</del><ins style="background-color: #dfd; 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 );
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
- if ( ! isset( $event_ids[ $event_id ] ) ) {
- // Not yet attending, mark as attending.
- $event_ids[ $event_id ] = true;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( $attendee instanceof Attendee ) {
+ $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">- // Currently attending, mark as not attending.
- unset( $event_ids[ $event_id ] );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $attendee = new Attendee( $event->id(), $user->ID );
+ $this->attendee_repository->insert_attendee( $attendee );
</ins><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">- update_user_meta( $user->ID, Translation_Events::USER_META_KEY_ATTENDING, $event_ids );
-
- wp_safe_redirect( gp_url( "/events/$event->post_name" ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ wp_safe_redirect( gp_url( "/events/{$event->slug()}" ) );
</ins><span class="cx" style="display: block; padding: 0 10px"> exit;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesroutesuserhosteventphp"></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/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 (rev 0)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/routes/user/host-event.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,70 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+namespace Wporg\TranslationEvents\Routes\User;
+
+use Wporg\TranslationEvents\Attendee\Attendee;
+use Wporg\TranslationEvents\Attendee\Attendee_Repository;
+use Wporg\TranslationEvents\Event\Event_Repository_Interface;
+use Wporg\TranslationEvents\Routes\Route;
+use Wporg\TranslationEvents\Translation_Events;
+
+/**
+ * Toggle whether the current user is hosting an event.
+ * If the user is not currently marked as host, they will be marked as host.
+ * If the user is currently marked as host, they will be marked as not host.
+ */
+class Host_Event_Route extends Route {
+ private Event_Repository_Interface $event_repository;
+ private Attendee_Repository $attendee_repository;
+
+ /**
+ * Host_Event_Route constructor.
+ */
+ public function __construct() {
+ parent::__construct();
+ $this->event_repository = Translation_Events::get_event_repository();
+ $this->attendee_repository = Translation_Events::get_attendee_repository();
+ }
+
+ /**
+ * Handle the request to toggle whether the current user is hosting an event.
+ *
+ * @param int $event_id The event ID.
+ * @param int $user_id The user ID.
+ * @return void
+ */
+ public function handle( int $event_id, int $user_id ): void {
+ $current_user = wp_get_current_user();
+ if ( ! $current_user->exists() ) {
+ $this->die_with_error( esc_html__( "Only logged-in users can manage event's hosts.", 'gp-translation-events' ), 403 );
+ }
+
+ $current_user_attendee = $this->attendee_repository->get_attendee( $event_id, $current_user->ID );
+ if ( ! current_user_can( 'manage_options' ) && ! $current_user_attendee->is_host() ) {
+ $this->die_with_error( esc_html__( "This user does not have permissions to manage event's hosts.", 'gp-translation-events' ), 403 );
+ }
+
+ $event = $this->event_repository->get_event( $event_id );
+ if ( ! $event ) {
+ $this->die_with_404();
+ }
+
+ $affected_attendee = $this->attendee_repository->get_attendee( $event_id, $user_id );
+ 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 );
+ }
+ // The user is attending to the event, so if I don't find the attendee, I won't create it.
+ if ( $affected_attendee instanceof Attendee ) {
+ if ( $affected_attendee->is_host() ) {
+ $affected_attendee->mark_as_non_host();
+ } else {
+ $affected_attendee->mark_as_host();
+ }
+
+ $this->attendee_repository->update_attendee( $affected_attendee );
+ }
+
+ wp_safe_redirect( gp_url( "/events/{$event->slug()}" ) );
+ exit;
+ }
+}
</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/routes/user/host-event.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_htmlwpcontentpluginswporggptranslationeventsincludesroutesusermyeventsphp"></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/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/includes/routes/user/my-events.php 2024-04-15 08:28:54 UTC (rev 13528)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/routes/user/my-events.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -2,9 +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\Routes\User;
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-use DateTime;
-use DateTimeZone;
-use WP_Query;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use Wporg\TranslationEvents\Event\Event_Repository_Interface;
</ins><span class="cx" style="display: block; padding: 0 10px"> use Wporg\TranslationEvents\Routes\Route;
</span><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="lines" style="display: block; padding: 0 10px; color: #888">@@ -12,6 +10,13 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * Displays the My Events page for a user.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> class My_Events_Route extends Route {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ private Event_Repository_Interface $event_repository;
+
+ public function __construct() {
+ parent::__construct();
+ $this->event_repository = Translation_Events::get_event_repository();
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> public function handle(): void {
</span><span class="cx" style="display: block; padding: 0 10px"> global $wp;
</span><span class="cx" style="display: block; padding: 0 10px"> if ( ! is_user_logged_in() ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -21,6 +26,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> include ABSPATH . 'wp-admin/includes/post.php';
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> $_events_i_created_paged = 1;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $_events_i_hosted_paged = 1;
</ins><span class="cx" style="display: block; padding: 0 10px"> $_events_i_attended_paged = 1;
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> // phpcs:disable WordPress.Security.NonceVerification.Recommended
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -30,6 +36,12 @@
</span><span class="cx" style="display: block; padding: 0 10px"> $_events_i_created_paged = (int) $value;
</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">+ if ( isset( $_GET['events_i_hosted_paged'] ) ) {
+ $value = sanitize_text_field( wp_unslash( $_GET['events_i_hosted_paged'] ) );
+ if ( is_numeric( $value ) ) {
+ $_events_i_hosted_paged = (int) $value;
+ }
+ }
</ins><span class="cx" style="display: block; padding: 0 10px"> if ( isset( $_GET['events_i_attended_paged'] ) ) {
</span><span class="cx" style="display: block; padding: 0 10px"> $value = sanitize_text_field( wp_unslash( $_GET['events_i_attended_paged'] ) );
</span><span class="cx" style="display: block; padding: 0 10px"> if ( is_numeric( $value ) ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -38,47 +50,10 @@
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> // phpcs:enable
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $user_id = get_current_user_id();
- $events = get_user_meta( $user_id, Translation_Events::USER_META_KEY_ATTENDING, true ) ?: array();
- $events = array_keys( $events );
- $current_datetime_utc = ( new DateTime( 'now', new DateTimeZone( 'UTC' ) ) )->format( 'Y-m-d H:i:s' );
- $args = array(
- 'post_type' => Translation_Events::CPT,
- 'posts_per_page' => 10,
- 'events_i_created_paged' => $_events_i_created_paged,
- 'paged' => $_events_i_created_paged,
- 'post_status' => array( 'publish', 'draft' ),
- 'author' => $user_id,
- // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
- 'meta_key' => '_event_start',
- 'orderby' => 'meta_value',
- 'order' => 'DESC',
- );
- $events_i_created_query = new WP_Query( $args );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $events_i_created_query = $this->event_repository->get_events_created_by_user( get_current_user_id(), $_events_i_created_paged, 10 );
+ $events_i_host_query = $this->event_repository->get_events_hosted_by_user( get_current_user_id(), $_events_i_hosted_paged, 10 );
+ $events_i_attended_query = $this->event_repository->get_past_events_for_user( get_current_user_id(), $_events_i_attended_paged, 10 );
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $args = array(
- 'post_type' => Translation_Events::CPT,
- 'posts_per_page' => 10,
- 'events_i_attended_paged' => $_events_i_attended_paged,
- 'paged' => $_events_i_attended_paged,
- 'post_status' => 'publish',
- 'post__in' => $events,
- // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
- 'meta_query' => array(
- array(
- 'key' => '_event_end',
- 'value' => $current_datetime_utc,
- 'compare' => '<',
- 'type' => 'DATETIME',
- ),
- ),
- // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
- 'meta_key' => '_event_end',
- 'orderby' => 'meta_value',
- 'order' => 'DESC',
- );
- $events_i_attended_query = new WP_Query( $args );
-
</del><span class="cx" style="display: block; padding: 0 10px"> $this->tmpl( 'events-my-events', get_defined_vars() );
</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_htmlwpcontentpluginswporggptranslationeventsincludesstatscalculatorphp"></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/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-15 08:28:54 UTC (rev 13528)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/stats-calculator.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -5,8 +5,11 @@
</span><span class="cx" style="display: block; padding: 0 10px"> use Exception;
</span><span class="cx" style="display: block; padding: 0 10px"> use WP_Post;
</span><span class="cx" style="display: block; padding: 0 10px"> use WP_User;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use GP;
</ins><span class="cx" style="display: block; padding: 0 10px"> use GP_Locale;
</span><span class="cx" style="display: block; padding: 0 10px"> use GP_Locales;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use DateTimeImmutable;
+use DateTimeZone;
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> class Stats_Row {
</span><span class="cx" style="display: block; padding: 0 10px"> public int $created;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -85,7 +88,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @throws Exception When stats calculation failed.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- public function for_event( WP_Post $event ): Event_Stats {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ public function for_event( int $event_id ): Event_Stats {
</ins><span class="cx" style="display: block; padding: 0 10px"> $stats = new Event_Stats();
</span><span class="cx" style="display: block; padding: 0 10px"> global $wpdb, $gp_table_prefix;
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -98,15 +101,15 @@
</span><span class="cx" style="display: block; padding: 0 10px"> $wpdb->prepare(
</span><span class="cx" style="display: block; padding: 0 10px"> "
</span><span class="cx" style="display: block; padding: 0 10px"> select locale,
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- sum(action = 'create') as created,
- count(*) as total,
- count(distinct user_id) as users
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ sum(action = 'create') as created,
+ count(*) as total,
+ count(distinct user_id) as users
</ins><span class="cx" style="display: block; padding: 0 10px"> from {$gp_table_prefix}event_actions
</span><span class="cx" style="display: block; padding: 0 10px"> where event_id = %d
</span><span class="cx" style="display: block; padding: 0 10px"> group by locale with rollup
</span><span class="cx" style="display: block; padding: 0 10px"> ",
</span><span class="cx" style="display: block; padding: 0 10px"> array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $event->ID,
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $event_id,
</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">@@ -147,7 +150,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px"> * Get contributors for an event.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- public function get_contributors( WP_Post $event ): array {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ public function get_contributors( int $event_id ): array {
</ins><span class="cx" style="display: block; padding: 0 10px"> global $wpdb, $gp_table_prefix;
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -164,7 +167,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> group by user_id
</span><span class="cx" style="display: block; padding: 0 10px"> ",
</span><span class="cx" style="display: block; padding: 0 10px"> array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $event->ID,
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $event_id,
</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">@@ -188,15 +191,109 @@
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * 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;
+ }
+
+ /**
</ins><span class="cx" style="display: block; padding: 0 10px"> * Check if an event has stats.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @param WP_Post $event The event to check.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @param int $event_id The id of the event to check.
</ins><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @return bool True if the event has stats, false otherwise.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- public function event_has_stats( WP_Post $event ): bool {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ public function event_has_stats( int $event_id ): bool {
</ins><span class="cx" style="display: block; padding: 0 10px"> try {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $stats = $this->for_event( $event );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $stats = $this->for_event( $event_id );
</ins><span class="cx" style="display: block; padding: 0 10px"> } catch ( Exception $e ) {
</span><span class="cx" style="display: block; padding: 0 10px"> return false;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -203,4 +300,40 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> return ! empty( $stats->rows() );
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+ /**
+ * 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"> }
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesstatslistenerphp"></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/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-15 08:28:54 UTC (rev 13528)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/stats-listener.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -7,6 +7,9 @@
</span><span class="cx" style="display: block; padding: 0 10px"> use Exception;
</span><span class="cx" style="display: block; padding: 0 10px"> use GP_Translation;
</span><span class="cx" style="display: block; padding: 0 10px"> use GP_Translation_Set;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use Wporg\TranslationEvents\Attendee\Attendee_Repository;
+use Wporg\TranslationEvents\Event\Event;
+use Wporg\TranslationEvents\Event\Event_Repository_Interface;
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> class Stats_Listener {
</span><span class="cx" style="display: block; padding: 0 10px"> const ACTION_CREATE = 'create';
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -14,10 +17,15 @@
</span><span class="cx" style="display: block; padding: 0 10px"> const ACTION_REJECT = 'reject';
</span><span class="cx" style="display: block; padding: 0 10px"> const ACTION_REQUEST_CHANGES = 'request_changes';
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- private Active_Events_Cache $active_events_cache;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ private Attendee_Repository $attendee_repository;
+ private Event_Repository_Interface $event_repository;
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- public function __construct( Active_Events_Cache $active_events_cache ) {
- $this->active_events_cache = $active_events_cache;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ public function __construct(
+ Event_Repository_Interface $event_repository,
+ Attendee_Repository $attendee_repository
+ ) {
+ $this->event_repository = $event_repository;
+ $this->attendee_repository = $attendee_repository;
</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 start(): void {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -69,8 +77,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> private function handle_action( GP_Translation $translation, int $user_id, string $action, DateTimeImmutable $happened_at ): void {
</span><span class="cx" style="display: block; padding: 0 10px"> try {
</span><span class="cx" style="display: block; padding: 0 10px"> // Get events that are active when the action happened, for which the user is registered for.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $active_events = $this->get_active_events( $happened_at );
- $events = $this->select_events_user_is_registered_for( $active_events, $user_id );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $active_events = $this->event_repository->get_current_events();
+ $events = $this->select_events_user_is_registered_for( $active_events->events, $user_id );
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> // phpcs:ignore Generic.Commenting.DocComment.MissingShort
</span><span class="cx" style="display: block; padding: 0 10px"> /** @var GP_Translation_Set $translation_set Translation set */
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -107,61 +115,6 @@
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Get active events at a given time.
- *
- * @return Event[]
- * @throws Exception When it fails to get active events.
- */
- private function get_active_events( DateTimeImmutable $at ): array {
- $events = $this->active_events_cache->get();
- if ( null === $events ) {
- $cache_duration = Active_Events_Cache::CACHE_DURATION;
- $boundary_start = $at;
- $boundary_end = $at->modify( "+$cache_duration seconds" );
-
- // Get events for which start is before $boundary_end AND end is after $boundary_start.
- $event_ids = get_posts(
- array(
- 'post_type' => Translation_Events::CPT,
- 'post_status' => 'publish',
- 'posts_per_page' => - 1,
- 'fields' => 'ids',
- 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
- array(
- 'key' => '_event_start',
- 'value' => $boundary_end->format( 'Y-m-d H:i:s' ),
- 'compare' => '<',
- 'type' => 'DATETIME',
- ),
- array(
- 'key' => '_event_end',
- 'value' => $boundary_start->format( 'Y-m-d H:i:s' ),
- 'compare' => '>',
- 'type' => 'DATETIME',
- ),
- ),
- ),
- );
-
- $events = array();
- foreach ( $event_ids as $event_id ) {
- $meta = get_post_meta( $event_id );
- $events[] = Event::from_post_meta( $event_id, $meta );
- }
-
- $this->active_events_cache->cache( $events );
- }
-
- // Filter out events that aren't actually active at $at.
- return array_filter(
- $events,
- function ( $event ) use ( $at ) {
- return $event->start() <= $at && $at <= $event->end();
- }
- );
- }
-
- /**
</del><span class="cx" style="display: block; padding: 0 10px"> * Filter an array of events so that it only includes events the given user is attending.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><span class="cx" style="display: block; padding: 0 10px"> * @param Event[] $events Events.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -171,11 +124,11 @@
</span><span class="cx" style="display: block; padding: 0 10px"> // phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
</span><span class="cx" style="display: block; padding: 0 10px"> // phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.Found
</span><span class="cx" style="display: block; padding: 0 10px"> private function select_events_user_is_registered_for( array $events, int $user_id ): array {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $attending_event_ids = get_user_meta( $user_id, Translation_Events::USER_META_KEY_ATTENDING, true );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $attending_event_ids = $this->attendee_repository->get_events_for_user( $user_id );
</ins><span class="cx" style="display: block; padding: 0 10px"> return array_filter(
</span><span class="cx" style="display: block; padding: 0 10px"> $events,
</span><span class="cx" style="display: block; padding: 0 10px"> function ( Event $event ) use ( $attending_event_ids ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- return isset( $attending_event_ids[ $event->id() ] );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ return in_array( $event->id(), $attending_event_ids, true );
</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></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventsincludesupgradephp"></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/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 (rev 0)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/includes/upgrade.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -0,0 +1,105 @@
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<?php
+
+namespace Wporg\TranslationEvents;
+
+use Exception;
+use WP_Query;
+use Wporg\TranslationEvents\Attendee\Attendee;
+
+class Upgrade {
+ private const VERSION = 2;
+ private const VERSION_OPTION = 'wporg_gp_translations_events_version';
+
+ public static function upgrade_if_needed(): void {
+ $previous_version = get_option( self::VERSION_OPTION );
+
+ // If previous version is not set yet, set it to version 1.
+ if ( false === $previous_version ) {
+ $previous_version = 1;
+ }
+
+ if ( self::VERSION === $previous_version ) {
+ // Nothing to do, we're already at the latest version.
+ return;
+ }
+
+ // Upgrade database schema.
+ require_once ABSPATH . 'wp-admin/includes/upgrade.php';
+ dbDelta( self::get_database_schema_sql() );
+
+ // Run version-specific upgrades.
+ $is_running_tests = 'yes' === getenv( 'WPORG_TRANSLATION_EVENTS_TESTS' );
+ if ( $previous_version < 2 && ! $is_running_tests ) {
+ try {
+ self::v2_import_legacy_attendees();
+ } catch ( Exception $e ) {
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
+ error_log( $e );
+ }
+ }
+
+ update_option( self::VERSION_OPTION, self::VERSION );
+ }
+
+ private static function get_database_schema_sql(): string {
+ global $gp_table_prefix;
+
+ return "
+ CREATE TABLE `{$gp_table_prefix}event_actions` (
+ `translate_event_actions_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+ `event_id` int(10) NOT NULL COMMENT 'Post_ID of the translation_event post in the wp_posts table',
+ `original_id` int(10) NOT NULL COMMENT 'ID of the translation',
+ `user_id` int(10) NOT NULL COMMENT 'ID of the user who made the action',
+ `action` enum('approve','create','reject','request_changes') NOT NULL COMMENT 'The action that the user made (create, reject, etc)',
+ `locale` varchar(10) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL COMMENT 'Locale of the translation',
+ `happened_at` datetime NOT NULL COMMENT 'When the action happened, in UTC',
+ PRIMARY KEY (`translate_event_actions_id`),
+ UNIQUE KEY `event_per_translated_original_per_user` (`event_id`,`locale`,`original_id`,`user_id`)
+ ) COMMENT='Tracks translation actions that happened during a translation event';
+
+ CREATE TABLE `{$gp_table_prefix}event_attendees` (
+ `translate_event_attendees_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+ `event_id` int(10) NOT NULL COMMENT 'Post_ID of the translation_event post in the wp_posts table',
+ `user_id` int(10) NOT NULL COMMENT 'ID of the user who is attending the event',
+ `is_host` tinyint(1) default 0 not null comment 'Whether the user is a host of the event',
+ PRIMARY KEY (`translate_event_attendees_id`),
+ UNIQUE KEY `event_per_user` (`event_id`,`user_id`),
+ INDEX `user` (`user_id`)
+ ) COMMENT='Attendees of events';
+ ";
+ }
+
+ /**
+ * Previously, event attendance was tracked through user_meta.
+ * This function imports this legacy attendance information into the attendees table.
+ *
+ * Instead of looping through all users, we consider only users who have contributed to an event.
+ *
+ * @throws Exception
+ */
+ private static function v2_import_legacy_attendees(): void {
+ $query = new WP_Query(
+ array(
+ 'post_type' => Translation_Events::CPT,
+ 'post_status' => 'publish',
+ )
+ );
+
+ $events = $query->get_posts();
+ $stats_calculator = new Stats_Calculator();
+ $attendee_repository = Translation_Events::get_attendee_repository();
+ foreach ( $events as $event ) {
+ $host_attendee = new Attendee( $event->ID, intval( $event->post_author ) );
+ $host_attendee->mark_as_host();
+ $attendee_repository->insert_attendee( $host_attendee );
+
+ foreach ( $stats_calculator->get_contributors( $event->ID ) as $user ) {
+ $attendee = $attendee_repository->get_attendee( $event->ID, $user->id );
+ if ( ! $attendee ) {
+ $attendee = new Attendee( $event->ID, $user->ID );
+ $attendee_repository->insert_attendee( $attendee );
+ }
+ }
+ }
+ }
+}
</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/upgrade.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_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-15 08:28:54 UTC (rev 13528)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/templates/event.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -5,39 +5,34 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> namespace Wporg\TranslationEvents;
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-use WP_Post;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use WP_User;
+use Wporg\TranslationEvents\Attendee\Attendee;
+use Wporg\TranslationEvents\Attendee\Attendee_Repository;
+use Wporg\TranslationEvents\Event\Event;
+use Wporg\TranslationEvents\Event\Event_End_Date;
+use Wporg\TranslationEvents\Event\Event_Start_Date;
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/** @var WP_Post $event */
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/** @var Attendee_Repository $attendee_repo */
+/** @var Attendee $attendee */
+/** @var Event $event */
</ins><span class="cx" style="display: block; padding: 0 10px"> /** @var int $event_id */
</span><span class="cx" style="display: block; padding: 0 10px"> /** @var string $event_title */
</span><span class="cx" style="display: block; padding: 0 10px"> /** @var string $event_description */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/** @var string $event_start */
-/** @var string $event_end */
-/** @var bool $user_is_attending */
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/** @var Event_Start_Date $event_start */
+/** @var Event_End_Date $event_end */
</ins><span class="cx" style="display: block; padding: 0 10px"> /** @var Event_Stats $event_stats */
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/** @var array $projects */
+/** @var WP_User $user */
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> /* translators: %s: Event title. */
</span><span class="cx" style="display: block; padding: 0 10px"> gp_title( sprintf( __( 'Translation Events - %s' ), esc_html( $event_title ) ) );
</span><span class="cx" style="display: block; padding: 0 10px"> gp_breadcrumb_translation_events( array( esc_html( $event_title ) ) );
</span><span class="cx" style="display: block; padding: 0 10px"> gp_tmpl_header();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+$event_page_title = $event_title;
</ins><span class="cx" style="display: block; padding: 0 10px"> gp_tmpl_load( 'events-header', get_defined_vars(), __DIR__ );
</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"> <div class="event-page-wrapper">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <div class="event-details-head">
- <h1>
- <?php echo esc_html( $event_title ); ?>
- <?php if ( 'draft' === $event->post_status ) : ?>
- <span class="event-label-draft"><?php echo esc_html( $event->post_status ); ?></span>
- <?php endif; ?>
- </h1>
- <p>
- Host: <a href="<?php echo esc_attr( get_author_posts_url( $event->post_author ) ); ?>"><?php echo esc_html( get_the_author_meta( 'display_name', $event->post_author ) ); ?></a>
- <?php if ( current_user_can( 'edit_post', $event_id ) ) : ?>
- <a class="event-page-edit-link button" href="<?php echo esc_url( gp_url( 'events/edit/' . $event_id ) ); ?>"><span class="dashicons dashicons-edit"></span>Edit event</a>
- <?php endif ?>
- </p>
- </div>
</del><span class="cx" style="display: block; padding: 0 10px"> <div class="event-details-left">
</span><span class="cx" style="display: block; padding: 0 10px"> <div class="event-page-content">
</span><span class="cx" style="display: block; padding: 0 10px"> <?php
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -44,133 +39,243 @@
</span><span class="cx" style="display: block; padding: 0 10px"> echo wp_kses_post( wpautop( make_clickable( $event_description ) ) );
</span><span class="cx" style="display: block; padding: 0 10px"> ?>
</span><span class="cx" style="display: block; padding: 0 10px"> </div>
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <?php if ( ! empty( $contributors ) ) : ?>
+ <div class="event-contributors">
+ <h2><?php esc_html_e( 'Contributors', 'gp-translation-events' ); ?></h2>
+ <ul>
+ <?php foreach ( $contributors as $contributor ) : ?>
+ <li class="event-contributor" title="<?php echo esc_html( implode( ', ', $contributor->locales ) ); ?>">
+ <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>
+ <?php if ( $stats_calculator->is_first_time_contributor( $event_start, $contributor->ID ) ) : ?>
+ <span class="first-time-contributor-tada"></span>
+ <?php endif; ?>
+ <?php
+ if ( ! $event->end()->is_in_the_past() ) :
+ 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>';
+ endif;
+ 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>';
+ endif;
+ endif;
+ endif;
+ ?>
+ </li>
+ <?php endforeach; ?>
+ </ul>
+ </div>
+ <?php endif; ?>
+ <?php if ( ! empty( $attendees ) && ( ! $event->end()->is_in_the_past() || ( ( $attendee instanceof Attendee && $attendee->is_host() ) || current_user_can( 'manage_options' ) ) ) ) : ?>
+ <div class="event-attendees">
+ <h2><?php esc_html_e( 'Attendees', 'gp-translation-events' ); ?></h2>
+ <ul>
+ <?php foreach ( $attendees as $_user ) : ?>
+ <li class="event-attendee">
+ <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>
+ <?php if ( $stats_calculator->is_first_time_contributor( $event_start, $_user->ID ) ) : ?>
+ <span class="first-time-contributor-tada"></span>
+ <?php endif; ?>
+ <?php
+ if ( ! $event->end()->is_in_the_past() ) :
+ 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>';
+ endif;
+ 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>';
+ endif;
+ endif;
+ endif;
+ ?>
+ </li>
+ <?php endforeach; ?>
+ </ul>
+ </div>
+ <?php endif; ?>
</ins><span class="cx" style="display: block; padding: 0 10px"> <?php if ( ! empty( $event_stats->rows() ) ) : ?>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <div class="event-details-stats">
- <h2><?php esc_html_e( 'Stats', 'gp-translation-events' ); ?></h2>
- <table>
- <thead>
- <tr>
- <th scope="col">Locale</th>
- <th scope="col">Translations created</th>
- <th scope="col">Translations reviewed</th>
- <th scope="col">Contributors</th>
- </tr>
- </thead>
- <tbody>
- <?php /** @var $row Stats_Row */ ?>
- <?php foreach ( $event_stats->rows() as $_locale => $row ) : ?>
- <tr>
- <td title="<?php echo esc_html( $_locale ); ?> "><a href="<?php echo esc_url( gp_url_join( gp_url( '/languages' ), $row->language->slug ) ); ?>"><?php echo esc_html( $row->language->english_name ); ?></a></td>
- <td><?php echo esc_html( $row->created ); ?></td>
- <td><?php echo esc_html( $row->reviewed ); ?></td>
- <td><?php echo esc_html( $row->users ); ?></td>
- </tr>
- <?php endforeach ?>
- <tr class="event-details-stats-totals">
- <td>Total</td>
- <td><?php echo esc_html( $event_stats->totals()->created ); ?></td>
- <td><?php echo esc_html( $event_stats->totals()->reviewed ); ?></td>
- <td><?php echo esc_html( $event_stats->totals()->users ); ?></td>
- </tr>
- </tbody>
- </table>
- </div>
- <div class="event-contributors">
- <h2><?php esc_html_e( 'Contributors', 'gp-translation-events' ); ?></h2>
- <ul>
- <?php foreach ( $contributors as $contributor ) : ?>
- <li class="event-contributor" title="<?php echo esc_html( implode( ', ', $contributor->locales ) ); ?>"
- <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>
- </li>
- <?php endforeach; ?>
- </ul>
- </div>
- <details class="event-stats-summary">
- <summary>View stats summary in text </summary>
- <p class="event-stats-text">
- <?php
- echo wp_kses(
- sprintf(
- // translators: %1$s: Event title, %2$d: Number of contributors, %3$d: Number of languages, %4$s: List of languages, %5$d: Number of strings translated, %6$d: Number of strings reviewed.
- __( 'At the <strong>%1$s</strong> event, %2$d people contributed in %3$d languages (%4$s), translated %5$d strings and reviewed %6$d strings.', 'gp-translation-events' ),
- esc_html( $event_title ),
- esc_html( $event_stats->totals()->users ),
- count( $event_stats->rows() ),
- esc_html(
- implode(
- ', ',
- array_map(
- function ( $row ) {
- return $row->language->english_name;
- },
- $event_stats->rows()
- )
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <div class="event-details-stats">
+ <h2><?php esc_html_e( 'Stats', 'gp-translation-events' ); ?></h2>
+ <table>
+ <thead>
+ <tr>
+ <th scope="col">Locale</th>
+ <th scope="col">Translations created</th>
+ <th scope="col">Translations reviewed</th>
+ <th scope="col">Contributors</th>
+ </tr>
+ </thead>
+ <tbody>
+ <?php /** @var $row Stats_Row */ ?>
+ <?php foreach ( $event_stats->rows() as $_locale => $row ) : ?>
+ <tr>
+ <td title="<?php echo esc_html( $_locale ); ?> "><a href="<?php echo esc_url( gp_url_join( gp_url( '/languages' ), $row->language->slug ) ); ?>"><?php echo esc_html( $row->language->english_name ); ?></a></td>
+ <td><?php echo esc_html( $row->created ); ?></td>
+ <td><?php echo esc_html( $row->reviewed ); ?></td>
+ <td><?php echo esc_html( $row->users ); ?></td>
+ </tr>
+ <?php endforeach ?>
+ <tr class="event-details-stats-totals">
+ <td>Total</td>
+ <td><?php echo esc_html( $event_stats->totals()->created ); ?></td>
+ <td><?php echo esc_html( $event_stats->totals()->reviewed ); ?></td>
+ <td><?php echo esc_html( $event_stats->totals()->users ); ?></td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ <div class="event-projects">
+ <h2><?php esc_html_e( 'Projects', 'gp-translation-events' ); ?></h2>
+ <ul>
+ <?php foreach ( $projects as $project_name => $row ) : ?>
+ <li class="event-project" title="<?php echo esc_html( str_replace( ',', ', ', $row->locales ) ); ?>">
+ <a href="<?php echo esc_url( gp_url_project( $row->project ) ); ?>"><?php echo esc_html( $project_name ); ?></a> <small> to
+ <?php
+ foreach ( explode( ',', $row->locales ) as $_locale ) {
+ $_locale = \GP_Locales::by_slug( $_locale );
+ ?>
+ <a href="<?php echo esc_url( gp_url_project_locale( $row->project, $_locale, 'default' ) ); ?>"><?php echo esc_html( $_locale->english_name ); ?></a>
+ <?php
+ }
+ // translators: %d: Number of contributors.
+ echo esc_html( sprintf( _n( 'by %d contributor', 'by %d contributors', $row->users, 'gp-translation-events' ), $row->users ) );
+ ?>
+ </small>
+ </li>
+ <?php endforeach; ?>
+ </ul>
+ </div>
+ <details class="event-stats-summary">
+ <summary>View stats summary in text </summary>
+ <p class="event-stats-text">
+ <?php
+ echo wp_kses(
+ sprintf(
+ // translators: %1$s: Event title, %2$d: Number of contributors, %3$d: Number of languages, %4$s: List of languages, %5$d: Number of strings translated, %6$d: Number of strings reviewed.
+ __( 'At the <strong>%1$s</strong> event, %2$d people contributed in %3$d languages (%4$s), translated %5$d strings and reviewed %6$d strings.', 'gp-translation-events' ),
+ esc_html( $event_title ),
+ esc_html( $event_stats->totals()->users ),
+ count( $event_stats->rows() ),
+ esc_html(
+ implode(
+ ', ',
+ array_map(
+ function ( $row ) {
+ return $row->language->english_name;
+ },
+ $event_stats->rows()
+ )
+ )
+ ),
+ esc_html( $event_stats->totals()->created ),
+ esc_html( $event_stats->totals()->reviewed )
+ ),
+ array(
+ 'strong' => array(),
</ins><span class="cx" style="display: block; padding: 0 10px"> )
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- ),
- esc_html( $event_stats->totals()->created ),
- esc_html( $event_stats->totals()->reviewed )
- ),
- array(
- 'strong' => array(),
- )
- );
- ?>
- <?php
- echo esc_html(
- sprintf(
- // translators: %s the contributors.
- __( 'Contributors were %s.', 'gp-translation-events' ),
- esc_html(
- implode(
- ', ',
- array_map(
- function ( $contributor ) {
- return '@' . $contributor->user_login;
- },
- $contributors
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ );
+ ?>
+ <?php
+ echo wp_kses(
+ sprintf(
+ // translators: %s the contributors.
+ esc_html__( 'Contributors were %s.', 'gp-translation-events' ),
+ implode(
+ ', ',
+ array_map(
+ function ( $contributor ) use ( $stats_calculator, $event_start ) {
+ $append_tada = $stats_calculator->is_first_time_contributor( $event_start, $contributor->ID ) ? '<span class="first-time-contributor-tada"></span>' : '';
+ return '@' . $contributor->user_login . $append_tada;
+ },
+ $contributors
+ )
</ins><span class="cx" style="display: block; padding: 0 10px"> )
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ ),
+ array(
+ 'span' => array(
+ 'class' => array(),
+ ),
</ins><span class="cx" style="display: block; padding: 0 10px"> )
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- )
- )
- );
- ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ );
+ ?>
</ins><span class="cx" style="display: block; padding: 0 10px"> </p>
</span><span class="cx" style="display: block; padding: 0 10px"> </details>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
- <?php endif; ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <?php endif; ?>
</ins><span class="cx" style="display: block; padding: 0 10px"> </div>
</span><span class="cx" style="display: block; padding: 0 10px"> <div class="event-details-right">
</span><span class="cx" style="display: block; padding: 0 10px"> <div class="event-details-date">
</span><span class="cx" style="display: block; padding: 0 10px"> <p>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <span class="event-details-date-label">Starts:</span> <time class="event-utc-time" datetime="<?php echo esc_attr( $event_start ); ?>"></time>
- <span class="event-details-date-label">Ends:</span><time class="event-utc-time" datetime="<?php echo esc_attr( $event_end ); ?>"></time>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <span class="event-details-date-label">
+ <?php echo esc_html( $event_start->is_in_the_past() ? __( 'Started', 'gp-translation-events' ) : __( 'Starts', 'gp-translation-events' ) ); ?>:
+ <?php $event_start->print_relative_time_html(); ?>
+ </span>
+ <?php $event_start->print_time_html(); ?>
+ <span class="event-details-date-label">
+ <?php echo esc_html( $event_end->is_in_the_past() ? __( 'Ended', 'gp-translation-events' ) : __( 'Ends', 'gp-translation-events' ) ); ?>:
+ <?php $event_end->print_relative_time_html(); ?>
+
+ </span>
+ <?php $event_end->print_time_html(); ?>
</ins><span class="cx" style="display: block; padding: 0 10px"> </p>
</span><span class="cx" style="display: block; padding: 0 10px"> </div>
</span><span class="cx" style="display: block; padding: 0 10px"> <?php if ( is_user_logged_in() ) : ?>
</span><span class="cx" style="display: block; padding: 0 10px"> <div class="event-details-join">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <?php
- $current_time = gmdate( 'Y-m-d H:i:s' );
- if ( strtotime( $current_time ) > strtotime( $event_end ) ) :
- ?>
- <?php if ( $user_is_attending ) : ?>
- <span class="event-details-join-expired"><?php esc_html_e( 'You attended', 'gp-translation-events' ); ?></span>
- <?php endif ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <?php if ( $event_end->is_in_the_past() ) : ?>
+ <?php if ( $attendee instanceof Attendee ) : ?>
+ <button disabled="disabled" class="button is-primary attend-btn"><?php esc_html_e( 'You attended', 'gp-translation-events' ); ?></button>
+ <?php endif; ?>
</ins><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><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <?php if ( ! $user_is_attending ) : ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <?php if ( $attendee instanceof Attendee ) : ?>
+ <?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; ?>
+ <?php else : ?>
</ins><span class="cx" style="display: block; padding: 0 10px"> <input type="submit" class="button is-primary attend-btn" value="Attend Event"/>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <?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">+ <?php endif; ?>
</ins><span class="cx" style="display: block; padding: 0 10px"> </form>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <?php endif ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <?php endif; ?>
</ins><span class="cx" style="display: block; padding: 0 10px"> </div>
</span><span class="cx" style="display: block; padding: 0 10px"> <?php else : ?>
</span><span class="cx" style="display: block; padding: 0 10px"> <div class="event-details-join">
</span><span class="cx" style="display: block; padding: 0 10px"> <p>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <?php global $wp; ?>
- <a href="<?php echo esc_url( wp_login_url( home_url( $wp->request ) ) ); ?>" class="button is-primary attend-btn"><?php esc_html_e( 'Login to attend', 'gp-translation-events' ); ?></a>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <?php if ( ! $event_end->is_in_the_past() ) : ?>
+ <a href="<?php echo esc_url( wp_login_url() ); ?>" class="button is-primary attend-btn"><?php esc_html_e( 'Login to attend', 'gp-translation-events' ); ?></a>
+ <?php else : ?>
+ <button disabled="disabled" class="button is-primary attend-btn"><?php esc_html_e( 'Event is over', 'gp-translation-events' ); ?></button>
+ <?php endif; ?>
</ins><span class="cx" style="display: block; padding: 0 10px"> </p>
</span><span class="cx" style="display: block; padding: 0 10px"> </div>
</span><span class="cx" style="display: block; padding: 0 10px"> <?php endif; ?>
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventstemplateseventsformphp"></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-form.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-form.php 2024-04-15 08:28:54 UTC (rev 13528)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/templates/events-form.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -5,24 +5,27 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> namespace Wporg\TranslationEvents;
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/** @var string $event_form_title */
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use DateTimeZone;
+use Wporg\TranslationEvents\Event\Event_End_Date;
+use Wporg\TranslationEvents\Event\Event_Start_Date;
+
+/** @var string $event_page_title */
</ins><span class="cx" style="display: block; padding: 0 10px"> /** @var string $event_form_name */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/** @var int $event_id */
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/** @var int $event_id */
</ins><span class="cx" style="display: block; padding: 0 10px"> /** @var string $event_title */
</span><span class="cx" style="display: block; padding: 0 10px"> /** @var string $event_description */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/** @var string $event_start */
-/** @var string $event_end */
-/** @var string $event_timezone */
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/** @var Event_Start_Date $event_start */
+/** @var Event_End_Date $event_end */
+/** @var DateTimeZone|null $event_timezone */
</ins><span class="cx" style="display: block; padding: 0 10px"> /** @var string $event_url */
</span><span class="cx" style="display: block; padding: 0 10px"> /** @var string $css_show_url */
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-gp_title( __( 'Translation Events' ) . ' - ' . esc_html( $event_form_title . ' - ' . $event_title ) );
-gp_breadcrumb_translation_events( array( esc_html( $event_form_title ) ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+gp_title( __( 'Translation Events' ) . ' - ' . esc_html( $event_page_title . ' - ' . $event_title ) );
+gp_breadcrumb_translation_events( array( esc_html( $event_page_title ) ) );
</ins><span class="cx" style="display: block; padding: 0 10px"> gp_tmpl_header();
</span><span class="cx" style="display: block; padding: 0 10px"> gp_tmpl_load( 'events-header', get_defined_vars(), __DIR__ );
</span><span class="cx" style="display: block; padding: 0 10px"> ?>
</span><span class="cx" style="display: block; padding: 0 10px"> <div class="event-page-wrapper">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-<h2 class="event-page-title"><?php echo esc_html( $event_form_title ); ?></h2>
</del><span class="cx" style="display: block; padding: 0 10px"> <form class="translation-event-form" action="" method="post">
</span><span class="cx" style="display: block; padding: 0 10px"> <?php wp_nonce_field( '_event_nonce', '_event_nonce' ); ?>
</span><span class="cx" style="display: block; padding: 0 10px"> <input type="hidden" name="action" value="submit_event_ajax">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -40,21 +43,34 @@
</span><span class="cx" style="display: block; padding: 0 10px"> <div>
</span><span class="cx" style="display: block; padding: 0 10px"> <label for="event-description">Event Description</label>
</span><span class="cx" style="display: block; padding: 0 10px"> <textarea id="event-description" name="event_description" rows="4" required><?php echo esc_html( $event_description ); ?></textarea>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- </div>
- <div>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <?php
+ echo wp_kses(
+ Event_Text_Snippet::get_snippet_links(),
+ array(
+ 'a' => array(
+ 'href' => array(),
+ 'data-snippet' => array(),
+ 'class' => array(),
+ ),
+ 'ul' => array( 'class' => array() ),
+ 'li' => array(),
+ )
+ );
+ ?>
+ <div>
</ins><span class="cx" style="display: block; padding: 0 10px"> <label for="event-start">Start Date</label>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <input type="datetime-local" id="event-start" name="event_start" value="<?php echo esc_attr( $event_start ); ?>" required>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <input type="datetime-local" id="event-start" name="event_start" value="<?php echo esc_attr( $event_start->format( 'Y-m-d H:i' ) ); ?>" required>
</ins><span class="cx" style="display: block; padding: 0 10px"> </div>
</span><span class="cx" style="display: block; padding: 0 10px"> <div>
</span><span class="cx" style="display: block; padding: 0 10px"> <label for="event-end">End Date</label>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <input type="datetime-local" id="event-end" name="event_end" value="<?php echo esc_attr( $event_end ); ?>" required>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <input type="datetime-local" id="event-end" name="event_end" value="<?php echo esc_attr( $event_end->format( 'Y-m-d H:i' ) ); ?>" required>
</ins><span class="cx" style="display: block; padding: 0 10px"> </div>
</span><span class="cx" style="display: block; padding: 0 10px"> <div>
</span><span class="cx" style="display: block; padding: 0 10px"> <label for="event-timezone">Event Timezone</label>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <select id="event-timezone" name="event_timezone" required>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <select id="event-timezone" name="event_timezone" required>
</ins><span class="cx" style="display: block; padding: 0 10px"> <?php
</span><span class="cx" style="display: block; padding: 0 10px"> echo wp_kses(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- wp_timezone_choice( $event_timezone, get_user_locale() ),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ wp_timezone_choice( $event_timezone ? $event_timezone->getName() : null, get_user_locale() ),
</ins><span class="cx" style="display: block; padding: 0 10px"> array(
</span><span class="cx" style="display: block; padding: 0 10px"> 'optgroup' => array( 'label' => array() ),
</span><span class="cx" style="display: block; padding: 0 10px"> 'option' => array(
</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-15 08:28:54 UTC (rev 13528)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/templates/events-header.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,10 +1,24 @@
</span><span class="cx" style="display: block; padding: 0 10px"> <?php
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><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 GP;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use Wporg\TranslationEvents\Attendee\Attendee;
+use Wporg\TranslationEvents\Event\Event;
+
+/** @var Attendee $attendee */
+/** @var Event $event */
+/** @var string $event_page_title */
+/** @var bool $is_editable_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"> <div class="event-list-top-bar">
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+<h2 class="event-page-title">
+ <?php echo esc_html( $event_page_title ); ?>
+ <?php if ( isset( $event ) && 'draft' === $event->status() ) : ?>
+ <span class="event-label-draft"><?php echo esc_html( $event->status() ); ?></span>
+ <?php endif; ?>
+</h2>
</ins><span class="cx" style="display: block; padding: 0 10px"> <ul class="event-list-nav">
</span><span class="cx" style="display: block; padding: 0 10px"> <?php if ( is_user_logged_in() ) : ?>
</span><span class="cx" style="display: block; padding: 0 10px"> <li><a href="<?php echo esc_url( gp_url( '/events/my-events/' ) ); ?>">My Events</a></li>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -21,4 +35,29 @@
</span><span class="cx" style="display: block; padding: 0 10px"> <?php endif; ?>
</span><span class="cx" style="display: block; padding: 0 10px"> <?php endif; ?>
</span><span class="cx" style="display: block; padding: 0 10px"> </ul>
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <?php if ( isset( $event ) && ! isset( $event_form_name ) ) : ?>
+ <p class="event-sub-head">
+ <span class="event-host">
+ <?php
+ if ( 1 === count( $hosts ) ) :
+ esc_html_e( 'Host:', 'gp-translation-events' );
+ else :
+ esc_html_e( 'Hosts:', 'gp-translation-events' );
+ endif;
+ ?>
+ <?php foreach ( $hosts as $host ) : ?>
+ <?php $user = get_userdata( $host->user_id() ); ?>
+ <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 if ( end( $hosts ) !== $host ) : ?>
+ ,
+ <?php endif; ?>
+ <?php endforeach; ?>
+ .</span>
+ <?php $show_edit_button = ( ( $attendee instanceof Attendee && $attendee->is_host() ) || current_user_can( 'edit_post', $event->id() ) ) && $is_editable_event; ?>
+ <?php if ( $show_edit_button ) : ?>
+ <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>
+ <?php endif ?>
+ </p>
+ <?php endif; ?>
+
</ins><span class="cx" style="display: block; padding: 0 10px"> </div>
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentpluginswporggptranslationeventstemplateseventslistphp"></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-list.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-list.php 2024-04-15 08:28:54 UTC (rev 13528)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/templates/events-list.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -7,38 +7,39 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> use DateTime;
</span><span class="cx" style="display: block; padding: 0 10px"> use WP_Query;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use Wporg\TranslationEvents\Event\Event;
+use Wporg\TranslationEvents\Event\Events_Query_Result;
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/** @var WP_Query $current_events_query */
-/** @var WP_Query $upcoming_events_query */
-/** @var WP_Query $past_events_query */
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/** @var Events_Query_Result $current_events_query */
+/** @var Events_Query_Result $upcoming_events_query */
+/** @var Events_Query_Result $past_events_query */
+/** @var Events_Query_Result $user_attending_events_query */
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> gp_title( __( 'Translation Events', 'gp-translation-events' ) );
</span><span class="cx" style="display: block; padding: 0 10px"> gp_breadcrumb_translation_events();
</span><span class="cx" style="display: block; padding: 0 10px"> gp_tmpl_header();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+$event_page_title = __( 'Translation Events', 'gp-translation-events' );
</ins><span class="cx" style="display: block; padding: 0 10px"> gp_tmpl_load( 'events-header', get_defined_vars(), __DIR__ );
</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"> <div class="event-page-wrapper">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <h1 class="event_page_title"><?php esc_html_e( 'Translation Events', 'gp-translation-events' ); ?></h1>
</del><span class="cx" style="display: block; padding: 0 10px"> <div class="event-left-col">
</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 ( $current_events_query->have_posts() ) :
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+if ( ! empty( $current_events_query->events ) ) :
</ins><span class="cx" style="display: block; padding: 0 10px"> ?>
</span><span class="cx" style="display: block; padding: 0 10px"> <h2><?php esc_html_e( 'Current events', 'gp-translation-events' ); ?></h2>
</span><span class="cx" style="display: block; padding: 0 10px"> <ul class="event-list">
</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">- while ( $current_events_query->have_posts() ) :
- $current_events_query->the_post();
- $event_end = Event::get_end_date_text( get_post_meta( get_the_ID(), '_event_end', true ) );
- $event_url = gp_url( wp_make_link_relative( get_the_permalink() ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ foreach ( $current_events_query->events as $event ) :
+ $event_url = gp_url( wp_make_link_relative( get_the_permalink( $event->id() ) ) );
</ins><span class="cx" style="display: block; padding: 0 10px"> ?>
</span><span class="cx" style="display: block; padding: 0 10px"> <li class="event-list-item">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <a href="<?php echo esc_url( $event_url ); ?>"><?php the_title(); ?></a>
- <span class="event-list-date"><?php echo esc_html( $event_end ); ?></span>
- <?php the_excerpt(); ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <a href="<?php echo esc_url( $event_url ); ?>"><?php echo esc_html( $event->title() ); ?></a>
+ <span class="event-list-date">ends <?php $event->end()->print_relative_time_html(); ?></time></span>
+ <?php echo esc_html( get_the_excerpt( $event->id() ) ); ?>
</ins><span class="cx" style="display: block; padding: 0 10px"> </li>
</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">- endwhile;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ endforeach;
</ins><span class="cx" style="display: block; padding: 0 10px"> ?>
</span><span class="cx" style="display: block; padding: 0 10px"> </ul>
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -46,8 +47,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> echo wp_kses_post(
</span><span class="cx" style="display: block; padding: 0 10px"> paginate_links(
</span><span class="cx" style="display: block; padding: 0 10px"> array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- 'total' => $current_events_query->max_num_pages,
- 'current' => max( 1, $current_events_query->query_vars['paged'] ),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ 'total' => $current_events_query->page_count,
+ 'current' => $current_events_query->current_page,
</ins><span class="cx" style="display: block; padding: 0 10px"> 'format' => '?current_events_paged=%#%',
</span><span class="cx" style="display: block; padding: 0 10px"> 'prev_text' => '« Previous',
</span><span class="cx" style="display: block; padding: 0 10px"> 'next_text' => 'Next »',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -57,22 +58,22 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> wp_reset_postdata();
</span><span class="cx" style="display: block; padding: 0 10px"> endif;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-if ( $upcoming_events_query->have_posts() ) :
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+if ( ! empty( $upcoming_events_query->events ) ) :
</ins><span class="cx" style="display: block; padding: 0 10px"> ?>
</span><span class="cx" style="display: block; padding: 0 10px"> <h2><?php esc_html_e( 'Upcoming events', 'gp-translation-events' ); ?></h2>
</span><span class="cx" style="display: block; padding: 0 10px"> <ul class="event-list">
</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">- while ( $upcoming_events_query->have_posts() ) :
- $upcoming_events_query->the_post();
- $event_start = ( new DateTime( get_post_meta( get_the_ID(), '_event_start', true ) ) )->format( 'l, F j, Y' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ foreach ( $upcoming_events_query->events as $event ) :
+ $event_url = gp_url( wp_make_link_relative( get_the_permalink( $event->id() ) ) );
</ins><span class="cx" style="display: block; padding: 0 10px"> ?>
</span><span class="cx" style="display: block; padding: 0 10px"> <li class="event-list-item">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <a href="<?php echo esc_url( gp_url( wp_make_link_relative( get_the_permalink() ) ) ); ?>"><?php the_title(); ?></a>
- <span class="event-list-date"><?php echo esc_html( $event_start ); ?></span>
- <?php the_excerpt(); ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <a href="<?php echo esc_url( $event_url ); ?>"><?php echo esc_html( $event->title() ); ?></a>
+ <span class="event-list-date">starts <?php $event->start()->print_relative_time_html(); ?></span>
+ <?php echo esc_html( get_the_excerpt( $event->id() ) ); ?>
</ins><span class="cx" style="display: block; padding: 0 10px"> </li>
</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">- endwhile;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ endforeach;
</ins><span class="cx" style="display: block; padding: 0 10px"> ?>
</span><span class="cx" style="display: block; padding: 0 10px"> </ul>
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -80,8 +81,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> echo wp_kses_post(
</span><span class="cx" style="display: block; padding: 0 10px"> paginate_links(
</span><span class="cx" style="display: block; padding: 0 10px"> array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- 'total' => $upcoming_events_query->max_num_pages,
- 'current' => max( 1, $upcoming_events_query->query_vars['paged'] ),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ 'total' => $upcoming_events_query->page_count,
+ 'current' => $upcoming_events_query->current_page,
</ins><span class="cx" style="display: block; padding: 0 10px"> 'format' => '?upcoming_events_paged=%#%',
</span><span class="cx" style="display: block; padding: 0 10px"> 'prev_text' => '« Previous',
</span><span class="cx" style="display: block; padding: 0 10px"> 'next_text' => 'Next »',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -91,27 +92,21 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> wp_reset_postdata();
</span><span class="cx" style="display: block; padding: 0 10px"> endif;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-if ( $past_events_query->have_posts() ) :
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+if ( ! empty( $past_events_query->events ) ) :
</ins><span class="cx" style="display: block; padding: 0 10px"> ?>
</span><span class="cx" style="display: block; padding: 0 10px"> <h2><?php esc_html_e( 'Past events', 'gp-translation-events' ); ?></h2>
</span><span class="cx" style="display: block; padding: 0 10px"> <ul class="event-list">
</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">- while ( $past_events_query->have_posts() ) :
- $past_events_query->the_post();
- $event_start = ( new DateTime( get_post_meta( get_the_ID(), '_event_start', true ) ) )->format( 'M j, Y' );
- $event_end = ( new DateTime( get_post_meta( get_the_ID(), '_event_end', true ) ) )->format( 'M j, Y' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ foreach ( $past_events_query->events as $event ) :
+ $event_url = gp_url( wp_make_link_relative( get_the_permalink( $event->id() ) ) );
</ins><span class="cx" style="display: block; padding: 0 10px"> ?>
</span><span class="cx" style="display: block; padding: 0 10px"> <li class="event-list-item">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <a href="<?php echo esc_url( gp_url( wp_make_link_relative( get_the_permalink() ) ) ); ?>"><?php the_title(); ?></a>
- <?php if ( $event_start === $event_end ) : ?>
- <span class="event-list-date"><?php echo esc_html( $event_start ); ?></span>
- <?php else : ?>
- <span class="event-list-date"><?php echo esc_html( $event_start ); ?> - <?php echo esc_html( $event_end ); ?></span>
- <?php endif; ?>
- <?php the_excerpt(); ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <a href="<?php echo esc_url( $event_url ); ?>"><?php echo esc_html( $event->title() ); ?></a>
+ <span class="event-list-date">ended <?php $event->end()->print_relative_time_html( 'F j, Y H:i T' ); ?></span>
+ <?php esc_html( get_the_excerpt( $event->id() ) ); ?>
</ins><span class="cx" style="display: block; padding: 0 10px"> </li>
</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">- endwhile;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ endforeach;
</ins><span class="cx" style="display: block; padding: 0 10px"> ?>
</span><span class="cx" style="display: block; padding: 0 10px"> </ul>
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -119,8 +114,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> echo wp_kses_post(
</span><span class="cx" style="display: block; padding: 0 10px"> paginate_links(
</span><span class="cx" style="display: block; padding: 0 10px"> array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- 'total' => $past_events_query->max_num_pages,
- 'current' => max( 1, $past_events_query->query_vars['paged'] ),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ 'total' => $past_events_query->page_count,
+ 'current' => $past_events_query->current_page,
</ins><span class="cx" style="display: block; padding: 0 10px"> 'format' => '?past_events_paged=%#%',
</span><span class="cx" style="display: block; padding: 0 10px"> 'prev_text' => '« Previous',
</span><span class="cx" style="display: block; padding: 0 10px"> 'next_text' => 'Next »',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -131,7 +126,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> wp_reset_postdata();
</span><span class="cx" style="display: block; padding: 0 10px"> endif;
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-if ( 0 === $current_events_query->post_count && 0 === $upcoming_events_query->post_count && 0 === $past_events_query->post_count ) :
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+if ( empty( $current_events_query->events ) && empty( $upcoming_events_query->events ) && empty( $past_events_query->post_count ) ) :
</ins><span class="cx" style="display: block; padding: 0 10px"> esc_html_e( 'No events found.', 'gp-translation-events' );
</span><span class="cx" style="display: block; padding: 0 10px"> endif;
</span><span class="cx" style="display: block; padding: 0 10px"> ?>
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -138,27 +133,25 @@
</span><span class="cx" style="display: block; padding: 0 10px"> </div>
</span><span class="cx" style="display: block; padding: 0 10px"> <?php if ( is_user_logged_in() ) : ?>
</span><span class="cx" style="display: block; padding: 0 10px"> <div class="event-right-col">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <h3 class="">Events I'm Attending</h3>
- <?php if ( ! $user_attending_events_query->have_posts() ) : ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <h2>Events I'm Attending</h2>
+ <?php if ( empty( $user_attending_events_query->events ) ) : ?>
</ins><span class="cx" style="display: block; padding: 0 10px"> <p>You don't have any events to attend.</p>
</span><span class="cx" style="display: block; padding: 0 10px"> <?php else : ?>
</span><span class="cx" style="display: block; padding: 0 10px"> <ul class="event-attending-list">
</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">- while ( $user_attending_events_query->have_posts() ) :
- $user_attending_events_query->the_post();
- $event_start = ( new DateTime( get_post_meta( get_the_ID(), '_event_start', true ) ) )->format( 'M j, Y' );
- $event_end = ( new DateTime( get_post_meta( get_the_ID(), '_event_end', true ) ) )->format( 'M j, Y' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ foreach ( $user_attending_events_query->events as $event ) :
+ $event_url = gp_url( wp_make_link_relative( get_the_permalink( $event->id() ) ) );
</ins><span class="cx" style="display: block; padding: 0 10px"> ?>
</span><span class="cx" style="display: block; padding: 0 10px"> <li class="event-list-item">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <a href="<?php echo esc_url( gp_url( wp_make_link_relative( get_the_permalink() ) ) ); ?>"><?php the_title(); ?></a>
- <?php if ( $event_start === $event_end ) : ?>
- <span class="event-list-date events-i-am-attending"><?php echo esc_html( $event_start ); ?></span>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <a href="<?php echo esc_url( $event_url ); ?>"><?php echo esc_html( $event->title() ); ?></a>
+ <?php if ( $event->start() === $event->end() ) : ?>
+ <span class="event-list-date events-i-am-attending"><?php $event->start()->print_time_html( 'F j, Y H:i T' ); ?></span>
</ins><span class="cx" style="display: block; padding: 0 10px"> <?php else : ?>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <span class="event-list-date events-i-am-attending"><?php echo esc_html( $event_start ); ?> - <?php echo esc_html( $event_end ); ?></span>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <span class="event-list-date events-i-am-attending"><?php $event->start()->print_time_html( 'F j, Y H:i T' ); ?> - <?php $event->end()->print_time_html( 'F j, Y H:i T' ); ?></span>
</ins><span class="cx" style="display: block; padding: 0 10px"> <?php endif; ?>
</span><span class="cx" style="display: block; padding: 0 10px"> </li>
</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">- endwhile;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ endforeach;
</ins><span class="cx" style="display: block; padding: 0 10px"> ?>
</span><span class="cx" style="display: block; padding: 0 10px"> </ul>
</span><span class="cx" style="display: block; padding: 0 10px"> <?php
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -165,8 +158,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> echo wp_kses_post(
</span><span class="cx" style="display: block; padding: 0 10px"> paginate_links(
</span><span class="cx" style="display: block; padding: 0 10px"> array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- 'total' => $user_attending_events_query->max_num_pages,
- 'current' => max( 1, $user_attending_events_query->query_vars['paged'] ),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ 'total' => $user_attending_events_query->page_count,
+ 'current' => $user_attending_events_query->current_page,
</ins><span class="cx" style="display: block; padding: 0 10px"> 'format' => '?user_attending_events_paged=%#%',
</span><span class="cx" style="display: block; padding: 0 10px"> 'prev_text' => '« Previous',
</span><span class="cx" style="display: block; padding: 0 10px"> 'next_text' => 'Next »',
</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-15 08:28:54 UTC (rev 13528)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/templates/events-my-events.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -5,50 +5,48 @@
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> namespace Wporg\TranslationEvents;
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-use DateTime;
-use WP_Query;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use Wporg\TranslationEvents\Event\Events_Query_Result;
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-/** @var WP_Query $events_i_created_query */
-/** @var WP_Query $events_i_attended_query */
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/** @var Events_Query_Result $events_i_created_query */
+/** @var Events_Query_Result $events_i_host_query */
+/** @var Events_Query_Result $events_i_attended_query */
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> gp_title( esc_html__( 'Translation Events', 'gp-translation-events' ) . ' - ' . esc_html__( 'My Events', 'gp-translation-events' ) );
</span><span class="cx" style="display: block; padding: 0 10px"> gp_breadcrumb_translation_events( array( esc_html__( 'My Events', 'gp-translation-events' ) ) );
</span><span class="cx" style="display: block; padding: 0 10px"> gp_tmpl_header();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+$event_page_title = __( 'My Events', 'gp-translation-events' );
</ins><span class="cx" style="display: block; padding: 0 10px"> gp_tmpl_load( 'events-header', get_defined_vars(), __DIR__ );
</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"> <div class="event-page-wrapper">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <h1 class="event_page_title"><?php esc_html_e( 'My Events', 'gp-translation-events' ); ?> </h1>
- <h2 class="event_page_title"><?php esc_html_e( 'Events I have created', 'gp-translation-events' ); ?> </h2>
- <?php if ( $events_i_created_query->have_posts() ) : ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <?php if ( ! empty( $events_i_host_query->events ) ) : ?>
+ <h2><?php esc_html_e( 'Events I host', 'gp-translation-events' ); ?> </h2>
</ins><span class="cx" style="display: block; padding: 0 10px"> <ul>
</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">- while ( $events_i_created_query->have_posts() ) :
- $events_i_created_query->the_post();
- $event_id = get_the_ID();
- $event_start = get_post_meta( $event_id, '_event_start', true );
- list( $permalink, $post_name ) = get_sample_permalink( $event_id );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ foreach ( $events_i_host_query->events as $event ) :
+ list( $permalink, $post_name ) = get_sample_permalink( $event->id() );
</ins><span class="cx" style="display: block; padding: 0 10px"> $permalink = str_replace( '%pagename%', $post_name, $permalink );
</span><span class="cx" style="display: block; padding: 0 10px"> $event_url = gp_url( wp_make_link_relative( $permalink ) );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $event_edit_url = gp_url( 'events/edit/' . $event_id );
- $event_status = get_post_status( $event_id );
- $event_start = ( new DateTime( get_post_meta( get_the_ID(), '_event_start', true ) ) )->format( 'M j, Y' );
- $event_end = ( new DateTime( get_post_meta( get_the_ID(), '_event_end', true ) ) )->format( 'M j, Y' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $event_edit_url = gp_url( 'events/edit/' . $event->id() );
+ $stats_calculator = new Stats_Calculator();
+ $has_stats = $stats_calculator->event_has_stats( $event->id() );
</ins><span class="cx" style="display: block; padding: 0 10px"> ?>
</span><span class="cx" style="display: block; padding: 0 10px"> <li class="event-list-item">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <a class="event-link-<?php echo esc_attr( $event_status ); ?>" href="<?php echo esc_url( $event_url ); ?>"><?php the_title(); ?></a>
- <a href="<?php echo esc_url( $event_edit_url ); ?>" class="button is-small action edit">Edit</a>
- <?php if ( 'draft' === $event_status ) : ?>
- <span class="event-label-<?php echo esc_attr( $event_status ); ?>"><?php echo esc_html( $event_status ); ?></span>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <a class="event-link-<?php echo esc_attr( $event->status() ); ?>" href="<?php echo esc_url( $event_url ); ?>"><?php echo esc_html( $event->title() ); ?></a>
+ <?php if ( ! $event->end()->is_in_the_past() && ! $has_stats ) : ?>
+ <a href="<?php echo esc_url( $event_edit_url ); ?>" class="button is-small action edit">Edit</a>
</ins><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 ( $event_start === $event_end ) : ?>
- <span class="event-list-date events-i-am-attending"><?php echo esc_html( $event_start ); ?></span>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <?php if ( 'draft' === $event->status() ) : ?>
+ <span class="event-label-<?php echo esc_attr( $event->status() ); ?>"><?php echo esc_html( $event->status() ); ?></span>
+ <?php endif; ?>
+ <?php if ( $event->start()->format( 'Y-m-d' ) === $event->end()->format( 'Y-m-d' ) ) : ?>
+ <span class="event-list-date events-i-am-attending"><?php $event->start()->print_time_html(); ?></span>
</ins><span class="cx" style="display: block; padding: 0 10px"> <?php else : ?>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <span class="event-list-date events-i-am-attending"><?php echo esc_html( $event_start ); ?> - <?php echo esc_html( $event_end ); ?></span>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <span class="event-list-date events-i-am-attending"><?php $event->start()->print_time_html(); ?> - <?php $event->end()->print_time_html(); ?></span>
</ins><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">- <p><?php the_excerpt(); ?></p>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <p><?php echo esc_html( get_the_excerpt( $event->id() ) ); ?></p>
</ins><span class="cx" style="display: block; padding: 0 10px"> </li>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <?php endwhile; ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <?php endforeach; ?>
</ins><span class="cx" style="display: block; padding: 0 10px"> </ul>
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> <?php
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -55,8 +53,55 @@
</span><span class="cx" style="display: block; padding: 0 10px"> echo wp_kses_post(
</span><span class="cx" style="display: block; padding: 0 10px"> paginate_links(
</span><span class="cx" style="display: block; padding: 0 10px"> array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- 'total' => $events_i_created_query->max_num_pages,
- 'current' => max( 1, $events_i_created_query->query_vars['events_i_created_paged'] ),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ 'total' => $events_i_host_query->page_count,
+ 'current' => $events_i_host_query->current_page,
+ 'format' => '?events_i_hosted_paged=%#%',
+ 'prev_text' => '« Previous',
+ 'next_text' => 'Next »',
+ )
+ ) ?? ''
+ );
+
+ wp_reset_postdata();
+ endif;
+ ?>
+
+ <?php if ( ! empty( $events_i_created_query->events ) ) : ?>
+ <h2><?php esc_html_e( 'Events I have created', 'gp-translation-events' ); ?> </h2>
+ <ul>
+ <?php
+ foreach ( $events_i_created_query->events as $event ) :
+ list( $permalink, $post_name ) = get_sample_permalink( $event->id() );
+ $permalink = str_replace( '%pagename%', $post_name, $permalink );
+ $event_url = gp_url( wp_make_link_relative( $permalink ) );
+ $event_edit_url = gp_url( 'events/edit/' . $event->id() );
+ $stats_calculator = new Stats_Calculator();
+ $has_stats = $stats_calculator->event_has_stats( $event->id() );
+ ?>
+ <li class="event-list-item">
+ <a class="event-link-<?php echo esc_attr( $event->status() ); ?>" href="<?php echo esc_url( $event_url ); ?>"><?php echo esc_html( $event->title() ); ?></a>
+ <?php if ( ! $event->end()->is_in_the_past() && ! $has_stats ) : ?>
+ <a href="<?php echo esc_url( $event_edit_url ); ?>" class="button is-small action edit">Edit</a>
+ <?php endif; ?>
+ <?php if ( 'draft' === $event->status() ) : ?>
+ <span class="event-label-<?php echo esc_attr( $event->status() ); ?>"><?php echo esc_html( $event->status() ); ?></span>
+ <?php endif; ?>
+ <?php if ( $event->start()->format( 'Y-m-d' ) === $event->end()->format( 'Y-m-d' ) ) : ?>
+ <span class="event-list-date events-i-am-attending"><?php $event->start()->print_time_html(); ?></span>
+ <?php else : ?>
+ <span class="event-list-date events-i-am-attending"><?php $event->start()->print_time_html(); ?> - <?php $event->end()->print_time_html(); ?></span>
+ <?php endif; ?>
+ <p><?php echo esc_html( get_the_excerpt( $event->id() ) ); ?></p>
+ </li>
+ <?php endforeach; ?>
+ </ul>
+
+ <?php
+ echo wp_kses_post(
+ paginate_links(
+ array(
+ 'total' => $events_i_created_query->page_count,
+ 'current' => $events_i_created_query->current_page,
</ins><span class="cx" style="display: block; padding: 0 10px"> 'format' => '?events_i_created_paged=%#%',
</span><span class="cx" style="display: block; padding: 0 10px"> 'prev_text' => '« Previous',
</span><span class="cx" style="display: block; padding: 0 10px"> 'next_text' => 'Next »',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -65,37 +110,28 @@
</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"> wp_reset_postdata();
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- else :
- echo 'No events found.';
</del><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">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <h2 class="event_page_title"><?php esc_html_e( 'Events I attended', 'gp-translation-events' ); ?> </h2>
- <?php if ( $events_i_attended_query->have_posts() ) : ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <h2><?php esc_html_e( 'Events I attended', 'gp-translation-events' ); ?> </h2>
+ <?php if ( ! empty( $events_i_attended_query->events ) ) : ?>
</ins><span class="cx" style="display: block; padding: 0 10px"> <ul>
</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">- while ( $events_i_attended_query->have_posts() ) :
- $events_i_attended_query->the_post();
- $event_id = get_the_ID();
- $event_start = get_post_meta( $event_id, '_event_start', true );
- list( $permalink, $post_name ) = get_sample_permalink( $event_id );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ foreach ( $events_i_attended_query->events as $event ) :
+ list( $permalink, $post_name ) = get_sample_permalink( $event->id() );
</ins><span class="cx" style="display: block; padding: 0 10px"> $permalink = str_replace( '%pagename%', $post_name, $permalink );
</span><span class="cx" style="display: block; padding: 0 10px"> $event_url = gp_url( wp_make_link_relative( $permalink ) );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $event_edit_url = gp_url( 'events/edit/' . $event_id );
- $event_status = get_post_status( $event_id );
- $event_start = ( new DateTime( get_post_meta( get_the_ID(), '_event_start', true ) ) )->format( 'M j, Y' );
- $event_end = ( new DateTime( get_post_meta( get_the_ID(), '_event_end', true ) ) )->format( 'M j, Y' );
</del><span class="cx" style="display: block; padding: 0 10px"> ?>
</span><span class="cx" style="display: block; padding: 0 10px"> <li class="event-list-item">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <a class="event-link-<?php echo esc_attr( $event_status ); ?>" href="<?php echo esc_url( $event_url ); ?>"><?php the_title(); ?></a>
- <?php if ( $event_start === $event_end ) : ?>
- <span class="event-list-date events-i-am-attending"><?php echo esc_html( $event_start ); ?></span>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <a class="event-link-<?php echo esc_attr( $event->status() ); ?>" href="<?php echo esc_url( $event_url ); ?>"><?php echo esc_html( $event->title() ); ?></a>
+ <?php if ( $event->start() === $event->end() ) : ?>
+ <span class="event-list-date events-i-am-attending"><?php $event->start()->print_time_html(); ?></span>
</ins><span class="cx" style="display: block; padding: 0 10px"> <?php else : ?>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <span class="event-list-date events-i-am-attending"><?php echo esc_html( $event_start ); ?> - <?php echo esc_html( $event_end ); ?></span>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <span class="event-list-date events-i-am-attending"><?php $event->start()->print_time_html(); ?> - <?php $event->end()->print_time_html(); ?></span>
</ins><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">- <p><?php the_excerpt(); ?></p>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <p><?php echo esc_html( get_the_excerpt( $event->id() ) ); ?></p>
</ins><span class="cx" style="display: block; padding: 0 10px"> </li>
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- <?php endwhile; ?>
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ <?php endforeach; ?>
</ins><span class="cx" style="display: block; padding: 0 10px"> </ul>
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> <?php
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -102,8 +138,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> echo wp_kses_post(
</span><span class="cx" style="display: block; padding: 0 10px"> paginate_links(
</span><span class="cx" style="display: block; padding: 0 10px"> array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- 'total' => $events_i_attended_query->max_num_pages,
- 'current' => max( 1, $events_i_attended_query->query_vars['events_i_attended_paged'] ),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ 'total' => $events_i_attended_query->page_count,
+ 'current' => $events_i_attended_query->current_page,
</ins><span class="cx" style="display: block; padding: 0 10px"> 'format' => '?events_i_attended_paged=%#%',
</span><span class="cx" style="display: block; padding: 0 10px"> 'prev_text' => '« Previous',
</span><span class="cx" style="display: block; padding: 0 10px"> 'next_text' => 'Next »',
</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-15 08:28:54 UTC (rev 13528)
+++ sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-events/wporg-gp-translation-events.php 2024-04-15 13:37:55 UTC (rev 13529)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -24,78 +24,74 @@
</span><span class="cx" style="display: block; padding: 0 10px"> use GP;
</span><span class="cx" style="display: block; padding: 0 10px"> use WP_Post;
</span><span class="cx" style="display: block; padding: 0 10px"> use WP_Query;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+use Wporg\TranslationEvents\Attendee\Attendee;
+use Wporg\TranslationEvents\Attendee\Attendee_Repository;
+use Wporg\TranslationEvents\Event\Event_Form_Handler;
+use Wporg\TranslationEvents\Event\Event_Repository_Cached;
+use Wporg\TranslationEvents\Event\Event_Repository_Interface;
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> class Translation_Events {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- public const CPT = 'translation_event';
- public const USER_META_KEY_ATTENDING = 'translation-events-attending';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ public const CPT = 'translation_event';
</ins><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- public static function get_instance() {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ public static function get_instance(): Translation_Events {
</ins><span class="cx" style="display: block; padding: 0 10px"> static $instance = null;
</span><span class="cx" style="display: block; padding: 0 10px"> if ( null === $instance ) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ require_once __DIR__ . '/autoload.php';
</ins><span class="cx" style="display: block; padding: 0 10px"> $instance = new self();
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> return $instance;
</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 static function get_event_repository(): Event_Repository_Interface {
+ static $event_repository = null;
+ if ( null === $event_repository ) {
+ $event_repository = new Event_Repository_Cached( self::get_attendee_repository() );
+ }
+ return $event_repository;
+ }
+
+ public static function get_attendee_repository(): Attendee_Repository {
+ static $attendee_repository = null;
+ if ( null === $attendee_repository ) {
+ $attendee_repository = new Attendee_Repository();
+ }
+ return $attendee_repository;
+ }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> public function __construct() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- \add_action( 'wp_ajax_submit_event_ajax', array( $this, 'submit_event_ajax' ) );
- \add_action( 'wp_ajax_nopriv_submit_event_ajax', array( $this, 'submit_event_ajax' ) );
- \add_action( 'wp_enqueue_scripts', array( $this, 'register_translation_event_js' ) );
- \add_action( 'init', array( $this, 'register_event_post_type' ) );
- \add_action( 'add_meta_boxes', array( $this, 'event_meta_boxes' ) );
- \add_action( 'save_post', array( $this, 'save_event_meta_boxes' ) );
- \add_action( 'transition_post_status', array( $this, 'event_status_transition' ), 10, 3 );
- \add_filter( 'gp_nav_menu_items', array( $this, 'gp_event_nav_menu_items' ), 10, 2 );
- \add_filter( 'wp_insert_post_data', array( $this, 'generate_event_slug' ), 10, 2 );
- \add_action( 'gp_init', array( $this, 'gp_init' ) );
- \add_action( 'gp_before_translation_table', array( $this, 'add_active_events_current_user' ) );
- \register_activation_hook( __FILE__, array( $this, 'activate' ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ add_action( 'wp_ajax_submit_event_ajax', array( $this, 'submit_event_ajax' ) );
+ add_action( 'wp_ajax_nopriv_submit_event_ajax', array( $this, 'submit_event_ajax' ) );
+ add_action( 'wp_enqueue_scripts', array( $this, 'register_translation_event_js' ) );
+ add_action( 'init', array( $this, 'register_event_post_type' ) );
+ add_action( 'add_meta_boxes', array( $this, 'event_meta_boxes' ) );
+ add_action( 'save_post', array( $this, 'save_event_meta_boxes' ) );
+ add_action( 'transition_post_status', array( $this, 'event_status_transition' ), 10, 3 );
+ add_filter( 'gp_nav_menu_items', array( $this, 'gp_event_nav_menu_items' ), 10, 2 );
+ add_filter( 'wp_insert_post_data', array( $this, 'generate_event_slug' ), 10, 2 );
+ add_action( 'gp_init', array( $this, 'gp_init' ) );
+ add_action( 'gp_before_translation_table', array( $this, 'add_active_events_current_user' ) );
+
+ if ( is_admin() ) {
+ Upgrade::upgrade_if_needed();
+ }
</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 gp_init() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- require_once __DIR__ . '/templates/helper-functions.php';
- require_once __DIR__ . '/includes/active-events-cache.php';
- require_once __DIR__ . '/includes/event.php';
- require_once __DIR__ . '/includes/routes/route.php';
- require_once __DIR__ . '/includes/routes/event/create.php';
- require_once __DIR__ . '/includes/routes/event/details.php';
- require_once __DIR__ . '/includes/routes/event/edit.php';
- require_once __DIR__ . '/includes/routes/event/list.php';
- require_once __DIR__ . '/includes/routes/user/attend-event.php';
- require_once __DIR__ . '/includes/routes/user/my-events.php';
- require_once __DIR__ . '/includes/stats-calculator.php';
- require_once __DIR__ . '/includes/stats-listener.php';
-
</del><span class="cx" style="display: block; padding: 0 10px"> GP::$router->add( '/events?', array( 'Wporg\TranslationEvents\Routes\Event\List_Route', 'handle' ) );
</span><span class="cx" style="display: block; padding: 0 10px"> GP::$router->add( '/events/new', array( 'Wporg\TranslationEvents\Routes\Event\Create_Route', 'handle' ) );
</span><span class="cx" style="display: block; padding: 0 10px"> GP::$router->add( '/events/edit/(\d+)', array( 'Wporg\TranslationEvents\Routes\Event\Edit_Route', 'handle' ) );
</span><span class="cx" style="display: block; padding: 0 10px"> GP::$router->add( '/events/attend/(\d+)', array( 'Wporg\TranslationEvents\Routes\User\Attend_Event_Route', 'handle' ), 'post' );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ GP::$router->add( '/events/host/(\d+)/(\d+)', array( 'Wporg\TranslationEvents\Routes\User\Host_Event_Route', 'handle' ), 'post' );
</ins><span class="cx" style="display: block; padding: 0 10px"> GP::$router->add( '/events/my-events', array( 'Wporg\TranslationEvents\Routes\User\My_Events_Route', 'handle' ) );
</span><span class="cx" style="display: block; padding: 0 10px"> GP::$router->add( '/events/([a-z0-9_-]+)', array( 'Wporg\TranslationEvents\Routes\Event\Details_Route', 'handle' ) );
</span><span class="cx" style="display: block; padding: 0 10px">
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $active_events_cache = new Active_Events_Cache();
- $stats_listener = new Stats_Listener( $active_events_cache );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $stats_listener = new Stats_Listener(
+ self::get_event_repository(),
+ self::get_attendee_repository(),
+ );
</ins><span class="cx" style="display: block; padding: 0 10px"> $stats_listener->start();
</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">- public function activate() {
- global $gp_table_prefix;
- $create_table = "
- CREATE TABLE `{$gp_table_prefix}event_actions` (
- `translate_event_actions_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
- `event_id` int(10) NOT NULL COMMENT 'Post_ID of the translation_event post in the wp_posts table',
- `original_id` int(10) NOT NULL COMMENT 'ID of the translation',
- `user_id` int(10) NOT NULL COMMENT 'ID of the user who made the action',
- `action` enum('approve','create','reject','request_changes') NOT NULL COMMENT 'The action that the user made (create, reject, etc)',
- `locale` varchar(10) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL COMMENT 'Locale of the translation',
- `happened_at` datetime NOT NULL COMMENT 'When the action happened, in UTC',
- PRIMARY KEY (`translate_event_actions_id`),
- UNIQUE KEY `event_per_translated_original_per_user` (`event_id`,`locale`,`original_id`,`user_id`)
- ) COMMENT='Tracks translation actions that happened during a translation event'";
- require_once ABSPATH . 'wp-admin/includes/upgrade.php';
- dbDelta( $create_table );
- }
-
</del><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px"> * Register the event post type.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -130,7 +126,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * Add meta boxes for the event post type.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> public function event_meta_boxes() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- \add_meta_box( 'event_dates', 'Event Dates', array( $this, 'event_dates_meta_box' ), self::CPT, 'normal', 'high' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ add_meta_box( 'event_dates', 'Event Dates', array( $this, 'event_dates_meta_box' ), self::CPT, 'normal', 'high' );
</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">@@ -175,207 +171,15 @@
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Validate the event dates.
- *
- * @param string $event_start The event start date.
- * @param string $event_end The event end date.
- * @return bool Whether the event dates are valid.
- * @throws Exception When dates are invalid.
- */
- public function validate_event_dates( string $event_start, string $event_end ): bool {
- if ( ! $event_start || ! $event_end ) {
- return false;
- }
- $event_start = new DateTime( $event_start );
- $event_end = new DateTime( $event_end );
- if ( $event_start < $event_end ) {
- return true;
- }
- return false;
- }
-
- /**
</del><span class="cx" style="display: block; padding: 0 10px"> * Handle the event form submission for the creation, editing, and deletion of events. This function is called via AJAX.
</span><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> public function submit_event_ajax() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- if ( ! is_user_logged_in() ) {
- wp_send_json_error( esc_html__( 'The user must be logged in.', 'gp-translation-events' ), 403 );
- }
- $action = isset( $_POST['form_name'] ) ? sanitize_text_field( wp_unslash( $_POST['form_name'] ) ) : '';
- $event_id = null;
- $event = null;
- $response_message = '';
- $form_actions = array( 'draft', 'publish', 'delete' );
- $is_nonce_valid = false;
- $nonce_name = '_event_nonce';
- if ( ! in_array( $action, array( 'create_event', 'edit_event', 'delete_event' ), true ) ) {
- wp_send_json_error( esc_html__( 'Invalid form name.', 'gp-translation-events' ), 403 );
- }
- /**
- * Filter the ability to create, edit, or delete an event.
- *
- * @param bool $can_crud_event Whether the user can create, edit, or delete an event.
- */
- $can_crud_event = apply_filters( 'gp_translation_events_can_crud_event', GP::$permission->current_user_can( 'admin' ) );
- if ( 'create_event' === $action && ( ! $can_crud_event ) ) {
- wp_send_json_error( esc_html__( 'The user does not have permission to create an event.', 'gp-translation-events' ), 403 );
- }
- if ( 'edit_event' === $action ) {
- $event_id = isset( $_POST['event_id'] ) ? sanitize_text_field( wp_unslash( $_POST['event_id'] ) ) : '';
- $event = get_post( $event_id );
- if ( ! ( $can_crud_event || current_user_can( 'edit_post', $event_id ) || intval( $event->post_author ) === get_current_user_id() ) ) {
- wp_send_json_error( esc_html__( 'The user does not have permission to edit or delete the event.', 'gp-translation-events' ), 403 );
- }
- }
- if ( 'delete_event' === $action ) {
- $event_id = isset( $_POST['event_id'] ) ? sanitize_text_field( wp_unslash( $_POST['event_id'] ) ) : '';
- $event = get_post( $event_id );
- if ( ! ( $can_crud_event || current_user_can( 'delete_post', $event->ID ) || get_current_user_id() === $event->post_author ) ) {
- wp_send_json_error( esc_html__( 'You do not have permission to delete this event.', 'gp-translation-events' ), 403 );
- }
- }
- if ( isset( $_POST[ $nonce_name ] ) ) {
- $nonce_value = sanitize_text_field( wp_unslash( $_POST[ $nonce_name ] ) );
- if ( wp_verify_nonce( $nonce_value, $nonce_name ) ) {
- $is_nonce_valid = true;
- }
- }
- if ( ! $is_nonce_valid ) {
- wp_send_json_error( esc_html__( 'Nonce verification failed.', 'gp-translation-events' ), 403 );
- }
- // This is a list of slugs that are not allowed, as they conflict with the event URLs.
- $invalid_slugs = array( 'new', 'edit', 'attend', 'my-events' );
- $title = isset( $_POST['event_title'] ) ? sanitize_text_field( wp_unslash( $_POST['event_title'] ) ) : '';
- // This will be sanitized by santitize_post which is called in wp_insert_post.
- $description = isset( $_POST['event_description'] ) ? force_balance_tags( wp_unslash( $_POST['event_description'] ) ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
- $event_start = isset( $_POST['event_start'] ) ? sanitize_text_field( wp_unslash( $_POST['event_start'] ) ) : '';
- $event_end = isset( $_POST['event_end'] ) ? sanitize_text_field( wp_unslash( $_POST['event_end'] ) ) : '';
- $event_timezone = isset( $_POST['event_timezone'] ) ? sanitize_text_field( wp_unslash( $_POST['event_timezone'] ) ) : '';
- if ( isset( $title ) && in_array( sanitize_title( $title ), $invalid_slugs, true ) ) {
- wp_send_json_error( esc_html__( 'Invalid slug.', 'gp-translation-events' ), 422 );
- }
-
- $is_valid_event_date = false;
- try {
- $is_valid_event_date = $this->validate_event_dates( $event_start, $event_end );
- } catch ( Exception $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
- // Deliberately ignored, handled below.
- }
- if ( ! $is_valid_event_date ) {
- wp_send_json_error( esc_html__( 'Invalid event dates.', 'gp-translation-events' ), 422 );
- }
-
- $event_status = '';
- if ( isset( $_POST['event_form_action'] ) && in_array( $_POST['event_form_action'], $form_actions, true ) ) {
- $event_status = sanitize_text_field( wp_unslash( $_POST['event_form_action'] ) );
- }
-
- if ( ! isset( $_POST['form_name'] ) ) {
- wp_send_json_error( esc_html__( 'Form name must be set.', 'gp-translation-events' ), 422 );
- }
-
- if ( 'create_event' === $action ) {
- $event_id = wp_insert_post(
- array(
- 'post_type' => self::CPT,
- 'post_title' => $title,
- 'post_content' => $description,
- 'post_status' => $event_status,
- )
- );
- $response_message = esc_html__( 'Event created successfully!', 'gp-translation-events' );
- }
- if ( 'edit_event' === $action ) {
- if ( ! isset( $_POST['event_id'] ) ) {
- wp_send_json_error( esc_html__( 'Event id is required.', 'gp-translation-events' ), 422 );
- }
- $event_id = sanitize_text_field( wp_unslash( $_POST['event_id'] ) );
- $event = get_post( $event_id );
- if ( ! $event || self::CPT !== $event->post_type || ! ( current_user_can( 'edit_post', $event->ID ) || intval( $event->post_author ) === get_current_user_id() ) ) {
- wp_send_json_error( esc_html__( 'Event does not exist.', 'gp-translation-events' ), 404 );
- }
- wp_update_post(
- array(
- 'ID' => $event_id,
- 'post_title' => $title,
- 'post_content' => $description,
- 'post_status' => $event_status,
- )
- );
- $response_message = esc_html__( 'Event updated successfully!', 'gp-translation-events' );
- }
- if ( 'delete_event' === $action ) {
- $event_id = sanitize_text_field( wp_unslash( $_POST['event_id'] ) );
- $event = get_post( $event_id );
- if ( ! $event || self::CPT !== $event->post_type ) {
- wp_send_json_error( esc_html__( 'Event does not exist.', 'gp-translation-events' ), 404 );
- }
- if ( ! ( current_user_can( 'delete_post', $event->ID ) || get_current_user_id() === $event->post_author ) ) {
- wp_send_json_error( 'You do not have permission to delete this event' );
- }
- $stats_calculator = new Stats_Calculator();
- try {
- $event_stats = $stats_calculator->for_event( $event );
- } catch ( Exception $e ) {
- wp_send_json_error( esc_html__( 'Failed to calculate event stats.', 'gp-translation-events' ), 500 );
- }
- if ( ! empty( $event_stats->rows() ) ) {
- wp_send_json_error( esc_html__( 'Event has translations and cannot be deleted.', 'gp-translation-events' ), 422 );
- }
- wp_trash_post( $event_id );
- $response_message = esc_html__( 'Event deleted successfully!', 'gp-translation-events' );
- }
- if ( ! $event_id ) {
- wp_send_json_error( esc_html__( 'Event could not be created or updated.', 'gp-translation-events' ), 422 );
- }
- if ( 'delete_event' !== $_POST['form_name'] ) {
- try {
- update_post_meta( $event_id, '_event_start', $this->convert_to_utc( $event_start, $event_timezone ) );
- update_post_meta( $event_id, '_event_end', $this->convert_to_utc( $event_end, $event_timezone ) );
- } catch ( Exception $e ) {
- wp_send_json_error( esc_html__( 'Invalid start or end', 'gp-translation-events' ), 422 );
- }
-
- update_post_meta( $event_id, '_event_timezone', $event_timezone );
- }
- try {
- Active_Events_Cache::invalidate();
- } catch ( Exception $e ) {
- // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
- error_log( $e );
- }
-
- list( $permalink, $post_name ) = get_sample_permalink( $event_id );
- $permalink = str_replace( '%pagename%', $post_name, $permalink );
- wp_send_json_success(
- array(
- 'message' => $response_message,
- 'eventId' => $event_id,
- 'eventUrl' => str_replace( '%pagename%', $post_name, $permalink ),
- 'eventStatus' => $event_status,
- 'eventEditUrl' => esc_url( gp_url( '/events/edit/' . $event_id ) ),
- 'eventDeleteUrl' => esc_url( gp_url( '/events/my-events/' ) ),
- )
- );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $form_handler = new Event_Form_Handler( self::get_event_repository(), self::get_attendee_repository() );
+ // Nonce verification is done by the form handler.
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ $form_handler->handle( $_POST );
</ins><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">-
-
-
- /**
- * Convert a date time in a time zone to UTC.
- *
- * @param string $date_time The date time in the time zone.
- * @param string $time_zone The time zone.
- * @return string The date time in UTC.
- * @throws Exception When dates are invalid.
- */
- public function convert_to_utc( string $date_time, string $time_zone ): string {
- $date_time = new DateTime( $date_time, new DateTimeZone( $time_zone ) );
- $date_time->setTimezone( new DateTimeZone( 'UTC' ) );
- return $date_time->format( 'Y-m-d H:i:s' );
- }
-
</del><span class="cx" style="display: block; padding: 0 10px"> public function register_translation_event_js() {
</span><span class="cx" style="display: block; padding: 0 10px"> wp_register_style( 'translation-events-css', plugins_url( 'assets/css/translation-events.css', __FILE__ ), array(), filemtime( __DIR__ . '/assets/css/translation-events.css' ) );
</span><span class="cx" style="display: block; padding: 0 10px"> gp_enqueue_style( 'translation-events-css' );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -399,6 +203,8 @@
</span><span class="cx" style="display: block; padding: 0 10px"> * @param string $new_status The new post status.
</span><span class="cx" style="display: block; padding: 0 10px"> * @param string $old_status The old post status.
</span><span class="cx" style="display: block; padding: 0 10px"> * @param WP_Post $post The post object.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ *
+ * @throws Exception
</ins><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> public function event_status_transition( string $new_status, string $old_status, WP_Post $post ): void {
</span><span class="cx" style="display: block; padding: 0 10px"> if ( self::CPT !== $post->post_type ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -405,13 +211,15 @@
</span><span class="cx" style="display: block; padding: 0 10px"> return;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> if ( 'publish' === $new_status && ( 'new' === $old_status || 'draft' === $old_status ) ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $current_user_id = get_current_user_id();
- $user_attending_events = get_user_meta( $current_user_id, self::USER_META_KEY_ATTENDING, true ) ?: array();
- $is_user_attending_event = in_array( $post->ID, $user_attending_events, true );
- if ( ! $is_user_attending_event ) {
- $new_user_attending_events = $user_attending_events;
- $new_user_attending_events[ $post->ID ] = true;
- update_user_meta( $current_user_id, self::USER_META_KEY_ATTENDING, $new_user_attending_events, $user_attending_events );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $event_id = $post->ID;
+ $user_id = $post->post_author;
+ $attendee_repository = self::get_attendee_repository();
+ $attendee = $attendee_repository->get_attendee( $event_id, $user_id );
+
+ if ( null === $attendee ) {
+ $attendee = new Attendee( $event_id, $user_id );
+ $attendee->mark_as_host();
+ $attendee_repository->insert_attendee( $attendee );
</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">@@ -465,11 +273,12 @@
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><span class="cx" style="display: block; padding: 0 10px"> * Add the active events for the current user before the translation table.
</span><span class="cx" style="display: block; padding: 0 10px"> *
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * @return void
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * @throws Exception
</ins><span class="cx" style="display: block; padding: 0 10px"> */
</span><span class="cx" style="display: block; padding: 0 10px"> public function add_active_events_current_user(): void {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- $user_attending_events = get_user_meta( get_current_user_id(), self::USER_META_KEY_ATTENDING, true ) ?: array();
- if ( empty( $user_attending_events ) ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $attendee_repository = new Attendee_Repository();
+ $user_attending_event_ids = $attendee_repository->get_events_for_user( get_current_user_id() );
+ if ( empty( $user_attending_event_ids ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> return;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px">
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -476,7 +285,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> $current_datetime_utc = ( new DateTime( 'now', new DateTimeZone( 'UTC' ) ) )->format( 'Y-m-d H:i:s' );
</span><span class="cx" style="display: block; padding: 0 10px"> $user_attending_events_args = array(
</span><span class="cx" style="display: block; padding: 0 10px"> 'post_type' => self::CPT,
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- 'post__in' => array_keys( $user_attending_events ),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ 'post__in' => $user_attending_event_ids,
</ins><span class="cx" style="display: block; padding: 0 10px"> 'post_status' => 'publish',
</span><span class="cx" style="display: block; padding: 0 10px"> // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
</span><span class="cx" style="display: block; padding: 0 10px"> 'meta_query' => array(
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -498,6 +307,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 'orderby' => 'meta_value',
</span><span class="cx" style="display: block; padding: 0 10px"> 'order' => 'ASC',
</span><span class="cx" style="display: block; padding: 0 10px"> );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px"> $user_attending_events_query = new WP_Query( $user_attending_events_args );
</span><span class="cx" style="display: block; padding: 0 10px"> $number_of_events = $user_attending_events_query->post_count;
</span><span class="cx" style="display: block; padding: 0 10px"> if ( 0 === $number_of_events ) {
</span></span></pre>
</div>
</div>
</body>
</html>