Version 4.3.6

This commit is contained in:
Neo committed 2025-12-19 05:49:12 -08:00
1 parent fe1acf984a
commit 1a0c7fd3c2
609 files changed
+14707 -5726

No files matched your search

+20 -13
View File
@@ -95,9 +95,14 @@ class _Date extends \IPS\DateTime
public static function getDate( $year=NULL, $month=NULL, $day=NULL, $hour=0, $minute=0, $second=0, $offset=NULL )
{
/* Get our time zone offset */
$timezone = NULL;
if ( $offset === NULL and \IPS\Member::loggedIn()->timezone )
{
$offset = \IPS\DateTime::create()->setTimezone( new \DateTimeZone( \IPS\Member::loggedIn()->timezone ) )->getOffset();
$timezone = \IPS\DateTime::create();
$timezone->setTimezone( new \DateTimeZone( \IPS\Member::loggedIn()->timezone ) );
$offset = $timezone->getOffset();
}
/* Set appropriate defaults for values not supplied, which is normal */
@@ -125,6 +130,14 @@ class _Date extends \IPS\DateTime
/* Create the timestamp */
$timeStamp = gmmktime( $hour, $minute, $second, $month, $day, $year );
/* Recalculate offset in case we go over DST boundary */
if( $timezone )
{
$timeZoneCheck = $timezone->setTimestamp( $timeStamp );
$offset = $timeZoneCheck->getOffset();
}
/* Store the information and return the object */
$obj = static::ts( $timeStamp - $offset );
$obj->getDateInformation( $timeStamp );
@@ -180,7 +193,7 @@ class _Date extends \IPS\DateTime
*
* @note This is basically a timezone aware wrapper for getdate
* @param int $time Timestamp
* @return void
* @return array
*/
public function getDateInformation( $time )
{
@@ -197,6 +210,7 @@ class _Date extends \IPS\DateTime
'month' => $this->strFormat( '%B' ),
0 => $time
);
return $this->dateInformation;
}
/**
@@ -519,25 +533,18 @@ class _Date extends \IPS\DateTime
/**
* Return the MySQL-style datetime value
*
* @param bool $includeTime Whether to include time or not
* @param bool $timezoned Whether to adjust for timezone or not. This will usually be FALSE for database purposes, but set to TRUE if you're using this to compare if two dates are on the same day
* @param bool $includeTime Whether to include time or not
* @return string
*/
public function mysqlDatetime( $includeTime=TRUE, $timezoned = FALSE )
public function mysqlDatetime( $includeTime=TRUE )
{
$timeStamp = isset( $this->dateInformation[0] ) ? $this->dateInformation[0] : $this->getTimestamp();
if ( $timezoned )
{
$timeStamp += $this->getTimezone()->getOffset( $this );
}
if( $includeTime )
{
return date( 'Y-m-d H:i:s', $timeStamp );
return date( 'Y-m-d H:i:s', isset( $this->dateInformation[0] ) ? $this->dateInformation[0] : $this->getTimestamp() );
}
else
{
return date( 'Y-m-d', $timeStamp );
return date( 'Y-m-d', isset( $this->dateInformation[0] ) ? $this->dateInformation[0] : $this->getTimestamp() );
}
}
+68 -23
View File
@@ -564,7 +564,8 @@ class _Event extends \IPS\Content\Item implements
( $eDate !== NULL AND $date->mysqlDatetime( FALSE ) <= $startDate->mysqlDatetime( FALSE ) AND $eDate->mysqlDatetime( FALSE ) >= $endDate->mysqlDatetime( FALSE ) )
)
{
$results[] = array( 'startDate' => new \IPS\calendar\Date( $dateOccurrence->mysqlDatetime( FALSE, TRUE ) ), 'endDate' => $eDate );
$thisOccurrence = $dateOccurrence->getDateInformation( $dateOccurrence->getTimestamp() );
$results[] = array( 'startDate' => \IPS\calendar\Date::getDate( $thisOccurrence['year'], $thisOccurrence['mon'], $thisOccurrence['mday'], $thisOccurrence['hours'], $thisOccurrence['minutes'], $thisOccurrence['seconds'] ), 'endDate' => $eDate );
}
$eDate = ( $eDate !== NULL ) ? $eDate->adjust( "+{$recurringData['event_repeat_freq']} {$keyword}" ) : NULL;
@@ -584,7 +585,8 @@ class _Event extends \IPS\Content\Item implements
( $eDate !== NULL AND $date->mysqlDatetime( FALSE ) <= $startDate->mysqlDatetime( FALSE ) AND $eDate->mysqlDatetime( FALSE ) >= $endDate->mysqlDatetime( FALSE ) )
)
{
$results[] = array( 'startDate' => new \IPS\calendar\Date( $dateOccurrence->mysqlDatetime( FALSE, TRUE ) ), 'endDate' => $eDate );
$thisOccurrence = $dateOccurrence->getDateInformation( $dateOccurrence->getTimestamp() );
$results[] = array( 'startDate' => \IPS\calendar\Date::getDate( $thisOccurrence['year'], $thisOccurrence['mon'], $thisOccurrence['mday'], $thisOccurrence['hours'], $thisOccurrence['minutes'], $thisOccurrence['seconds'] ), 'endDate' => $eDate );
}
$eDate = ( $eDate !== NULL ) ? $eDate->adjust( "+{$recurringData['event_repeat_freq']} {$keyword}" ) : NULL;
@@ -602,7 +604,8 @@ class _Event extends \IPS\Content\Item implements
( $eDate !== NULL AND $date->mysqlDatetime( FALSE ) <= $startDate->mysqlDatetime( FALSE ) AND $eDate->mysqlDatetime( FALSE ) >= $endDate->mysqlDatetime( FALSE ) )
)
{
$results[] = array( 'startDate' => new \IPS\calendar\Date( $dateOccurrence->mysqlDatetime( FALSE, TRUE ) ), 'endDate' => $eDate );
$thisOccurrence = $dateOccurrence->getDateInformation( $dateOccurrence->getTimestamp() );
$results[] = array( 'startDate' => \IPS\calendar\Date::getDate( $thisOccurrence['year'], $thisOccurrence['mon'], $thisOccurrence['mday'], $thisOccurrence['hours'], $thisOccurrence['minutes'], $thisOccurrence['seconds'] ), 'endDate' => $eDate );
}
$eDate = ( $eDate !== NULL ) ? $eDate->adjust( "+{$recurringData['event_repeat_freq']} {$keyword}" ) : NULL;
@@ -1132,9 +1135,9 @@ class _Event extends \IPS\Content\Item implements
$val['start_time'] = str_replace( '.', ':', $val['start_time'] );
}
if( isset( $val['no_end_time'] ) AND $val['no_end_time'] AND isset( $val['end_time'] ) )
if ( isset( $val['no_end_time'] ) AND $val['no_end_time'] AND ( isset( $val['end_time'] ) OR isset( $val['end_date'] ) ) )
{
unset( $val['end_time'] );
unset( $val['end_time'], $val['end_date'] );
}
if( isset( $val['end_time'] ) )
@@ -1152,7 +1155,7 @@ class _Event extends \IPS\Content\Item implements
}
$end = null;
if( isset( $val['end_date'] ) AND $val['end_date'] )
{
if( !isset( $val['single_day'] ) OR !$val['single_day'] )
@@ -1169,7 +1172,7 @@ class _Event extends \IPS\Content\Item implements
}
}
}
else
elseif( isset( $val['end_time'] ) )
{
try
{
@@ -1214,6 +1217,38 @@ class _Event extends \IPS\Content\Item implements
}
}
/* Check we are not trying to recur in such a way that a new occurance starts before
the last ends, which could cause timeouts if someone does something like sets an
event to recur every day and span many days */
if ( isset( $val['event_repeat'] ) and $val['event_repeat'] and $end )
{
$diff = intval( strtotime( $end ) ) - intval( strtotime( $start ) );
switch ( $val['event_repeats'] )
{
case 'daily':
$maxDiff = intval( $val['event_repeat_freq'] ) * 86400;
break;
case 'weekly':
$maxDiff = intval( $val['event_repeat_freq'] ) * 86400 * 7;
break;
case 'monthly':
$maxDiff = intval( $val['event_repeat_freq'] ) * 86400 * 31;
break;
case 'yearly':
$maxDiff = intval( $val['event_repeat_freq'] ) * 86400 * 365;
break;
}
if ( $diff > $maxDiff )
{
throw new \DomainException( "invalid_recurrence" );
}
}
}, NULL, NULL, 'event_dates' );
/* Init */
@@ -1230,16 +1265,18 @@ class _Event extends \IPS\Content\Item implements
/* Get default elements */
$return = array_merge( $return, parent::formElements( $item, $container ) );
/* Event description */
$return['description'] = new \IPS\Helpers\Form\Editor( 'event_content', $item ? $item->content : NULL, TRUE, array( 'app' => 'calendar', 'key' => 'Calendar', 'autoSaveKey' => 'calendar-event', 'attachIds' => ( $item === NULL ? NULL : array( $item->id, NULL, 'description' ) ) ) );
$return['description'] = new \IPS\Helpers\Form\Editor( 'event_content', $item ? $item->content : NULL, TRUE, array( 'app' => 'calendar', 'key' => 'Calendar', 'autoSaveKey' => ( $item === NULL ) ? 'calendar-event' : "calendar-event-{$item->id}", 'attachIds' => ( $item === NULL ? NULL : array( $item->id, NULL, 'description' ) ) ) );
/* 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, 'storageExtension' => 'calendar_Events' ) );
if( \IPS\Settings::i()->calendar_venues_enabled )
{
$return['venue'] = new \IPS\Helpers\Form\Node( static::$formLangPrefix . 'venue', ( $item ) ? $item->venue ?: 0 : ( isset( \IPS\Request::i()->venue ) ? \IPS\Request::i()->venue : NULL ), FALSE, array(
$roots = \IPS\calendar\Venue::roots();
$return['venue'] = new \IPS\Helpers\Form\Node( static::$formLangPrefix . 'venue', ( $item ) ? $item->venue ?: 0 : ( isset( \IPS\Request::i()->venue ) ? \IPS\Request::i()->venue : ( count( $roots ) ? NULL : 0 ) ), FALSE, array(
'url' => \IPS\Http\Url::internal( 'app=calendar&module=calendar&controller=submit', 'front', 'calendar_submit' ),
'class' => 'IPS\calendar\Venue',
'zeroVal' => 'venues_not_listed',
@@ -1355,7 +1392,7 @@ class _Event extends \IPS\Content\Item implements
$this->end_date = \IPS\calendar\Date::createFromForm( $values['event_dates']['end_date'], ( ( !isset( $values['event_dates']['all_day'] ) OR !$values['event_dates']['all_day'] ) ? $values['event_dates']['end_time'] : NULL ), ( isset( $values['event_dates']['all_day'] ) AND $values['event_dates']['all_day'] ) ? 'UTC' : $values['event_dates']['event_timezone'] )->format( 'Y-m-d H:i' );
}
}
else if( ( !isset( $values['event_dates']['all_day'] ) OR !$values['event_dates']['all_day'] ) AND $values['event_dates']['end_time'] != $values['event_dates']['start_time'] )
else if( ( !isset( $values['event_dates']['all_day'] ) OR !$values['event_dates']['all_day'] ) AND isset( $values['event_dates']['end_time'] ) AND $values['event_dates']['end_time'] != $values['event_dates']['start_time'] )
{
$this->end_date = \IPS\calendar\Date::createFromForm( $values['event_dates']['start_date'], $values['event_dates']['end_time'], ( isset( $values['event_dates']['all_day'] ) AND $values['event_dates']['all_day'] ) ? 'UTC' : $values['event_dates']['event_timezone'] )->format( 'Y-m-d H:i' );
}
@@ -1679,20 +1716,20 @@ class _Event extends \IPS\Content\Item implements
foreach( $events as $event )
{
/* Is this a ranged event? */
if( $event->_end_date !== NULL AND $event->_start_date->mysqlDatetime( FALSE ) < $event->_end_date->mysqlDatetime( FALSE ) )
if( $event->_end_date !== NULL AND $event->_start_date->mysqlDatetime( FALSE, TRUE ) < $event->_end_date->mysqlDatetime( FALSE, TRUE ) )
{
$date = $event->_start_date;
while( $date->mysqlDatetime( FALSE ) < $event->_end_date->mysqlDatetime( FALSE ) )
while( $date->mysqlDatetime( FALSE, TRUE ) < $event->_end_date->mysqlDatetime( FALSE, TRUE ) )
{
$formattedEvents[ $date->mysqlDatetime( FALSE ) ]['ranged'][ $event->id ] = $event;
$date = $date->adjust( '+1 day' );
}
$formattedEvents[ $event->_end_date->mysqlDatetime( FALSE ) ]['ranged'][ $event->id ] = $event;
$formattedEvents[ $event->_end_date->mysqlDatetime( FALSE, TRUE ) ]['ranged'][ $event->id ] = $event;
}
else
{
$formattedEvents[ $event->_start_date->mysqlDatetime( FALSE ) ]['single'][ $event->id ] = $event;
$formattedEvents[ $event->_start_date->mysqlDatetime( FALSE, TRUE ) ]['single'][ $event->id ] = $event;
}
}
}
@@ -1723,18 +1760,26 @@ class _Event extends \IPS\Content\Item implements
if( $occurrence['endDate'] !== NULL )
{
$date = $occurrence['startDate'];
$eDate = ( $thisEndDate->mysqlDatetime( FALSE ) < $occurrence['endDate']->mysqlDatetime( FALSE ) ) ? $thisEndDate : $occurrence['endDate'];
while( $date->mysqlDatetime( FALSE ) < $eDate->mysqlDatetime( FALSE ) )
{
$formattedEvents[ $date->mysqlDatetime( FALSE ) ]['ranged'][ $event->id ] = $event;
$date = $date->adjust( '+1 day' );
}
$eDate = ( $thisEndDate->mysqlDatetime( FALSE, TRUE ) < $occurrence['endDate']->mysqlDatetime( FALSE, TRUE ) ) ? $thisEndDate : $occurrence['endDate'];
$formattedEvents[ $occurrence['endDate']->mysqlDatetime( FALSE ) ]['ranged'][ $event->id ] = $event;
if( $date->mysqlDatetime( FALSE, TRUE ) < $eDate->mysqlDatetime( FALSE, TRUE ) )
{
while( $date->mysqlDatetime( FALSE, TRUE ) < $eDate->mysqlDatetime( FALSE, TRUE ) )
{
$formattedEvents[ $date->mysqlDatetime( FALSE ) ]['ranged'][ $event->id ] = $event;
$date = $date->adjust( '+1 day' );
}
$formattedEvents[ $occurrence['endDate']->mysqlDatetime( FALSE, TRUE ) ]['ranged'][ $event->id ] = $event;
}
else
{
$formattedEvents[ $date->mysqlDatetime( FALSE, TRUE ) ]['single'][ $event->id ] = $event;
}
}
else
{
$formattedEvents[ $occurrence['startDate']->mysqlDatetime( FALSE ) ]['single'][ $event->id ] = $event;
$formattedEvents[ $occurrence['startDate']->mysqlDatetime( FALSE, TRUE ) ]['single'][ $event->id ] = $event;
}
}
}
@@ -449,11 +449,20 @@ class _ICSParser
/* Basics */
$newEvent->title = ( isset( $event['summary'] ) AND $event['summary'] ) ? $event['summary'] : mb_substr( strip_tags( $event['description'] ), 0, 100 );
$newEvent->content = ( isset( $event['description'] ) AND $event['description'] ) ? nl2br( $event['description'] ) : $event['summary'] . ( isset( $event['location'] ) ? '<br>' . $event['location'] : '' );
$content = ( isset( $event['description'] ) AND $event['description'] ) ? nl2br( $event['description'] ) : $event['summary'] . ( isset( $event['location'] ) ? '<br>' . $event['location'] : '' );
$newEvent->content = \IPS\Text\Parser::parseStatic( $content, TRUE, NULL, $this->member );
$newEvent->sequence = ( isset( $event['sequence'] ) ? intval( $event['sequence'] ) : 0 );
/* Times and dates */
$newEvent->lastupdated = ( isset( $event['last_modified'] ) AND $event['last_modified'] AND $event['last_modified'] < time() ) ? $event['last_modified'] : ( ( isset( $event['created'] ) AND $event['created'] AND $event['created'] < time() ) ? $event['created'] : time() );
if( isset( $event['last_modified'] ) AND $event['last_modified'] AND $event['last_modified'] < time() )
{
$newEvent->lastupdated = $event['last_modified'];
}
elseif( !$eventId )
{
$newEvent->lastupdated = ( isset( $event['created'] ) AND $event['created'] AND $event['created'] < time() ) ? $event['created'] : time();
}
$newEvent->all_day = $event_all_day;
$newEvent->recurring = ( isset( $event['recurr'] ) ) ? $event['recurr'] : NULL;
$newEvent->start_date = $event_unix_from->setTimezone( new \DateTimeZone( 'UTC' ) )->format( 'Y-m-d H:i:s' );
@@ -462,11 +471,27 @@ class _ICSParser
/* Geolocation? */
if( isset( $event['geo'] ) AND is_array( $event['geo'] ) AND count( $event['geo'] ) )
{
try
/* If we are updating an event, don't pull geo data if we already have it and it hasn't changed */
$update = TRUE;
if( $newEvent->location )
{
$newEvent->location = json_encode( \IPS\GeoLocation::getByLatLong( $event['geo']['lat'], $event['geo']['long'] ) );
$existingLocation = json_decode( $newEvent->location, true );
if( isset( $existingLocation['lat'] ) AND $existingLocation['lat'] == $event['geo']['lat'] AND isset( $existingLocation['long'] ) AND $existingLocation['long'] == $event['geo']['long'] )
{
$update = FALSE;
}
}
if( $update === TRUE )
{
try
{
$newEvent->location = json_encode( \IPS\GeoLocation::getByLatLong( $event['geo']['lat'], $event['geo']['long'] ) );
}
catch( \BadFunctionCallException $e ){}
}
catch( \BadFunctionCallException $e ){}
}
elseif( isset( $event['location'] ) )
{
@@ -474,10 +499,9 @@ class _ICSParser
{
$location = new \IPS\GeoLocation;
$location->addressLines = array( $event['location'] );
$location->getLatLong();
$location->getLatLong( TRUE );
/* We get by LatLong because getLatLong() does not populate the other address data. */
$newEvent->location = json_encode( \IPS\GeoLocation::getByLatLong( $location->lat, $location->long ) );
$newEvent->location = json_encode( $location );
}
catch( \BadFunctionCallException $e ){}
}
@@ -190,6 +190,7 @@ class _Venue extends \IPS\Node\Model
*/
public function delete()
{
\IPS\Lang::deleteCustom( 'calendar', 'calendar_venue_' . $this->id );
\IPS\Lang::deleteCustom( 'calendar', 'calendar_venue_' . $this->id . '_desc' );
return parent::delete();