Version 4.3.0
This commit is contained in:
1 parent
96997ddd8e
commit
fe1acf984a
1349 files changed
+116159
-67711
No files matched your search
@@ -69,9 +69,9 @@ class _Date extends \IPS\DateTime
|
||||
public static $dateFormats = array(
|
||||
'locale' => "%x",
|
||||
'd_sm_y' => "%d %b %Y",
|
||||
'd_lm_y' => "%d %B %Y",
|
||||
'd_lm_y' => "%d {monthName} %Y",
|
||||
'sm_d_y' => "%b %d, %Y",
|
||||
'lm_d_y' => "%B %d, %Y",
|
||||
'lm_d_y' => "{monthName} %d, %Y",
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -127,7 +127,7 @@ class _Date extends \IPS\DateTime
|
||||
|
||||
/* Store the information and return the object */
|
||||
$obj = static::ts( $timeStamp - $offset );
|
||||
$obj->dateInformation = getdate( $timeStamp );
|
||||
$obj->getDateInformation( $timeStamp );
|
||||
$obj->offset = $offset;
|
||||
|
||||
return $obj;
|
||||
@@ -152,7 +152,7 @@ class _Date extends \IPS\DateTime
|
||||
$result = parent::__construct( $time );
|
||||
}
|
||||
|
||||
$this->dateInformation = getdate( $this->getTimestamp() );
|
||||
$this->getDateInformation( $this->getTimestamp() );
|
||||
$this->offset = $this->getOffset();
|
||||
|
||||
return $result;
|
||||
@@ -169,12 +169,36 @@ class _Date extends \IPS\DateTime
|
||||
{
|
||||
$result = parent::setTimezone( $timezone );
|
||||
|
||||
$this->dateInformation = getdate( $this->getTimestamp() );
|
||||
$this->getDateInformation( $this->getTimestamp() );
|
||||
$this->offset = $this->getOffset();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the date information
|
||||
*
|
||||
* @note This is basically a timezone aware wrapper for getdate
|
||||
* @param int $time Timestamp
|
||||
* @return void
|
||||
*/
|
||||
public function getDateInformation( $time )
|
||||
{
|
||||
$this->dateInformation = array(
|
||||
'seconds' => (int) $this->strFormat( '%S' ),
|
||||
'minutes' => (int) $this->strFormat( '%M' ),
|
||||
'hours' => (int) $this->strFormat( '%H' ),
|
||||
'mday' => (int) $this->strFormat( '%d' ),
|
||||
'wday' => (int) $this->strFormat( '%w' ),
|
||||
'mon' => (int) $this->strFormat( '%m' ),
|
||||
'year' => (int) $this->strFormat( '%Y' ),
|
||||
'yday' => (int) $this->strFormat( '%j' ) - 1,
|
||||
'weekday' => $this->strFormat( '%A' ),
|
||||
'month' => $this->strFormat( '%B' ),
|
||||
0 => $time
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a date object created based on an arbitrary string. Used for both relative time strings and SQL datetime values.
|
||||
*
|
||||
@@ -186,7 +210,47 @@ class _Date extends \IPS\DateTime
|
||||
public static function parseTime( $datetime, $forceUTC=FALSE )
|
||||
{
|
||||
/* Create an \IPS\DateTime object from the datetime value passed in */
|
||||
$timezone = ( $forceUTC === TRUE ) ? new \DateTimeZone( 'UTC' ) : ( \IPS\Member::loggedIn()->timezone ? new \DateTimeZone( \IPS\Member::loggedIn()->timezone ) : NULL );
|
||||
if ( !$forceUTC AND \IPS\Dispatcher::hasInstance() )
|
||||
{
|
||||
if( !\IPS\Member::loggedIn()->timezone )
|
||||
{
|
||||
$timezone = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
$validTimezone = TRUE;
|
||||
if( in_array( \IPS\Member::loggedIn()->timezone, static::getTimezoneIdentifiers() ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$timezone = new \DateTimeZone( \IPS\Member::loggedIn()->timezone );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
$validTimezone = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$validTimezone = FALSE;
|
||||
}
|
||||
|
||||
if( ! $validTimezone )
|
||||
{
|
||||
\IPS\Member::loggedIn()->timezone = null;
|
||||
|
||||
if ( \IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
\IPS\Member::loggedIn()->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$timezone = new \DateTimeZone( 'UTC' );
|
||||
}
|
||||
|
||||
$datetime = new \IPS\DateTime( $datetime, $timezone );
|
||||
|
||||
/* Now correct it back if necessary */
|
||||
@@ -444,7 +508,7 @@ class _Date extends \IPS\DateTime
|
||||
}
|
||||
elseif( isset( static::$dateFormats[ \IPS\Settings::i()->calendar_date_format ] ) )
|
||||
{
|
||||
return static::$dateFormats[ \IPS\Settings::i()->calendar_date_format ];
|
||||
return str_replace( '{monthName}', static::setMonthModifier(), static::$dateFormats[ \IPS\Settings::i()->calendar_date_format ] );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -455,18 +519,25 @@ class _Date extends \IPS\DateTime
|
||||
/**
|
||||
* Return the MySQL-style datetime value
|
||||
*
|
||||
* @param bool $includeTime Whether to include time or not
|
||||
* @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
|
||||
* @return string
|
||||
*/
|
||||
public function mysqlDatetime( $includeTime=TRUE )
|
||||
public function mysqlDatetime( $includeTime=TRUE, $timezoned = FALSE )
|
||||
{
|
||||
$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', isset( $this->dateInformation[0] ) ? $this->dateInformation[0] : $this->getTimestamp() );
|
||||
return date( 'Y-m-d H:i:s', $timeStamp );
|
||||
}
|
||||
else
|
||||
{
|
||||
return date( 'Y-m-d', isset( $this->dateInformation[0] ) ? $this->dateInformation[0] : $this->getTimestamp() );
|
||||
return date( 'Y-m-d', $timeStamp );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -756,7 +827,7 @@ class _Date extends \IPS\DateTime
|
||||
|
||||
if( $key == 'monthName' AND isset( $data[0] ) )
|
||||
{
|
||||
return mb_convert_case( \IPS\Member::loggedIn()->language()->convertString( strftime( '%B', $data[0] ) ), MB_CASE_TITLE );
|
||||
return mb_convert_case( \IPS\Member::loggedIn()->language()->convertString( strftime( static::setMonthModifier(), $data[0] ) ), MB_CASE_TITLE );
|
||||
}
|
||||
|
||||
if( $key == 'monthNameShort' AND isset( $data[0] ) )
|
||||
@@ -777,6 +848,36 @@ class _Date extends \IPS\DateTime
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief strftime-compatible modifier for month name
|
||||
*/
|
||||
protected static $monthNameModifier = NULL;
|
||||
|
||||
/**
|
||||
* Sets the month name modifier
|
||||
*
|
||||
* @note Some languages on some OS's (e.g. FreeBSD) require using a different modifier for full month name
|
||||
* @return void
|
||||
*/
|
||||
static protected function setMonthModifier()
|
||||
{
|
||||
if( static::$monthNameModifier === NULL )
|
||||
{
|
||||
$test = @strftime( '%OB' );
|
||||
|
||||
if( $test === FALSE OR $test == '%OB' )
|
||||
{
|
||||
static::$monthNameModifier = '%B';
|
||||
}
|
||||
else
|
||||
{
|
||||
static::$monthNameModifier = '%OB';
|
||||
}
|
||||
}
|
||||
|
||||
return static::$monthNameModifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the time according to the user's locale (without the date)
|
||||
*
|
||||
|
||||
@@ -21,9 +21,9 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
/**
|
||||
* Event Comment Model
|
||||
*/
|
||||
class _Comment extends \IPS\Content\Comment implements \IPS\Content\EditHistory, \IPS\Content\ReportCenter, \IPS\Content\Hideable, \IPS\Content\Searchable, \IPS\Content\Embeddable
|
||||
class _Comment extends \IPS\Content\Comment implements \IPS\Content\EditHistory, \IPS\Content\Hideable, \IPS\Content\Searchable, \IPS\Content\Embeddable
|
||||
{
|
||||
use \IPS\Content\Reactable;
|
||||
use \IPS\Content\Reactable, \IPS\Content\Reportable;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
@@ -99,7 +99,7 @@ class _Comment extends \IPS\Content\Comment implements \IPS\Content\EditHistory,
|
||||
*/
|
||||
public static function contentTableTemplate()
|
||||
{
|
||||
return array( \IPS\Theme::i()->getTemplate( 'tables', 'core' ), 'commentRows' );
|
||||
return array( \IPS\Theme::i()->getTemplate( 'tables', 'core', 'front' ), 'commentRows' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,7 +25,6 @@ class _Event extends \IPS\Content\Item implements
|
||||
\IPS\Content\Permissions,
|
||||
\IPS\Content\Tags,
|
||||
\IPS\Content\Followable,
|
||||
\IPS\Content\ReportCenter,
|
||||
\IPS\Content\ReadMarkers,
|
||||
\IPS\Content\Hideable, \IPS\Content\Featurable, \IPS\Content\Lockable,
|
||||
\IPS\Content\Shareable,
|
||||
@@ -33,7 +32,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
\IPS\Content\Embeddable,
|
||||
\IPS\Content\MetaData
|
||||
{
|
||||
use \IPS\Content\Reactable;
|
||||
use \IPS\Content\Reactable, \IPS\Content\Reportable;
|
||||
|
||||
/**
|
||||
* @brief Application
|
||||
@@ -124,6 +123,11 @@ class _Event extends \IPS\Content\Item implements
|
||||
* @brief Cover Photo Storage Extension
|
||||
*/
|
||||
public static $coverPhotoStorageExtension = 'calendar_Events';
|
||||
|
||||
/**
|
||||
* @brief Use a default cover photo
|
||||
*/
|
||||
public static $coverPhotoDefault = true;
|
||||
|
||||
/**
|
||||
* @brief Cached date objects
|
||||
@@ -134,6 +138,11 @@ class _Event extends \IPS\Content\Item implements
|
||||
* @brief Cached venue
|
||||
*/
|
||||
protected $venueObject = NULL;
|
||||
|
||||
/**
|
||||
* @brief Location Data Cache
|
||||
*/
|
||||
protected $locationData = NULL;
|
||||
|
||||
/**
|
||||
* @brief [Content] Key for hide reasons
|
||||
@@ -546,19 +555,19 @@ class _Event extends \IPS\Content\Item implements
|
||||
/* Do we have an occurrences limit? */
|
||||
if( $recurringData['repeat_end_occurrences'] )
|
||||
{
|
||||
while( $occurrences < $recurringData['repeat_end_occurrences'] )
|
||||
$period = new \DatePeriod( $date, new \DateInterval( 'P' . $recurringData['event_repeat_freq'] . mb_strtoupper( mb_substr( $keyword, 0, 1 ) ) ), $recurringData['repeat_end_occurrences'] );
|
||||
|
||||
foreach( $period as $dateOccurrence )
|
||||
{
|
||||
if( ( $date->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) AND $date->mysqlDatetime( FALSE ) <= $endDate->mysqlDatetime( FALSE ) ) OR
|
||||
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 $date->mysqlDatetime( FALSE ) <= $startDate->mysqlDatetime( FALSE ) AND $eDate->mysqlDatetime( FALSE ) >= $endDate->mysqlDatetime( FALSE ) )
|
||||
)
|
||||
{
|
||||
$results[] = array( 'startDate' => $date, 'endDate' => $eDate );
|
||||
$results[] = array( 'startDate' => new \IPS\calendar\Date( $dateOccurrence->mysqlDatetime( FALSE, TRUE ) ), 'endDate' => $eDate );
|
||||
}
|
||||
|
||||
$date = $date->adjust( "+{$recurringData['event_repeat_freq']} {$keyword}" );
|
||||
$eDate = ( $eDate !== NULL ) ? $eDate->adjust( "+{$recurringData['event_repeat_freq']} {$keyword}" ) : NULL;
|
||||
$occurrences++;
|
||||
}
|
||||
}
|
||||
/* Do we have an end date for the recurrences? */
|
||||
@@ -566,34 +575,36 @@ class _Event extends \IPS\Content\Item implements
|
||||
{
|
||||
$endDateToUse = ( $endDate->mysqlDatetime( FALSE ) < $recurringData['repeat_end_date']->mysqlDatetime( FALSE ) ) ? $endDate : $recurringData['repeat_end_date'];
|
||||
|
||||
while( $date->mysqlDatetime( FALSE ) <= $endDateToUse->mysqlDatetime( FALSE ) )
|
||||
$period = new \DatePeriod( $date, new \DateInterval( 'P' . $recurringData['event_repeat_freq'] . mb_strtoupper( mb_substr( $keyword, 0, 1 ) ) ), $endDateToUse );
|
||||
|
||||
foreach( $period as $dateOccurrence )
|
||||
{
|
||||
if( ( $date->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) AND $date->mysqlDatetime( FALSE ) <= $endDate->mysqlDatetime( FALSE ) ) OR
|
||||
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 $date->mysqlDatetime( FALSE ) <= $startDate->mysqlDatetime( FALSE ) AND $eDate->mysqlDatetime( FALSE ) >= $endDate->mysqlDatetime( FALSE ) )
|
||||
)
|
||||
{
|
||||
$results[] = array( 'startDate' => $date, 'endDate' => $eDate );
|
||||
$results[] = array( 'startDate' => new \IPS\calendar\Date( $dateOccurrence->mysqlDatetime( FALSE, TRUE ) ), 'endDate' => $eDate );
|
||||
}
|
||||
|
||||
$date = $date->adjust( "+{$recurringData['event_repeat_freq']} {$keyword}" );
|
||||
$eDate = ( $eDate !== NULL ) ? $eDate->adjust( "+{$recurringData['event_repeat_freq']} {$keyword}" ) : NULL;
|
||||
}
|
||||
}
|
||||
/* Recurs indefinitely... the most fun type... */
|
||||
else
|
||||
{
|
||||
while( $date->mysqlDatetime( FALSE ) <= $endDate->mysqlDatetime( FALSE ) )
|
||||
$period = new \DatePeriod( $date, new \DateInterval( 'P' . $recurringData['event_repeat_freq'] . mb_strtoupper( mb_substr( $keyword, 0, 1 ) ) ), $endDate );
|
||||
|
||||
foreach( $period as $dateOccurrence )
|
||||
{
|
||||
if( ( $date->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) AND $date->mysqlDatetime( FALSE ) <= $endDate->mysqlDatetime( FALSE ) ) OR
|
||||
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 $date->mysqlDatetime( FALSE ) <= $startDate->mysqlDatetime( FALSE ) AND $eDate->mysqlDatetime( FALSE ) >= $endDate->mysqlDatetime( FALSE ) )
|
||||
)
|
||||
{
|
||||
$results[] = array( 'startDate' => $date, 'endDate' => $eDate );
|
||||
$results[] = array( 'startDate' => new \IPS\calendar\Date( $dateOccurrence->mysqlDatetime( FALSE, TRUE ) ), 'endDate' => $eDate );
|
||||
}
|
||||
|
||||
$date = $date->adjust( "+{$recurringData['event_repeat_freq']} {$keyword}" );
|
||||
$eDate = ( $eDate !== NULL ) ? $eDate->adjust( "+{$recurringData['event_repeat_freq']} {$keyword}" ) : NULL;
|
||||
}
|
||||
}
|
||||
@@ -622,7 +633,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
{
|
||||
foreach( $this->parsedOccurrences as $occurrence )
|
||||
{
|
||||
if( $occurrence[ $type ] AND $occurrence[ $type ]->mysqlDatetime( FALSE ) >= $date->mysqlDatetime( FALSE ) )
|
||||
if( $occurrence[ $type ] AND $occurrence[ $type ]->mysqlDatetime( FALSE, TRUE ) >= $date->mysqlDatetime( FALSE, TRUE ) )
|
||||
{
|
||||
return $occurrence[ $type ];
|
||||
}
|
||||
@@ -632,7 +643,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
/* Get the occurrences over the next year then and try from there. We go back one month to start with to account for the event stream. */
|
||||
foreach( $this->findOccurrences( $date->adjust( "-1 month" ), $date->adjust( "+2 years" ) ) as $occurrence )
|
||||
{
|
||||
if( $occurrence[ $type ] AND $occurrence[ $type ]->mysqlDatetime( FALSE ) >= $date->mysqlDatetime( FALSE ) )
|
||||
if( $occurrence[ $type ] AND $occurrence[ $type ]->mysqlDatetime( FALSE, TRUE ) >= $date->mysqlDatetime( FALSE, TRUE ) )
|
||||
{
|
||||
return $occurrence[ $type ];
|
||||
}
|
||||
@@ -905,9 +916,9 @@ class _Event extends \IPS\Content\Item implements
|
||||
*/
|
||||
public static function contentTableTemplate()
|
||||
{
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'calendar.css', 'calendar' ) );
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'calendar_responsive.css', 'calendar' ) );
|
||||
return array( \IPS\Theme::i()->getTemplate( 'global', 'calendar' ), 'rows' );
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'calendar.css', 'calendar', 'front' ) );
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'calendar_responsive.css', 'calendar', 'front' ) );
|
||||
return array( \IPS\Theme::i()->getTemplate( 'global', 'calendar', 'front' ), 'rows' );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1011,7 +1022,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
{
|
||||
if ( $container and $container->moderate and !$member->group['g_avoid_q'] )
|
||||
{
|
||||
return TRUE;
|
||||
return !static::modPermission( 'approve', $member, $container );
|
||||
}
|
||||
|
||||
return parent::moderateNewItems( $member, $container );
|
||||
@@ -1086,6 +1097,15 @@ class _Event extends \IPS\Content\Item implements
|
||||
'repeat_end_date' => NULL, /* Ends on x date (which is separate from the event end date - e.g. jan 9 2014 3pm to jan 10 2014 3pm, repeat annually until jan 9 2019) */
|
||||
);
|
||||
|
||||
/* If we're copying an event, reset the date & time fields */
|
||||
if ( \IPS\Request::i()->do === 'copy' )
|
||||
{
|
||||
$dateValues['start_date'] = NULL;
|
||||
$dateValues['start_time'] = NULL;
|
||||
$dateValues['end_date'] = NULL;
|
||||
$dateValues['end_time'] = NULL;
|
||||
}
|
||||
|
||||
foreach( \IPS\calendar\Date::getDayNames() as $day )
|
||||
{
|
||||
$dateValues['repeat_freq_on_' . $day['ical'] ] = NULL; /* If repeating weekly, this is the days of the week as checkboxes (e.g. repeat every wed, fri and sat) */
|
||||
@@ -1112,6 +1132,11 @@ 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'] ) )
|
||||
{
|
||||
unset( $val['end_time'] );
|
||||
}
|
||||
|
||||
if( isset( $val['end_time'] ) )
|
||||
{
|
||||
$val['end_time'] = str_replace( '.', ':', $val['end_time'] );
|
||||
@@ -1192,7 +1217,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
}, NULL, NULL, 'event_dates' );
|
||||
|
||||
/* Init */
|
||||
if ( !$container or !$container->club() )
|
||||
if ( ( !$container or !$container->club() ) AND !\IPS\calendar\Calendar::theOnlyNode() )
|
||||
{
|
||||
$return['calendar'] = new \IPS\Helpers\Form\Node( static::$formLangPrefix . 'container', $container ? $container->id : ( isset( \IPS\Request::i()->calendar ) ? \IPS\Request::i()->calendar : NULL ), TRUE, array(
|
||||
'url' => \IPS\Http\Url::internal( 'app=calendar&module=calendar&controller=submit', 'front', 'calendar_submit' ),
|
||||
@@ -1207,7 +1232,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
$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 ) ) ) );
|
||||
$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' ) ) ) );
|
||||
|
||||
/* 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' ) );
|
||||
@@ -1250,6 +1275,12 @@ class _Event extends \IPS\Content\Item implements
|
||||
$return['rsvplimit'] = new \IPS\Helpers\Form\Number( 'event_rsvp_limit', $item ? $item->rsvp_limit : -1, FALSE, array( 'unlimited' => -1 ), NULL, NULL, NULL, 'event_rsvp_limit' );
|
||||
}
|
||||
|
||||
/* If the calendar does not allow comments or reviews, disable the auto follow option */
|
||||
if( $container AND !$container->allow_comments AND !$container->allow_reviews )
|
||||
{
|
||||
unset( $return['auto_follow'] );
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
@@ -1262,7 +1293,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
protected function processBeforeCreate( $values )
|
||||
{
|
||||
/* Post key is very much needed because...bacon */
|
||||
$this->post_key = isset( $values['post_key'] ) ? $values['post_key'] : md5( uniqid() );
|
||||
$this->post_key = isset( $values['post_key'] ) ? $values['post_key'] : md5( mt_rand() );
|
||||
|
||||
parent::processBeforeCreate( $values );
|
||||
}
|
||||
@@ -1281,6 +1312,11 @@ class _Event extends \IPS\Content\Item implements
|
||||
$values['event_dates']['start_time'] = str_replace( '.', ':', $values['event_dates']['start_time'] );
|
||||
}
|
||||
|
||||
if( isset( $values['event_dates']['no_end_time'] ) AND $values['event_dates']['no_end_time'] AND isset( $values['event_dates']['end_time'] ) )
|
||||
{
|
||||
unset( $values['event_dates']['end_time'] );
|
||||
}
|
||||
|
||||
if( isset( $values['event_dates']['end_time'] ) )
|
||||
{
|
||||
$values['event_dates']['end_time'] = str_replace( '.', ':', $values['event_dates']['end_time'] );
|
||||
@@ -1324,7 +1360,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
$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' );
|
||||
}
|
||||
}
|
||||
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' );
|
||||
}
|
||||
@@ -1365,7 +1401,10 @@ class _Event extends \IPS\Content\Item implements
|
||||
$venue = new \IPS\calendar\Venue;
|
||||
$venue->address = json_encode( $values['event_location'] );
|
||||
$venue->save();
|
||||
|
||||
|
||||
/* Node titles can contain HTML, but we should prevent this from user submissions as these go right into the language DB */
|
||||
$values['venue_title'] = array_map( 'strip_tags', $values['venue_title'] );
|
||||
|
||||
\IPS\Lang::saveCustom( 'calendar', 'calendar_venue_' . $venue->id, $values['venue_title'] );
|
||||
\IPS\Lang::saveCustom( 'calendar', 'calendar_venue_' . $venue->id . '_desc', $values['venue_description'] );
|
||||
$venue->title_seo = \IPS\Http\Url\Friendly::seoTitle( $values['venue_title'][ \IPS\Lang::defaultLanguage() ] );
|
||||
@@ -1416,8 +1455,6 @@ class _Event extends \IPS\Content\Item implements
|
||||
{
|
||||
parent::processAfterCreate( $comment, $values );
|
||||
|
||||
$this->expireWidgetCaches();
|
||||
|
||||
/* And claim attachments */
|
||||
\IPS\File::claimAttachments( 'calendar-event', $this->id );
|
||||
|
||||
@@ -1671,7 +1708,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
foreach( $recurringEvents as $event )
|
||||
{
|
||||
/* Find occurrences within our date range (if any) */
|
||||
$thisEndDate = ( $endDate ? $endDate : $startDate->adjust( "+2 years" ) );
|
||||
$thisEndDate = ( $endDate ? $endDate->setTime( 23, 59, 59 ) : $startDate->adjust( "+2 years" ) );
|
||||
$occurrences = $event->findOccurrences( $startDate, $thisEndDate );
|
||||
|
||||
/* Do we have any? */
|
||||
@@ -1739,6 +1776,36 @@ class _Event extends \IPS\Content\Item implements
|
||||
$formattedEvents = array_slice( $formattedEvents, 0, $limit, TRUE );
|
||||
}
|
||||
}
|
||||
/* Resort formatted events by time */
|
||||
else
|
||||
{
|
||||
foreach( $formattedEvents as $date => $type )
|
||||
{
|
||||
foreach( $type as $typeKey => $event )
|
||||
{
|
||||
/* @note: Error suppressor is needed due to PHP bug https://bugs.php.net/bug.php?id=50688 */
|
||||
@usort( $formattedEvents[ $date ][ $typeKey ], function( $a, $b ) use ( $startDate )
|
||||
{
|
||||
if( $a->nextOccurrence( $startDate, 'startDate' ) === NULL )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( $b->nextOccurrence( $startDate, 'startDate' ) === NULL )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( $a->nextOccurrence( $startDate, 'startDate' )->mysqlDatetime() == $b->nextOccurrence( $startDate, 'startDate' )->mysqlDatetime() )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ( $a->nextOccurrence( $startDate, 'startDate' )->format( 'H:i:s' ) < $b->nextOccurrence( $startDate, 'startDate' )->format( 'H:i:s' ) ) ? -1 : 1;
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $formattedEvents;
|
||||
}
|
||||
@@ -1855,6 +1922,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
/**
|
||||
* Get output for API
|
||||
*
|
||||
* @param \IPS\Member|NULL $authorizedMember The member making the API request or NULL for API Key / client_credentials
|
||||
* @return array
|
||||
* @apiresponse int id ID number
|
||||
* @apiresponse string title Title
|
||||
@@ -1865,7 +1933,8 @@ class _Event extends \IPS\Content\Item implements
|
||||
* @apiresponse bool rsvp If this event accepts RSVPs
|
||||
* @apiresponse int rsvpLimit The number of RSVPs the event is limited to
|
||||
* @apiresponse \IPS\GeoLocation location The location where the event is taking place
|
||||
* @apiresponse \IPS\Member author The member thgat created the event
|
||||
* @apiresponse \IPS\calendar\Venue venue The venue data
|
||||
* @apiresponse \IPS\Member author The member that created the event
|
||||
* @apiresponse datetime postedDate When the event was created
|
||||
* @apiresponse string description Event description
|
||||
* @apiresponse int comments Number of comments
|
||||
@@ -1878,19 +1947,20 @@ class _Event extends \IPS\Content\Item implements
|
||||
* @apiresponse bool featured Event is featured
|
||||
* @apiresponse string url URL
|
||||
*/
|
||||
public function apiOutput()
|
||||
public function apiOutput( \IPS\Member $authorizedMember = NULL )
|
||||
{
|
||||
return array(
|
||||
'id' => $this->tid,
|
||||
'id' => $this->id,
|
||||
'title' => $this->title,
|
||||
'calendar' => $this->container()->apiOutput(),
|
||||
'calendar' => $this->container()->apiOutput( $authorizedMember ),
|
||||
'start' => $this->_start_date->rfc3339(),
|
||||
'end' => $this->_end_date ? $this->_end_date->rfc3339() : NULL,
|
||||
'recurrence' => $this->recurring,
|
||||
'rsvp' => (bool) $this->rsvp,
|
||||
'rsvpLimit' => $this->rsvp_limit == -1 ? null : $this->rsvp_limit,
|
||||
'location' => $this->location ? \IPS\GeoLocation::buildFromJson( $this->location )->apiOutput() : null,
|
||||
'author' => $this->author()->apiOutput(),
|
||||
'rsvpLimit' => $this->rsvp_limit == -1 ? NULL : $this->rsvp_limit,
|
||||
'location' => $this->_location ? $this->_location->apiOutput( $authorizedMember ) : NULL,
|
||||
'venue' => $this->venue() ? $this->venue()->apiOutput( $authorizedMember ) : NULL,
|
||||
'author' => $this->author()->apiOutput( $authorizedMember ),
|
||||
'postedDate' => \IPS\DateTime::ts( $this->saved )->rfc3339(),
|
||||
'description' => $this->content(),
|
||||
'comments' => $this->comments,
|
||||
@@ -2009,4 +2079,30 @@ class _Event extends \IPS\Content\Item implements
|
||||
{
|
||||
return array( 'core_FeaturedComments', 'core_ContentMessages' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the real location, this method takes also the venue into account
|
||||
*
|
||||
* @return NULL|\IPS\GeoLocation
|
||||
*/
|
||||
public function get__location()
|
||||
{
|
||||
if ( $this->locationData === NULL )
|
||||
{
|
||||
if ( $this->venue() )
|
||||
{
|
||||
$this->locationData = \IPS\GeoLocation::buildFromjson( $this->venue()->address );
|
||||
}
|
||||
else if ( $this->location )
|
||||
{
|
||||
$this->locationData = \IPS\GeoLocation::buildFromjson( $this->location );
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->locationData = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->locationData;
|
||||
}
|
||||
}
|
||||
@@ -21,9 +21,9 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
/**
|
||||
* Event Review Model
|
||||
*/
|
||||
class _Review extends \IPS\Content\Review implements \IPS\Content\EditHistory, \IPS\Content\ReportCenter, \IPS\Content\Hideable, \IPS\Content\Searchable, \IPS\Content\Embeddable
|
||||
class _Review extends \IPS\Content\Review implements \IPS\Content\EditHistory, \IPS\Content\Hideable, \IPS\Content\Searchable, \IPS\Content\Embeddable
|
||||
{
|
||||
use \IPS\Content\Reactable;
|
||||
use \IPS\Content\Reactable, \IPS\Content\Reportable;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
@@ -63,6 +63,7 @@ class _Review extends \IPS\Content\Review implements \IPS\Content\EditHistory, \
|
||||
'votes_helpful' => 'votes_helpful',
|
||||
'votes_data' => 'votes_data',
|
||||
'approved' => 'approved',
|
||||
'author_response' => 'author_response',
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -103,7 +104,7 @@ class _Review extends \IPS\Content\Review implements \IPS\Content\EditHistory, \
|
||||
*/
|
||||
public static function contentTableTemplate()
|
||||
{
|
||||
return array( \IPS\Theme::i()->getTemplate( 'tables', 'core' ), 'commentRows' );
|
||||
return array( \IPS\Theme::i()->getTemplate( 'tables', 'core', 'front' ), 'commentRows' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -303,15 +303,30 @@ class _ICSParser
|
||||
$_imported = 0;
|
||||
$_skipped = 0;
|
||||
$_newEvents = 0;
|
||||
|
||||
$maxImport = 500;
|
||||
|
||||
// Leave this here - useful for debugging
|
||||
// print_r($this->_parsedIcsData);exit;
|
||||
|
||||
if ( count( $this->_parsedIcsData ) and isset( $this->_parsedIcsData['events'] ) )
|
||||
{
|
||||
usort( $this->_parsedIcsData['events'], function( $a, $b ) {
|
||||
if ( $a['start']['raw_ts'] == $b['start']['raw_ts'] )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ( $a['start']['raw_ts'] > $b['start']['raw_ts'] ) ? -1 : 1;
|
||||
} );
|
||||
|
||||
/* Loop over the events */
|
||||
foreach( $this->_parsedIcsData['events'] as $event )
|
||||
{
|
||||
if ( $_imported > $maxImport )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* Quickly, if we don't support the recurrence data provided let's just skip this event */
|
||||
if( isset( $event['recurr'] ) )
|
||||
{
|
||||
@@ -413,7 +428,7 @@ class _ICSParser
|
||||
$_new = TRUE;
|
||||
|
||||
/* Basics */
|
||||
$newEvent->post_key = md5( uniqid() );
|
||||
$newEvent->post_key = md5( mt_rand() );
|
||||
$newEvent->member_id = $this->member->member_id;
|
||||
$newEvent->calendar_id = $this->calendar->id;
|
||||
|
||||
@@ -1312,7 +1327,20 @@ class _ICSParser
|
||||
/* Is a timezone specified? */
|
||||
if ( isset( $event[ $method ]['tzid'] ) AND $event[ $method ]['tzid'] )
|
||||
{
|
||||
$event[ $method ]['utc_time'] = new \IPS\DateTime( $event[ $method ]['raw'], new \DateTimeZone( $event[ $method ]['tzid'] ) );
|
||||
/* Let's test it first... */
|
||||
if( in_array( $event[ $method ]['tzid'], \IPS\DateTime::getTimezoneIdentifiers() ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$timezone = new \DateTimeZone( $event[ $method ]['tzid'] );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
$timezone = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
$event[ $method ]['utc_time'] = new \IPS\DateTime( $event[ $method ]['raw'], $timezone );
|
||||
}
|
||||
elseif( isset( $event[ $method ]['raw'] ) )
|
||||
{
|
||||
|
||||
@@ -142,7 +142,7 @@ class _Venue extends \IPS\Node\Model
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Translatable( 'venue_title', NULL, TRUE, array( 'app' => 'calendar', 'key' => ( $this->id ? "calendar_venue_{$this->id}" : NULL ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Translatable( 'venue_description', NULL, FALSE, array( 'app' => 'calendar', 'key' => ( $this->id ? "calendar_venue_{$this->id}_desc" : NULL ), 'editor' => array( 'app' => 'calendar', 'key' => 'Venue', 'autoSaveKey' => ( $this->id ? "calendar-venue-{$this->id}" : "calendar-new-venue" ), 'attachIds' => $this->id ? array( $this->id, NULL, 'description' ) : NULL ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Address( 'venue_address', $this->id ? \IPS\GeoLocation::buildFromJson( $this->address ) : NULL, TRUE, array( 'minimize' => FALSE, 'requireFullAddress' => TRUE ), NULL, NULL, NULL, 'venue_address' ) );
|
||||
$form->add( new \IPS\Helpers\Form\Address( 'venue_address', $this->id ? \IPS\GeoLocation::buildFromJson( $this->address ) : NULL, TRUE, array( 'minimize' => FALSE, 'requireFullAddress' => FALSE ), NULL, NULL, NULL, 'venue_address' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,7 +169,7 @@ class _Venue extends \IPS\Node\Model
|
||||
|
||||
if( isset( $values['venue_description'] ) )
|
||||
{
|
||||
\IPS\Lang::saveCustom( 'venues', 'calendar_venue_' . $this->id .'_desc', $values['venue_description'] );
|
||||
\IPS\Lang::saveCustom( 'calendar', 'calendar_venue_' . $this->id .'_desc', $values['venue_description'] );
|
||||
unset( $values['venue_description'] );
|
||||
}
|
||||
|
||||
@@ -216,4 +216,22 @@ class _Venue extends \IPS\Node\Model
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get output for API
|
||||
*
|
||||
* @param \IPS\Member|NULL $authorizedMember The member making the API request or NULL for API Key / client_credentials
|
||||
* @return array
|
||||
* @apiresponse int id ID number
|
||||
* @apiresponse string title Title
|
||||
* @apiresponse \IPS\GeoLocation address The address
|
||||
*/
|
||||
public function apiOutput( \IPS\Member $authorizedMember = NULL )
|
||||
{
|
||||
return array(
|
||||
'id' => $this->id,
|
||||
'title' => $this->_title,
|
||||
'address' => \IPS\GeoLocation::buildFromJson( $this->address )->apiOutput( $authorizedMember )
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user