Version 4.7.6

This commit is contained in:
Neo committed 2025-12-19 16:05:19 -08:00
1 parent 8ba7d43898
commit 7b7404e741
1085 files changed
+30590 -7837

No files matched your search

+139 -17
View File
@@ -151,6 +151,11 @@ class _Event extends \IPS\Content\Item implements
* @brief Location Data Cache
*/
protected $locationData = NULL;
/**
* @brief Happening Cache
*/
protected $happeningData = FALSE;
/**
* @brief [Content] Key for hide reasons
@@ -360,7 +365,8 @@ class _Event extends \IPS\Content\Item implements
}
/* Return the results we found after storing them */
$this->parsedOccurrences = static::_findOccurances( $this->_start_date, $this->_end_date, $startDate, $endDate, $recurringData );
$timezone = ( !empty( $this->timezone ) and \in_array( \IPS\DateTime::getFixedTimezone( $this->timezone ), \DateTimeZone::listIdentifiers() ) ) ? new \DateTimeZone( $this->timezone ) : NULL;
$this->parsedOccurrences = static::_findOccurances( $this->_start_date, $this->_end_date, $startDate, $endDate, $recurringData, $timezone );
return $this->parsedOccurrences;
}
@@ -400,9 +406,10 @@ class _Event extends \IPS\Content\Item implements
* @param \IPS\calendar\Date $startDate Date to start from
* @param \IPS\calendar\Date $endDate Date to end at
* @param array $recurringData Reccurance data
* @param \DateTimeZone $eventTimezone Event timezone
* @return array
*/
public static function _findOccurances( $eventStart, $eventEnd, $startDate, $endDate, $recurringData )
public static function _findOccurances( $eventStart, $eventEnd, $startDate, $endDate, $recurringData, ?\DateTimeZone $eventTimezone=NULL )
{
$keyword = NULL;
$results = array();
@@ -425,11 +432,25 @@ class _Event extends \IPS\Content\Item implements
/* Get the days we repeat on */
$_repeatDays = array();
foreach ( \IPS\calendar\Date::getDayNames() as $day )
/* adjust repeat freq relative to event start date */
$offset = 0;
if( $eventTimezone )
{
$relativeDate = clone $eventStart;
$relativeDate->setTimezone( $eventTimezone );
if( $relativeDate->weekday !== $eventStart->weekday )
{
$offset = $relativeDate->wday - $eventStart->wday;
}
}
foreach ( \IPS\calendar\Date::getDayNames() as $key => $day )
{
if ( $recurringData['repeat_freq_on_' . $day['ical'] ] == TRUE )
{
$_repeatDays[] = $day['english'];
$_repeatDays[] = \IPS\calendar\Date::getDayNames()[$key-$offset]['english'];
}
}
@@ -768,6 +789,8 @@ class _Event extends \IPS\Content\Item implements
/* Get our occurrences based on the period we are looping */
foreach ( $period as $dateOccurrence )
{
$dateOccurrence = \IPS\calendar\Date::dateTimeToCalendarDate( $dateOccurrence );
$thisOccurrence = $dateOccurrence->getDateInformation( $dateOccurrence->getTimestamp() );
$dateOccurrence = \IPS\calendar\Date::getDate( $thisOccurrence['year'], $thisOccurrence['mon'], $thisOccurrence['mday'], $thisOccurrence['hours'], $thisOccurrence['minutes'], $thisOccurrence['seconds'] );
@@ -776,7 +799,7 @@ class _Event extends \IPS\Content\Item implements
if ( ( $dateOccurrence->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) AND $dateOccurrence->mysqlDatetime( FALSE ) <= $endDate->mysqlDatetime( FALSE ) ) OR
( $eDate !== NULL AND $eDate->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) AND $eDate->mysqlDatetime( FALSE ) <= $endDate->mysqlDatetime( FALSE ) ) OR
( $eDate !== NULL AND $dateOccurrence->mysqlDatetime( FALSE ) <= $startDate->mysqlDatetime( FALSE ) AND $eDate->mysqlDatetime( FALSE ) >= $endDate->mysqlDatetime( FALSE ) )
)
)
{
$results[] = array( 'startDate' => $dateOccurrence, 'endDate' => $eDate );
}
@@ -913,7 +936,7 @@ class _Event extends \IPS\Content\Item implements
$occurrences = $this->findOccurrences( $date->adjust( "-2 years" ), $date );
$occurrence = array_pop( $occurrences );
if ( $occurrence[ $type ] )
if ( $occurrence and $occurrence[ $type ] )
{
return $occurrence[ $type ];
}
@@ -1565,6 +1588,8 @@ class _Event extends \IPS\Content\Item implements
/* Cover photo and location */
$return['header'] = new \IPS\Helpers\Form\Upload( 'event_cover_photo', ( $item AND $item->cover_photo ) ? \IPS\File::get( 'calendar_Events', $item->cover_photo ) : NULL, FALSE, array( 'image' => TRUE, 'allowStockPhotos' => TRUE, 'storageExtension' => 'calendar_Events', 'canBeModerated' => TRUE, 'retainDeleted' => $isCopy ) );
$return['event_online'] = new \IPS\Helpers\Form\YesNo( 'event_online', ( $item ) ? $item->online : FALSE, FALSE, array( 'togglesOff' => array( 'venue', 'event_location' ), 'togglesOn' => array( 'event_url' ) ) );
if ( \IPS\Settings::i()->calendar_venues_enabled )
{
$roots = \IPS\calendar\Venue::roots();
@@ -1575,10 +1600,12 @@ class _Event extends \IPS\Content\Item implements
'zeroVal' => 'venues_not_listed',
'zeroValTogglesOn' => array( 'event_location', 'event_new_venue' ),
'permissionCheck' => 'add',
) );
), NULL,NULL, NULL, 'venue' );
}
$return['location'] = new \IPS\Helpers\Form\Address( 'event_location', ( $item AND $item->location ) ? \IPS\GeoLocation::buildFromJson( $item->location ) : NULL, FALSE, array( 'minimize' => ( $item AND $item->location ) ? FALSE : TRUE, 'requireFullAddress' => FALSE, 'preselectCountry' => FALSE ), NULL, NULL, NULL, 'event_location' );
$return['location'] = new \IPS\Helpers\Form\Address( 'event_location', ( $item AND $item->location ) ? \IPS\GeoLocation::buildFromJson( $item->location ) : NULL, FALSE, array( 'minimize' => ( $item AND $item->location ) ? FALSE : TRUE, 'requireFullAddress' => FALSE, 'preselectCountry' => FALSE ), NULL, NULL, NULL, 'event_location' );
$return['url'] = new \IPS\Helpers\Form\Url( 'event_url', ( $item AND $item->url ) ? $item->url : NULL, FALSE, array(), NULL, NULL, NULL, 'event_url' );
/* Save location as a new venue? */
if ( \IPS\Settings::i()->calendar_venues_enabled and \IPS\Member::loggedIn()->hasAcpRestriction( 'calendar', 'calendars', 'venues_manage' ) )
@@ -1825,6 +1852,33 @@ class _Event extends \IPS\Content\Item implements
}
if ( isset( $this->venue ) or isset( $this->location ) )
{
$location = json_decode( ( isset( $this->venue ) ) ? $this->venue()->address : $this->location, true );
$this->latitude = $location['lat'];
$this->longitude = $location['long'];
}
$this->online = $values['event_online'];
$this->url = $values['event_url'];
/* Do we know the event type */
if( $this->online and $values['event_url'] )
{
$domain = preg_replace("/^([a-zA-Z0-9].*\.)?([a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z.]{2,})$/", '$2', $values['event_url']->data['host']);
$services = $this->onlineEventServices();
if( \array_key_exists( $domain, $services ) )
{
$this->online_type = $services[$domain];
}
else
{
$this->online_type = NULL;
}
}
/* Gallery album association */
if ( \IPS\Application::appIsEnabled( 'gallery' ) AND $values['event_album'] instanceof \IPS\gallery\Album )
{
@@ -1912,9 +1966,7 @@ class _Event extends \IPS\Content\Item implements
/* We should not delete maps for imported events, because we do not want to reimport them */
//\IPS\Db::i()->delete( 'calendar_import_map', array( 'import_event_id=?', $this->id ) );
/* Delete Cover Photo -specifically call parent otherwise deleteOrMoveContent process cannot run within the AdminCP */
$photo = parent::coverPhoto();
$photo->delete();
$this->coverPhotoFile()?->delete();
}
/**
@@ -1964,11 +2016,12 @@ class _Event extends \IPS\Content\Item implements
* @param \IPS\Member $member The member (NULL to use currently logged in member)
* @param \IPS\calendar\Venue $venue The venue to filter by (if provided)
* @param bool $skipPermissions Skip permission checks (used by REST API to fetch all events which are filtered on later)
* @param array|null $location Array of item lat and long
* @return \IPS\Patterns\ActiveRecordIterator
* @throws \InvalidArgumentException
* @see \IPS\Content\_Item::getItemsWithPermission()
*/
public static function retrieveEvents ( $startDate, $endDate=NULL, $calendar=NULL, $limit=NULL, $formatEvents=TRUE, $member=NULL, $venue=NULL, $skipPermissions=FALSE )
public static function retrieveEvents ( $startDate, $endDate=NULL, $calendar=NULL, $limit=NULL, $formatEvents=TRUE, $member=NULL, $venue=NULL, $skipPermissions=FALSE, $location = NULL, $online = NULL )
{
$where = array();
@@ -1995,6 +2048,16 @@ class _Event extends \IPS\Content\Item implements
throw new \InvalidArgumentException;
}
if( $online !== NULL )
{
$where[] = array( '( event_online = ? )', (int) $online );
}
if( $location )
{
$where[] = array( '( event_location IS NOT NULL )' );
}
/* Load member */
if ( $member === NULL AND $skipPermissions === FALSE )
{
@@ -2084,7 +2147,7 @@ class _Event extends \IPS\Content\Item implements
}
/* Get the non-recurring events */
$events = \IPS\calendar\Event::getItemsWithPermission( array_merge( $where, $nonRecurring ), 'event_start_date ASC', NULL, ( $skipPermissions === TRUE ) ? NULL : 'read', ( $skipPermissions === TRUE ) ? \IPS\Content\Hideable::FILTER_SHOW_HIDDEN : \IPS\Content\Hideable::FILTER_AUTOMATIC, 0, $member );
$events = \IPS\calendar\Event::getItemsWithPermission( array_merge( $where, $nonRecurring ), 'event_start_date ASC', NULL, ( $skipPermissions === TRUE ) ? NULL : 'read', ( $skipPermissions === TRUE ) ? \IPS\Content\Hideable::FILTER_SHOW_HIDDEN : \IPS\Content\Hideable::FILTER_AUTOMATIC, 0, $member, FALSE, FALSE, FALSE,FALSE, NULL, FALSE, TRUE, TRUE, TRUE, FALSE, $location );
/* We need to make sure ranged events repeat each day that they occur on */
$formattedEvents = array();
@@ -2116,7 +2179,7 @@ class _Event extends \IPS\Content\Item implements
}
/* Now get the recurring events.... */
$recurringEvents = \IPS\calendar\Event::getItemsWithPermission( array_merge( $where, array( array( "event_recurring IS NOT NULL AND (event_recurring_end_date IS NULL OR DATE(event_recurring_end_date) >= '{$startDate->mysqlDatetime( FALSE )}')" ) ) ), 'event_start_date ASC', NULL, ( $skipPermissions === TRUE ) ? NULL : 'read', ( $skipPermissions === TRUE ) ? \IPS\Content\Hideable::FILTER_SHOW_HIDDEN : \IPS\Content\Hideable::FILTER_AUTOMATIC, 0, $member );
$recurringEvents = \IPS\calendar\Event::getItemsWithPermission( array_merge( $where, array( array( "event_recurring IS NOT NULL AND (event_recurring_end_date IS NULL OR DATE(event_recurring_end_date) >= '{$startDate->mysqlDatetime( FALSE )}')" ) ) ), 'event_start_date ASC', NULL, ( $skipPermissions === TRUE ) ? NULL : 'read', ( $skipPermissions === TRUE ) ? \IPS\Content\Hideable::FILTER_SHOW_HIDDEN : \IPS\Content\Hideable::FILTER_AUTOMATIC, 0, $member, FALSE, FALSE, FALSE,FALSE, NULL, FALSE, TRUE, TRUE, TRUE, FALSE, $location );
/* Loop over any results */
foreach( $recurringEvents as $event )
@@ -2240,7 +2303,8 @@ class _Event extends \IPS\Content\Item implements
*/
public function hasPassed()
{
$lastOccurrence = $this->lastOccurrence( 'endDate' ) ?? $this->lastOccurrence( 'startDate' );
// Get the end date. If none is available use the start date plus an hour so that online event join links show for a short while after the start
$lastOccurrence = $this->lastOccurrence( 'endDate' ) ?? $this->lastOccurrence( 'startDate' )->add( new \DateInterval("PT1H") );
if ( $lastOccurrence < \IPS\DateTime::ts( time() ) )
{
return true;
@@ -2257,7 +2321,7 @@ class _Event extends \IPS\Content\Item implements
public function coverPhoto()
{
$photo = parent::coverPhoto();
$photo->overlay = \IPS\Theme::i()->getTemplate('view', 'calendar')->coverPhotoOverlay($this);
$photo->overlay = \IPS\Theme::i()->getTemplate('view', 'calendar', 'front')->coverPhotoOverlay($this);
return $photo;
}
@@ -2601,4 +2665,62 @@ class _Event extends \IPS\Content\Item implements
return \count( $attachments ) ? \array_slice( $attachments, 0, $limit ) : NULL;
}
}
/**
* Get Online Event Services
*
* @return array
*/
protected static function onlineEventServices()
{
$services = array(
'eventbrite.com' => 'eventbrite',
'on24.com' => 'on24',
'zoom.com' => 'zoom',
'zoom.us' => 'zoom',
'facebook.com' => 'facebook',
'google.com' => 'google',
'webex.com' => 'webex',
'slack.com' => 'slack',
'discord.com' => 'discord',
'discord.gg' => 'discord',
'microsoft.com' => 'teams',
'tiktok.com' => 'tiktok',
'twitch.tv' => 'twitch',
'vimeo.com' => 'vimeo',
'spotme.com' => 'spotme',
);
return $services;
}
/**
* Is the event today/now?
*
* @return string|bool
*/
public function get__happening()
{
if( !$this->happeningData )
{
$now = \IPS\calendar\Date::ts( time() );
/* Non recurring and events with end date*/
if( !$this->recurring and $this->_start_date and $this->_end_date and ( ( $now > $this->_start_date ) and $now < $this->_end_date ) )
{
$this->happeningData = \IPS\Member::loggedIn()->language()->get( 'event_happening_now' );
}
/* recurring/no end date */
elseif( $this->nextOccurrence( $now ) and $now->format('Y-m-d') == $this->nextOccurrence( $now )->format('Y-m-d') )
{
$this->happeningData = \IPS\Member::loggedIn()->language()->get( 'event_happening_today' );
}
else
{
$this->happeningData = FALSE;
}
}
return $this->happeningData;
}
}