Version 5.0.0 beta 1
This commit is contained in:
1 parent
25ddeb65d6
commit
15c7beabc5
6736 files changed
+627902
-497943
No files matched your search
@@ -12,43 +12,66 @@
|
||||
namespace IPS\calendar;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use BadMethodCallException;
|
||||
use IPS\Content\ClubContainer;
|
||||
use IPS\Content\Item;
|
||||
use IPS\Content\ViewUpdates;
|
||||
use IPS\Db;
|
||||
use IPS\Helpers\Form;
|
||||
use IPS\Helpers\Form\Color;
|
||||
use IPS\Helpers\Form\Radio;
|
||||
use IPS\Helpers\Form\Text;
|
||||
use IPS\Helpers\Form\Translatable;
|
||||
use IPS\Helpers\Form\YesNo;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Http\Url\Friendly;
|
||||
use IPS\Lang;
|
||||
use IPS\Member;
|
||||
use IPS\Member\Club;
|
||||
use IPS\Node\Model;
|
||||
use IPS\Node\Permissions;
|
||||
use IPS\Output;
|
||||
use IPS\Settings;
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calendar Node
|
||||
*/
|
||||
class _Calendar extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
class Calendar extends Model implements Permissions
|
||||
{
|
||||
use \IPS\Content\ClubContainer, \IPS\Content\ViewUpdates;
|
||||
use ClubContainer, ViewUpdates;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
protected static array $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'calendar_calendars';
|
||||
public static ?string $databaseTable = 'calendar_calendars';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'cal_';
|
||||
public static string $databasePrefix = 'cal_';
|
||||
|
||||
/**
|
||||
* @brief [Node] Order Database Column
|
||||
*/
|
||||
public static $databaseColumnOrder = 'position';
|
||||
public static ?string $databaseColumnOrder = 'position';
|
||||
|
||||
/**
|
||||
* @brief [Node] Node Title
|
||||
*/
|
||||
public static $nodeTitle = 'calendars';
|
||||
public static string $nodeTitle = 'calendars';
|
||||
|
||||
/**
|
||||
* @brief [Node] ACP Restrictions
|
||||
@@ -66,7 +89,7 @@ class _Calendar extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
'prefix' => 'foo_', // [Optional] Rather than specifying each key in the map, you can specify a prefix, and it will automatically look for restrictions with the key "[prefix]_add/edit/permissions/delete"
|
||||
* @endcode
|
||||
*/
|
||||
protected static $restrictions = array(
|
||||
protected static ?array $restrictions = array(
|
||||
'app' => 'calendar',
|
||||
'module' => 'calendars',
|
||||
'prefix' => 'calendars_'
|
||||
@@ -75,17 +98,17 @@ class _Calendar extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
/**
|
||||
* @brief [Node] App for permission index
|
||||
*/
|
||||
public static $permApp = 'calendar';
|
||||
public static ?string $permApp = 'calendar';
|
||||
|
||||
/**
|
||||
* @brief [Node] Type for permission index
|
||||
*/
|
||||
public static $permType = 'calendar';
|
||||
public static ?string $permType = 'calendar';
|
||||
|
||||
/**
|
||||
* @brief The map of permission columns
|
||||
*/
|
||||
public static $permissionMap = array(
|
||||
public static array $permissionMap = array(
|
||||
'view' => 'view',
|
||||
'read' => 2,
|
||||
'add' => 3,
|
||||
@@ -98,27 +121,27 @@ class _Calendar extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
/**
|
||||
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
|
||||
*/
|
||||
public static $titleLangPrefix = 'calendar_calendar_';
|
||||
public static ?string $titleLangPrefix = 'calendar_calendar_';
|
||||
|
||||
/**
|
||||
* @brief [Node] Moderator Permission
|
||||
*/
|
||||
public static $modPerm = 'calendar_calendars';
|
||||
public static string $modPerm = 'calendar_calendars';
|
||||
|
||||
/**
|
||||
* @brief Content Item Class
|
||||
*/
|
||||
public static $contentItemClass = 'IPS\calendar\Event';
|
||||
public static ?string $contentItemClass = 'IPS\calendar\Event';
|
||||
|
||||
/**
|
||||
* @brief [Node] Prefix string that is automatically prepended to permission matrix language strings
|
||||
*/
|
||||
public static $permissionLangPrefix = 'calperm_';
|
||||
public static string $permissionLangPrefix = 'calperm_';
|
||||
|
||||
/**
|
||||
* @brief Bitwise values for cal_bitoptions field
|
||||
*/
|
||||
public static $bitOptions = array(
|
||||
public static array $bitOptions = array(
|
||||
'calendar_bitoptions' => array(
|
||||
'calendar_bitoptions' => array(
|
||||
'bw_disable_tagging' => 1,
|
||||
@@ -127,18 +150,41 @@ class _Calendar extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Mapping of node columns to specific actions (e.g. comment, review)
|
||||
* Note: Mappings can also reference bitoptions keys.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static array $actionColumnMap = array(
|
||||
'comments' => 'allow_comments',
|
||||
'reviews' => 'allow_reviews',
|
||||
'moderate_comments' => 'comment_moderate',
|
||||
'moderate_items' => 'moderate',
|
||||
'moderate_reviews' => 'review_moderate',
|
||||
'tags' => 'bw_disable_tagging', // bitoption
|
||||
'prefix' => 'bw_disable_prefixes' // bitoption
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief The class of the ACP \IPS\Node\Controller that manages this node type
|
||||
*/
|
||||
protected static $acpController = "IPS\\calendar\\modules\\admin\\calendars\\calendars";
|
||||
protected static ?string $acpController = "IPS\\calendar\\modules\\admin\\calendars\\calendars";
|
||||
|
||||
/**
|
||||
* Determines if this class can be extended via UI Extension
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static bool $canBeExtended = true;
|
||||
|
||||
/**
|
||||
* [Node] Set whether or not this node is enabled
|
||||
*
|
||||
* @param bool|int $enabled Whether to set it enabled or disabled
|
||||
* @param bool|int $enabled Whether to set it enabled or disabled
|
||||
* @return void
|
||||
*/
|
||||
protected function set__enabled( $enabled )
|
||||
protected function set__enabled( bool|int $enabled ) : void
|
||||
{
|
||||
}
|
||||
|
||||
@@ -147,40 +193,54 @@ class _Calendar extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_title_seo()
|
||||
public function get_title_seo(): string
|
||||
{
|
||||
if( !$this->_data['title_seo'] )
|
||||
{
|
||||
$this->title_seo = \IPS\Http\Url\Friendly::seoTitle( \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( 'calendar_calendar_' . $this->id ) );
|
||||
$this->title_seo = Friendly::seoTitle( Lang::load( Lang::defaultLanguage() )->get( 'calendar_calendar_' . $this->id ) );
|
||||
$this->save();
|
||||
}
|
||||
|
||||
return $this->_data['title_seo'] ?: \IPS\Http\Url\Friendly::seoTitle( \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( 'calendar_calendar_' . $this->id ) );
|
||||
return $this->_data['title_seo'] ?: Friendly::seoTitle( Lang::load( Lang::defaultLanguage() )->get( 'calendar_calendar_' . $this->id ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the action column map if the action is enabled in this node
|
||||
*
|
||||
* @param string $action
|
||||
* @return bool
|
||||
*/
|
||||
public function checkAction( string $action ) : bool
|
||||
{
|
||||
$return = parent::checkAction( $action );
|
||||
|
||||
/* Some actions here are reversed, we mark them as disabled instead of enabled */
|
||||
if( in_array( $action, array( 'tags', 'prefix' ) ) )
|
||||
{
|
||||
return !$return;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Add/Edit Form
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @param Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function form( &$form )
|
||||
public function form( Form &$form ) : void
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Translatable( 'cal_title', NULL, TRUE, array( 'app' => 'calendar', 'key' => ( $this->id ? "calendar_calendar_{$this->id}" : NULL ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\Color( 'cal_color', $this->id ? $this->color : $this->_generateColor(), TRUE ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'cal_moderate', $this->id ? $this->moderate : FALSE, FALSE ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'cal_allow_comments', $this->id ? $this->allow_comments : TRUE, FALSE, array( 'togglesOn' => array( 'cal_comment_moderate' ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'cal_comment_moderate', $this->id ? $this->comment_moderate : FALSE, FALSE, array(), NULL, NULL, NULL, 'cal_comment_moderate' ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'cal_allow_reviews', $this->id ? $this->allow_reviews : FALSE, FALSE, array( 'togglesOn' => array( 'cal_review_moderate' ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'cal_review_moderate', $this->id ? $this->review_moderate : FALSE, FALSE, array(), NULL, NULL, NULL, 'cal_review_moderate' ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'cal_allow_anonymous', $this->id ? $this->allow_anonymous : FALSE, FALSE, array(), NULL, NULL, NULL, 'cal_allow_anonymous' ) );
|
||||
$form->add( new Translatable( 'cal_title', NULL, TRUE, array( 'app' => 'calendar', 'key' => ( $this->id ? "calendar_calendar_{$this->id}" : NULL ) ) ) );
|
||||
$form->add( new Color( 'cal_color', $this->id ? $this->color : $this->_generateColor(), TRUE ) );
|
||||
$form->add( new YesNo( 'cal_moderate', $this->id ? $this->moderate : FALSE, FALSE ) );
|
||||
$form->add( new YesNo( 'cal_allow_comments', $this->id ? $this->allow_comments : TRUE, FALSE, array( 'togglesOn' => array( 'cal_comment_moderate' ) ) ) );
|
||||
$form->add( new YesNo( 'cal_comment_moderate', $this->id ? $this->comment_moderate : FALSE, FALSE, array(), NULL, NULL, NULL, 'cal_comment_moderate' ) );
|
||||
$form->add( new YesNo( 'cal_allow_reviews', $this->id ? $this->allow_reviews : FALSE, FALSE, array( 'togglesOn' => array( 'cal_review_moderate' ) ) ) );
|
||||
$form->add( new YesNo( 'cal_review_moderate', $this->id ? $this->review_moderate : FALSE, FALSE, array(), NULL, NULL, NULL, 'cal_review_moderate' ) );
|
||||
$form->add( new YesNo( 'cal_allow_anonymous', $this->id ? $this->allow_anonymous : FALSE, FALSE, array(), NULL, NULL, NULL, 'cal_allow_anonymous' ) );
|
||||
|
||||
if ( \IPS\Settings::i()->tags_enabled )
|
||||
{
|
||||
$form->addHeader( 'tags' );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'bw_disable_tagging', !$this->calendar_bitoptions['bw_disable_tagging'], FALSE, array( 'togglesOn' => array( 'bw_disable_prefixes' ) ), NULL, NULL, NULL, 'bw_disable_tagging' ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'bw_disable_prefixes', !$this->calendar_bitoptions['bw_disable_prefixes'], FALSE, array(), NULL, NULL, NULL, 'bw_disable_prefixes' ) );
|
||||
}
|
||||
parent::form( $form );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,7 +249,7 @@ class _Calendar extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
* @param array $values Values from the form
|
||||
* @return array
|
||||
*/
|
||||
public function formatFormValues( $values )
|
||||
public function formatFormValues( array $values ): array
|
||||
{
|
||||
if ( !$this->id )
|
||||
{
|
||||
@@ -198,61 +258,51 @@ 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\Friendly::seoTitle( $values['cal_title'][ \IPS\Lang::defaultLanguage() ] );
|
||||
Lang::saveCustom( 'calendar', 'calendar_calendar_' . $this->id, $values['cal_title'] );
|
||||
$values['title_seo'] = Friendly::seoTitle( $values['cal_title'][ Lang::defaultLanguage() ] );
|
||||
|
||||
unset( $values['cal_title'] );
|
||||
}
|
||||
|
||||
/* Bitwise */
|
||||
foreach ( array( 'bw_disable_tagging', 'bw_disable_prefixes' ) as $k )
|
||||
{
|
||||
if( isset( $values[ $k ] ) )
|
||||
{
|
||||
$values['calendar_bitoptions'][ $k ] = !$values[ $k ];
|
||||
unset( $values[ $k ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cached URL
|
||||
*/
|
||||
protected $_url = NULL;
|
||||
protected mixed $_url = NULL;
|
||||
|
||||
/**
|
||||
* @brief URL Base
|
||||
*/
|
||||
public static $urlBase = 'app=calendar&module=calendar&controller=view&id=';
|
||||
public static string $urlBase = 'app=calendar&module=calendar&controller=view&id=';
|
||||
|
||||
/**
|
||||
* @brief URL Base
|
||||
*/
|
||||
public static $urlTemplate = 'calendar_calendar';
|
||||
public static string $urlTemplate = 'calendar_calendar';
|
||||
|
||||
/**
|
||||
* @brief SEO Title Column
|
||||
*/
|
||||
public static $seoTitleColumn = 'title_seo';
|
||||
public static string $seoTitleColumn = 'title_seo';
|
||||
|
||||
/**
|
||||
* [ActiveRecord] Delete Record
|
||||
*
|
||||
* @return void
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
public function delete(): void
|
||||
{
|
||||
\IPS\Db::i()->delete( 'calendar_import_feeds', array( 'feed_calendar_id=?', $this->id ) );
|
||||
Db::i()->delete( 'calendar_import_feeds', array( 'feed_calendar_id=?', $this->id ) );
|
||||
|
||||
return parent::delete();
|
||||
parent::delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Default colors
|
||||
*/
|
||||
protected static $colors = array(
|
||||
protected static array $colors = array(
|
||||
'#6E4F99', // Purple
|
||||
'#4F994F', // Green
|
||||
'#4F7C99', // Blue
|
||||
@@ -266,7 +316,7 @@ class _Calendar extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function _generateColor()
|
||||
public function _generateColor(): string
|
||||
{
|
||||
foreach( static::$colors as $color )
|
||||
{
|
||||
@@ -292,7 +342,7 @@ class _Calendar extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function addCss()
|
||||
public static function addCss() : void
|
||||
{
|
||||
$output = '';
|
||||
|
||||
@@ -303,7 +353,7 @@ class _Calendar extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
}\n";
|
||||
}
|
||||
|
||||
\IPS\Output::i()->headCss = \IPS\Output::i()->headCss . $output;
|
||||
Output::i()->headCss = Output::i()->headCss . $output;
|
||||
}
|
||||
|
||||
/* !Clubs */
|
||||
@@ -313,91 +363,60 @@ class _Calendar extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function clubFrontTitle()
|
||||
public static function clubFrontTitle(): string
|
||||
{
|
||||
return 'calendars_sg';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set form for creating a node of this type in a club
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form Form object
|
||||
* @return void
|
||||
* @param Form $form Form object
|
||||
* @param Club $club
|
||||
* @return void
|
||||
*/
|
||||
public function clubForm( \IPS\Helpers\Form $form, \IPS\Member\Club $club )
|
||||
public function clubForm( Form $form, Club $club ) : void
|
||||
{
|
||||
/* @var Item $itemClass */
|
||||
$itemClass = static::$contentItemClass;
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'club_node_name', $this->_id ? $this->_title : \IPS\Member::loggedIn()->language()->addToStack( $itemClass::$title . '_pl' ), TRUE, array( 'maxLength' => 255 ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'cal_allow_comments', $this->id ? $this->allow_comments : TRUE, FALSE, array( 'togglesOn' => array( 'cal_comment_moderate' ) ) ) );
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'cal_allow_reviews', $this->id ? $this->allow_reviews : FALSE, FALSE, array( 'togglesOn' => array( 'cal_review_moderate' ) ) ) );
|
||||
$form->add( new Text( 'club_node_name', $this->_id ? $this->_title : Member::loggedIn()->language()->addToStack( $itemClass::$title . '_pl' ), TRUE, array( 'maxLength' => 255 ) ) );
|
||||
$form->add( new YesNo( 'cal_allow_comments', $this->id ? $this->allow_comments : TRUE, FALSE, array( 'togglesOn' => array( 'cal_comment_moderate' ) ) ) );
|
||||
$form->add( new YesNo( 'cal_allow_reviews', $this->id ? $this->allow_reviews : FALSE, FALSE, array( 'togglesOn' => array( 'cal_review_moderate' ) ) ) );
|
||||
if( $club->type == 'closed' )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'club_node_public', $this->id ? $this->isPublic() : 0, TRUE, array( 'options' => array( '0' => 'club_node_public_no', '1' => 'club_node_public_view', '2' => 'club_node_public_participate' ) ) ) );
|
||||
$form->add( new Radio( 'club_node_public', $this->id ? $this->isPublic() : 0, TRUE, array( 'options' => array( '0' => 'club_node_public_no', '1' => 'club_node_public_view', '2' => 'club_node_public_participate' ) ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class-specific routine when saving club form
|
||||
*
|
||||
* @param \IPS\Member\Club $club The club
|
||||
* @param Club $club The club
|
||||
* @param array $values Values
|
||||
* @return void
|
||||
*/
|
||||
public function _saveClubForm( \IPS\Member\Club $club, $values )
|
||||
public function _saveClubForm( Club $club, array $values ) : void
|
||||
{
|
||||
if ( $values['club_node_name'] )
|
||||
{
|
||||
$this->title_seo = \IPS\Http\Url\Friendly::seoTitle( $values['club_node_name'] );
|
||||
$this->title_seo = Friendly::seoTitle( $values['club_node_name'] );
|
||||
}
|
||||
|
||||
$this->allow_comments = $values['cal_allow_comments'];
|
||||
$this->allow_reviews = $values['cal_allow_reviews'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Content was held for approval by container
|
||||
* Allow node classes that can determine if content should be held for approval in individual nodes
|
||||
*
|
||||
* @param string $content The type of content we are checking (item, comment, review).
|
||||
* @param \IPS\Member|NULL $member Member to check or NULL for currently logged in member.
|
||||
* @return bool
|
||||
*/
|
||||
public function contentHeldForApprovalByNode( string $content, ?\IPS\Member $member = NULL ): bool
|
||||
{
|
||||
/* If members group bypasses, then no. */
|
||||
$member = $member ?: \IPS\Member::loggedIn();
|
||||
if ( $member->group['g_avoid_q'] )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch( $content )
|
||||
{
|
||||
case 'item':
|
||||
return (bool) $this->moderate;
|
||||
break;
|
||||
|
||||
case 'comment':
|
||||
return (bool) $this->comment_moderate;
|
||||
break;
|
||||
|
||||
case 'review':
|
||||
return (bool) $this->comment_review;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL
|
||||
*
|
||||
* @return \IPS\Http\Url
|
||||
* @throws \BadMethodCallException
|
||||
* @return Url|string|null
|
||||
* @throws BadMethodCallException
|
||||
*/
|
||||
public function url()
|
||||
public function url(): Url|string|null
|
||||
{
|
||||
$url = parent::url();
|
||||
|
||||
if( \IPS\Settings::i()->calendar_default_view == 'overview' )
|
||||
if( Settings::i()->calendar_default_view == 'overview' )
|
||||
{
|
||||
$url = $url->setQueryString( array( 'view' => 'month') );
|
||||
}
|
||||
|
||||
@@ -12,61 +12,80 @@
|
||||
namespace IPS\calendar;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use DateInterval;
|
||||
use DateTimeZone;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use IPS\DateTime;
|
||||
use IPS\Dispatcher;
|
||||
use IPS\Helpers\Form\Date as FormDate;
|
||||
use IPS\Lang;
|
||||
use IPS\Member;
|
||||
use IPS\Settings;
|
||||
use TypeError;
|
||||
use function count;
|
||||
use function defined;
|
||||
use function get_class;
|
||||
use function in_array;
|
||||
use function strpos;
|
||||
use function substr;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calendar-specific date functions
|
||||
*/
|
||||
class _Date extends \IPS\DateTime
|
||||
class Date extends DateTime
|
||||
{
|
||||
/**
|
||||
* @brief Data retrieved from get_date() with timezone accounted for
|
||||
*/
|
||||
protected $dateInformation = array();
|
||||
protected array $dateInformation = array();
|
||||
|
||||
/**
|
||||
* @brief Information about the first day of the month we are working with
|
||||
*/
|
||||
protected $firstDayOfMonth = array();
|
||||
protected array $firstDayOfMonth = array();
|
||||
|
||||
/**
|
||||
* @brief Information about the last day of the month we are working with
|
||||
*/
|
||||
protected $lastDayOfMonth = array();
|
||||
protected array $lastDayOfMonth = array();
|
||||
|
||||
/**
|
||||
* @brief Information about the first day of the week we are working with
|
||||
*/
|
||||
protected $firstDayOfWeek = array();
|
||||
protected array $firstDayOfWeek = array();
|
||||
|
||||
/**
|
||||
* @brief Information about the last day of the week we are working with
|
||||
*/
|
||||
protected $lastDayOfWeek = array();
|
||||
protected array $lastDayOfWeek = array();
|
||||
|
||||
/**
|
||||
* @brief Information about the previous month
|
||||
*/
|
||||
protected $lastMonth = array();
|
||||
protected array $lastMonth = array();
|
||||
|
||||
/**
|
||||
* @brief Information about the next month
|
||||
*/
|
||||
protected $nextMonth = array();
|
||||
protected array $nextMonth = array();
|
||||
|
||||
/**
|
||||
* @brief Timezone offset for the current user
|
||||
*/
|
||||
public $offset = NULL;
|
||||
public ?int $offset = NULL;
|
||||
|
||||
/**
|
||||
* @brief Custom date formatting options for calendar
|
||||
*/
|
||||
public static $dateFormats = array(
|
||||
public static array $dateFormats = array(
|
||||
'locale' => "%x",
|
||||
'd_sm_y' => "%d %b %Y",
|
||||
'd_lm_y' => "%d {monthName} %Y",
|
||||
@@ -77,37 +96,37 @@ class _Date extends \IPS\DateTime
|
||||
/**
|
||||
* @brief Cache date objects we've created through getDate()
|
||||
*/
|
||||
protected static $dateObjects = array();
|
||||
protected static array $dateObjects = array();
|
||||
|
||||
/**
|
||||
* Creates a new object to represent the requested date
|
||||
*
|
||||
* @param int|NULL $year Year, or NULL for current year
|
||||
* @param int|NULL $month Month, or NULL for current month
|
||||
* @param int|NULL $day Day, or NULL for current day
|
||||
* @param int $hour Hour (defaults to 0)
|
||||
* @param int $minute Minutes (defaults to 0)
|
||||
* @param int $second Seconds (defaults to 0)
|
||||
* @param int $offset The offset from GMT (NULL to calculate automatically based on member's current time)
|
||||
* @return \IPS\calendar\Date
|
||||
* @throws \InvalidArgumentException
|
||||
* @param int|null $year Year, or NULL for current year
|
||||
* @param int|null $month Month, or NULL for current month
|
||||
* @param int|null $day Day, or NULL for current day
|
||||
* @param int $hour Hour (defaults to 0)
|
||||
* @param int $minute Minutes (defaults to 0)
|
||||
* @param int $second Seconds (defaults to 0)
|
||||
* @param int|null $offset The offset from GMT (NULL to calculate automatically based on member's current time)
|
||||
* @return static|DateTime
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public static function getDate( $year=NULL, $month=NULL, $day=NULL, $hour=0, $minute=0, $second=0, $offset=NULL )
|
||||
public static function getDate( int $year=NULL, int $month=NULL, int $day=NULL, int $hour=0, int $minute=0, int $second=0, int $offset=NULL ): static|DateTime
|
||||
{
|
||||
/* Get our time zone offset */
|
||||
$timezone = NULL;
|
||||
|
||||
if ( $offset === NULL and \IPS\Member::loggedIn()->timezone )
|
||||
if ( $offset === NULL and Member::loggedIn()->timezone )
|
||||
{
|
||||
$timezone = \IPS\DateTime::create();
|
||||
$timezone = DateTime::create();
|
||||
$validTimezone = TRUE;
|
||||
if( \in_array( \IPS\Member::loggedIn()->timezone, static::getTimezoneIdentifiers() ) )
|
||||
if( in_array( Member::loggedIn()->timezone, static::getTimezoneIdentifiers() ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$timezone->setTimezone( new \DateTimeZone( \IPS\Member::loggedIn()->timezone ) );
|
||||
$timezone->setTimezone( new DateTimeZone( Member::loggedIn()->timezone ) );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch ( Exception $e )
|
||||
{
|
||||
$validTimezone = FALSE;
|
||||
}
|
||||
@@ -119,11 +138,11 @@ class _Date extends \IPS\DateTime
|
||||
|
||||
if( ! $validTimezone )
|
||||
{
|
||||
\IPS\Member::loggedIn()->timezone = null;
|
||||
Member::loggedIn()->timezone = null;
|
||||
|
||||
if ( \IPS\Member::loggedIn()->member_id )
|
||||
if ( Member::loggedIn()->member_id )
|
||||
{
|
||||
\IPS\Member::loggedIn()->save();
|
||||
Member::loggedIn()->save();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,12 +170,12 @@ class _Date extends \IPS\DateTime
|
||||
{
|
||||
if( !checkdate( $month, $day, $year ) )
|
||||
{
|
||||
throw new \InvalidArgumentException;
|
||||
throw new InvalidArgumentException;
|
||||
}
|
||||
}
|
||||
catch ( \TypeError $e )
|
||||
catch ( TypeError )
|
||||
{
|
||||
throw new \InvalidArgumentException;
|
||||
throw new InvalidArgumentException;
|
||||
}
|
||||
|
||||
/* Create the timestamp */
|
||||
@@ -183,10 +202,9 @@ class _Date extends \IPS\DateTime
|
||||
*
|
||||
* @note We override to update dateInformation and stored offset
|
||||
* @param string $time Time
|
||||
* @param \DateTimeZone|null $timezone Timezone
|
||||
* @return \IPS\calendar\Date
|
||||
* @param DateTimeZone|null $timezone Timezone
|
||||
*/
|
||||
public function __construct( $time="now", $timezone=NULL )
|
||||
public function __construct( string $time="now", ?DateTimeZone $timezone=NULL )
|
||||
{
|
||||
if ( $timezone )
|
||||
{
|
||||
@@ -207,11 +225,11 @@ class _Date extends \IPS\DateTime
|
||||
* Convert the Root DateTime instance to a \IPS\calendar\Date instance
|
||||
*
|
||||
* @param \DateTime $dateTime
|
||||
* @return Date
|
||||
* @return static|\DateTime
|
||||
*/
|
||||
public static function dateTimeToCalendarDate( \DateTime $dateTime ): \IPS\calendar\Date
|
||||
public static function dateTimeToCalendarDate( \DateTime $dateTime ): static|\DateTime
|
||||
{
|
||||
if( \in_array( \get_class( $dateTime ), [ 'DateTime', 'IPS\\DateTime'] ) )
|
||||
if( in_array( get_class( $dateTime ), [ 'DateTime', 'IPS\\DateTime'] ) )
|
||||
{
|
||||
return new static( $dateTime->format('c'), $dateTime->getTimezone() );
|
||||
}
|
||||
@@ -223,10 +241,10 @@ class _Date extends \IPS\DateTime
|
||||
* Sets the time zone for the DateTime object
|
||||
*
|
||||
* @note We override to update dateInformation and stored offset
|
||||
* @param \DateTimeZone $timezone New timezone
|
||||
* @return \IPS\calendar\Date|FALSE
|
||||
* @param DateTimeZone $timezone New timezone
|
||||
* @return \DateTime
|
||||
*/
|
||||
public function setTimezone( $timezone )
|
||||
public function setTimezone( DateTimeZone $timezone ): \DateTime
|
||||
{
|
||||
$result = parent::setTimezone( $timezone );
|
||||
|
||||
@@ -240,10 +258,10 @@ class _Date extends \IPS\DateTime
|
||||
* Get the date information
|
||||
*
|
||||
* @note This is basically a timezone aware wrapper for getdate
|
||||
* @param int $time Timestamp
|
||||
* @param int $time Timestamp
|
||||
* @return array
|
||||
*/
|
||||
public function getDateInformation( $time )
|
||||
public function getDateInformation( int $time ): array
|
||||
{
|
||||
$this->dateInformation = array(
|
||||
'seconds' => (int) $this->strFormat( '%S' ),
|
||||
@@ -265,29 +283,29 @@ class _Date extends \IPS\DateTime
|
||||
* Returns a date object created based on an arbitrary string. Used for both relative time strings and SQL datetime values.
|
||||
*
|
||||
* @note Datetime values are stored in the database normalized to UTC
|
||||
* @param string $datetime String-based date/time
|
||||
* @param bool $forceUTC Force timezone to UTC (necessary when passing a datetime retrieved from the database)
|
||||
* @return \IPS\calendar\Date
|
||||
* @param string $datetime String-based date/time
|
||||
* @param bool $forceUTC Force timezone to UTC (necessary when passing a datetime retrieved from the database)
|
||||
* @return Date
|
||||
*/
|
||||
public static function parseTime( $datetime, $forceUTC=FALSE )
|
||||
public static function parseTime( string $datetime, bool $forceUTC=FALSE): Date
|
||||
{
|
||||
/* Create an \IPS\DateTime object from the datetime value passed in */
|
||||
if ( !$forceUTC AND \IPS\Dispatcher::hasInstance() )
|
||||
if ( !$forceUTC AND Dispatcher::hasInstance() )
|
||||
{
|
||||
if( !\IPS\Member::loggedIn()->timezone )
|
||||
if( !Member::loggedIn()->timezone )
|
||||
{
|
||||
$timezone = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
$validTimezone = TRUE;
|
||||
if( \in_array( \IPS\Member::loggedIn()->timezone, static::getTimezoneIdentifiers() ) )
|
||||
if( in_array( Member::loggedIn()->timezone, static::getTimezoneIdentifiers() ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$timezone = new \DateTimeZone( \IPS\Member::loggedIn()->timezone );
|
||||
$timezone = new DateTimeZone( Member::loggedIn()->timezone );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch ( Exception $e )
|
||||
{
|
||||
$validTimezone = FALSE;
|
||||
}
|
||||
@@ -299,26 +317,26 @@ class _Date extends \IPS\DateTime
|
||||
|
||||
if( ! $validTimezone )
|
||||
{
|
||||
\IPS\Member::loggedIn()->timezone = null;
|
||||
Member::loggedIn()->timezone = null;
|
||||
|
||||
if ( \IPS\Member::loggedIn()->member_id )
|
||||
if ( Member::loggedIn()->member_id )
|
||||
{
|
||||
\IPS\Member::loggedIn()->save();
|
||||
Member::loggedIn()->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$timezone = new \DateTimeZone( 'UTC' );
|
||||
$timezone = new DateTimeZone( 'UTC' );
|
||||
}
|
||||
|
||||
$datetime = new \IPS\DateTime( $datetime, $timezone );
|
||||
$datetime = new DateTime( $datetime, $timezone );
|
||||
|
||||
/* Now correct it back if necessary */
|
||||
if( $forceUTC === TRUE AND \IPS\Dispatcher::hasInstance() AND \IPS\Member::loggedIn()->timezone )
|
||||
if( $forceUTC === TRUE AND Dispatcher::hasInstance() AND Member::loggedIn()->timezone )
|
||||
{
|
||||
$datetime->setTimezone( new \DateTimeZone( \IPS\Member::loggedIn()->timezone ) );
|
||||
$datetime->setTimezone( new DateTimeZone( Member::loggedIn()->timezone ) );
|
||||
}
|
||||
|
||||
return static::getDate( $datetime->format('Y'), $datetime->format('m'), $datetime->format('d'), $datetime->format('H'), $datetime->format('i'), $datetime->format('s'), $datetime->getOffset() );
|
||||
@@ -327,14 +345,14 @@ class _Date extends \IPS\DateTime
|
||||
/**
|
||||
* Adjusts the date and returns a new date object representing the adjustment
|
||||
*
|
||||
* @param string $adjustment String to turn into a \DateInterval object which will be applied to the current date/time (supports most strtotime adjustments)
|
||||
* @return \IPS\calendar\Date
|
||||
* @param string $adjustment String to turn into a \DateInterval object which will be applied to the current date/time (supports most strtotime adjustments)
|
||||
* @return Date
|
||||
* @see <a href='http://www.php.net/manual/en/dateinterval.createfromdatestring.php'>DateInterval::createFromDateString() docs</a>
|
||||
*/
|
||||
public function adjust( $adjustment )
|
||||
public function adjust( string $adjustment ): Date
|
||||
{
|
||||
$datetime = \IPS\DateTime::ts( $this->dateInformation[0] )->setTimezone( new \DateTimeZone( "UTC" ) );
|
||||
$dateInterval=\DateInterval::createFromDateString( $adjustment );
|
||||
$datetime = DateTime::ts( $this->dateInformation[0] )->setTimezone( new DateTimeZone( "UTC" ) );
|
||||
$dateInterval= DateInterval::createFromDateString( $adjustment );
|
||||
|
||||
if( $dateInterval )
|
||||
{
|
||||
@@ -348,7 +366,7 @@ class _Date extends \IPS\DateTime
|
||||
/**
|
||||
* @brief Cache results of getDayNames() for performance
|
||||
*/
|
||||
protected static $cachedDayNames = NULL;
|
||||
protected static ?array $cachedDayNames = NULL;
|
||||
|
||||
/**
|
||||
* Get the localized day names in correct order
|
||||
@@ -356,7 +374,7 @@ class _Date extends \IPS\DateTime
|
||||
* @return array
|
||||
* @see <a href='http://stackoverflow.com/questions/7765469/retrieving-day-names-in-php'>Get localized day names in PHP</a>
|
||||
*/
|
||||
public static function getDayNames()
|
||||
public static function getDayNames(): array
|
||||
{
|
||||
if( static::$cachedDayNames !== NULL )
|
||||
{
|
||||
@@ -364,14 +382,14 @@ class _Date extends \IPS\DateTime
|
||||
}
|
||||
|
||||
$dayNames = array();
|
||||
$startDay = \IPS\Settings::i()->ipb_calendar_mon ? 'Monday' : 'Sunday';
|
||||
$startDay = Settings::i()->ipb_calendar_mon ? 'Monday' : 'Sunday';
|
||||
|
||||
for( $i = 0; $i < 7; $i++ )
|
||||
{
|
||||
$_time = strtotime( 'next ' . $startDay . ' +' . $i . ' days' );
|
||||
$_abbr = \IPS\Member::loggedIn()->language()->convertString( strftime( '%a', $_time ) );
|
||||
$_abbr = Member::loggedIn()->language()->convertString( date( 'D', $_time ) );
|
||||
|
||||
$dayNames[] = array( 'full' => \IPS\Member::loggedIn()->language()->convertString( strftime( '%A', $_time ) ), 'english' => date( 'l', $_time ), 'abbreviated' => $_abbr, 'letter' => mb_substr( $_abbr, 0, 1 ), 'ical' => mb_strtoupper( mb_substr( date( 'D', $_time ), 0, 2 ) ) );
|
||||
$dayNames[] = array( 'full' => Member::loggedIn()->language()->convertString( date( 'l', $_time ) ), 'english' => date( 'l', $_time ), 'abbreviated' => $_abbr, 'letter' => mb_substr( $_abbr, 0, 1 ), 'ical' => mb_strtoupper( mb_substr( date( 'D', $_time ), 0, 2 ) ) );
|
||||
}
|
||||
|
||||
static::$cachedDayNames = $dayNames;
|
||||
@@ -384,14 +402,14 @@ class _Date extends \IPS\DateTime
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getTimezones()
|
||||
public static function getTimezones(): array
|
||||
{
|
||||
$zones = \DateTimeZone::listIdentifiers( \DateTimeZone::ALL );
|
||||
$zones = DateTimeZone::listIdentifiers( DateTimeZone::ALL );
|
||||
|
||||
$timezones[\IPS\Member::loggedIn()->timezone] = \IPS\Member::loggedIn()->timezone;
|
||||
$timezones[Member::loggedIn()->timezone] = Member::loggedIn()->timezone;
|
||||
foreach($zones as $timezone)
|
||||
{
|
||||
if( $timezone == \IPS\Member::loggedIn()->timezone )
|
||||
if( $timezone == Member::loggedIn()->timezone )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -404,15 +422,15 @@ class _Date extends \IPS\DateTime
|
||||
/**
|
||||
* Return a date object based on supplied values, factoring in the timezone offset which could be in the "friendly" timezone format
|
||||
*
|
||||
* @param string $date Date as a textual string, from the date form helper
|
||||
* @param string $time Time as a textual string
|
||||
* @param string $timezone Timezone chosen
|
||||
* @return \IPS\calendar\Date
|
||||
* @param string $date Date as a textual string, from the date form helper
|
||||
* @param string|null $time Time as a textual string
|
||||
* @param string $timezone Timezone chosen
|
||||
* @return Date
|
||||
*/
|
||||
public static function createFromForm( $date, $time, $timezone )
|
||||
public static function createFromForm( string $date, ?string $time, string $timezone ): Date
|
||||
{
|
||||
/* Correct date */
|
||||
$date = \IPS\Helpers\Form\Date::_convertDateFormat( $date );
|
||||
$date = FormDate::_convertDateFormat( $date );
|
||||
|
||||
/* Fix time inconsistencies */
|
||||
if( $time )
|
||||
@@ -420,9 +438,9 @@ class _Date extends \IPS\DateTime
|
||||
$time = mb_strtolower( $time );
|
||||
|
||||
/* If they typed in 'am', convert '12' to 00, and then strip 'am' */
|
||||
if( \strpos( $time, 'am' ) !== FALSE )
|
||||
if( strpos( $time, 'am' ) !== FALSE )
|
||||
{
|
||||
if( \strpos( $time, '12' ) === 0 )
|
||||
if( strpos( $time, '12' ) === 0 )
|
||||
{
|
||||
$time = substr_replace( $time, '00', 0, 2 );
|
||||
}
|
||||
@@ -430,10 +448,10 @@ class _Date extends \IPS\DateTime
|
||||
$time = str_replace( 'am', '', $time );
|
||||
}
|
||||
/* If they typed in 'pm', add 12 to anything other than 12 and strip 'pm' */
|
||||
else if( \strpos( $time, 'pm' ) !== FALSE )
|
||||
else if( strpos( $time, 'pm' ) !== FALSE )
|
||||
{
|
||||
$_timeBits = explode( ':', $time );
|
||||
$_timeBits[0] = $_timeBits[0] < 12 ? ( $_timeBits[0] + 12 ) : $_timeBits[0];
|
||||
$_timeBits[0] = $_timeBits[0] < 12 ? ( (int)$_timeBits[0] + 12 ) : $_timeBits[0];
|
||||
$time = implode( ':', $_timeBits );
|
||||
|
||||
$time = str_replace( 'pm', '', $time );
|
||||
@@ -442,9 +460,9 @@ class _Date extends \IPS\DateTime
|
||||
/* Make sure we have 3 pieces and that all are 2 digits */
|
||||
$_timeBits = explode( ':', $time );
|
||||
|
||||
if ( \count( $_timeBits ) < 3 )
|
||||
if ( count( $_timeBits ) < 3 )
|
||||
{
|
||||
while( \count( $_timeBits ) < 3 )
|
||||
while( count( $_timeBits ) < 3 )
|
||||
{
|
||||
$_timeBits[] = '00';
|
||||
}
|
||||
@@ -459,20 +477,21 @@ class _Date extends \IPS\DateTime
|
||||
$time = implode( ':', $_timeBits );
|
||||
}
|
||||
|
||||
$dateObject = new static( $date . ( $time ? ' ' . $time : '' ), new \DateTimeZone( $timezone ) );
|
||||
$dateObject = new static( $date . ( $time ? ' ' . $time : '' ), new DateTimeZone( $timezone ) );
|
||||
|
||||
return $dateObject->setTimezone( new \DateTimeZone( 'UTC' ) );
|
||||
$dateObject->setTimezone( new DateTimeZone( 'UTC' ) );
|
||||
return $dateObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modified version of ISO-8601 used by iCalendar - omits the timezone identifier and all dashes and colons
|
||||
*
|
||||
* @param bool $includeTime Whether to include time or not
|
||||
* @param bool $includeIdentifier Whether to include 'Z' at the end or not
|
||||
* @param bool $includeTime Whether to include time or not
|
||||
* @param bool $includeIdentifier Whether to include 'Z' at the end or not
|
||||
* @return string
|
||||
* @see <a href='http://www.kanzaki.com/docs/ical/dateTime.html'>DateTime explanation</a>
|
||||
*/
|
||||
public function modifiedIso8601( $includeTime=TRUE, $includeIdentifier=FALSE )
|
||||
public function modifiedIso8601( bool $includeTime=TRUE, bool $includeIdentifier=FALSE ): string
|
||||
{
|
||||
if( $includeTime )
|
||||
{
|
||||
@@ -487,10 +506,10 @@ 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
|
||||
* @param Lang|Member|null $memberOrLanguage The language or member to use, or NULL for currently logged in member
|
||||
* @return string
|
||||
*/
|
||||
public function calendarDate( $memberOrLanguage=NULL )
|
||||
public function calendarDate( Lang|Member $memberOrLanguage=NULL ): string
|
||||
{
|
||||
return static::determineLanguage( $memberOrLanguage )->convertString( strftime( static::calendarDateFormat(), $this->getTimestamp() + $this->offset ) );
|
||||
}
|
||||
@@ -500,15 +519,15 @@ class _Date extends \IPS\DateTime
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function calendarDateFormat()
|
||||
public static function calendarDateFormat(): string
|
||||
{
|
||||
if( \IPS\Settings::i()->calendar_date_format == -1 AND \IPS\Settings::i()->calendar_date_format_custom )
|
||||
if( Settings::i()->calendar_date_format == -1 AND Settings::i()->calendar_date_format_custom )
|
||||
{
|
||||
return \IPS\Settings::i()->calendar_date_format_custom;
|
||||
return Settings::i()->calendar_date_format_custom;
|
||||
}
|
||||
elseif( isset( static::$dateFormats[ \IPS\Settings::i()->calendar_date_format ] ) )
|
||||
elseif( isset( static::$dateFormats[ Settings::i()->calendar_date_format ] ) )
|
||||
{
|
||||
return str_replace( '{monthName}', static::setMonthModifier(), static::$dateFormats[ \IPS\Settings::i()->calendar_date_format ] );
|
||||
return str_replace( '{monthName}', static::setMonthModifier(), static::$dateFormats[ Settings::i()->calendar_date_format ] );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -519,10 +538,10 @@ 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
|
||||
* @return string
|
||||
*/
|
||||
public function mysqlDatetime( $includeTime=TRUE )
|
||||
public function mysqlDatetime( bool $includeTime=TRUE ): string
|
||||
{
|
||||
if( $includeTime )
|
||||
{
|
||||
@@ -540,7 +559,7 @@ class _Date extends \IPS\DateTime
|
||||
* @param mixed $key Value we tried to retrieve
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get( $key )
|
||||
public function __get( mixed $key )
|
||||
{
|
||||
return $this->_findValue( $key, $this->dateInformation );
|
||||
}
|
||||
@@ -551,7 +570,7 @@ class _Date extends \IPS\DateTime
|
||||
* @param mixed $key Key (from getdate()) we want to retrieve
|
||||
* @return mixed
|
||||
*/
|
||||
public function firstDayOfMonth( $key )
|
||||
public function firstDayOfMonth( mixed $key ): mixed
|
||||
{
|
||||
if( !isset( $this->firstDayOfMonth[0] ) )
|
||||
{
|
||||
@@ -567,7 +586,7 @@ class _Date extends \IPS\DateTime
|
||||
* @param mixed $key Key (from getdate()) we want to retrieve
|
||||
* @return mixed
|
||||
*/
|
||||
public function lastDayOfMonth( $key )
|
||||
public function lastDayOfMonth( mixed $key ): mixed
|
||||
{
|
||||
if( !isset( $this->lastDayOfMonth[0] ) )
|
||||
{
|
||||
@@ -583,7 +602,7 @@ class _Date extends \IPS\DateTime
|
||||
* @param mixed $key Key (from getdate()) we want to retrieve
|
||||
* @return mixed
|
||||
*/
|
||||
public function lastMonth( $key )
|
||||
public function lastMonth( mixed $key ): mixed
|
||||
{
|
||||
if( !isset( $this->lastMonth[0] ) )
|
||||
{
|
||||
@@ -599,7 +618,7 @@ class _Date extends \IPS\DateTime
|
||||
* @param mixed $key Key (from getdate()) we want to retrieve
|
||||
* @return mixed
|
||||
*/
|
||||
public function nextMonth( $key )
|
||||
public function nextMonth( mixed $key ): mixed
|
||||
{
|
||||
if( !isset( $this->nextMonth[0] ) )
|
||||
{
|
||||
@@ -615,7 +634,7 @@ class _Date extends \IPS\DateTime
|
||||
* @param mixed $key Key (from getdate()) we want to retrieve
|
||||
* @return mixed
|
||||
*/
|
||||
public function firstDayOfWeek( $key )
|
||||
public function firstDayOfWeek( mixed $key ): mixed
|
||||
{
|
||||
if( !isset( $this->firstDayOfWeek[0] ) )
|
||||
{
|
||||
@@ -631,7 +650,7 @@ class _Date extends \IPS\DateTime
|
||||
* @param mixed $key Key (from getdate()) we want to retrieve
|
||||
* @return mixed
|
||||
*/
|
||||
public function lastDayOfWeek( $key )
|
||||
public function lastDayOfWeek( mixed $key ): mixed
|
||||
{
|
||||
if( !isset( $this->lastDayOfWeek[0] ) )
|
||||
{
|
||||
@@ -646,7 +665,7 @@ class _Date extends \IPS\DateTime
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function leapYear()
|
||||
public function leapYear(): bool
|
||||
{
|
||||
return (bool) gmdate( 'L', $this->dateInformation[0] );
|
||||
}
|
||||
@@ -657,18 +676,18 @@ class _Date extends \IPS\DateTime
|
||||
* @return bool
|
||||
* @see <a href='http://stackoverflow.com/questions/6871258/how-to-determine-if-current-locale-has-24-hour-or-12-hour-time-format-in-php'>Check for 24 hour locale use</a>
|
||||
*/
|
||||
public static function usesAmPm()
|
||||
public static function usesAmPm(): bool
|
||||
{
|
||||
return ( \substr( gmstrftime( '%X', 57600 ), 0, 2) != 16 );
|
||||
return ( substr( gmstrftime( '%X', 57600 ), 0, 2) != 16 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the 12 hour version of an hour value
|
||||
*
|
||||
* @param int $hour The hour value between 0 and 23
|
||||
* @param int $hour The hour value between 0 and 23
|
||||
* @return int
|
||||
*/
|
||||
public static function getTwelveHour( $hour )
|
||||
public static function getTwelveHour( int $hour ): int
|
||||
{
|
||||
if( $hour == 0 )
|
||||
{
|
||||
@@ -687,10 +706,10 @@ class _Date extends \IPS\DateTime
|
||||
/**
|
||||
* Get the AM/PM value for the current locale
|
||||
*
|
||||
* @param int $hour The hour value between 0 and 23
|
||||
* @param int $hour The hour value between 0 and 23
|
||||
* @return string
|
||||
*/
|
||||
public static function getAmPm( $hour )
|
||||
public static function getAmPm( int $hour ): string
|
||||
{
|
||||
return gmstrftime( '%p', $hour * 60 * 60 );
|
||||
}
|
||||
@@ -699,14 +718,14 @@ class _Date extends \IPS\DateTime
|
||||
* Find a value in the supplied array and return it. Also supports a few 'special' keys.
|
||||
*
|
||||
* @param mixed $key Key (from getdate()) we want to retrieve
|
||||
* @param array $data Array to look for the key in
|
||||
* @param array $data Array to look for the key in
|
||||
* @return mixed
|
||||
*/
|
||||
protected function _findValue( $key, $data )
|
||||
protected function _findValue( mixed $key, array $data ): mixed
|
||||
{
|
||||
if( isset( $data[ $key ] ) )
|
||||
{
|
||||
if( $key == 'wday' AND \IPS\Settings::i()->ipb_calendar_mon )
|
||||
if( $key == 'wday' AND Settings::i()->ipb_calendar_mon )
|
||||
{
|
||||
return ( $data[ $key ] == 0 ) ? 6: ( $data[ $key ] - 1 );
|
||||
}
|
||||
@@ -721,22 +740,22 @@ class _Date extends \IPS\DateTime
|
||||
|
||||
if( $key == 'monthName' AND isset( $data[0] ) )
|
||||
{
|
||||
return mb_convert_case( \IPS\Member::loggedIn()->language()->convertString( strftime( static::setMonthModifier(), $data[0] ) ), MB_CASE_TITLE );
|
||||
return mb_convert_case( Member::loggedIn()->language()->convertString( strftime( static::setMonthModifier(), $data[0] ) ), MB_CASE_TITLE );
|
||||
}
|
||||
|
||||
if( $key == 'monthNameShort' AND isset( $data[0] ) )
|
||||
{
|
||||
return mb_convert_case( \IPS\Member::loggedIn()->language()->convertString( strftime( '%b', $data[0] ) ), MB_CASE_TITLE );
|
||||
return mb_convert_case( Member::loggedIn()->language()->convertString( strftime( '%b', $data[0] ) ), MB_CASE_TITLE );
|
||||
}
|
||||
|
||||
if( $key == 'dayName' AND isset( $data[0] ) )
|
||||
{
|
||||
return mb_convert_case( \IPS\Member::loggedIn()->language()->convertString( strftime( '%A', $data[0] ) ), MB_CASE_TITLE );
|
||||
return mb_convert_case( Member::loggedIn()->language()->convertString( strftime( '%A', $data[0] ) ), MB_CASE_TITLE );
|
||||
}
|
||||
|
||||
if( $key == 'dayNameShort' AND isset( $data[0] ) )
|
||||
{
|
||||
return mb_convert_case( \IPS\Member::loggedIn()->language()->convertString( strftime( '%a', $data[0] ) ), MB_CASE_TITLE );
|
||||
return mb_convert_case( Member::loggedIn()->language()->convertString( strftime( '%a', $data[0] ) ), MB_CASE_TITLE );
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -745,15 +764,15 @@ class _Date extends \IPS\DateTime
|
||||
/**
|
||||
* @brief strftime-compatible modifier for month name
|
||||
*/
|
||||
protected static $monthNameModifier = NULL;
|
||||
protected static ?string $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
|
||||
* @return string|null
|
||||
*/
|
||||
static protected function setMonthModifier()
|
||||
static protected function setMonthModifier(): ?string
|
||||
{
|
||||
if( static::$monthNameModifier === NULL )
|
||||
{
|
||||
@@ -775,12 +794,12 @@ 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 \IPS\Lang|\IPS\Member|NULL $memberOrLanguage The language or member to use, or NULL for currently logged in member
|
||||
* @param bool $seconds If TRUE, will include seconds
|
||||
* @param bool $minutes If TRUE, will include minutes
|
||||
* @param Lang|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, $memberOrLanguage=NULL )
|
||||
public function localeTime( bool $seconds=TRUE, bool $minutes=TRUE, Lang|Member $memberOrLanguage=NULL ): string
|
||||
{
|
||||
return static::determineLanguage( $memberOrLanguage )->convertString( strftime( static::localeTimeFormat( $seconds, $minutes, $memberOrLanguage ), $this->getTimestamp() + $this->offset ) );
|
||||
}
|
||||
|
||||
@@ -12,43 +12,66 @@
|
||||
namespace IPS\calendar\Event;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\Content\Anonymous;
|
||||
use IPS\Content\Comment as ContentComment;
|
||||
use IPS\Content\EditHistory;
|
||||
use IPS\Content\Embeddable;
|
||||
use IPS\Content\Filter;
|
||||
use IPS\Content\Hideable;
|
||||
use IPS\Content\Featurable;
|
||||
use IPS\Content\Reactable;
|
||||
use IPS\Content\Reportable;
|
||||
use IPS\Content\Shareable;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Output;
|
||||
use IPS\Theme;
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event Comment Model
|
||||
*/
|
||||
class _Comment extends \IPS\Content\Comment implements \IPS\Content\EditHistory, \IPS\Content\Hideable, \IPS\Content\Searchable, \IPS\Content\Embeddable, \IPS\Content\Anonymous
|
||||
class Comment extends ContentComment implements Embeddable,
|
||||
Filter
|
||||
{
|
||||
use \IPS\Content\Reactable, \IPS\Content\Reportable;
|
||||
use Reactable,
|
||||
Reportable,
|
||||
Anonymous,
|
||||
Shareable,
|
||||
EditHistory,
|
||||
Hideable,
|
||||
Featurable;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
protected static array $multitons;
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Item Class
|
||||
*/
|
||||
public static $itemClass = 'IPS\calendar\Event';
|
||||
public static ?string $itemClass = 'IPS\calendar\Event';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'calendar_event_comments';
|
||||
public static ?string $databaseTable = 'calendar_event_comments';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'comment_';
|
||||
public static string $databasePrefix = 'comment_';
|
||||
|
||||
/**
|
||||
* @brief Database Column Map
|
||||
*/
|
||||
public static $databaseColumnMap = array(
|
||||
public static array $databaseColumnMap = array(
|
||||
'item' => 'eid',
|
||||
'author' => 'mid',
|
||||
'author_name' => 'author',
|
||||
@@ -65,30 +88,30 @@ class _Comment extends \IPS\Content\Comment implements \IPS\Content\EditHistory,
|
||||
/**
|
||||
* @brief Application
|
||||
*/
|
||||
public static $application = 'calendar';
|
||||
public static string $application = 'calendar';
|
||||
|
||||
/**
|
||||
* @brief Title
|
||||
*/
|
||||
public static $title = 'calendar_event_comment';
|
||||
public static string $title = 'calendar_event_comment';
|
||||
|
||||
/**
|
||||
* @brief Icon
|
||||
*/
|
||||
public static $icon = 'calendar';
|
||||
public static string $icon = 'calendar';
|
||||
|
||||
/**
|
||||
* @brief [Content] Key for hide reasons
|
||||
*/
|
||||
public static $hideLogKey = 'calendar-events';
|
||||
public static ?string $hideLogKey = 'calendar-events';
|
||||
|
||||
/**
|
||||
* Get URL for doing stuff
|
||||
*
|
||||
* @param string|NULL $action Action
|
||||
* @return \IPS\Http\Url
|
||||
* @param string|null $action Action
|
||||
* @return Url
|
||||
*/
|
||||
public function url( $action='find' )
|
||||
public function url( ?string $action='find' ): Url
|
||||
{
|
||||
return parent::url( $action )->setQueryString( 'tab', 'comments' );
|
||||
}
|
||||
@@ -96,44 +119,11 @@ class _Comment extends \IPS\Content\Comment implements \IPS\Content\EditHistory,
|
||||
/**
|
||||
* Get template for content tables
|
||||
*
|
||||
* @return callable
|
||||
* @return array
|
||||
*/
|
||||
public static function contentTableTemplate()
|
||||
public static function contentTableTemplate(): array
|
||||
{
|
||||
return array( \IPS\Theme::i()->getTemplate( 'tables', 'core', 'front' ), 'commentRows' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get snippet HTML for search result display
|
||||
*
|
||||
* @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 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'
|
||||
* @return callable
|
||||
*/
|
||||
public static function searchResultSnippet( array $indexData, array $authorData, array $itemData, ?array $containerData, array $reputationData, $reviewRating, $view )
|
||||
{
|
||||
$startDate = \IPS\calendar\Date::parseTime( $itemData['event_start_date'], $itemData['event_all_day'] ? FALSE : TRUE );
|
||||
$endDate = $itemData['event_end_date'] ? \IPS\calendar\Date::parseTime( $itemData['event_end_date'], $itemData['event_all_day'] ? FALSE : TRUE ) : NULL;
|
||||
$nextOccurance = $startDate;
|
||||
if ( $itemData['event_recurring'] )
|
||||
{
|
||||
$occurances = \IPS\calendar\Event::_findOccurances( $startDate, $endDate, $startDate->adjust( "-1 month" ), $startDate->adjust( "+2 years" ), \IPS\calendar\Icalendar\ICSParser::parseRrule( $itemData['event_recurring'] ), NULL, $itemData['event_all_day'] );
|
||||
foreach( $occurances as $occurrence )
|
||||
{
|
||||
if( $occurrence['startDate'] AND $occurrence['startDate']->mysqlDatetime( FALSE ) >= $startDate->mysqlDatetime( FALSE ) )
|
||||
{
|
||||
$nextOccurance = $occurrence['startDate'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'global', 'calendar', 'front' )->searchResultCommentSnippet( $indexData, $nextOccurance, $startDate, $endDate, $itemData['event_all_day'], $reviewRating, $view == 'condensed' );
|
||||
return array( Theme::i()->getTemplate( 'tables', 'core', 'front' ), 'commentRows' );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,7 +131,7 @@ class _Comment extends \IPS\Content\Comment implements \IPS\Content\EditHistory,
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function reactionType()
|
||||
public static function reactionType(): string
|
||||
{
|
||||
return 'comment_id';
|
||||
}
|
||||
@@ -149,12 +139,12 @@ class _Comment extends \IPS\Content\Comment implements \IPS\Content\EditHistory,
|
||||
/**
|
||||
* Get content for embed
|
||||
*
|
||||
* @param array $params Additional parameters to add to URL
|
||||
* @param array $params Additional parameters to add to URL
|
||||
* @return string
|
||||
*/
|
||||
public function embedContent( $params )
|
||||
public function embedContent( array $params ): string
|
||||
{
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'embed.css', 'calendar', 'front' ) );
|
||||
return \IPS\Theme::i()->getTemplate( 'global', 'calendar' )->embedEventComment( $this, $this->item(), $this->url()->setQueryString( $params ) );
|
||||
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, Theme::i()->css( 'embed.css', 'calendar', 'front' ) );
|
||||
return Theme::i()->getTemplate( 'global', 'calendar' )->embedEventComment( $this, $this->item(), $this->url()->setQueryString( $params ) );
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -12,43 +12,64 @@
|
||||
namespace IPS\calendar\Event;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use BadMethodCallException;
|
||||
use IPS\Content\EditHistory;
|
||||
use IPS\Content\Embeddable;
|
||||
use IPS\Content\Filter;
|
||||
use IPS\Content\Hideable;
|
||||
use IPS\Content\Reactable;
|
||||
use IPS\Content\Reportable;
|
||||
use IPS\Content\Review as ContentReview;
|
||||
use IPS\Content\Shareable;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Http\Url\Exception;
|
||||
use IPS\Output;
|
||||
use IPS\Theme;
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event Review Model
|
||||
*/
|
||||
class _Review extends \IPS\Content\Review implements \IPS\Content\EditHistory, \IPS\Content\Hideable, \IPS\Content\Searchable, \IPS\Content\Embeddable
|
||||
class Review extends ContentReview implements Embeddable,
|
||||
Filter
|
||||
{
|
||||
use \IPS\Content\Reactable, \IPS\Content\Reportable;
|
||||
use Reactable,
|
||||
Reportable,
|
||||
Shareable,
|
||||
EditHistory,
|
||||
Hideable;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
protected static array $multitons;
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Item Class
|
||||
*/
|
||||
public static $itemClass = 'IPS\calendar\Event';
|
||||
public static ?string $itemClass = 'IPS\calendar\Event';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'calendar_event_reviews';
|
||||
public static ?string $databaseTable = 'calendar_event_reviews';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'review_';
|
||||
public static string $databasePrefix = 'review_';
|
||||
|
||||
/**
|
||||
* @brief Database Column Map
|
||||
*/
|
||||
public static $databaseColumnMap = array(
|
||||
public static array $databaseColumnMap = array(
|
||||
'item' => 'eid',
|
||||
'author' => 'mid',
|
||||
'author_name' => 'author_name',
|
||||
@@ -69,32 +90,32 @@ class _Review extends \IPS\Content\Review implements \IPS\Content\EditHistory, \
|
||||
/**
|
||||
* @brief Application
|
||||
*/
|
||||
public static $application = 'calendar';
|
||||
public static string $application = 'calendar';
|
||||
|
||||
/**
|
||||
* @brief Title
|
||||
*/
|
||||
public static $title = 'calendar_event_review';
|
||||
public static string $title = 'calendar_event_review';
|
||||
|
||||
/**
|
||||
* @brief Icon
|
||||
*/
|
||||
public static $icon = 'calendar';
|
||||
public static string $icon = 'calendar';
|
||||
|
||||
/**
|
||||
* @brief [Content] Key for hide reasons
|
||||
*/
|
||||
public static $hideLogKey = 'calendar-events-rev';
|
||||
public static ?string $hideLogKey = 'calendar-events-rev';
|
||||
|
||||
/**
|
||||
* Get URL for doing stuff
|
||||
*
|
||||
* @param string|NULL $action Action
|
||||
* @return \IPS\Http\Url
|
||||
* @throws \BadMethodCallException
|
||||
* @throws \IPS\Http\Url\Exception
|
||||
* @return Url
|
||||
* @throws BadMethodCallException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function url( $action='find' )
|
||||
public function url( ?string $action='find' ): Url
|
||||
{
|
||||
return parent::url( $action )->setQueryString( 'tab', 'reviews' );
|
||||
}
|
||||
@@ -102,28 +123,11 @@ class _Review extends \IPS\Content\Review implements \IPS\Content\EditHistory, \
|
||||
/**
|
||||
* Get template for content tables
|
||||
*
|
||||
* @return callable
|
||||
* @return array
|
||||
*/
|
||||
public static function contentTableTemplate()
|
||||
public static function contentTableTemplate(): array
|
||||
{
|
||||
return array( \IPS\Theme::i()->getTemplate( 'tables', 'core', 'front' ), 'commentRows' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get snippet HTML for search result display
|
||||
*
|
||||
* @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 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'
|
||||
* @return callable
|
||||
*/
|
||||
public static function searchResultSnippet( array $indexData, array $authorData, array $itemData, ?array $containerData, array $reputationData, $reviewRating, $view )
|
||||
{
|
||||
return \IPS\calendar\Event\Comment::searchResultSnippet( $indexData, $authorData, $itemData, $containerData, $reputationData, $reviewRating, $view );
|
||||
return array( Theme::i()->getTemplate( 'tables', 'core', 'front' ), 'commentRows' );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,7 +135,7 @@ class _Review extends \IPS\Content\Review implements \IPS\Content\EditHistory, \
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function reactionType()
|
||||
public static function reactionType(): string
|
||||
{
|
||||
return 'review_id';
|
||||
}
|
||||
@@ -139,12 +143,12 @@ class _Review extends \IPS\Content\Review implements \IPS\Content\EditHistory, \
|
||||
/**
|
||||
* Get content for embed
|
||||
*
|
||||
* @param array $params Additional parameters to add to URL
|
||||
* @return string
|
||||
* @param array $params Additional parameters to add to URL
|
||||
* @return string
|
||||
*/
|
||||
public function embedContent( $params )
|
||||
public function embedContent( array $params ): string
|
||||
{
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'embed.css', 'calendar', 'front' ) );
|
||||
return \IPS\Theme::i()->getTemplate( 'global', 'calendar' )->embedEventReview( $this, $this->item(), $this->url()->setQueryString( $params ) );
|
||||
Output::i()->cssFiles = array_merge( Output::i()->cssFiles, Theme::i()->css( 'embed.css', 'calendar', 'front' ) );
|
||||
return Theme::i()->getTemplate( 'global', 'calendar' )->embedEventReview( $this, $this->item(), $this->url()->setQueryString( $params ) );
|
||||
}
|
||||
}
|
||||
@@ -12,9 +12,45 @@
|
||||
namespace IPS\calendar\Icalendar;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use BadFunctionCallException;
|
||||
use BadMethodCallException;
|
||||
use DateInterval;
|
||||
use DateTimeZone;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use IPS\Api\Webhook;
|
||||
use IPS\Application;
|
||||
use IPS\calendar\Calendar;
|
||||
use IPS\calendar\Date;
|
||||
use IPS\calendar\Event;
|
||||
use IPS\calendar\Icalendar;
|
||||
use IPS\Content\Search\Index;
|
||||
use IPS\DateTime;
|
||||
use IPS\Db;
|
||||
use IPS\File;
|
||||
use IPS\GeoLocation;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Member;
|
||||
use IPS\Settings;
|
||||
use IPS\Text\Parser;
|
||||
use OutOfRangeException;
|
||||
use UnderflowException;
|
||||
use UnexpectedValueException;
|
||||
use function count;
|
||||
use function defined;
|
||||
use function get_class;
|
||||
use function in_array;
|
||||
use function intval;
|
||||
use function is_array;
|
||||
use function is_null;
|
||||
use function stripos;
|
||||
use function strlen;
|
||||
use function substr;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -22,23 +58,23 @@ if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
* iCalendar ICS Parser
|
||||
* @todo [Future] Tags we do not support but may want to look into supporting: EXDATE, EXRULE, RDATE
|
||||
*/
|
||||
class _ICSParser
|
||||
class ICSParser
|
||||
{
|
||||
/**
|
||||
* Parse an RRULE into an array of recurrence data we can use
|
||||
*
|
||||
* @param string $rrule The ICS RRULE value
|
||||
* @param string $timezone Timezone to treat recurring end date as
|
||||
* @param NULL|\IPS\calendar\Date $startDate If supplied, we can use the start date to help convert certain repeat rules to make them simpler
|
||||
* @param string $rrule The ICS RRULE value
|
||||
* @param string|null $timezone Timezone to treat recurring end date as
|
||||
* @param Date|null $startDate If supplied, we can use the start date to help convert certain repeat rules to make them simpler
|
||||
* @return array
|
||||
* @todo [Future] We do not support HOURLY, MINUTELY or SECONDLY "FREQ" values
|
||||
* @todo [Future] We do not support the properties BYSETPOS, BYYEARDAY, BYMONTH, BYHOUR, BYMINUTE, BYSECOND, BYWEEKNO, WKST
|
||||
* @throws InvalidArgumentException
|
||||
* @note Some implementations separate with : and some with ; so we have to support both
|
||||
*@todo [Future] We do not support the properties BYSETPOS, BYYEARDAY, BYMONTH, BYHOUR, BYMINUTE, BYSECOND, BYWEEKNO, WKST
|
||||
* @todo [Future] We do not support complex BYDAY values, such as 1TU or -1FR
|
||||
* @todo [Future] We do not support multiple values for BYMONTHDAY, nor do we support negative values
|
||||
* @throws \InvalidArgumentException
|
||||
* @note Some implementations separate with : and some with ; so we have to support both
|
||||
* @todo [Future] We do not support HOURLY, MINUTELY or SECONDLY "FREQ" values
|
||||
*/
|
||||
public static function parseRrule( $rrule, $timezone=NULL, $startDate = NULL )
|
||||
public static function parseRrule( string $rrule, string $timezone=NULL, Date $startDate = NULL ): array
|
||||
{
|
||||
$rule = array_map( 'trim', explode( ';', str_replace( ':', ';', $rrule ) ) );
|
||||
$dayNames = array();
|
||||
@@ -50,7 +86,7 @@ class _ICSParser
|
||||
'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) */
|
||||
);
|
||||
|
||||
foreach( \IPS\calendar\Date::getDayNames() as $day )
|
||||
foreach( Date::getDayNames() as $day )
|
||||
{
|
||||
$repeatData['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) */
|
||||
$dayNames[] = $day['ical'];
|
||||
@@ -63,21 +99,20 @@ class _ICSParser
|
||||
switch( $_ruleData[0] )
|
||||
{
|
||||
default:
|
||||
throw new \InvalidArgumentException( $_ruleData[0] );
|
||||
break;
|
||||
throw new InvalidArgumentException( $_ruleData[0] );
|
||||
|
||||
case 'WKST':
|
||||
/* We can safely ignore this when it is set to the default value of MO. We can't make assumptions in other cases. */
|
||||
if( mb_strtolower( $_ruleData[1] ) != 'mo' )
|
||||
{
|
||||
throw new \InvalidArgumentException( $_ruleData[0] );
|
||||
throw new InvalidArgumentException( $_ruleData[0] );
|
||||
}
|
||||
break;
|
||||
|
||||
case 'FREQ':
|
||||
$frequency = mb_strtolower( $_ruleData[1] );
|
||||
|
||||
if( \in_array( $frequency, array( 'daily', 'weekly', 'monthly', 'yearly' ) ) )
|
||||
if( in_array( $frequency, array( 'daily', 'weekly', 'monthly', 'yearly' ) ) )
|
||||
{
|
||||
$repeatData['event_repeats'] = $frequency;
|
||||
$repeatData['event_repeat'] = TRUE;
|
||||
@@ -85,7 +120,7 @@ class _ICSParser
|
||||
else
|
||||
{
|
||||
/* We don't support less than daily*/
|
||||
throw new \InvalidArgumentException( 'FREQ' );
|
||||
throw new InvalidArgumentException( 'FREQ' );
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -96,14 +131,14 @@ class _ICSParser
|
||||
{
|
||||
foreach( $dayNames as $dayName )
|
||||
{
|
||||
$dayPos = \stripos( $day, $dayName );
|
||||
$dayPos = stripos( $day, $dayName );
|
||||
|
||||
if( $dayPos !== FALSE )
|
||||
{
|
||||
/* We only support basic day recurrence values, not the negative/positive numbers */
|
||||
if( $dayPos > 0 )
|
||||
{
|
||||
throw new \InvalidArgumentException( 'BYDAY' );
|
||||
throw new InvalidArgumentException( 'BYDAY' );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -119,9 +154,9 @@ class _ICSParser
|
||||
case 'BYMONTHDAY':
|
||||
$values = array_map( 'trim', explode( ',', $_ruleData[1] ) );
|
||||
|
||||
if( \count( $values ) > 1 OR \stripos( $values[0], '-' ) !== FALSE )
|
||||
if( count( $values ) > 1 OR stripos( $values[0], '-' ) !== FALSE )
|
||||
{
|
||||
throw new \InvalidArgumentException( 'BYMONTHDAY' );
|
||||
throw new InvalidArgumentException( 'BYMONTHDAY' );
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -134,7 +169,7 @@ class _ICSParser
|
||||
break;
|
||||
|
||||
case 'UNTIL':
|
||||
$repeatData['repeat_end_date'] = new \IPS\calendar\Date( $_ruleData[1], $timezone ? new \DateTimeZone( $timezone ) : NULL );
|
||||
$repeatData['repeat_end_date'] = new Date( $_ruleData[1], $timezone ? new DateTimeZone( $timezone ) : NULL );
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -158,15 +193,15 @@ class _ICSParser
|
||||
{
|
||||
$_repeatDays = array();
|
||||
|
||||
foreach( \IPS\calendar\Date::getDayNames() as $day )
|
||||
foreach( Date::getDayNames() as $day )
|
||||
{
|
||||
if( $repeatData['repeat_freq_on_' . $day['ical'] ] == TRUE )
|
||||
if( $repeatData['repeat_freq_on_' . $day['ical']] )
|
||||
{
|
||||
$_repeatDays[] = $day['english'];
|
||||
}
|
||||
}
|
||||
|
||||
if( ( \count( $_repeatDays ) == 1 AND $startDate->weekday == $_repeatDays[0] ) OR \count( $_repeatDays ) == 7 )
|
||||
if( ( count( $_repeatDays ) == 1 AND $startDate->weekday == $_repeatDays[0] ) OR count( $_repeatDays ) == 7 )
|
||||
{
|
||||
foreach( $dayNames as $day )
|
||||
{
|
||||
@@ -182,11 +217,11 @@ class _ICSParser
|
||||
* Create an RRULE value from an array of data
|
||||
*
|
||||
* @note This is basically the opposite of parseRrule
|
||||
* @see self::parseRrule()
|
||||
* @param array $repeat The event repeat data
|
||||
* @return string|NULL
|
||||
*@see self::parseRrule()
|
||||
*/
|
||||
public static function buildRrule( $repeat )
|
||||
public static function buildRrule( array $repeat ): ?string
|
||||
{
|
||||
/* If checkbox was not checked, just return */
|
||||
if( !isset( $repeat['event_repeat'] ) OR !$repeat['event_repeat'] )
|
||||
@@ -208,13 +243,13 @@ class _ICSParser
|
||||
|
||||
if( isset( $repeat['repeat_end_date'] ) AND $repeat['repeat_end_date'] )
|
||||
{
|
||||
$rrule[] = 'UNTIL=' . \IPS\calendar\Date::createFromForm( $repeat['repeat_end_date'], NULL, 'UTC' )->modifiedIso8601();
|
||||
$rrule[] = 'UNTIL=' . Date::createFromForm( $repeat['repeat_end_date'], '', 'UTC' )->modifiedIso8601();
|
||||
}
|
||||
|
||||
/* By-day rule */
|
||||
$days = array();
|
||||
|
||||
foreach( \IPS\calendar\Date::getDayNames() as $day )
|
||||
foreach( Date::getDayNames() as $day )
|
||||
{
|
||||
if( isset( $repeat['repeat_freq_on_' . $day['ical'] ] ) AND $repeat['repeat_freq_on_' . $day['ical'] ] )
|
||||
{
|
||||
@@ -222,7 +257,7 @@ class _ICSParser
|
||||
}
|
||||
}
|
||||
|
||||
if( \count( $days ) )
|
||||
if( count( $days ) )
|
||||
{
|
||||
$rrule[] = 'BYDAY=' . implode( ',', $days );
|
||||
}
|
||||
@@ -233,45 +268,45 @@ class _ICSParser
|
||||
/**
|
||||
* @brief Calendar we are importing to
|
||||
*/
|
||||
protected $calendar = NULL;
|
||||
protected ?Calendar $calendar = NULL;
|
||||
|
||||
/**
|
||||
* @brief Member we are importing as
|
||||
*/
|
||||
protected $member = NULL;
|
||||
protected ?Member $member = NULL;
|
||||
|
||||
/**
|
||||
* @brief Feed we are importing from
|
||||
*/
|
||||
protected $feed = NULL;
|
||||
protected ?Icalendar $feed = NULL;
|
||||
|
||||
/**
|
||||
* Perform some basic error checking
|
||||
*
|
||||
* @param string $content The ICS contents
|
||||
* @param string $content The ICS contents
|
||||
* @return bool
|
||||
* @throws \UnexpectedValueException
|
||||
* @throws UnexpectedValueException
|
||||
* @note This is abstracted as a static method so we can perform error checking prior to saving the feed
|
||||
*/
|
||||
public static function isValid( $content )
|
||||
public static function isValid( string $content ): bool
|
||||
{
|
||||
/* Perform some basic error checking */
|
||||
if( !$content )
|
||||
{
|
||||
throw new \UnexpectedValueException( "NO_CONTENT" );
|
||||
throw new UnexpectedValueException( "NO_CONTENT" );
|
||||
}
|
||||
|
||||
$_raw = preg_replace( "#(\n\r|\r|\n){1,}#", "\n", $content );
|
||||
$_raw = explode( "\n", $_raw );
|
||||
|
||||
if( !\count($_raw) )
|
||||
if( !count($_raw) )
|
||||
{
|
||||
throw new \UnexpectedValueException( "NO_CONTENT" );
|
||||
throw new UnexpectedValueException( "NO_CONTENT" );
|
||||
}
|
||||
|
||||
if( $_raw[0] != 'BEGIN:VCALENDAR' )
|
||||
{
|
||||
throw new \UnexpectedValueException( "BAD_CONTENT" );
|
||||
throw new UnexpectedValueException( "BAD_CONTENT" );
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@@ -280,26 +315,26 @@ class _ICSParser
|
||||
/**
|
||||
* Parse the supplied contents (which may come from a URL or an uploaded file) and import events
|
||||
*
|
||||
* @param string $content The ICS contents
|
||||
* @param int|\IPS\calendar\Calendar $calendar The calendar to import to
|
||||
* @param int|\IPS\Member $member The member the imported events should be 'from'
|
||||
* @param int $feed The feed we are importing (used to detect and prevent duplicate imports)
|
||||
* @param int $venue The venue if provided
|
||||
* @param string $content The ICS contents
|
||||
* @param int|Calendar $calendar The calendar to import to
|
||||
* @param int|Member $member The member the imported events should be 'from'
|
||||
* @param int|null $feed The feed we are importing (used to detect and prevent duplicate imports)
|
||||
* @param int|null $venue The venue if provided
|
||||
* @return array Number of events imported and skipped
|
||||
* @throws \UnexpectedValueException
|
||||
* @throws UnexpectedValueException
|
||||
*/
|
||||
public function parse( $content, $calendar, $member, $feed=NULL, $venue=NULL )
|
||||
public function parse( string $content, Calendar|int $calendar, int|Member $member, int $feed=NULL, int $venue=NULL ): array
|
||||
{
|
||||
/* Load the calendar */
|
||||
$this->calendar = ( $calendar instanceof \IPS\calendar\Calendar ) ? $calendar : \IPS\calendar\Calendar::load( $calendar );
|
||||
$this->calendar = ( $calendar instanceof Calendar ) ? $calendar : Calendar::load( $calendar );
|
||||
|
||||
/* And the member */
|
||||
$this->member = ( $member instanceof \IPS\Member ) ? $member : \IPS\Member::load( $member );
|
||||
$this->member = ( $member instanceof Member ) ? $member : Member::load( $member );
|
||||
|
||||
/* And the feed */
|
||||
if( $feed !== NULL )
|
||||
{
|
||||
$this->feed = \IPS\calendar\Icalendar::load( $feed );
|
||||
$this->feed = Icalendar::load( $feed );
|
||||
}
|
||||
|
||||
/* Perform some basic error checking */
|
||||
@@ -333,7 +368,7 @@ class _ICSParser
|
||||
}
|
||||
|
||||
/* Convert the raw ICS data to GMT now */
|
||||
if( \count($this->_parsedIcsData) )
|
||||
if( count($this->_parsedIcsData) )
|
||||
{
|
||||
$this->_parsedIcsData = $this->_convertToGmt( $this->_parsedIcsData );
|
||||
}
|
||||
@@ -347,7 +382,7 @@ class _ICSParser
|
||||
// Leave this here - useful for debugging
|
||||
// print_r($this->_parsedIcsData);exit;
|
||||
|
||||
if ( \count( $this->_parsedIcsData ) and isset( $this->_parsedIcsData['events'] ) )
|
||||
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'] )
|
||||
@@ -373,18 +408,18 @@ class _ICSParser
|
||||
{
|
||||
$rrule = static::parseRrule( $event['recurr'] );
|
||||
}
|
||||
catch( \InvalidArgumentException $e )
|
||||
catch( InvalidArgumentException $e )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$event['uid'] = $event['uid'] ? $event['uid'] : md5( implode( ',', $event['start'] ) . implode( ',', $event['end'] ) );
|
||||
$event['uid'] = $event['uid'] ?: md5( implode( ',', $event['start'] ) . implode( ',', $event['end'] ) );
|
||||
|
||||
/* Figure out some times */
|
||||
$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;
|
||||
$event_all_day = $event['start']['type'] == 'DATE';
|
||||
|
||||
/* End dates in iCalendar format are "exclusive", meaning they are actually the day ahead. */
|
||||
/* @link http://microformats.org/wiki/dtend-issue */
|
||||
@@ -393,7 +428,7 @@ class _ICSParser
|
||||
|
||||
if( $event_unix_to AND $event['end']['type'] == 'DATE' AND ( $event_unix_from->getTimestamp() != $event_unix_to->getTimestamp() ) )
|
||||
{
|
||||
$event_unix_to = $event_unix_to->sub( new \DateInterval( 'P1D' ) );
|
||||
$event_unix_to = $event_unix_to->sub( new DateInterval( 'P1D' ) );
|
||||
}
|
||||
|
||||
/* It is a single day event if end date is equal to start date */
|
||||
@@ -406,15 +441,15 @@ class _ICSParser
|
||||
if ( ! $event_unix_to AND isset( $event['duration'] ) AND $event['duration'] )
|
||||
{
|
||||
preg_match( "#(\d+?)H#is", $event['duration'], $match );
|
||||
$hour = isset( $match[1] ) ? $match[1] : 0;
|
||||
$hour = $match[1] ?? 0;
|
||||
|
||||
preg_match( "#(\d+?)M#is", $event['duration'], $match );
|
||||
$minute = isset( $match[1] ) ? $match[1] : 0;
|
||||
$minute = $match[1] ?? 0;
|
||||
|
||||
preg_match( "#(\d+?)S#is", $event['duration'], $match );
|
||||
$second = isset( $match[1] ) ? $match[1] : 0;
|
||||
$second = $match[1] ?? 0;
|
||||
|
||||
$event_unix_to = $event_unix_from->add( new \DateInterval( 'PT' . ( $hour * 3600 ) . 'H' . ( $minute * 60 ) . 'M' . $second . 'S' ) );
|
||||
$event_unix_to = $event_unix_from->add( new DateInterval( 'PT' . ( $hour * 3600 ) . 'H' . ( $minute * 60 ) . 'M' . $second . 'S' ) );
|
||||
}
|
||||
|
||||
/* If this is an all day event, adjust the timestamps */
|
||||
@@ -440,19 +475,19 @@ class _ICSParser
|
||||
try
|
||||
{
|
||||
/* If we are importing an ICS file, feed here will be null. */
|
||||
if ( \is_null( $this->feed ) )
|
||||
if ( is_null( $this->feed ) )
|
||||
{
|
||||
/* Bubble up so we can create a new event */
|
||||
throw new \UnderflowException;
|
||||
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();
|
||||
$eventId = Db::i()->select( 'import_event_id', 'calendar_import_map', array( array( 'import_guid=? and import_feed_id=?', $event['uid'], $this->feed->id ) ) )->first();
|
||||
|
||||
try
|
||||
{
|
||||
$newEvent = \IPS\calendar\Event::load( $eventId );
|
||||
$newEvent = Event::load( $eventId );
|
||||
}
|
||||
catch( \OutOfRangeException $e )
|
||||
catch( OutOfRangeException $e )
|
||||
{
|
||||
/* This event seems to have been deleted - skip it. */
|
||||
$_skipped++;
|
||||
@@ -461,9 +496,9 @@ class _ICSParser
|
||||
|
||||
$_skipped++;
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
catch( UnderflowException $e )
|
||||
{
|
||||
$newEvent = new \IPS\calendar\Event;
|
||||
$newEvent = new Event;
|
||||
$_new = TRUE;
|
||||
|
||||
/* Basics */
|
||||
@@ -490,16 +525,16 @@ class _ICSParser
|
||||
/* Basics */
|
||||
$newEvent->title = ( isset( $event['summary'] ) AND $event['summary'] ) ? $event['summary'] : mb_substr( strip_tags( $event['description'] ), 0, 100 );
|
||||
$content = ( isset( $event['description'] ) AND $event['description'] ) ? nl2br( $event['description'] ) : $event['summary'] . ( isset( $event['location'] ) ? '<br>' . $event['location'] : '' );
|
||||
$newEvent->content = \IPS\Text\Parser::parseStatic( $content, TRUE, NULL, $this->member );
|
||||
$newEvent->sequence = ( isset( $event['sequence'] ) ? \intval( $event['sequence'] ) : 0 );
|
||||
$newEvent->content = Parser::parseStatic( $content, NULL, $this->member );
|
||||
$newEvent->sequence = ( isset( $event['sequence'] ) ? intval( $event['sequence'] ) : 0 );
|
||||
|
||||
$newEvent->all_day = $event_all_day;
|
||||
$newEvent->recurring = ( isset( $event['recurr'] ) ) ? $event['recurr'] : NULL;
|
||||
$newEvent->start_date = $event_unix_from->setTimezone( new \DateTimeZone( 'UTC' ) )->format( 'Y-m-d H:i:s' );
|
||||
$newEvent->end_date = $event_unix_to ? $event_unix_to->setTimezone( new \DateTimeZone( 'UTC' ) )->format( 'Y-m-d H:i:s' ) : 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'] ) )
|
||||
if( isset( $event['geo'] ) AND is_array( $event['geo'] ) AND count( $event['geo'] ) )
|
||||
{
|
||||
/* If we are updating an event, don't pull geo data if we already have it and it hasn't changed */
|
||||
$update = TRUE;
|
||||
@@ -518,22 +553,22 @@ class _ICSParser
|
||||
{
|
||||
try
|
||||
{
|
||||
$newEvent->location = json_encode( \IPS\GeoLocation::getByLatLong( $event['geo']['lat'], $event['geo']['long'] ) );
|
||||
$newEvent->location = json_encode( GeoLocation::getByLatLong( $event['geo']['lat'], $event['geo']['long'] ) );
|
||||
}
|
||||
catch( \BadFunctionCallException $e ){}
|
||||
catch( BadFunctionCallException $e ){}
|
||||
}
|
||||
}
|
||||
elseif( isset( $event['location'] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$location = new \IPS\GeoLocation;
|
||||
$location = new GeoLocation;
|
||||
$location->addressLines = array( $event['location'] );
|
||||
$location->getLatLong( TRUE );
|
||||
|
||||
$newEvent->location = json_encode( $location );
|
||||
}
|
||||
catch( \BadFunctionCallException $e ){}
|
||||
catch( BadFunctionCallException $e ){}
|
||||
}
|
||||
|
||||
/* Save */
|
||||
@@ -545,17 +580,17 @@ class _ICSParser
|
||||
/* Increment only if this is a new event */
|
||||
if( $_new )
|
||||
{
|
||||
\IPS\Api\Webhook::fire( str_replace( '\\', '', \substr( \get_class( $newEvent ), 3 ) ) . '_create', $newEvent, $newEvent->webhookFilters() );
|
||||
Webhook::fire( str_replace( '\\', '', substr( get_class( $newEvent ), 3 ) ) . '_create', $newEvent, $newEvent->webhookFilters() );
|
||||
$_newEvents++;
|
||||
}
|
||||
|
||||
/* Add to index */
|
||||
\IPS\Content\Search\Index::i()->index( $newEvent );
|
||||
Index::i()->index( $newEvent );
|
||||
|
||||
/* Update map */
|
||||
if( $this->feed !== NULL AND !$eventId )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'calendar_import_map', array(
|
||||
Db::i()->insert( 'calendar_import_map', array(
|
||||
'import_feed_id' => $this->feed->id,
|
||||
'import_event_id' => $newEvent->id,
|
||||
'import_guid' => $event['uid'],
|
||||
@@ -563,17 +598,17 @@ class _ICSParser
|
||||
}
|
||||
|
||||
/* Add any event attendees that are members of our installation */
|
||||
if( !$eventId AND isset($event['attendee']) AND \count($event['attendee']) )
|
||||
if( !$eventId AND isset($event['attendee']) AND count($event['attendee']) )
|
||||
{
|
||||
foreach( $event['attendee'] as $attendee )
|
||||
{
|
||||
if( $attendee['email'] )
|
||||
{
|
||||
$_loadedMember = \IPS\Member::load( $attendee['email'] );
|
||||
$_loadedMember = Member::load( $attendee['email'] );
|
||||
|
||||
if( $_loadedMember->member_id )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'calendar_event_rsvp', array(
|
||||
Db::i()->insert( 'calendar_event_rsvp', array(
|
||||
'rsvp_member_id' => $_loadedMember->member_id,
|
||||
'rsvp_event_id' => $newEvent->id,
|
||||
'rsvp_date' => time(),
|
||||
@@ -600,29 +635,29 @@ class _ICSParser
|
||||
/**
|
||||
* @brief Array of calendar events we are adding to an iCalendar export
|
||||
*/
|
||||
protected $_events = array();
|
||||
protected array $_events = array();
|
||||
|
||||
/**
|
||||
* Add an event
|
||||
*
|
||||
* @param \IPS\calendar\Event $event Event data
|
||||
* @param Event $event Event data
|
||||
* @return void
|
||||
*/
|
||||
public function addEvent( $event )
|
||||
public function addEvent( Event $event ) : void
|
||||
{
|
||||
if( $event->id )
|
||||
{
|
||||
$this->_events[ $event->id ] = $event;
|
||||
$this->_events[ $event->id ] = $event;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an event
|
||||
*
|
||||
* @param int $eventId Event id
|
||||
* @param int $eventId Event id
|
||||
* @return void
|
||||
*/
|
||||
public function removeEvent( $eventId )
|
||||
public function removeEvent( int $eventId ) : void
|
||||
{
|
||||
if( $eventId )
|
||||
{
|
||||
@@ -633,18 +668,18 @@ class _ICSParser
|
||||
/**
|
||||
* Build iCalendar feed and return
|
||||
*
|
||||
* @param int|\IPS\calendar\Calendar|NULL $calendar The calendar the feed belongs to
|
||||
* @param int|Calendar|null $calendar The calendar the feed belongs to
|
||||
* @return string iCalendar feed (can be downloaded or sent as webcal subscription)
|
||||
*/
|
||||
public function buildICalendarFeed( $calendar=NULL )
|
||||
public function buildICalendarFeed( Calendar|int $calendar=NULL ): string
|
||||
{
|
||||
/* Load the calendar */
|
||||
$this->calendar = ( $calendar instanceof \IPS\calendar\Calendar ) ? $calendar : ( $calendar !== NULL ? \IPS\calendar\Calendar::load( $calendar ) : NULL );
|
||||
$this->calendar = ( $calendar instanceof Calendar ) ? $calendar : ( $calendar !== NULL ? Calendar::load( $calendar ) : NULL );
|
||||
|
||||
/* Start formatting the output */
|
||||
$output = "BEGIN:VCALENDAR\r\n";
|
||||
$output .= "VERSION:2.0\r\n";
|
||||
$output .= "PRODID:-//InvisionCommunity Events " . \IPS\Application::load( 'calendar' )->version . "//EN\r\n";
|
||||
$output .= "PRODID:-//InvisionCommunity Events " . Application::load( 'calendar' )->version . "//EN\r\n";
|
||||
$output .= "METHOD:PUBLISH\r\n";
|
||||
$output .= "CALSCALE:GREGORIAN\r\n";
|
||||
$output .= "REFRESH-INTERVAL:PT15M\r\n";
|
||||
@@ -656,9 +691,9 @@ class _ICSParser
|
||||
}
|
||||
else
|
||||
{
|
||||
$text = \IPS\Member::loggedIn()->language()->get('all_calendars');
|
||||
$output .= "X-WR-CALNAME:" . $this->_encodeSpecialCharacters( $text . ' - ' . \IPS\Settings::i()->board_name ) . "\r\n";
|
||||
$output .= "NAME:" . $this->_encodeSpecialCharacters( $text . ' - ' . \IPS\Settings::i()->board_name ) . "\r\n";
|
||||
$text = Member::loggedIn()->language()->get('all_calendars');
|
||||
$output .= "X-WR-CALNAME:" . $this->_encodeSpecialCharacters( $text . ' - ' . Settings::i()->board_name ) . "\r\n";
|
||||
$output .= "NAME:" . $this->_encodeSpecialCharacters( $text . ' - ' . Settings::i()->board_name ) . "\r\n";
|
||||
}
|
||||
|
||||
/* Add the time zones to the export */
|
||||
@@ -679,7 +714,7 @@ class _ICSParser
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _addTimezones()
|
||||
protected function _addTimezones(): string
|
||||
{
|
||||
/* Initialize */
|
||||
$output = '';
|
||||
@@ -687,7 +722,7 @@ class _ICSParser
|
||||
/* Get the years that all events span */
|
||||
$years = array();
|
||||
|
||||
if( \count( $this->_events ) )
|
||||
if( count( $this->_events ) )
|
||||
{
|
||||
foreach( $this->_events as $event )
|
||||
{
|
||||
@@ -718,14 +753,14 @@ class _ICSParser
|
||||
|
||||
$output .= "BEGIN:VTIMEZONE\r\n";
|
||||
$output .= "TZID:Europe/London\r\n";
|
||||
$output .= "TZURL:http://tzurl.org/zoneinfo/Europe/London\r\n";
|
||||
$output .= "TZURL:https://tzurl.org/zoneinfo/Europe/London\r\n";
|
||||
$output .= "X-LIC-LOCATION:Europe/London\r\n";
|
||||
|
||||
$output .= "BEGIN:DAYLIGHT\r\n";
|
||||
$output .= "TZOFFSETFROM:+0000\r\n";
|
||||
$output .= "TZOFFSETTO:+0100\r\n";
|
||||
$output .= "TZNAME:BST\r\n";
|
||||
$output .= "DTSTART:" . \IPS\calendar\Date::ts( $_daylight )->modifiedIso8601( TRUE, TRUE ) . "\r\n";
|
||||
$output .= "DTSTART:" . Date::ts( $_daylight )->modifiedIso8601( TRUE, TRUE ) . "\r\n";
|
||||
$output .= "RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU\r\n";
|
||||
$output .= "END:DAYLIGHT\r\n";
|
||||
|
||||
@@ -733,7 +768,7 @@ class _ICSParser
|
||||
$output .= "TZOFFSETFROM:+0100\r\n";
|
||||
$output .= "TZOFFSETTO:+0000\r\n";
|
||||
$output .= "TZNAME:GMT\r\n";
|
||||
$output .= "DTSTART:" . \IPS\calendar\Date::ts( $_standard )->modifiedIso8601( TRUE, TRUE ) . "\r\n";
|
||||
$output .= "DTSTART:" . Date::ts( $_standard )->modifiedIso8601( TRUE, TRUE ) . "\r\n";
|
||||
$output .= "RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU\r\n";
|
||||
$output .= "END:STANDARD\r\n";
|
||||
|
||||
@@ -747,12 +782,12 @@ class _ICSParser
|
||||
/**
|
||||
* Return a UID for iCalendar
|
||||
*
|
||||
* @param \IPS\calendar\Event $event Event
|
||||
* @param string
|
||||
* @param Event $event Event
|
||||
* @return string
|
||||
*/
|
||||
protected static function _buildUid( $event )
|
||||
protected static function _buildUid( Event $event ): string
|
||||
{
|
||||
$baseUrl = \IPS\Http\Url::internal('');
|
||||
$baseUrl = Url::internal('');
|
||||
return $event->id . '-' . $event->calendar_id . '-' . md5( (string) $baseUrl ) . '@' . $baseUrl->data['host'];
|
||||
}
|
||||
|
||||
@@ -761,30 +796,30 @@ class _ICSParser
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _addEvents()
|
||||
protected function _addEvents(): string
|
||||
{
|
||||
/* Basic Init */
|
||||
$output = '';
|
||||
|
||||
/* Loop over the events */
|
||||
if( \count( $this->_events ) )
|
||||
if( count( $this->_events ) )
|
||||
{
|
||||
foreach( $this->_events as $event )
|
||||
{
|
||||
/* Normal stuff */
|
||||
$output .= "BEGIN:VEVENT\r\n";
|
||||
$output .= "SUMMARY:" . $this->_encodeSpecialCharacters( $event->title ) . "\r\n";
|
||||
$output .= "DTSTAMP:" . \IPS\calendar\Date::ts( $event->saved )->modifiedIso8601( TRUE, TRUE ) . "\r\n";
|
||||
$output .= "DTSTAMP:" . Date::ts( $event->saved )->modifiedIso8601( TRUE, TRUE ) . "\r\n";
|
||||
$output .= "SEQUENCE:" . $event->sequence . "\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";
|
||||
$output .= $this->_foldLines( "ORGANIZER;CN=\"" . $this->_encodeSpecialCharacters( $event->author()->name, false ) . '":' . Settings::i()->email_out ) . "\r\n";
|
||||
|
||||
/* Attachments */
|
||||
$attachments = array();
|
||||
|
||||
preg_match_all( "/(http.+?attachment\.php\?id=(\d+))/i", $event->content, $matches );
|
||||
|
||||
if( \is_array($matches) AND \count($matches) )
|
||||
if( is_array($matches) AND count($matches) )
|
||||
{
|
||||
foreach( $matches[2] as $k => $v )
|
||||
{
|
||||
@@ -792,12 +827,12 @@ class _ICSParser
|
||||
}
|
||||
}
|
||||
|
||||
if( \count( $attachments ) )
|
||||
if( count( $attachments ) )
|
||||
{
|
||||
foreach( \IPS\Db::i()->select( '*', 'core_attachments', 'attach_id IN(' . implode( ',', array_keys( $attachments ) ) . ')' ) as $attachment )
|
||||
foreach( Db::i()->select( '*', 'core_attachments', 'attach_id IN(' . implode( ',', array_keys( $attachments ) ) . ')' ) as $attachment )
|
||||
{
|
||||
$file = \IPS\File::get( 'core_Attachment', $attachment['attach_location'] );
|
||||
$output .= "ATTACH;FMTTYPE=" . \IPS\File::getMimeType( $file->originalFilename ) . ":" . $attachments[ $attachment['attach_id'] ] . "\r\n";
|
||||
$file = File::get( 'core_Attachment', $attachment['attach_location'] );
|
||||
$output .= "ATTACH;FMTTYPE=" . File::getMimeType( $file->originalFilename ) . ":" . $attachments[ $attachment['attach_id'] ] . "\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -810,7 +845,7 @@ class _ICSParser
|
||||
if( $event->all_day )
|
||||
{
|
||||
$output .= "DTSTART;VALUE=DATE:" . $event->_start_date->modifiedIso8601( FALSE ) . "\r\n";
|
||||
$output .= "DTEND;VALUE=DATE:" . $event->_end_date->add( new \DateInterval( 'P1D' ) )->modifiedIso8601( FALSE ) . "\r\n";
|
||||
$output .= "DTEND;VALUE=DATE:" . $event->_end_date->add( new DateInterval( 'P1D' ) )->modifiedIso8601( FALSE ) . "\r\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -839,12 +874,12 @@ class _ICSParser
|
||||
/* Any attendees to the event? */
|
||||
try
|
||||
{
|
||||
foreach( $event->attendees( \IPS\calendar\Event::RSVP_YES ) as $attendee )
|
||||
foreach( $event->attendees( Event::RSVP_YES ) as $attendee )
|
||||
{
|
||||
$output .= $this->_foldLines( "ATTENDEE;CN=\"" . $this->_encodeSpecialCharacters( $attendee->name, false ) . '";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:' . \IPS\Settings::i()->email_out ) . "\r\n";
|
||||
$output .= $this->_foldLines( "ATTENDEE;CN=\"" . $this->_encodeSpecialCharacters( $attendee->name, false ) . '";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:' . Settings::i()->email_out ) . "\r\n";
|
||||
}
|
||||
}
|
||||
catch( \BadMethodCallException $e ){}
|
||||
catch( BadMethodCallException $e ){}
|
||||
|
||||
/* End */
|
||||
$output .= "END:VEVENT\r\n";
|
||||
@@ -858,11 +893,11 @@ class _ICSParser
|
||||
/**
|
||||
* Encode special characters in a string for iCalendar
|
||||
*
|
||||
* @param string $text String to encode
|
||||
* @param bool $lineFold Line-fold
|
||||
* @param string $text String to encode
|
||||
* @param bool $lineFold Line-fold
|
||||
* @return string Encoded string
|
||||
*/
|
||||
protected function _encodeSpecialCharacters( $text, $lineFold=true )
|
||||
protected function _encodeSpecialCharacters( string $text, bool $lineFold=true ): string
|
||||
{
|
||||
$text = strip_tags( str_replace( array( "<br>", "<br />" ), "\n", $text ) );
|
||||
$text = str_replace( "\\", "\\\\", $text );
|
||||
@@ -883,16 +918,16 @@ class _ICSParser
|
||||
/**
|
||||
* Fold lines per RFC2445
|
||||
*
|
||||
* @param string $text String to fold
|
||||
* @param string $text String to fold
|
||||
* @return string
|
||||
* @link https://gist.github.com/81747
|
||||
*/
|
||||
protected function _foldLines( $text )
|
||||
protected function _foldLines( string $text ): string
|
||||
{
|
||||
$return = array();
|
||||
$_extra = 15; /* Takes into account line beginning, i.e. "DESCRIPTION:" */
|
||||
|
||||
while( \strlen($text) > 60 )
|
||||
while( strlen($text) > 60 )
|
||||
{
|
||||
$space = 75 - $_extra; /* Remove line beginning - subsequent loops this will be tab character */
|
||||
$mbcc = $space;
|
||||
@@ -900,7 +935,7 @@ class _ICSParser
|
||||
while( $mbcc )
|
||||
{
|
||||
$line = mb_substr( $text, 0, $mbcc ); /* Get first chunk of chars */
|
||||
$octet = \strlen( $line ); /* Determine how long this really is (3-byte letters could triple the size) */
|
||||
$octet = strlen( $line ); /* Determine how long this really is (3-byte letters could triple the size) */
|
||||
|
||||
/* Too long ? */
|
||||
if( $octet > $space )
|
||||
@@ -937,38 +972,38 @@ class _ICSParser
|
||||
/**
|
||||
* @brief Type of begin block we are currently parsing
|
||||
*/
|
||||
protected $_begin = '';
|
||||
protected string $_begin = '';
|
||||
|
||||
/**
|
||||
* @brief Raw iCalendar feed data after parsing
|
||||
*/
|
||||
protected $_parsedIcsData = array();
|
||||
protected array $_parsedIcsData = array();
|
||||
|
||||
/**
|
||||
* @brief Raw iCalendar data before parsing
|
||||
*/
|
||||
protected $_rawIcsData = array();
|
||||
protected array $_rawIcsData = array();
|
||||
|
||||
/**
|
||||
* @brief Earliest timestamp from feed
|
||||
*/
|
||||
protected $_feedEarliest = 0;
|
||||
protected int $_feedEarliest = 0;
|
||||
|
||||
/**
|
||||
* @brief Latest timestamp from feed
|
||||
*/
|
||||
protected $_feedLatest = 0;
|
||||
protected int $_feedLatest = 0;
|
||||
|
||||
/**
|
||||
* Un-encode special characters in a string coming from iCalendar feed
|
||||
*
|
||||
* @param string $text String to unencode
|
||||
* @param string $text String to unencode
|
||||
* @return string Unencoded string
|
||||
*/
|
||||
protected function _unencodeSpecialCharacters( $text )
|
||||
protected function _unencodeSpecialCharacters( string $text ): string
|
||||
{
|
||||
/* Reverse encoding */
|
||||
if( \stripos( $text, 'encoding=' ) === 0 )
|
||||
if( stripos( $text, 'encoding=' ) === 0 )
|
||||
{
|
||||
preg_match( "#encoding=(.+?):(.+?)$#i", $text, $matches );
|
||||
|
||||
@@ -1003,11 +1038,11 @@ class _ICSParser
|
||||
/**
|
||||
* Unfold lines per RFC2445 4.1
|
||||
*
|
||||
* @param string $string Starting string
|
||||
* @param int $line Starting line number
|
||||
* @param string $string Starting string
|
||||
* @param int $line Starting line number
|
||||
* @return string
|
||||
*/
|
||||
protected function _unfoldLines( $string, $line )
|
||||
protected function _unfoldLines( string $string, int $line ): string
|
||||
{
|
||||
/* Recursively unfold lines as needed */
|
||||
if( isset( $this->_rawIcsData[ $line + 1 ] ) AND ( mb_substr( $this->_rawIcsData[ $line + 1 ], 0, 1 ) == ' ' OR mb_substr( $this->_rawIcsData[ $line + 1 ], 0, 1 ) == "\t" ) )
|
||||
@@ -1022,10 +1057,10 @@ class _ICSParser
|
||||
/**
|
||||
* Unparse time information from iCalendar datetime info
|
||||
*
|
||||
* @param string $string iCalendar line
|
||||
* @param string $string iCalendar line
|
||||
* @return array Time information
|
||||
*/
|
||||
protected function _unparseTimeInfo( $string )
|
||||
protected function _unparseTimeInfo( string $string ): array
|
||||
{
|
||||
/* init */
|
||||
$value = NULL;
|
||||
@@ -1089,11 +1124,11 @@ class _ICSParser
|
||||
/**
|
||||
* Parse a 'BEGIN:' block in an iCalendar feed
|
||||
*
|
||||
* @param string $type Type of 'BEGIN' object
|
||||
* @param int $start Line number
|
||||
* @param string $type Type of 'BEGIN' object
|
||||
* @param int $start Line number
|
||||
* @return void
|
||||
*/
|
||||
protected function _parseBeginBlock( $type, $start )
|
||||
protected function _parseBeginBlock( string $type, int $start ) : void
|
||||
{
|
||||
switch( $type )
|
||||
{
|
||||
@@ -1123,15 +1158,15 @@ class _ICSParser
|
||||
/**
|
||||
* @brief Keep track of object we are parsing inside an event object
|
||||
*/
|
||||
protected $currentlyParsing = NULL;
|
||||
protected ?string $currentlyParsing = NULL;
|
||||
|
||||
/**
|
||||
* Parse event object in an ical feed
|
||||
*
|
||||
* @param int $start Line number
|
||||
* @param int $start Line number
|
||||
* @return void
|
||||
*/
|
||||
protected function _processEventObject( $start )
|
||||
protected function _processEventObject( int $start ) : void
|
||||
{
|
||||
/* Init */
|
||||
$_break = false;
|
||||
@@ -1142,7 +1177,7 @@ class _ICSParser
|
||||
/* Loop over the lines */
|
||||
$_recid = null;
|
||||
|
||||
for( $i = $start, $j = \count( $this->_rawIcsData ); $i < $j; $i++ )
|
||||
for( $i = $start, $j = count( $this->_rawIcsData ); $i < $j; $i++ )
|
||||
{
|
||||
/* Unparse and get content */
|
||||
$tmp = $this->_unparseContent( $this->_rawIcsData[$i], $i );
|
||||
@@ -1155,7 +1190,7 @@ class _ICSParser
|
||||
$_type = $tmp['type'];
|
||||
$_data = $tmp['data'];
|
||||
|
||||
if( $this->currentlyParsing != 'EVENT' AND !\in_array( $_type, array( 'END', 'BEGIN' ) ) )
|
||||
if( $this->currentlyParsing != 'EVENT' AND !in_array( $_type, array( 'END', 'BEGIN' ) ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -1258,7 +1293,7 @@ class _ICSParser
|
||||
break;
|
||||
|
||||
case 'SEQUENCE':
|
||||
$_event['sequence'] = \intval($_data);
|
||||
$_event['sequence'] = intval($_data);
|
||||
break;
|
||||
|
||||
case 'RRULE':
|
||||
@@ -1302,13 +1337,13 @@ class _ICSParser
|
||||
/**
|
||||
* Parse core vcalendar object in an ical feed
|
||||
*
|
||||
* @param int $start Line number
|
||||
* @param int $start Line number
|
||||
* @return void
|
||||
*/
|
||||
protected function _processVcalendarObject( $start )
|
||||
protected function _processVcalendarObject( int $start ) : void
|
||||
{
|
||||
/* Loop over the lines */
|
||||
for( $i = $start, $j = \count( $this->_rawIcsData ); $i < $j; $i++ )
|
||||
for( $i = $start, $j = count( $this->_rawIcsData ); $i < $j; $i++ )
|
||||
{
|
||||
/* Unparse and get the data */
|
||||
$tmp = $this->_unparseContent( $this->_rawIcsData[$i], $i );
|
||||
@@ -1341,7 +1376,6 @@ class _ICSParser
|
||||
|
||||
case 'END':
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1349,14 +1383,14 @@ class _ICSParser
|
||||
/**
|
||||
* Unformat content from incoming ical feed
|
||||
*
|
||||
* @param string $string String content to unparse
|
||||
* @param int $line Line number
|
||||
* @param string $string String content to unparse
|
||||
* @param int $line Line number
|
||||
* @return mixed Array of data, or false
|
||||
*/
|
||||
protected function _unparseContent( $string, $line )
|
||||
protected function _unparseContent( string $string, int $line ): mixed
|
||||
{
|
||||
/* If the line starts with a space it was folded (skip it) */
|
||||
if( \substr( $this->_rawIcsData[ $line ], 0, 1 ) == ' ' )
|
||||
if( substr( $this->_rawIcsData[ $line ], 0, 1 ) == ' ' )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -1376,13 +1410,13 @@ class _ICSParser
|
||||
/**
|
||||
* Convert times to GMT based on timezones
|
||||
*
|
||||
* @param array $data Parsed data
|
||||
* @param array $data Parsed data
|
||||
* @return array
|
||||
*/
|
||||
protected function _convertToGmt( $data )
|
||||
protected function _convertToGmt( array $data ): array
|
||||
{
|
||||
/* Fix events */
|
||||
if ( isset( $data['events'] ) AND \is_array( $data['events'] ) AND \count( $data['events'] ) )
|
||||
if ( isset( $data['events'] ) AND is_array( $data['events'] ) AND count( $data['events'] ) )
|
||||
{
|
||||
foreach( $data['events'] as $id => $event )
|
||||
{
|
||||
@@ -1394,20 +1428,20 @@ class _ICSParser
|
||||
/* Let's test it first... */
|
||||
$timezone = NULL;
|
||||
|
||||
if( \in_array( $event[ $method ]['tzid'], \IPS\DateTime::getTimezoneIdentifiers() ) )
|
||||
if( in_array( $event[ $method ]['tzid'], DateTime::getTimezoneIdentifiers() ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$timezone = new \DateTimeZone( $event[ $method ]['tzid'] );
|
||||
$timezone = new DateTimeZone( $event[ $method ]['tzid'] );
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
catch ( Exception $e ) {}
|
||||
}
|
||||
|
||||
$event[ $method ]['utc_time'] = new \IPS\DateTime( $event[ $method ]['raw'], $timezone );
|
||||
$event[ $method ]['utc_time'] = new DateTime( $event[ $method ]['raw'], $timezone );
|
||||
}
|
||||
elseif( isset( $event[ $method ]['raw'] ) )
|
||||
{
|
||||
$event[ $method ]['utc_time'] = new \IPS\DateTime( $event[ $method ]['raw'] );
|
||||
$event[ $method ]['utc_time'] = new DateTime( $event[ $method ]['raw'] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,38 +12,47 @@
|
||||
namespace IPS\calendar;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use IPS\calendar\Icalendar\ICSParser;
|
||||
use IPS\Db;
|
||||
use IPS\Http\Url;
|
||||
use IPS\Patterns\ActiveRecord;
|
||||
use OutOfRangeException;
|
||||
use UnexpectedValueException;
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* iCalendar active record
|
||||
*/
|
||||
class _Icalendar extends \IPS\Patterns\ActiveRecord
|
||||
class Icalendar extends ActiveRecord
|
||||
{
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
protected static array $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'calendar_import_feeds';
|
||||
public static ?string $databaseTable = 'calendar_import_feeds';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'feed_';
|
||||
public static string $databasePrefix = 'feed_';
|
||||
|
||||
/**
|
||||
* Set Default Values
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setDefaultValues()
|
||||
public function setDefaultValues() : void
|
||||
{
|
||||
$this->added = time();
|
||||
$this->lastupdated = time();
|
||||
@@ -53,18 +62,18 @@ class _Icalendar extends \IPS\Patterns\ActiveRecord
|
||||
/**
|
||||
* Reimport iCalendar events
|
||||
*
|
||||
* @return int
|
||||
* @throws \UnexpectedValueException
|
||||
* @return array
|
||||
* @throws UnexpectedValueException
|
||||
* @note PHP installs do not (at least typically) have stream wrappers for webcal://, so we have to change the scheme to http://
|
||||
*/
|
||||
public function refresh()
|
||||
public function refresh(): array
|
||||
{
|
||||
$this->last_run = time();
|
||||
$this->save();
|
||||
|
||||
$icsParser = new \IPS\calendar\Icalendar\ICSParser;
|
||||
$icsParser = new ICSParser;
|
||||
|
||||
return $icsParser->parse( \IPS\Http\Url::external( str_replace( array( 'webcal://', 'webcals://' ), array( 'http://', 'https://' ), $this->url ) )->request()->get(), $this->calendar_id, $this->member_id, $this->id, $this->venue_id );
|
||||
return $icsParser->parse( Url::external( str_replace( array( 'webcal://', 'webcals://' ), array( 'http://', 'https://' ), $this->url ) )->request()->get(), $this->calendar_id, $this->member_id, $this->id, $this->venue_id );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,28 +81,28 @@ class _Icalendar extends \IPS\Patterns\ActiveRecord
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deleteFeedEvents()
|
||||
public function deleteFeedEvents() : void
|
||||
{
|
||||
/* Looping over all event IDs this feed has imported, delete them */
|
||||
foreach( \IPS\Db::i()->select( '*', 'calendar_import_map', array( 'import_feed_id=?', $this->id ) ) as $mappedEvent )
|
||||
foreach( Db::i()->select( '*', 'calendar_import_map', array( 'import_feed_id=?', $this->id ) ) as $mappedEvent )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\calendar\Event::load( $mappedEvent['import_event_id'] )->delete();
|
||||
Event::load( $mappedEvent['import_event_id'] )->delete();
|
||||
}
|
||||
/* An out of range exception means the event no longer exists, so we can ignore the exception in this case */
|
||||
catch( \OutOfRangeException $e ){ }
|
||||
catch( OutOfRangeException $e ){ }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [ActiveRecord] Delete Record
|
||||
*
|
||||
* @return void
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
public function delete(): void
|
||||
{
|
||||
\IPS\Db::i()->delete( 'calendar_import_map', array( 'import_feed_id=?', $this->id ) );
|
||||
return parent::delete();
|
||||
Db::i()->delete( 'calendar_import_map', array( 'import_feed_id=?', $this->id ) );
|
||||
parent::delete();
|
||||
}
|
||||
}
|
||||
@@ -12,51 +12,65 @@
|
||||
namespace IPS\calendar;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use BadMethodCallException;
|
||||
use IPS\File;
|
||||
use IPS\GeoLocation;
|
||||
use IPS\Helpers\Form;
|
||||
use IPS\Helpers\Form\Address;
|
||||
use IPS\Helpers\Form\Translatable;
|
||||
use IPS\Http\Url\Friendly;
|
||||
use IPS\Lang;
|
||||
use IPS\Member;
|
||||
use IPS\Node\Model;
|
||||
use IPS\Request;
|
||||
use function defined;
|
||||
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calendar Node
|
||||
*/
|
||||
class _Venue extends \IPS\Node\Model
|
||||
class Venue extends Model
|
||||
{
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
protected static array $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'calendar_venues';
|
||||
public static ?string $databaseTable = 'calendar_venues';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'venue_';
|
||||
public static string $databasePrefix = 'venue_';
|
||||
|
||||
/**
|
||||
* @brief [Node] Order Database Column
|
||||
*/
|
||||
public static $databaseColumnOrder = 'position';
|
||||
public static ?string $databaseColumnOrder = 'position';
|
||||
|
||||
/**
|
||||
* @brief [Node] Node Title
|
||||
*/
|
||||
public static $nodeTitle = 'venues';
|
||||
public static string $nodeTitle = 'venues';
|
||||
|
||||
/**
|
||||
* @brief URL Base
|
||||
*/
|
||||
public static $urlTemplate = 'calendar_venue';
|
||||
public static string $urlTemplate = 'calendar_venue';
|
||||
|
||||
/**
|
||||
* @brief URL Base
|
||||
*/
|
||||
public static $urlBase = 'app=calendar&module=calendar&controller=venue&id=';
|
||||
public static string $urlBase = 'app=calendar&module=calendar&controller=venue&id=';
|
||||
|
||||
/**
|
||||
* @brief [Node] ACP Restrictions
|
||||
@@ -74,36 +88,43 @@ class _Venue extends \IPS\Node\Model
|
||||
'prefix' => 'foo_', // [Optional] Rather than specifying each key in the map, you can specify a prefix, and it will automatically look for restrictions with the key "[prefix]_add/edit/permissions/delete"
|
||||
* @endcode
|
||||
*/
|
||||
protected static $restrictions = array(
|
||||
protected static ?array $restrictions = array(
|
||||
'app' => 'calendar',
|
||||
'module' => 'calendars',
|
||||
'all' => 'venues_manage'
|
||||
'module' => 'venues',
|
||||
'prefix' => 'venues_'
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
|
||||
*/
|
||||
public static $titleLangPrefix = 'calendar_venue_';
|
||||
public static ?string $titleLangPrefix = 'calendar_venue_';
|
||||
|
||||
/**
|
||||
* @brief [Node] Description suffix. If specified, will look for a language key with "{$titleLangPrefix}_{$id}_{$descriptionLangSuffix}" as the key
|
||||
*/
|
||||
public static $descriptionLangSuffix = '_desc';
|
||||
public static ?string $descriptionLangSuffix = '_desc';
|
||||
|
||||
/**
|
||||
* @brief [Node] Moderator Permission
|
||||
*/
|
||||
public static $modPerm = 'calendar_venues';
|
||||
public static string $modPerm = 'calendar_venues';
|
||||
|
||||
/**
|
||||
* @brief [Node] Maximum results to display at a time in any node helper form elements. Useful for user-submitted node types when there may be a lot. NULL for no limit.
|
||||
*/
|
||||
public static $maxFormHelperResults = 2000;
|
||||
public static ?int $maxFormHelperResults = 2000;
|
||||
|
||||
/**
|
||||
* @brief The class of the ACP \IPS\Node\Controller that manages this node type
|
||||
*/
|
||||
protected static $acpController = "IPS\\calendar\\modules\\admin\\calendars\\venues";
|
||||
protected static ?string $acpController = "IPS\\calendar\\modules\\admin\\calendars\\venues";
|
||||
|
||||
/**
|
||||
* Determines if this class can be extended via UI Extension
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static bool $canBeExtended = true;
|
||||
|
||||
/**
|
||||
* [Node] Get whether or not this node is enabled
|
||||
@@ -111,7 +132,7 @@ class _Venue extends \IPS\Node\Model
|
||||
* @note Return value NULL indicates the node cannot be enabled/disabled
|
||||
* @return bool|null
|
||||
*/
|
||||
protected function get__enabled()
|
||||
protected function get__enabled(): ?bool
|
||||
{
|
||||
return (bool) $this->enabled;
|
||||
}
|
||||
@@ -122,7 +143,7 @@ class _Venue extends \IPS\Node\Model
|
||||
* @param bool|int $enabled Whether to set it enabled or disabled
|
||||
* @return void
|
||||
*/
|
||||
protected function set__enabled( $enabled )
|
||||
protected function set__enabled( bool|int $enabled ): void
|
||||
{
|
||||
$this->enabled = $enabled;
|
||||
}
|
||||
@@ -130,35 +151,37 @@ class _Venue extends \IPS\Node\Model
|
||||
/**
|
||||
* @brief Cached URL
|
||||
*/
|
||||
protected $_url = NULL;
|
||||
protected mixed $_url = NULL;
|
||||
|
||||
/**
|
||||
* Get SEO name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_title_seo()
|
||||
public function get_title_seo(): string
|
||||
{
|
||||
if( !$this->_data['title_seo'] )
|
||||
{
|
||||
$this->title_seo = \IPS\Http\Url\Friendly::seoTitle( \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( 'calendar_venue_' . $this->id ) );
|
||||
$this->title_seo = Friendly::seoTitle( Lang::load( Lang::defaultLanguage() )->get( 'calendar_venue_' . $this->id ) );
|
||||
$this->save();
|
||||
}
|
||||
|
||||
return $this->_data['title_seo'] ?: \IPS\Http\Url\Friendly::seoTitle( \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( 'calendar_venue_' . $this->id ) );
|
||||
return $this->_data['title_seo'] ?: Friendly::seoTitle( Lang::load( Lang::defaultLanguage() )->get( 'calendar_venue_' . $this->id ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Add/Edit Form
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @param Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function form( &$form )
|
||||
public function form( Form &$form ) : void
|
||||
{
|
||||
$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' => ( $this->id and $this->address ) ? FALSE : TRUE, 'requireFullAddress' => FALSE, 'preselectCountry' => FALSE ), NULL, NULL, NULL, 'venue_address' ) );
|
||||
$form->add( new Translatable( 'venue_title', NULL, TRUE, array( 'app' => 'calendar', 'key' => ( $this->id ? "calendar_venue_{$this->id}" : NULL ) ) ) );
|
||||
$form->add( new 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 Address( 'venue_address', $this->id ? GeoLocation::buildFromJson( $this->address ) : NULL, TRUE, array( 'minimize' => !( ( $this->id and $this->address ) ), 'requireFullAddress' => FALSE, 'preselectCountry' => FALSE ), NULL, NULL, NULL, 'venue_address' ) );
|
||||
|
||||
parent::form( $form );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,32 +190,32 @@ class _Venue extends \IPS\Node\Model
|
||||
* @param array $values Values from the form
|
||||
* @return array
|
||||
*/
|
||||
public function formatFormValues( $values )
|
||||
public function formatFormValues( array $values ): array
|
||||
{
|
||||
if ( !$this->id )
|
||||
{
|
||||
$this->save();
|
||||
\IPS\File::claimAttachments( 'calendar-new-venue', $this->id, NULL, 'description', TRUE );
|
||||
File::claimAttachments( 'calendar-new-venue', $this->id, NULL, 'description', TRUE );
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ( \IPS\Lang::languages() as $lang )
|
||||
foreach ( Lang::languages() as $lang )
|
||||
{
|
||||
\IPS\Request::i()->setClearAutosaveCookie( "calendar-venue-{$this->id}{$lang->id}" );
|
||||
Request::i()->setClearAutosaveCookie( "calendar-venue-{$this->id}{$lang->id}" );
|
||||
}
|
||||
}
|
||||
|
||||
if( isset( $values['venue_title'] ) )
|
||||
{
|
||||
\IPS\Lang::saveCustom( 'calendar', 'calendar_venue_' . $this->id, $values['venue_title'] );
|
||||
$values['title_seo'] = \IPS\Http\Url\Friendly::seoTitle( $values['venue_title'][ \IPS\Lang::defaultLanguage() ] );
|
||||
Lang::saveCustom( 'calendar', 'calendar_venue_' . $this->id, $values['venue_title'] );
|
||||
$values['title_seo'] = Friendly::seoTitle( $values['venue_title'][ Lang::defaultLanguage() ] );
|
||||
|
||||
unset( $values['venue_title'] );
|
||||
}
|
||||
|
||||
if( isset( $values['venue_description'] ) )
|
||||
{
|
||||
\IPS\Lang::saveCustom( 'calendar', 'calendar_venue_' . $this->id .'_desc', $values['venue_description'] );
|
||||
Lang::saveCustom( 'calendar', 'calendar_venue_' . $this->id .'_desc', $values['venue_description'] );
|
||||
unset( $values['venue_description'] );
|
||||
}
|
||||
|
||||
@@ -204,19 +227,19 @@ class _Venue extends \IPS\Node\Model
|
||||
/**
|
||||
* @brief SEO Title Column
|
||||
*/
|
||||
public static $seoTitleColumn = 'title_seo';
|
||||
public static string $seoTitleColumn = 'title_seo';
|
||||
|
||||
/**
|
||||
* [ActiveRecord] Delete Record
|
||||
*
|
||||
* @return void
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
public function delete(): void
|
||||
{
|
||||
\IPS\Lang::deleteCustom( 'calendar', 'calendar_venue_' . $this->id );
|
||||
\IPS\Lang::deleteCustom( 'calendar', 'calendar_venue_' . $this->id . '_desc' );
|
||||
Lang::deleteCustom( 'calendar', 'calendar_venue_' . $this->id );
|
||||
Lang::deleteCustom( 'calendar', 'calendar_venue_' . $this->id . '_desc' );
|
||||
|
||||
return parent::delete();
|
||||
parent::delete();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,15 +250,15 @@ class _Venue extends \IPS\Node\Model
|
||||
* @return string
|
||||
* @note \BadMethodCallException can be thrown if the google maps integration is shut off - don't show any error if that happens.
|
||||
*/
|
||||
public function map( $width, $height )
|
||||
public function map( int $width, int $height ): string
|
||||
{
|
||||
if( $this->address )
|
||||
{
|
||||
try
|
||||
{
|
||||
return \IPS\GeoLocation::buildFromJson( $this->address )->map()->render( $width, $height );
|
||||
return GeoLocation::buildFromJson( $this->address )->map()->render( $width, $height );
|
||||
}
|
||||
catch( \BadMethodCallException $e ){}
|
||||
catch( BadMethodCallException $e ){}
|
||||
}
|
||||
|
||||
return '';
|
||||
@@ -244,20 +267,20 @@ class _Venue extends \IPS\Node\Model
|
||||
/**
|
||||
* Get output for API
|
||||
*
|
||||
* @param \IPS\Member|NULL $authorizedMember The member making the API request or NULL for API Key / client_credentials
|
||||
* @param 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 string description Description
|
||||
* @apiresponse \IPS\GeoLocation address The address
|
||||
*/
|
||||
public function apiOutput( \IPS\Member $authorizedMember = NULL )
|
||||
public function apiOutput( Member $authorizedMember = NULL ): array
|
||||
{
|
||||
return array(
|
||||
'id' => $this->id,
|
||||
'title' => $this->_title,
|
||||
'description' => \IPS\Member::loggedIn()->language()->addToStack('calendar_venue_' . $this->id . '_desc', NULL, array( 'removeLazyLoad' => true ) ),
|
||||
'address' => \IPS\GeoLocation::buildFromJson( $this->address )->apiOutput( $authorizedMember )
|
||||
'description' => Member::loggedIn()->language()->addToStack('calendar_venue_' . $this->id . '_desc' ),
|
||||
'address' => GeoLocation::buildFromJson( $this->address )->apiOutput( $authorizedMember )
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user