Version 4.1.19
This commit is contained in:
1 parent
28bd025b35
commit
2bd5025018
2674 files changed
+233518
-77766
No files matched your search
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Calendar Node
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Calendar
|
||||
* @since 18 Dec 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
@@ -133,11 +133,11 @@ class _Calendar extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
{
|
||||
if( !$this->_data['title_seo'] )
|
||||
{
|
||||
$this->title_seo = \IPS\Http\Url::seoTitle( \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( 'calendar_calendar_' . $this->id ) );
|
||||
$this->title_seo = \IPS\Http\Url\Friendly::seoTitle( \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( 'calendar_calendar_' . $this->id ) );
|
||||
$this->save();
|
||||
}
|
||||
|
||||
return $this->_data['title_seo'] ?: \IPS\Http\Url::seoTitle( \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( 'calendar_calendar_' . $this->id ) );
|
||||
return $this->_data['title_seo'] ?: \IPS\Http\Url\Friendly::seoTitle( \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( 'calendar_calendar_' . $this->id ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,7 +173,7 @@ class _Calendar extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
if( isset( $values['cal_title'] ) )
|
||||
{
|
||||
\IPS\Lang::saveCustom( 'calendar', 'calendar_calendar_' . $this->id, $values['cal_title'] );
|
||||
$values['title_seo'] = \IPS\Http\Url::seoTitle( $values['cal_title'][ \IPS\Lang::defaultLanguage() ] );
|
||||
$values['title_seo'] = \IPS\Http\Url\Friendly::seoTitle( $values['cal_title'][ \IPS\Lang::defaultLanguage() ] );
|
||||
|
||||
unset( $values['cal_title'] );
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Calendar-specific date functions
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Calendar
|
||||
* @since 30 Dec 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
@@ -75,6 +75,11 @@ class _Date extends \IPS\DateTime
|
||||
'lm_d_y' => "%B %d, %Y",
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Cache date objects we've created through getDate()
|
||||
*/
|
||||
protected static $dateObjects = array();
|
||||
|
||||
/**
|
||||
* Creates a new object to represent the requested date
|
||||
*
|
||||
@@ -88,10 +93,10 @@ class _Date extends \IPS\DateTime
|
||||
* @return \IPS\calendar\Date
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function getDate( $year=NULL, $month=NULL, $day=NULL, $hour=0, $minute=0, $second=0, $offset=0 )
|
||||
public static function getDate( $year=NULL, $month=NULL, $day=NULL, $hour=0, $minute=0, $second=0, $offset=NULL )
|
||||
{
|
||||
/* Get our time zone offset */
|
||||
if ( !$offset and \IPS\Member::loggedIn()->timezone )
|
||||
if ( $offset === NULL and \IPS\Member::loggedIn()->timezone )
|
||||
{
|
||||
$offset = \IPS\DateTime::create()->setTimezone( new \DateTimeZone( \IPS\Member::loggedIn()->timezone ) )->getOffset();
|
||||
}
|
||||
@@ -419,17 +424,18 @@ class _Date extends \IPS\DateTime
|
||||
/**
|
||||
* Return the date for use in calendar (used instead of localeDate() to allow admin to configure)
|
||||
*
|
||||
* @param \IPS\Lang|\IPS\Member|NULL $memberOrLanguage The language or member to use, or NULL for currently logged in member
|
||||
* @return string
|
||||
*/
|
||||
public function calendarDate()
|
||||
public function calendarDate( $memberOrLanguage=NULL )
|
||||
{
|
||||
if( \IPS\Settings::i()->calendar_date_format == -1 AND \IPS\Settings::i()->calendar_date_format_custom )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->convertString( strftime( \IPS\Settings::i()->calendar_date_format_custom, $this->getTimestamp() + $this->offset ) );
|
||||
return static::determineLanguage( $memberOrLanguage )->convertString( strftime( \IPS\Settings::i()->calendar_date_format_custom, $this->getTimestamp() + $this->offset ) );
|
||||
}
|
||||
elseif( isset( static::$dateFormats[ \IPS\Settings::i()->calendar_date_format ] ) )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->convertString( strftime( static::$dateFormats[ \IPS\Settings::i()->calendar_date_format ], $this->getTimestamp() + $this->offset ) );
|
||||
return static::determineLanguage( $memberOrLanguage )->convertString( strftime( static::$dateFormats[ \IPS\Settings::i()->calendar_date_format ], $this->getTimestamp() + $this->offset ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -458,10 +464,12 @@ class _Date extends \IPS\DateTime
|
||||
/**
|
||||
* Retrieve the birthdays for the date
|
||||
*
|
||||
* @param bool $day Whether to limit to the current day or not
|
||||
* @param bool $day Whether to limit to the current day or not
|
||||
* @param bool $count Flag to indicate we only need the count
|
||||
* @note When $count is TRUE we return an array of dates => integers (counts), when it is FALSE we return an array of dates => array( member objects )
|
||||
* @return array
|
||||
*/
|
||||
public function getBirthdays( $day=FALSE )
|
||||
public function getBirthdays( $day=FALSE, $count=FALSE )
|
||||
{
|
||||
$birthdays = array();
|
||||
|
||||
@@ -471,10 +479,58 @@ class _Date extends \IPS\DateTime
|
||||
return $birthdays;
|
||||
}
|
||||
|
||||
/* Get where clause */
|
||||
$where = $this->getBirthdaysWhere( $day );
|
||||
|
||||
/* Now, do we just want the count? */
|
||||
if( $count )
|
||||
{
|
||||
$members = \IPS\Db::i()->select( 'COUNT(*) as total, bday_month, bday_day', 'core_members', $where, NULL, NULL, array( 'bday_month', 'bday_day' ) );
|
||||
|
||||
foreach( $members as $member )
|
||||
{
|
||||
$birthdays[ str_pad( $member['bday_month'], 2, 0, STR_PAD_LEFT ) . str_pad( $member['bday_day'], 2, 0, STR_PAD_LEFT ) ] = $member['total'];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$members = \IPS\Db::i()->select( '*', 'core_members', $where, 'name ASC', array( 0, 5 ) );
|
||||
|
||||
if( $members->count() )
|
||||
{
|
||||
foreach( $members as $member )
|
||||
{
|
||||
/* If it's not leap year we do the nice thing and show Feb 29th birthdays on Feb 28th */
|
||||
if( $this->mon == 2 AND !$this->leapYear() AND $member['bday_month'] == 2 AND $member['bday_day'] == 29 )
|
||||
{
|
||||
$member['bday_day'] = 28;
|
||||
}
|
||||
|
||||
$member = \IPS\Member::constructFromData( $member );
|
||||
|
||||
$birthdays[ str_pad( $member->bday_month, 2, 0, STR_PAD_LEFT ) . str_pad( $member->bday_day, 2, 0, STR_PAD_LEFT ) ][] = $member;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $birthdays;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the where clause to fetch birthdays
|
||||
*
|
||||
* @param bool $day Whether to limit to the current day or not
|
||||
* @return array
|
||||
*/
|
||||
public function getBirthdaysWhere( $day=FALSE )
|
||||
{
|
||||
/* We always limit by month */
|
||||
$where = array( array( 'bday_month=?', $this->mon ) );
|
||||
|
||||
/* Are we also limiting by day? */
|
||||
if( $day === TRUE )
|
||||
{
|
||||
/* February 29th is special */
|
||||
if( $this->mon == 2 AND $this->mday == 28 AND !$this->leapYear() )
|
||||
{
|
||||
$where[] = array( 'bday_day IN(28,29)' );
|
||||
@@ -485,43 +541,23 @@ class _Date extends \IPS\DateTime
|
||||
}
|
||||
}
|
||||
|
||||
$members = \IPS\DB::i()->select( '*', 'core_members', $where );
|
||||
/* Exclude banned users */
|
||||
$where[] = array( 'temp_ban=?', 0 );
|
||||
|
||||
if( $members->count() )
|
||||
/* Groups with 'g_view_board' off are also 'banned', so factor those in too */
|
||||
$goodGroups = array();
|
||||
|
||||
foreach( \IPS\Member\Group::groups() as $group )
|
||||
{
|
||||
foreach( $members as $member )
|
||||
if( $group->g_view_board )
|
||||
{
|
||||
/* If it's not leap year we do the nice thing and show Feb 29th birthdays on Feb 28th */
|
||||
if( $this->mon == 2 AND !$this->leapYear() AND $member['bday_month'] == 2 AND $member['bday_day'] == 29 )
|
||||
{
|
||||
$member['bday_day'] = 28;
|
||||
}
|
||||
|
||||
$member = \IPS\Member::constructFromData( $member );
|
||||
|
||||
$banned = FALSE;
|
||||
|
||||
if ( $member->temp_ban != 0 )
|
||||
{
|
||||
if ( $member->temp_ban > 0 OR $member->temp_ban == -1 )
|
||||
{
|
||||
$banned = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if( !$member->group['g_view_board'] )
|
||||
{
|
||||
$banned = TRUE;
|
||||
}
|
||||
|
||||
if ( !$banned )
|
||||
{
|
||||
$birthdays[ str_pad( $member->bday_month, 2, 0, STR_PAD_LEFT ) . str_pad( $member->bday_day, 2, 0, STR_PAD_LEFT ) ][] = $member;
|
||||
}
|
||||
$goodGroups[] = $group->g_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $birthdays;
|
||||
$where[] = array( "member_group_id IN(" . implode( ',', $goodGroups ) . ")" );
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -735,12 +771,13 @@ class _Date extends \IPS\DateTime
|
||||
/**
|
||||
* Format the time according to the user's locale (without the date)
|
||||
*
|
||||
* @param bool $seconds If TRUE, will include seconds
|
||||
* @param bool $minutes If TRUE, will include minutes
|
||||
* @param bool $seconds If TRUE, will include seconds
|
||||
* @param bool $minutes If TRUE, will include minutes
|
||||
* @param \IPS\Lang|\IPS\Member|NULL $memberOrLanguage The language or member to use, or NULL for currently logged in member
|
||||
* @return string
|
||||
*/
|
||||
public function localeTime( $seconds=TRUE, $minutes=TRUE )
|
||||
public function localeTime( $seconds=TRUE, $minutes=TRUE, $memberOrLanguage=NULL )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->convertString( strftime( $this->localeTimeFormat( $seconds, $minutes ), $this->getTimestamp() + $this->offset ) );
|
||||
return static::determineLanguage( $memberOrLanguage )->convertString( strftime( $this->localeTimeFormat( $seconds, $minutes, $memberOrLanguage ), $this->getTimestamp() + $this->offset ) );
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Event Comment Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Calendar
|
||||
* @since 7 Jan 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
@@ -91,7 +91,7 @@ class _Comment extends \IPS\Content\Comment implements \IPS\Content\EditHistory,
|
||||
* @param string|NULL $action Action
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
public function url( $action=NULL )
|
||||
public function url( $action='find' )
|
||||
{
|
||||
return parent::url( $action )->setQueryString( 'tab', 'comments' );
|
||||
}
|
||||
@@ -112,7 +112,7 @@ class _Comment extends \IPS\Content\Comment implements \IPS\Content\EditHistory,
|
||||
* @param array $indexData Data from the search index
|
||||
* @param array $authorData Basic data about the author. Only includes columns returned by \IPS\Member::columnsForPhoto()
|
||||
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
|
||||
* @param array|NULL $containerData Basic data about the author. Only includes columns returned by container::basicDataColumns()
|
||||
* @param array|NULL $containerData Basic data about the container. Only includes columns returned by container::basicDataColumns()
|
||||
* @param array $reputationData Array of people who have given reputation and the reputation they gave
|
||||
* @param int|NULL $reviewRating If this is a review, the rating
|
||||
* @param string $view 'expanded' or 'condensed'
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Calendar Event Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Calendar
|
||||
* @since 7 Jan 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
@@ -169,7 +169,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
public function set_title( $title )
|
||||
{
|
||||
$this->_data['title'] = $title;
|
||||
$this->_data['title_seo'] = \IPS\Http\Url::seoTitle( $title );
|
||||
$this->_data['title_seo'] = \IPS\Http\Url\Friendly::seoTitle( $title );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,11 +181,11 @@ class _Event extends \IPS\Content\Item implements
|
||||
{
|
||||
if( !$this->_data['title_seo'] )
|
||||
{
|
||||
$this->title_seo = \IPS\Http\Url::seoTitle( $this->title );
|
||||
$this->title_seo = \IPS\Http\Url\Friendly::seoTitle( $this->title );
|
||||
$this->save();
|
||||
}
|
||||
|
||||
return $this->_data['title_seo'] ?: \IPS\Http\Url::seoTitle( $this->title );
|
||||
return $this->_data['title_seo'] ?: \IPS\Http\Url\Friendly::seoTitle( $this->title );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,14 +234,15 @@ class _Event extends \IPS\Content\Item implements
|
||||
|
||||
/* Hold parameters to sprintf() into the language string */
|
||||
$params = array();
|
||||
$pluralize = array();
|
||||
|
||||
/* Figure out the basic language string */
|
||||
$langString = "recur_human_" . $recurringData['event_repeats'];
|
||||
|
||||
if( $recurringData['event_repeat_freq'] > 1 )
|
||||
{
|
||||
$langString = $langString . '_multi';
|
||||
$params[] = $recurringData['event_repeat_freq'];
|
||||
$langString = $langString . '_multi';
|
||||
$pluralize[] = $recurringData['event_repeat_freq'];
|
||||
}
|
||||
|
||||
/* If recurring weekly, take days into account */
|
||||
@@ -278,7 +279,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
$params[] = \IPS\Member::loggedIn()->language()->addToStack('recur_human__forever');
|
||||
}
|
||||
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( $langString, FALSE, array( 'sprintf' => $params ) );
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( $langString, FALSE, array( 'pluralize' => $pluralize, 'sprintf' => $params ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -384,7 +385,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
/* Figure out which of teh days is next. For example, if the start date is a Wednesday, and the
|
||||
event repeats every Monday and Friday, we need to start with Friday (not Monday) because that's
|
||||
when the first occurance is */
|
||||
$nextTimes = array();
|
||||
$nextTimes = array();
|
||||
foreach ( $_repeatDays as $repeatDay )
|
||||
{
|
||||
$nextTimes[ $repeatDay ] = $date->adjust( "next {$repeatDay}" )->getTimestamp();
|
||||
@@ -393,14 +394,28 @@ class _Event extends \IPS\Content\Item implements
|
||||
$nextTimes = array_keys( $nextTimes );
|
||||
$nextDay = array_shift( $nextTimes );
|
||||
|
||||
/* We have to reset the $_repeatDays array pointer so that it matches $nextDay, otherwise it is possible a day might be skipped */
|
||||
while( current( $_repeatDays ) !== $nextDay )
|
||||
{
|
||||
$resetNextDay = next( $_repeatDays );
|
||||
|
||||
if( $resetNextDay === FALSE )
|
||||
{
|
||||
reset( $_repeatDays );
|
||||
$resetNextDay = current( $_repeatDays );
|
||||
}
|
||||
}
|
||||
|
||||
/* We need to set a counter in case we need to repeat every X weeks */
|
||||
$iteration = 1;
|
||||
|
||||
/* Do we have an occurrences limit? */
|
||||
if( $recurringData['repeat_end_occurrences'] )
|
||||
{
|
||||
while( $occurrences < $recurringData['repeat_end_occurrences'] )
|
||||
{
|
||||
$date = $date->adjust( "next {$nextDay}" );
|
||||
$eDate = ( $eDate !== NULL ) ? $eDate->adjust( "next {$nextDay}" ) : NULL;
|
||||
$occurrences++;
|
||||
$eDate = ( $eDate !== NULL ) ? $eDate->adjust( "next {$nextDay}" ) : NULL;
|
||||
|
||||
/* Figure out the next day this occurs on */
|
||||
$nextDay = next( $_repeatDays );
|
||||
@@ -411,6 +426,16 @@ class _Event extends \IPS\Content\Item implements
|
||||
$nextDay = current( $_repeatDays );
|
||||
}
|
||||
|
||||
/* Are we repeating every other week or something? */
|
||||
if( $recurringData['event_repeat_freq'] AND $iteration % $recurringData['event_repeat_freq'] != 0 )
|
||||
{
|
||||
$iteration++;
|
||||
continue;
|
||||
}
|
||||
|
||||
$iteration++;
|
||||
$occurrences++;
|
||||
|
||||
if( ( $date->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) AND $date->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 ) )
|
||||
@@ -437,6 +462,15 @@ class _Event extends \IPS\Content\Item implements
|
||||
$nextDay = current( $_repeatDays );
|
||||
}
|
||||
|
||||
/* Are we repeating every other week or something? */
|
||||
if( $recurringData['event_repeat_freq'] AND $iteration % $recurringData['event_repeat_freq'] != 0 )
|
||||
{
|
||||
$iteration++;
|
||||
continue;
|
||||
}
|
||||
|
||||
$iteration++;
|
||||
|
||||
if( ( $date->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) AND $date->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 ) )
|
||||
@@ -463,6 +497,15 @@ class _Event extends \IPS\Content\Item implements
|
||||
$nextDay = current( $_repeatDays );
|
||||
}
|
||||
|
||||
/* Are we repeating every other week or something? */
|
||||
if( $recurringData['event_repeat_freq'] AND $iteration % $recurringData['event_repeat_freq'] != 0 )
|
||||
{
|
||||
$iteration++;
|
||||
continue;
|
||||
}
|
||||
|
||||
$iteration++;
|
||||
|
||||
if( ( $date->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) AND $date->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 ) )
|
||||
@@ -553,7 +596,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
@@ -750,6 +793,68 @@ class _Event extends \IPS\Content\Item implements
|
||||
|
||||
return $this->dateObjects['end'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string with the event date/times in the timezone of the user who created the event
|
||||
* Used in outgoing emails
|
||||
*
|
||||
* @param \IPS\Lang $language The language to use
|
||||
* @return string
|
||||
*/
|
||||
public function fixedDateTimeDescription( \IPS\Lang $language )
|
||||
{
|
||||
/* Init */
|
||||
$return = '';
|
||||
try
|
||||
{
|
||||
$authorTimezone = new \DateTimeZone( $this->author()->timezone );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
$authorTimezone = new \DateTimeZone('UTC');
|
||||
}
|
||||
|
||||
/* Start */
|
||||
$start = $this->_start_date->setTimezone( $authorTimezone );
|
||||
$startOffset = $authorTimezone->getOffset( $start ) / 3600;
|
||||
$return .= $start->calendarDate( $language );
|
||||
if ( !$this->all_day )
|
||||
{
|
||||
$return .= ' ' . $start->localeTime( FALSE, TRUE, $language );
|
||||
}
|
||||
if ( $startOffset )
|
||||
{
|
||||
$return .= ' (GMT' . ( ( $startOffset > 0 ) ? '+' : '' ) . $startOffset . ')';
|
||||
}
|
||||
else
|
||||
{
|
||||
$return .= ' (GMT)';
|
||||
}
|
||||
|
||||
/* End */
|
||||
if ( $this->_end_date )
|
||||
{
|
||||
$return .= ' - ';
|
||||
$end = $this->_end_date->setTimezone( $authorTimezone );
|
||||
$endOffset = $authorTimezone->getOffset( $end ) / 3600; // Unlikely, but if the event spans the DST switch, the end offset could be different to the start
|
||||
$return .= $end->calendarDate( $language );
|
||||
if ( !$this->all_day )
|
||||
{
|
||||
$return .= ' ' . $end->localeTime( FALSE, TRUE, $language );
|
||||
}
|
||||
if ( $endOffset )
|
||||
{
|
||||
$return .= ' (GMT' . ( ( $endOffset > 0 ) ? '+' : '' ) . $endOffset . ')';
|
||||
}
|
||||
else
|
||||
{
|
||||
$return .= ' (GMT)';
|
||||
}
|
||||
}
|
||||
|
||||
/* Return */
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cached URLs
|
||||
@@ -865,11 +970,11 @@ class _Event extends \IPS\Content\Item implements
|
||||
*/
|
||||
public function commentReviews( $tab )
|
||||
{
|
||||
if ( $tab === 'reviews' )
|
||||
if ( $tab === 'reviews' and $this->container()->allow_reviews )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate('view')->reviews( $this );
|
||||
}
|
||||
elseif( $tab === 'comments' )
|
||||
elseif( $tab === 'comments' and $this->container()->allow_comments )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate('view')->comments( $this );
|
||||
}
|
||||
@@ -903,7 +1008,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
public function moderateNewComments( \IPS\Member $member )
|
||||
{
|
||||
$commentClass = static::$commentClass;
|
||||
return $this->container()->comment_moderate and !$member->group['g_avoid_q'];
|
||||
return ( $this->container()->comment_moderate and !$member->group['g_avoid_q'] ) or parent::moderateNewComments( $member );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -915,7 +1020,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
public function moderateNewReviews( \IPS\Member $member )
|
||||
{
|
||||
$reviewClass = static::$reviewClass;
|
||||
return $this->container()->review_moderate and !$member->group['g_avoid_q'];
|
||||
return ( $this->container()->review_moderate and !$member->group['g_avoid_q'] ) or parent::moderateNewReviews( $member );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -933,7 +1038,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
* Get elements for add/edit form
|
||||
*
|
||||
* @param \IPS\Content\Item|NULL $item The current item if editing or NULL if creating
|
||||
* @param int $container Container (e.g. forum) ID, if appropriate
|
||||
* @param \IPS\Node\Model|NULL $container Container (e.g. forum) ID, if appropriate
|
||||
* @return array
|
||||
*/
|
||||
public static function formElements( $item=NULL, \IPS\Node\Model $container=NULL )
|
||||
@@ -949,7 +1054,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
|
||||
/* We are using a custom template to provide an optimal experience for the user instead of a basic linear top-down form elements for the date fields */
|
||||
$dateValues = array(
|
||||
'single_day' => $item ? !$item->end_date : TRUE,
|
||||
'single_day' => $item ? ( !$item->end_date or ( \IPS\calendar\Date::parseTime( $item->start_date, $item->all_day ? FALSE : TRUE )->format('Y-m-d') === \IPS\calendar\Date::parseTime( $item->end_date, $item->all_day ? FALSE : TRUE )->format('Y-m-d') ) ) : TRUE,
|
||||
'start_date' => $item ? \IPS\calendar\Date::parseTime( $item->start_date, $item->all_day ? FALSE : TRUE ) : \IPS\calendar\Date::parseTime( $newDefault ),
|
||||
'end_date' => ( $item AND $item->end_date ) ? \IPS\calendar\Date::parseTime( $item->end_date, $item->all_day ? FALSE : TRUE ) : NULL,
|
||||
'all_day' => $item ? $item->all_day : $allDay,
|
||||
@@ -1004,7 +1109,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'] )
|
||||
@@ -1021,8 +1126,19 @@ class _Event extends \IPS\Content\Item implements
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
$end = \IPS\calendar\Date::createFromForm( $val['start_date'], ( ( !isset( $val['all_day'] ) OR !$val['all_day'] ) ? $val['end_time'] : NULL ), ( isset( $val['all_day'] ) AND $val['all_day'] ) ? 'UTC' : $val['event_timezone'] )->format( 'Y-m-d H:i' );
|
||||
}
|
||||
catch( \Exception $e )
|
||||
{
|
||||
throw new \DomainException( "invalid_end_date" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Check the dates */
|
||||
if( $start === NULL )
|
||||
{
|
||||
@@ -1056,9 +1172,9 @@ class _Event extends \IPS\Content\Item implements
|
||||
}
|
||||
|
||||
}, NULL, NULL, 'event_dates' );
|
||||
|
||||
|
||||
/* Init */
|
||||
$return['calendar'] = new \IPS\Helpers\Form\Node( static::$formLangPrefix . 'container', $container ? $container->id : ( isset( \IPS\Request::i()->id ) ? \IPS\Request::i()->id : NULL ), TRUE, array(
|
||||
$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' ),
|
||||
'class' => 'IPS\calendar\Calendar',
|
||||
'permissionCheck' => 'add',
|
||||
@@ -1087,8 +1203,11 @@ class _Event extends \IPS\Content\Item implements
|
||||
}
|
||||
|
||||
/* Event - request RSVP */
|
||||
$return['rsvp'] = new \IPS\Helpers\Form\YesNo( 'event_rsvp', $item ? $item->rsvp : NULL, FALSE, array( 'togglesOn' => array( 'event_rsvp_limit' ) ), NULL, NULL, NULL, 'event_rsvp' );
|
||||
$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( $container and $container->can( 'askrsvp', $item ? $item->author() : \IPS\Member::loggedIn() ) )
|
||||
{
|
||||
$return['rsvp'] = new \IPS\Helpers\Form\YesNo( 'event_rsvp', $item ? $item->rsvp : NULL, FALSE, array( 'togglesOn' => array( 'event_rsvp_limit' ) ), NULL, NULL, NULL, 'event_rsvp' );
|
||||
$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' );
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
@@ -1133,6 +1252,20 @@ class _Event extends \IPS\Content\Item implements
|
||||
$this->start_date = \IPS\calendar\Date::createFromForm( $values['event_dates']['start_date'], ( ( !isset( $values['event_dates']['all_day'] ) OR !$values['event_dates']['all_day'] ) ? $values['event_dates']['start_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' );
|
||||
$this->end_date = null;
|
||||
|
||||
/* Clear clear fields for non-selected items */
|
||||
switch( $values['event_dates']['repeat_end'] )
|
||||
{
|
||||
case 'never':
|
||||
unset( $values['event_dates']['repeat_end_occurrences'], $values['event_dates']['repeat_end_date'] );
|
||||
break;
|
||||
case 'after':
|
||||
unset( $values['event_dates']['repeat_end_date'] );
|
||||
break;
|
||||
case 'date':
|
||||
unset( $values['event_dates']['repeat_end_occurrences'] );
|
||||
break;
|
||||
}
|
||||
|
||||
if( isset( $values['event_dates']['end_date'] ) AND $values['event_dates']['end_date'] )
|
||||
{
|
||||
if( !isset( $values['event_dates']['single_day'] ) OR !$values['event_dates']['single_day'] )
|
||||
@@ -1170,7 +1303,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
}
|
||||
|
||||
/* Cover photo */
|
||||
$this->cover_photo = ( $values['event_cover_photo'] !== NULL ) ? $values['event_cover_photo']->url : NULL;
|
||||
$this->cover_photo = ( $values['event_cover_photo'] !== NULL ) ? (string) $values['event_cover_photo'] : NULL;
|
||||
|
||||
/* Set location */
|
||||
$this->location = ( $values['event_location'] !== NULL ) ? json_encode( $values['event_location'] ) : NULL;
|
||||
@@ -1186,8 +1319,8 @@ class _Event extends \IPS\Content\Item implements
|
||||
}
|
||||
|
||||
/* RSVP options */
|
||||
$this->rsvp = $values['event_rsvp'];
|
||||
$this->rsvp_limit = $values['event_rsvp_limit'];
|
||||
$this->rsvp = isset( $values['event_rsvp'] ) ? $values['event_rsvp'] : FALSE;
|
||||
$this->rsvp_limit = isset( $values['event_rsvp_limit'] ) ? $values['event_rsvp_limit'] : 0;
|
||||
|
||||
/* Get the normal stuff */
|
||||
parent::processForm( $values );
|
||||
@@ -1206,6 +1339,21 @@ class _Event extends \IPS\Content\Item implements
|
||||
|
||||
/* And claim attachments */
|
||||
\IPS\File::claimAttachments( 'calendar-event', $this->id );
|
||||
|
||||
/* And expire widget caches so an event for today will show in the upcoming events widget properly */
|
||||
$this->expireWidgetCaches();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Notification
|
||||
*
|
||||
* @param string|NULL $extra Additional data
|
||||
* @return \IPS\Notification
|
||||
*/
|
||||
protected function createNotification( $extra=NULL )
|
||||
{
|
||||
// New content is sent with itself as the item as we deliberately do not group notifications about new content items. Unlike comments where you're going to read them all - you might scan the notifications list for topic titles you're interested in
|
||||
return new \IPS\Notification( \IPS\Application::load( 'calendar' ), 'new_content', $this, array( $this ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1227,7 +1375,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
* Return the map for the event, if location is specified
|
||||
*
|
||||
* @param int $width Width
|
||||
* @param int $heigth Height
|
||||
* @param int $height Height
|
||||
* @return string
|
||||
* @note \BadMethodCallException can be thrown if the google maps integration is shut off - don't show any error if that happens.
|
||||
*/
|
||||
@@ -1251,8 +1399,9 @@ class _Event extends \IPS\Content\Item implements
|
||||
* @param \IPS\calendar\Date $startDate Date to start from
|
||||
* @param \IPS\calendar\Date|NULL $endDate Cut off date for events. NULL accepted as a possible value only if $formatEvents is set to FALSE.
|
||||
* @param \IPS\calendar\Calendar|NULL|array $calendar Calendar to filter by
|
||||
* @param int|null $limit Maximum number of events to return (only supported when not formatting events)
|
||||
* @param bool $formatEvents Whether or not to format events into a structured array
|
||||
* @param int|null $limit Maximum number of events to return (only supported when not formatting events)
|
||||
* @param bool $formatEvents Whether or not to format events into a structured array
|
||||
* @param \IPS\Member $member The member (NULL to use currently logged in member)
|
||||
* @return \IPS\Patterns\ActiveRecordIterator
|
||||
* @throws \InvalidArgumentException
|
||||
* @see \IPS\Content\_Item::getItemsWithPermission()
|
||||
@@ -1286,7 +1435,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
}
|
||||
|
||||
/* Get timezone adjusted versions of start/end time */
|
||||
$startDateTimezone = \IPS\calendar\Date::parseTime( $startDate->mysqlDatetime() );
|
||||
$startDateTimezone = \IPS\calendar\Date::parseTime( $startDate->mysqlDatetime(), TRUE );
|
||||
$endDateTimezone = ( $endDate !== NULL ) ? \IPS\calendar\Date::parseTime( $endDate->mysqlDatetime() ) : NULL;
|
||||
|
||||
if ( $member->timezone )
|
||||
@@ -1368,7 +1517,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, 'read', NULL, 0, $member );
|
||||
$events = \IPS\calendar\Event::getItemsWithPermission( array_merge( $where, $nonRecurring ), 'event_start_date ASC', NULL, 'read', \IPS\Content\Hideable::FILTER_AUTOMATIC, 0, $member );
|
||||
|
||||
/* We need to make sure ranged events repeat each day that they occur on */
|
||||
$formattedEvents = array();
|
||||
@@ -1391,14 +1540,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
}
|
||||
else
|
||||
{
|
||||
if( $event->all_day )
|
||||
{
|
||||
$formattedEvents[ \IPS\calendar\Date::parseTime( $event->start_date, FALSE )->mysqlDatetime( FALSE ) ]['single'][ $event->id ] = $event;
|
||||
}
|
||||
else
|
||||
{
|
||||
$formattedEvents[ $event->_start_date->mysqlDatetime( FALSE ) ]['single'][ $event->id ] = $event;
|
||||
}
|
||||
$formattedEvents[ $event->_start_date->mysqlDatetime( FALSE ) ]['single'][ $event->id ] = $event;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1408,13 +1550,14 @@ 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' ) ) ), 'event_start_date ASC', NULL, 'read', NULL, 0, $member );
|
||||
$recurringEvents = \IPS\calendar\Event::getItemsWithPermission( array_merge( $where, array( array( 'event_recurring IS NOT NULL' ) ) ), 'event_start_date ASC', NULL, 'read', \IPS\Content\Hideable::FILTER_AUTOMATIC, 0, $member );
|
||||
|
||||
/* Loop over any results */
|
||||
foreach( $recurringEvents as $event )
|
||||
{
|
||||
/* Find occurrences within our date range (if any) */
|
||||
$occurrences = $event->findOccurrences( $startDate, ( $endDate ? $endDate : $startDate->adjust( "+2 years" ) ) );
|
||||
$thisEndDate = ( $endDate ? $endDate : $startDate->adjust( "+2 years" ) );
|
||||
$occurrences = $event->findOccurrences( $startDate, $thisEndDate );
|
||||
|
||||
/* Do we have any? */
|
||||
if( count( $occurrences ) )
|
||||
@@ -1428,7 +1571,8 @@ class _Event extends \IPS\Content\Item implements
|
||||
if( $occurrence['endDate'] !== NULL )
|
||||
{
|
||||
$date = $occurrence['startDate'];
|
||||
while( $date->mysqlDatetime( FALSE ) < $occurrence['endDate']->mysqlDatetime( FALSE ) )
|
||||
$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' );
|
||||
@@ -1456,6 +1600,16 @@ class _Event extends \IPS\Content\Item implements
|
||||
/* @note: Error suppressor is needed due to PHP bug https://bugs.php.net/bug.php?id=50688 */
|
||||
@usort( $formattedEvents, 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;
|
||||
@@ -1555,7 +1709,7 @@ class _Event extends \IPS\Content\Item implements
|
||||
* @param array $indexData Data from the search index
|
||||
* @param array $authorData Basic data about the author. Only includes columns returned by \IPS\Member::columnsForPhoto()
|
||||
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
|
||||
* @param array|NULL $containerData Basic data about the author. Only includes columns returned by container::basicDataColumns()
|
||||
* @param array|NULL $containerData Basic data about the container. Only includes columns returned by container::basicDataColumns()
|
||||
* @param array $reputationData Array of people who have given reputation and the reputation they gave
|
||||
* @param int|NULL $reviewRating If this is a review, the rating
|
||||
* @param string $view 'expanded' or 'condensed'
|
||||
@@ -1581,4 +1735,81 @@ class _Event extends \IPS\Content\Item implements
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'global', 'calendar', 'front' )->searchResultEventSnippet( $indexData, $itemData, $nextOccurance, $startDate, $endDate, $itemData['event_all_day'], $view == 'condensed' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get output for API
|
||||
*
|
||||
* @return array
|
||||
* @apiresponse int id ID number
|
||||
* @apiresponse string title Title
|
||||
* @apiresponse \IPS\calendar\Calendar calendar Calendar
|
||||
* @apiresponse datetime start Event start time
|
||||
* @apiresponse datetime end Event end time
|
||||
* @apiresponse string recurrence If this event recurs, the ICS recurrence definition
|
||||
* @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 datetime postedDate When the event was created
|
||||
* @apiresponse string description Event description
|
||||
* @apiresponse int comments Number of comments
|
||||
* @apiresponse int reviews Number of reviews
|
||||
* @apiresponse int views Number of posts
|
||||
* @apiresponse string prefix The prefix tag, if there is one
|
||||
* @apiresponse [string] tags The tags
|
||||
* @apiresponse bool locked Event is locked
|
||||
* @apiresponse bool hidden Event is hidden
|
||||
* @apiresponse bool featured Event is featured
|
||||
* @apiresponse string url URL
|
||||
*/
|
||||
public function apiOutput()
|
||||
{
|
||||
return array(
|
||||
'id' => $this->tid,
|
||||
'title' => $this->title,
|
||||
'calendar' => $this->container()->apiOutput(),
|
||||
'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(),
|
||||
'postedDate' => \IPS\DateTime::ts( $this->saved )->rfc3339(),
|
||||
'description' => $this->content(),
|
||||
'comments' => $this->comments,
|
||||
'reviews' => $this->reviews,
|
||||
'views' => $this->views,
|
||||
'prefix' => $this->prefix(),
|
||||
'tags' => $this->tags(),
|
||||
'locked' => (bool) $this->locked(),
|
||||
'hidden' => (bool) $this->hidden(),
|
||||
'featured' => (bool) $this->mapped('featured'),
|
||||
'url' => (string) $this->url(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can comment?
|
||||
*
|
||||
* @param \IPS\Member\NULL $member The member (NULL for currently logged in member)
|
||||
* @return bool
|
||||
*/
|
||||
public function canComment( $member=NULL )
|
||||
{
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
return parent::canComment( $member ) and $this->container()->allow_comments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can review?
|
||||
*
|
||||
* @param \IPS\Member\NULL $member The member (NULL for currently logged in member)
|
||||
* @return bool
|
||||
*/
|
||||
public function canReview( $member = NULL )
|
||||
{
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
return parent::canReview( $member ) and $this->container()->allow_reviews;
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Event Review Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Calendar
|
||||
* @since 7 Jan 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
@@ -116,7 +116,7 @@ class _Review extends \IPS\Content\Review implements \IPS\Content\EditHistory, \
|
||||
* @param array $indexData Data from the search index
|
||||
* @param array $authorData Basic data about the author. Only includes columns returned by \IPS\Member::columnsForPhoto()
|
||||
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
|
||||
* @param array|NULL $containerData Basic data about the author. Only includes columns returned by container::basicDataColumns()
|
||||
* @param array|NULL $containerData Basic data about the container. Only includes columns returned by container::basicDataColumns()
|
||||
* @param array $reputationData Array of people who have given reputation and the reputation they gave
|
||||
* @param int|NULL $reviewRating If this is a review, the rating
|
||||
* @param string $view 'expanded' or 'condensed'
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief iCalendar ICS Parser
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Calendar
|
||||
* @since 19 Dec 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
@@ -298,15 +298,16 @@ class _ICSParser
|
||||
{
|
||||
$this->_parsedIcsData = $this->_convertToGmt( $this->_parsedIcsData );
|
||||
}
|
||||
|
||||
|
||||
/* Now loop over the results in order to insert */
|
||||
$_imported = 0;
|
||||
$_skipped = 0;
|
||||
$_newEvents = 0;
|
||||
|
||||
// Leave this here - useful for debugging
|
||||
// print_r($this->_parsedIcsData);exit;
|
||||
|
||||
if ( count( $this->_parsedIcsData ) )
|
||||
if ( count( $this->_parsedIcsData ) and isset( $this->_parsedIcsData['events'] ) )
|
||||
{
|
||||
/* Loop over the events */
|
||||
foreach( $this->_parsedIcsData['events'] as $event )
|
||||
@@ -316,7 +317,7 @@ class _ICSParser
|
||||
{
|
||||
try
|
||||
{
|
||||
$rrule = self::parseRrule( $event['recurr'] );
|
||||
$rrule = static::parseRrule( $event['recurr'] );
|
||||
}
|
||||
catch( \InvalidArgumentException $e )
|
||||
{
|
||||
@@ -327,24 +328,24 @@ class _ICSParser
|
||||
$event['uid'] = $event['uid'] ? $event['uid'] : md5( implode( ',', $event['start'] ) . implode( ',', $event['end'] ) );
|
||||
|
||||
/* Figure out some times */
|
||||
$event_unix_from = $event['start']['gmt_ts'];
|
||||
$event_unix_to = isset( $event['end'] ) ? $event['end']['gmt_ts'] : NULL;
|
||||
$event_all_day = ( $event['start']['type'] == 'DATE' ) ? 1 : 0;
|
||||
$event_unix_from = $event['start']['utc_time'];
|
||||
$event_unix_to = isset( $event['end'] ) ? $event['end']['utc_time'] : NULL;
|
||||
$event_all_day = ( $event['start']['type'] == 'DATE' ) ? TRUE : FALSE;
|
||||
|
||||
/* End dates in iCalendar format are "exclusive", meaning they are actually the day ahead. */
|
||||
/* @link http://microformats.org/wiki/dtend-issue */
|
||||
/* Only adjust end date if end date is not equal too the start date already. */
|
||||
/* @see Ticket 876817 */
|
||||
|
||||
if( $event_unix_to AND $event['end']['type'] == 'DATE' AND ( $event_unix_from != $event_unix_to ) )
|
||||
if( $event_unix_to AND $event['end']['type'] == 'DATE' AND ( $event_unix_from->getTimestamp() != $event_unix_to->getTimestamp() ) )
|
||||
{
|
||||
$event_unix_to -= 86400;
|
||||
$event_unix_to = $event_unix_to->sub( new \DateInterval( 'P1D' ) );
|
||||
}
|
||||
|
||||
/* It is a single day event if end date is equal to start date */
|
||||
if( $event_unix_from == $event_unix_to )
|
||||
{
|
||||
$event_unix_to = 0;
|
||||
$event_unix_to = NULL;
|
||||
}
|
||||
|
||||
/* If there is a duration, calculate the end date again */
|
||||
@@ -359,14 +360,14 @@ class _ICSParser
|
||||
preg_match( "#(\d+?)S#is", $event['duration'], $match );
|
||||
$second = $match[1] ? $match[1] : 0;
|
||||
|
||||
$event_unix_to = $event_unix_from + ( $hour * 3600 ) + ( $minute * 60 ) + $second;
|
||||
$event_unix_to = $event_unix_from->add( new \DateIntveral( 'PT' . ( $hour * 3600 ) . 'H' . ( $minute * 60 ) . 'M' . $second . 'S' ) );
|
||||
}
|
||||
|
||||
/* If this is an all day event, adjust the timestamps */
|
||||
if( $event_all_day )
|
||||
{
|
||||
$event_unix_from = gmmktime( 0, 0, 0, gmstrftime( '%m', $event_unix_from ), gmstrftime( '%d', $event_unix_from ), gmstrftime( '%Y', $event_unix_from ) );
|
||||
$event_unix_to = $event_unix_to ? gmmktime( 0, 0, 0, gmstrftime( '%m', $event_unix_to ), gmstrftime( '%d', $event_unix_to ), gmstrftime( '%Y', $event_unix_to ) ) : 0;
|
||||
$event_unix_from = $event_unix_from->setTime( 0, 0, 0 );
|
||||
$event_unix_to = $event_unix_to ? $event_unix_to->setTime( 0, 0, 0 ) : NULL;
|
||||
}
|
||||
|
||||
/* If we are missing crucial data, skip this event */
|
||||
@@ -378,11 +379,19 @@ class _ICSParser
|
||||
|
||||
/* Update previously imported events, if possible */
|
||||
$eventId = NULL;
|
||||
$_new = FALSE;
|
||||
|
||||
if( $event['uid'] )
|
||||
{
|
||||
try
|
||||
{
|
||||
/* If we are importing an ICS file, feed here will be null. */
|
||||
if ( is_null( $this->feed ) )
|
||||
{
|
||||
/* Bubble up so we can create a new event */
|
||||
throw new \UnderflowException;
|
||||
}
|
||||
|
||||
$eventId = \IPS\Db::i()->select( 'import_event_id', 'calendar_import_map', array( array( 'import_guid=? and import_feed_id=?', $event['uid'], $this->feed->id ) ) )->first();
|
||||
|
||||
try
|
||||
@@ -401,6 +410,7 @@ class _ICSParser
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
$newEvent = new \IPS\calendar\Event;
|
||||
$_new = TRUE;
|
||||
|
||||
/* Basics */
|
||||
$newEvent->post_key = md5( uniqid() );
|
||||
@@ -425,8 +435,8 @@ class _ICSParser
|
||||
$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() );
|
||||
$newEvent->all_day = $event_all_day;
|
||||
$newEvent->recurring = ( isset( $event['recurr'] ) ) ? $event['recurr'] : NULL;
|
||||
$newEvent->start_date = gmstrftime( "%Y-%m-%d %H:%M:00", $event_unix_from );
|
||||
$newEvent->end_date = $event_unix_to ? gmstrftime( "%Y-%m-%d %H:%M:00", $event_unix_to ) : NULL;
|
||||
$newEvent->start_date = $event_unix_from->setTimezone( new \DateTimeZone( 'UTC' ) )->format( 'Y-m-d H:i:s' );
|
||||
$newEvent->end_date = $event_unix_to ? $event_unix_to->setTimezone( new \DateTimeZone( 'UTC' ) )->format( 'Y-m-d H:i:s' ) : NULL;
|
||||
|
||||
/* Geolocation? */
|
||||
if( isset( $event['geo'] ) AND is_array( $event['geo'] ) AND count( $event['geo'] ) )
|
||||
@@ -444,6 +454,12 @@ class _ICSParser
|
||||
/* Increment counter */
|
||||
$_imported++;
|
||||
|
||||
/* Increment only if this is a new event */
|
||||
if( $_new )
|
||||
{
|
||||
$_newEvents++;
|
||||
}
|
||||
|
||||
/* Add to index */
|
||||
\IPS\Content\Search\Index::i()->index( $newEvent );
|
||||
|
||||
@@ -481,9 +497,12 @@ class _ICSParser
|
||||
}
|
||||
|
||||
/* Increment post counts */
|
||||
$this->member->member_posts = $this->member->member_posts + $_imported;
|
||||
$this->member->member_last_post = time();
|
||||
$this->member->save();
|
||||
if( $_newEvents )
|
||||
{
|
||||
$this->member->member_posts = $this->member->member_posts + $_newEvents;
|
||||
$this->member->member_last_post = time();
|
||||
$this->member->save();
|
||||
}
|
||||
|
||||
/* Return the data */
|
||||
return array( 'skipped' => $_skipped, 'imported' => $_imported );
|
||||
@@ -630,12 +649,13 @@ class _ICSParser
|
||||
/**
|
||||
* Return a UID for iCalendar
|
||||
*
|
||||
* @param array $params Parameters to use to generate UID
|
||||
* @param \IPS\calendar\Event $event Event
|
||||
* @param string
|
||||
*/
|
||||
protected function _buildUid( $params )
|
||||
protected static function _buildUid( $event )
|
||||
{
|
||||
return md5( implode( '.', $params ) ) . '@' . $_SERVER['SERVER_ADDR'];
|
||||
$baseUrl = \IPS\Http\Url::internal('');
|
||||
return $event->id . '-' . $event->calendar_id . '-' . md5( (string) $baseUrl ) . '@' . $baseUrl->data['host'];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -658,7 +678,7 @@ class _ICSParser
|
||||
$output .= "SUMMARY:" . $this->_encodeSpecialCharacters( $event->title ) . "\r\n";
|
||||
$output .= "DTSTAMP:" . \IPS\calendar\Date::ts( $event->saved )->modifiedIso8601( TRUE, TRUE ) . "\r\n";
|
||||
$output .= "SEQUENCE:" . $event->sequence . "\r\n";
|
||||
$output .= "UID:" . $this->_buildUid( array( $event->saved, $event->id ) ) . "\r\n";
|
||||
$output .= "UID:" . static::_buildUid( $event ) . "\r\n";
|
||||
$output .= $this->_foldLines( "ORGANIZER;CN=\"" . $this->_encodeSpecialCharacters( $event->author()->name, false ) . '":' . \IPS\Settings::i()->email_out ) . "\r\n";
|
||||
|
||||
/* Attachments */
|
||||
@@ -696,8 +716,8 @@ class _ICSParser
|
||||
}
|
||||
else
|
||||
{
|
||||
$output .= "DTSTART;" . $event->_start_date->modifiedIso8601( TRUE, TRUE ) . "\r\n";
|
||||
$output .= "DTEND;" . $event->_end_date->modifiedIso8601( TRUE, TRUE ) . "\r\n";
|
||||
$output .= "DTSTART:" . $event->_start_date->modifiedIso8601( TRUE, TRUE ) . "\r\n";
|
||||
$output .= "DTEND:" . $event->_end_date->modifiedIso8601( TRUE, TRUE ) . "\r\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -708,7 +728,7 @@ class _ICSParser
|
||||
}
|
||||
else
|
||||
{
|
||||
$output .= "DTSTART;" . $event->_start_date->modifiedIso8601( TRUE, TRUE ) . "\r\n";
|
||||
$output .= "DTSTART:" . $event->_start_date->modifiedIso8601( TRUE, TRUE ) . "\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -830,16 +850,6 @@ class _ICSParser
|
||||
* @brief Raw iCalendar data before parsing
|
||||
*/
|
||||
protected $_rawIcsData = array();
|
||||
|
||||
/**
|
||||
* @brief Temp: Current timezone ID we are parsing
|
||||
*/
|
||||
protected $_tzId = '';
|
||||
|
||||
/**
|
||||
* @brief Temp: Current timezone ID we are beginning to parse
|
||||
*/
|
||||
protected $_tzBegin = '';
|
||||
|
||||
/**
|
||||
* @brief Earliest timestamp from feed
|
||||
@@ -931,32 +941,28 @@ class _ICSParser
|
||||
$_tmp = array();
|
||||
$_key = array();
|
||||
$tmp = explode( ':', $string );
|
||||
$tmp[0] = 'DATETIME';
|
||||
|
||||
/* The date string may be in the format of "DTSTART;20160219T140000Z" (for example) */
|
||||
if ( !isset( $tmp[1] ) )
|
||||
{
|
||||
if ( mb_strpos( $string, ';' ) !== false )
|
||||
{
|
||||
$tmp = explode( ';', $string );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$tzid = '';
|
||||
|
||||
/* Got a TZID? */
|
||||
if ( count( $_key ) AND $_key[1] == 'TZID' )
|
||||
{
|
||||
$tzid = $tmp[0];
|
||||
}
|
||||
$tzid = ( count( $_key ) AND $_key[1] == 'TZID' ) ? $tmp[0] : '';
|
||||
|
||||
/* Is it a date? */
|
||||
if ( $tmp[0] == 'DATE' )
|
||||
{
|
||||
$timestamp = strtotime( $tmp[1] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$timestamp = '?';
|
||||
}
|
||||
/* If the value is a date without a time, then type should be reset to date */
|
||||
$type = ( mb_strlen( $tmp[1] ) === 8 ) ? 'DATE' : 'DATETIME';
|
||||
|
||||
/* Format return array */
|
||||
$return = array(
|
||||
'type' => $tmp[0],
|
||||
'type' => $type,
|
||||
'raw' => $tmp[1],
|
||||
'raw_ts' => strtotime( $tmp[1] ),
|
||||
'ts' => $timestamp,
|
||||
'tzid' => str_replace( '"', '', $tzid ),
|
||||
);
|
||||
|
||||
@@ -990,26 +996,14 @@ class _ICSParser
|
||||
$this->_begin = 'VCALENDAR';
|
||||
$this->_processVcalendarObject( $start + 1 );
|
||||
break;
|
||||
|
||||
case 'VTIMEZONE':
|
||||
$this->_begin = 'VTIMEZONE';
|
||||
$this->_processTimezoneObject( $start + 1 );
|
||||
break;
|
||||
|
||||
|
||||
case 'STANDARD':
|
||||
if ( $this->_begin == 'VTIMEZONE' )
|
||||
{
|
||||
$this->_processTimezoneTypeObject( $start + 1, 'STANDARD' );
|
||||
}
|
||||
break;
|
||||
|
||||
case 'DAYLIGHT':
|
||||
if ( $this->_begin == 'VTIMEZONE' )
|
||||
{
|
||||
$this->_processTimezoneTypeObject( $start + 1, 'DAYLIGHT' );
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'VEVENT':
|
||||
$this->_begin = 'VEVENT';
|
||||
$this->_processEventObject( $start + 1 );
|
||||
@@ -1249,106 +1243,6 @@ class _ICSParser
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a timezone object in an ical feed
|
||||
*
|
||||
* @param int $start Line number
|
||||
* @param string $type Type of time zone object to parse
|
||||
* @return void
|
||||
*/
|
||||
protected function _processTimezoneTypeObject( $start, $type )
|
||||
{
|
||||
/* Init */
|
||||
$type = mb_strtolower( $type );
|
||||
$break = FALSE;
|
||||
|
||||
/* Loop over the lines */
|
||||
for( $i = $start, $j = count( $this->_rawIcsData ); $i < $j; $i++ )
|
||||
{
|
||||
/* Unparse and get the data */
|
||||
$tmp = $this->_unparseContent( $this->_rawIcsData[$i], $i );
|
||||
|
||||
if ( !$tmp )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$_type = $tmp['type'];
|
||||
$_data = $tmp['data'];
|
||||
|
||||
switch( $_type )
|
||||
{
|
||||
case 'DTSTART':
|
||||
$this->_parsedIcsData['timezones'][ $this->_tzId ][ $type ]['start'] = strtotime( $_data );
|
||||
break;
|
||||
|
||||
case 'TZOFFSETTO':
|
||||
$this->_parsedIcsData['timezones'][ $this->_tzId ][ $type ]['tz_offset_to'] = $_data;
|
||||
break;
|
||||
|
||||
case 'TZOFFSETFROM':
|
||||
$this->_parsedIcsData['timezones'][ $this->_tzId ][ $type ]['tz_offset_from'] = $_data;
|
||||
break;
|
||||
|
||||
case 'TZNAME':
|
||||
$this->_parsedIcsData['timezones'][ $this->_tzId ][ $type ]['tz_name'] = $_data;
|
||||
break;
|
||||
|
||||
case 'END':
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a timezone object in an ical feed
|
||||
*
|
||||
* @param int $start Line number
|
||||
* @return void
|
||||
*/
|
||||
protected function _processTimezoneObject( $start )
|
||||
{
|
||||
/* Loop over the lines */
|
||||
for( $i = $start, $j = count( $this->_rawIcsData ); $i < $j; $i++ )
|
||||
{
|
||||
/* Unparse and get the data */
|
||||
$tmp = $this->_unparseContent( $this->_rawIcsData[$i], $i );
|
||||
|
||||
if( !$tmp )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$_type = $tmp['type'];
|
||||
$_data = $tmp['data'];
|
||||
|
||||
switch( $_type )
|
||||
{
|
||||
case 'TZID':
|
||||
$this->_tzId = $_data;
|
||||
$this->_parsedIcsData['timezones'][ $_data ] = array();
|
||||
break;
|
||||
|
||||
case 'LAST-MODIFIED':
|
||||
$this->_parsedIcsData['timezones'][ $this->_tzId ]['last_modified'] = $_data;
|
||||
break;
|
||||
|
||||
case 'BEGIN':
|
||||
$this->_tzBegin = $_data;
|
||||
$this->_parseBeginBlock( $_data, $i );
|
||||
break;
|
||||
|
||||
case 'END':
|
||||
if ( $this->_tzBegin == $_data )
|
||||
{
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unformat content from incoming ical feed
|
||||
*
|
||||
@@ -1384,17 +1278,6 @@ class _ICSParser
|
||||
*/
|
||||
protected function _convertToGmt( $data )
|
||||
{
|
||||
/* Get timezones */
|
||||
$timezones = array();
|
||||
|
||||
if ( isset( $data['timezones'] ) AND is_array( $data['timezones'] ) AND count( $data['timezones'] ) )
|
||||
{
|
||||
foreach( $data['timezones'] as $type => $_data )
|
||||
{
|
||||
$timezones[ $type ] = $_data;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fix events */
|
||||
if ( is_array( $data['events'] ) AND count( $data['events'] ) )
|
||||
{
|
||||
@@ -1402,43 +1285,14 @@ class _ICSParser
|
||||
{
|
||||
foreach( array( 'start', 'end' ) as $method )
|
||||
{
|
||||
/* Set up constraints */
|
||||
if ( isset( $event[ $method ]['tzid'] ) AND isset( $timezones[ $event[ $method ]['tzid'] ] ) AND is_array( $timezones[ $event[ $method ]['tzid'] ] ) )
|
||||
/* Is a timezone specified? */
|
||||
if ( isset( $event[ $method ]['tzid'] ) AND $event[ $method ]['tzid'] )
|
||||
{
|
||||
$_standard = ( isset($timezones[ $event[ $method ]['tzid'] ]['standard']['start'] ) ) ? intval( $timezones[ $event[ $method ]['tzid'] ]['standard']['start'] ) : 0;
|
||||
$_daylight = ( isset($timezones[ $event[ $method ]['tzid'] ]['daylight']['start'] ) ) ? intval( $timezones[ $event[ $method ]['tzid'] ]['daylight']['start'] ) : 0;
|
||||
$_offset = 0;
|
||||
|
||||
if ( isset( $event[ $method ]['tzid'] ) AND $event[ $method ]['raw_ts'] )
|
||||
{
|
||||
//if ( $event[ $method ]['raw_ts'] < $_daylight )
|
||||
//{
|
||||
// $_offset = $timezones[ $event[ $method ]['tzid'] ]['standard']['tz_offset_to'];
|
||||
//}
|
||||
//else if ( $event[ $method ]['raw_ts'] > $_standard )
|
||||
//{
|
||||
// $_offset = $timezones[ $event[ $method ]['tzid'] ]['standard']['tz_offset_to'];
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// $_offset = $timezones[ $event[ $method ]['tzid'] ]['daylight']['tz_offset_to'];
|
||||
//}
|
||||
|
||||
$_offset = $timezones[ $event[ $method ]['tzid'] ]['standard']['tz_offset_to'];
|
||||
|
||||
$event[ $method ]['gmt_ts'] = $event[ $method ]['raw_ts'] - ( $_offset / 100 * 3600 );
|
||||
$event[ $method ]['offset'] = $_offset;
|
||||
$event[ $method ]['gmt_rfc'] = gmdate( 'r', $event[ $method ]['gmt_ts'] );
|
||||
}
|
||||
$event[ $method ]['utc_time'] = new \IPS\DateTime( $event[ $method ]['raw'], new \DateTimeZone( $event[ $method ]['tzid'] ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( isset( $event[ $method ]['raw_ts'] ) )
|
||||
{
|
||||
$event[ $method ]['gmt_ts'] = $event[ $method ]['raw_ts'];
|
||||
$event[ $method ]['offset'] = 0;
|
||||
$event[ $method ]['gmt_rfc'] = gmdate( 'r', $event[ $method ]['gmt_ts'] );
|
||||
}
|
||||
$event[ $method ]['utc_time'] = new \IPS\DateTime( $event[ $method ]['raw'] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief iCalendar active record
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Calendar
|
||||
* @since 19 Dec 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
|
||||
Reference in new issue
Block a user