Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@
margin-top: 1em;
}

.translation-event-form .event-end-fields {
display: inline-block;
vertical-align: top;
}

.translation-event-form label.event-end-open-ended-toggle {
display: block;
width: auto;
margin-top: 0.5em;
font-weight: normal;
}

.translation-event-form #submit-event {
margin-left: 10%;
width: 30%;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
selectUserTimezone();
}
validateEventDates();
bindOpenEndedToggle();
convertToUserLocalTime();
setInterval( convertToUserLocalTime, 10000 );

Expand Down Expand Up @@ -94,7 +95,9 @@
$( '#event-title' ).val( wordcamp.title.rendered );
$( '#event-description' ).val( wordcamp.content.rendered );
$( '#event-start' ).val( new Date( 1000 * wordcamp['Start Date (YYYY-mm-dd)'] ).toISOString().slice( 0,11 ) + '09:00' );
$( '#event-end' ).val( new Date( 1000 * wordcamp['End Date (YYYY-mm-dd)'] ).toISOString().slice( 0,11 ) + '18:00' );
if ( ! $( '#event-is-open-ended' ).is( ':checked' ) ) {
$( '#event-end' ).val( new Date( 1000 * wordcamp['End Date (YYYY-mm-dd)'] ).toISOString().slice( 0,11 ) + '18:00' );
}
$( '#event-timezone' ).val( wordcamp['Event Timezone'] );

}
Expand Down Expand Up @@ -123,13 +126,16 @@
$gp.notices.error( 'Event start date and time must be set.' );
return;
}
if ( '' === $( '#event-end' ).val() ) {
$gp.notices.error( 'Event end date and time must be set.' );
return;
}
if ( $( '#event-end' ).val() <= $( '#event-start' ).val() ) {
$gp.notices.error( 'Event end date and time must be later than event start date and time.' );
return;
const isOpenEnded = $( '#event-is-open-ended' ).is( ':checked' );
if ( ! isOpenEnded ) {
if ( '' === $( '#event-end' ).val() ) {
$gp.notices.error( 'Event end date and time must be set.' );
return;
}
if ( $( '#event-end' ).val() <= $( '#event-start' ).val() ) {
$gp.notices.error( 'Event end date and time must be later than event start date and time.' );
return;
}
}
if ( eventStatus === 'publish' && isDraft ) {
const submitPrompt = 'Are you sure you want to publish this event?';
Expand Down Expand Up @@ -197,6 +203,37 @@
);
}

function bindOpenEndedToggle() {
const $checkbox = $( '#event-is-open-ended' );
const $endInput = $( '#event-end' );
if ( ! $checkbox.length || ! $endInput.length ) {
return;
}

$checkbox.on(
'change',
function () {
if ( $checkbox.is( ':checked' ) ) {
$endInput.prop( 'disabled', true ).val( '' );
return;
}
$endInput.prop( 'disabled', false );
if ( '' === $endInput.val() ) {
const startVal = $( '#event-start' ).val();
if ( startVal ) {
const start = new Date( startVal );
start.setHours( start.getHours() + 1 );
const pad = ( n ) => String( n ).padStart( 2, '0' );
$endInput.val(
start.getFullYear() + '-' + pad( start.getMonth() + 1 ) + '-' + pad( start.getDate() )
+ 'T' + pad( start.getHours() ) + ':' + pad( start.getMinutes() )
);
}
}
Comment on lines +220 to +232
}
);
}

function validateEventDates() {
const startDateTimeInput = $( '#event-start' );
const endDateTimeInput = $( '#event-end' );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Exception;
use Wporg\TranslationEvents\Event\Event;
use Wporg\TranslationEvents\Stats\Stats_Listener;
use Wporg\TranslationEvents\Translation_Events;

class Attendee_Adder {
private Attendee_Repository $attendee_repository;
Expand Down Expand Up @@ -37,6 +38,20 @@ public function add_to_event( Event $event, Attendee $attendee ): void {

private function import_stats( Event $event, Attendee $attendee ): void {
global $wpdb, $gp_table_prefix;

$now = Translation_Events::now();
$end = $event->end() ? $event->end()->utc() : $now;
$start = $event->start()->utc();

// Open-ended events can span arbitrary durations. Cap the lookback to avoid
// a full table scan over `translations` when a new attendee joins.
if ( null === $event->end() ) {
$one_year_ago = $now->modify( '-1 year' );
if ( $start < $one_year_ago ) {
$start = $one_year_ago;
}
}

// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
Expand All @@ -57,8 +72,8 @@ private function import_stats( Event $event, Attendee $attendee ): void {
'event_id' => $event->id(),
'action' => Stats_Listener::ACTION_CREATE,
'user_id' => $attendee->user_id(),
'date_added_after' => $event->start()->utc()->format( 'Y-m-d H:i:s' ),
'date_added_before' => $event->end()->utc()->format( 'Y-m-d H:i:s' ),
'date_added_after' => $start->format( 'Y-m-d H:i:s' ),
'date_added_before' => $end->format( 'Y-m-d H:i:s' ),
),
),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,6 @@ private function has_edit_attendees( WP_User $user, Event $event ): bool {
* @return bool
*/
private function has_edit_field( WP_User $user, Event $event, $cap ): bool {
$event_end_plus_1_hr = $event->end()->modify( '+1 hour' );

if ( self::EDIT_DESCRIPTION === $cap ) {
return true;
}
Expand All @@ -284,10 +282,11 @@ private function has_edit_field( WP_User $user, Event $event, $cap ): bool {
return ( self::EDIT_TITLE === $cap || self::EDIT_END === $cap );
}

if ( $event->end()->is_in_the_past() && $this->now < $event_end_plus_1_hr ) {
return ( self::EDIT_TITLE === $cap || self::EDIT_END === $cap );
}
if ( $event->end()->is_in_the_past() && $this->now > $event_end_plus_1_hr ) {
if ( $event->is_past() ) {
$event_end_plus_1_hr = $event->end()->modify( '+1 hour' );
if ( $this->now < $event_end_plus_1_hr ) {
return ( self::EDIT_TITLE === $cap || self::EDIT_END === $cap );
}
return ( self::EDIT_DESCRIPTION === $cap );
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,11 @@ private function parse_form_data( array $data ): Event {
// 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'] ) ) : '';
$attendance_mode = isset( $data['event_attendance_mode'] ) ? sanitize_text_field( wp_unslash( $data['event_attendance_mode'] ) ) : 'onsite';
$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_is_open_ended = ! empty( $data['event_is_open_ended'] );
$event_timezone = isset( $data['event_timezone'] ) ? sanitize_text_field( wp_unslash( $data['event_timezone'] ) ) : '';
$attendance_mode = isset( $data['event_attendance_mode'] ) ? sanitize_text_field( wp_unslash( $data['event_attendance_mode'] ) ) : 'onsite';

$event_status = '';
if ( isset( $data['event_form_action'] ) && in_array( $data['event_form_action'], array( 'draft', 'publish', 'trash' ), true ) ) {
Expand All @@ -223,16 +224,21 @@ private function parse_form_data( array $data ): Event {
throw new InvalidStart();
}

try {
$end = new Event_End_Date( $event_end, $timezone );
} catch ( Exception $e ) {
throw new InvalidEnd();
if ( $event_is_open_ended ) {
$end = null;
} else {
try {
$end = new Event_End_Date( $event_end, $timezone );
} catch ( Exception $e ) {
throw new InvalidEnd();
}
$end = $end->setTimezone( new DateTimeZone( 'UTC' ) );
}

$event = new Event(
get_current_user_id(),
$start->setTimezone( new DateTimeZone( 'UTC' ) ),
$end->setTimezone( new DateTimeZone( 'UTC' ) ),
$end,
$timezone,
$event_status,
$title,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ public function get_current_events( int $page = -1, int $page_size = -1 ): Event
array_filter(
$events,
function ( $event ) {
return $event->start() <= $this->now && $this->now <= $event->end();
if ( $event->start() > $this->now ) {
return false;
}
return null === $event->end() || $this->now <= $event->end();
}
)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,12 +227,7 @@ public function get_current_and_upcoming_events( int $page = - 1, int $page_size
$page_size,
array(
'meta_query' => array(
array(
'key' => '_event_end',
'value' => $this->now->format( 'Y-m-d H:i:s' ),
'compare' => '>',
'type' => 'DATETIME',
),
$this->meta_query_end_after_or_unbounded( $this->now ),
),
'meta_key' => '_event_start',
'orderby' => array(
Expand Down Expand Up @@ -290,12 +285,7 @@ public function get_current_events_for_user( int $user_id, int $page = -1, int $
'compare' => '<=',
'type' => 'DATETIME',
),
array(
'key' => '_event_end',
'value' => $this->now->format( 'Y-m-d H:i:s' ),
'compare' => '>=',
'type' => 'DATETIME',
),
$this->meta_query_end_after_or_unbounded( $this->now, '>=' ),
),
'meta_key' => '_event_start',
'orderby' => array(
Expand All @@ -318,12 +308,7 @@ public function get_current_and_upcoming_events_for_user( int $user_id, int $pag
$page_size,
array(
'meta_query' => array(
array(
'key' => '_event_end',
'value' => $this->now->format( 'Y-m-d H:i:s' ),
'compare' => '>',
'type' => 'DATETIME',
),
$this->meta_query_end_after_or_unbounded( $this->now ),
),
'meta_key' => '_event_start',
'orderby' => array(
Expand Down Expand Up @@ -454,12 +439,7 @@ protected function get_events_active_between(
'compare' => '<=',
'type' => 'DATETIME',
),
array(
'key' => '_event_end',
'value' => $boundary_start->format( 'Y-m-d H:i:s' ),
'compare' => '>',
'type' => 'DATETIME',
),
$this->meta_query_end_after_or_unbounded( $boundary_start ),
),
'meta_key' => '_event_start',
'meta_type' => 'DATETIME',
Expand Down Expand Up @@ -604,18 +584,43 @@ private function get_event_meta( int $event_id ): ?array {
$meta = get_post_meta( $event_id );
$utc = new DateTimeZone( 'UTC' );

if ( ! isset( $meta['_event_start'][0], $meta['_event_end'][0], $meta['_event_timezone'][0] ) ) {
if ( ! isset( $meta['_event_start'][0], $meta['_event_timezone'][0] ) ) {
return null;
}

$end = null;
if ( isset( $meta['_event_end'][0] ) && '' !== $meta['_event_end'][0] ) {
$end = new Event_End_Date( $meta['_event_end'][0], $utc );
}

return array(
'start' => new Event_Start_Date( $meta['_event_start'][0], $utc ),
'end' => new Event_End_Date( $meta['_event_end'][0], $utc ),
'end' => $end,
'timezone' => new DateTimeZone( $meta['_event_timezone'][0] ),
'attendance_mode' => ! isset( $meta['_event_attendance_mode'][0] ) ? 'onsite' : $meta['_event_attendance_mode'][0],
);
}

/**
* Returns a meta_query fragment that matches events whose _event_end is after
* the given boundary, OR which have no _event_end meta (open-ended events).
*/
private function meta_query_end_after_or_unbounded( DateTimeImmutable $boundary, string $compare = '>' ): array {
return array(
'relation' => 'OR',
array(
'key' => '_event_end',
'value' => $boundary->format( 'Y-m-d H:i:s' ),
'compare' => $compare,
'type' => 'DATETIME',
),
array(
'key' => '_event_end',
'compare' => 'NOT EXISTS',
),
);
}

private function update_event_meta( Event $event ) {
$hosts = $this->attendee_repository->get_hosts( $event->id() );
$hosts_ids = array_map(
Expand All @@ -626,7 +631,11 @@ function ( $host ) {
);
$hosts_ids = implode( ', ', $hosts_ids );
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' ) );
if ( null === $event->end() ) {
delete_post_meta( $event->id(), '_event_end' );
} else {
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() );
update_post_meta( $event->id(), '_hosts', $hosts_ids );
update_post_meta( $event->id(), '_event_attendance_mode', $event->attendance_mode() );
Expand Down
Loading
Loading