Files
server/usr/share/psa-horde/kronolith/lib/CalendarsManager.php
2026-01-07 20:52:11 +01:00

622 lines
22 KiB
PHP

<?php
/**
* Copyright 2013-2017 Horde LLC (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (GPL). If you
* did not receive this file, see http://www.horde.org/licenses/gpl.
*
* @author Michael J Rubinsky <mrubinsk@horde.org>
* @license http://www.horde.org/licenses/gpl GPL
* @package Kronolith
* @category Horde
*/
/**
* Handles management of the various global calendar lists.
*
* @author Michael J Rubinsky <mrubinsk@horde.org>
* @license http://www.horde.org/licenses/gpl GPL
* @package Kronolith
* @category Horde
*/
class Kronolith_CalendarsManager
{
/**
* List of all available internal calendars.
*
* @var array
*/
protected $_allCalendars = array();
/**
* List of all available remote calendars.
*
* @var array
*/
protected $_allRemote = false;
/**
* List of all available external calendars.
*
* @var array
*/
protected $_allExternal = false;
/**
* List of all available Holiday calendars.
*
* @var array
*/
protected $_allHolidays = false;
/**
* List of all internal calendars that are currently selected to be visible.
*
* @var array
*/
protected $_displayCalendars;
/**
* List of remote calendars selected for display.
*
* @var array
*/
protected $_displayRemote;
/**
* List of resource calendars selected for display.
*
* @var array
*/
protected $_displayResource;
/**
* Lazy loaded list of all resource calendars.
*
* @var array.
*/
protected $_allResource = false;
/**
* List of holiday calendars selected for display. Used internally to hold
* the user prefs for displayed holiday calendars before we need to see
* if they are all available.
*
* @var array
*/
protected $_displayHolidaysInternal = array();
/**
* List of all holidays selected for display.
*
* @var array
*/
protected $_displayHolidays = false;
/**
* List of external (listTimeObjects) calendars selected for display.
*
* @var array
*/
protected $_displayExternal = false;
/**
* Const'r
* Sets up various display lists and session variables:
*
* Always set:
* - allCalendars
* - displayCalendars
* - displayResource
*
* Lazy loaded:
* - allRemote
* - allExternal
* - allHolidays
* - allResource
* - displayRemote
* - displayExternal
* - displayHolidays
*
* @param string $user The user to initialize for, if not the current.
* @since 4.2.4
*/
public function __construct($user = null)
{
$emptyUser = false;
if (empty($user)) {
$user = $GLOBALS['registry']->getAuth();
$emptyUser = true;
}
// Always perform the display related checks.
$this->_checkDisplayCals();
$this->_checkToggleCalendars();
// Check that all selected shares still exist.
foreach (Kronolith::listInternalCalendars(false, Horde_Perms::SHOW, $user) as $id => $calendar) {
$this->_allCalendars[$id] = new Kronolith_Calendar_Internal(array('share' => $calendar));
}
$this->_displayCalendars = array_intersect($this->_displayCalendars, array_keys($this->_allCalendars));
// Check that the user owns a calendar if we aren't loading a different
// user.
if ($emptyUser) {
$this->_checkForOwnedCalendar();
}
}
/**
* Return the requested list.
*
* @param string $list A Kronolith:: calendar manager constant.
*
* @return array
*/
public function get($list)
{
switch ($list) {
case Kronolith::ALL_CALENDARS:
case Kronolith::DISPLAY_CALENDARS:
case Kronolith::DISPLAY_RESOURCE_CALENDARS:
$property = '_' . $list;
return $this->$property;
//Lazy loaded
case Kronolith::ALL_RESOURCE_CALENDARS:
if ($this->_allResource !== false) {
return $this->_allResource;
}
return $this->_getAllResource();
case Kronolith::ALL_REMOTE_CALENDARS:
if ($this->_allRemote !== false) {
return $this->_allRemote;
}
return $this->_getRemoteCalendars();
case Kronolith::DISPLAY_REMOTE_CALENDARS:
// Need to run this at least once to validate remote calendars
// still exist in prefs.
if ($this->_allRemote === false) {
$this->_getRemoteCalendars();
}
return $this->_displayRemote;
case Kronolith::ALL_EXTERNAL_CALENDARS:
if ($this->_allExternal !== false) {
return $this->_allExternal;
}
return $this->_getAllExternal();
case Kronolith::DISPLAY_EXTERNAL_CALENDARS:
if ($this->_displayExternal !== false) {
return $this->_displayExternal;
}
return $this->_getDisplayExternal();
case Kronolith::ALL_HOLIDAYS:
if ($this->_allHolidays !== false) {
return $this->_allHolidays;
}
return $this->_getAllHolidays();
case Kronolith::DISPLAY_HOLIDAYS:
if ($this->_displayHolidays !== false) {
return $this->_displayHolidays;
}
return $this->_getDisplayHolidays();
}
}
/**
* Set or replace an existing list with $value.
*
* @param string $list The list to set.
* @param array $value The value to set it to.
*/
public function set($list, array $value)
{
$property = '_' . $list;
$this->$property = $value;
}
/**
* Shortcut method for obtaining a single entry in one of the calendar lists
*
* @param string $list The calendar list to obtain an entry from.
* @param string $entry The entry to retrieve.
*
* @return mixed The requested value | false if not found.
*/
public function getEntry($list, $entry)
{
$temp = $this->get($list);
if (isset($temp[$entry])) {
return $temp[$entry];
}
return false;
}
/**
* Update display preferences
*/
protected function _checkDisplayCals()
{
global $session, $prefs, $conf;
// Update preferences for which calendars to display. If the
// user doesn't have any selected calendars to view then fall
// back to an available calendar. An empty string passed in this
// parameter will clear any existing session value.
if (($calId = Horde_Util::getFormData('display_cal')) !== null) {
$session->set('kronolith', 'display_cal', $calId);
} else {
$calId = $session->get('kronolith', 'display_cal');
}
if (strlen($calId)) {
// Specifying a value for display_cal is always to make sure
// that only the specified calendars are shown. Use the
// "toggle_calendar" argument to toggle the state of a single
// calendar.
$this->_displayCalendars = array();
$this->_displayRemote = array();
$this->_displayExternal = array();
$this->_displayResource = array();
$this->_displayHolidaysInternal = array();
if (strncmp($calId, 'remote_', 7) === 0) {
$this->_displayRemote[] = substr($calId, 7);
} elseif (strncmp($calId, 'external_', 9) === 0) {
$this->_displayExternal[] = substr($calId, 9);
} elseif (strncmp($calId, 'resource_', 9) === 0) {
$this->_displayResource[] = substr($calId, 9);
} elseif (strncmp($calId, 'holidays_', 9) === 0) {
$this->_displayHolidaysInternal[] = substr($calId, 9);
} else {
$this->_displayCalendars[] = (strncmp($calId, 'internal_', 9) === 0)
? substr($calId, 9)
: $calId;
}
} else {
// Fetch display preferences.
$display_prefs = array(
'display_cals' => 'displayCalendars',
'display_remote_cals' => 'displayRemote',
'display_external_cals' => 'displayExternal',
'holiday_drivers' => 'displayHolidaysInternal',
'display_resource_cals' => 'displayResource'
);
foreach ($display_prefs as $key => $val) {
$pref_val = @unserialize($prefs->getValue($key));
$val = '_' . $val;
$this->$val = is_array($pref_val)
? $pref_val
: array();
}
// Run through getDisplayExternal to trim any that no longer exist.
$this->_getDisplayExternal();
if (empty($conf['holidays']['enable'])) {
$this->_displayHolidays = array();
$this->_displayHolidaysInternal = array();
}
}
}
/**
* Check for single, "toggle" calendars and set display lists and
* session values appropriately.
*/
protected function _checkToggleCalendars()
{
global $prefs, $registry;
if (($calId = Horde_Util::getFormData('toggle_calendar')) !== null) {
if (strncmp($calId, 'remote_', 7) === 0) {
$calId = substr($calId, 7);
if (($key = array_search($calId, $this->_displayRemote)) === false) {
$this->_displayRemote[] = $calId;
} else {
unset($this->_displayRemote[$key]);
}
$prefs->setValue('display_remote_cals', serialize($this->_displayRemote));
} elseif ((strncmp($calId, 'external_', 9) === 0 &&
($calId = substr($calId, 9))) ||
(strncmp($calId, 'tasklists_', 10) === 0 &&
($calId = substr($calId, 10)))) {
if (($key = array_search($calId, $this->_displayExternal)) === false) {
$this->_displayExternal[] = $calId;
} else {
unset($this->_displayExternal[$key]);
}
$prefs->setValue('display_external_cals', serialize($this->_displayExternal));
if (strpos($calId, 'tasks/') === 0) {
$tasklists = array();
foreach ($this->_displayExternal as $id) {
if (strpos($id, 'tasks/') === 0) {
$tasklists[] = substr($id, 6);
}
}
try {
$registry->tasks->setDisplayedTasklists($tasklists);
} catch (Horde_Exception $e) {}
}
} elseif (strncmp($calId, 'holiday_', 8) === 0) {
$calId = substr($calId, 8);
if (($key = array_search($calId, $this->_displayHolidaysInternal)) === false) {
$this->_displayHolidaysInternal[] = $calId;
} else {
unset($this->_displayHolidaysInternal[$key]);
}
$prefs->setValue('holiday_drivers', serialize($this->_displayHolidaysInternal));
} elseif (strncmp($calId, 'resource_', 9) === 0) {
$calId = substr($calId, 9);
if (($key = array_search($calId, $this->_displayResource)) === false) {
$this->_displayResource[] = $calId;
} else {
unset($this->_displayResource[$key]);
}
$prefs->setValue('display_resource_cals', serialize($this->_displayResource));
} elseif (($key = array_search($calId, $this->_displayCalendars)) === false) {
$this->_displayCalendars[] = $calId;
} else {
unset($this->_displayCalendars[$key]);
}
$prefs->setValue('display_cals', serialize($this->_displayCalendars));
}
}
/**
* Check that the user owns a calendar and if not, creates one.
*/
protected function _checkForOwnedCalendar()
{
global $prefs, $registry, $conf;
if (!empty($conf['share']['auto_create']) &&
$registry->getAuth() &&
!count(Kronolith::listInternalCalendars(true))) {
$calendars = $GLOBALS['injector']
->getInstance('Kronolith_Factory_Calendars')
->create();
$share = $calendars->createDefaultShare();
$this->_allCalendars[$share->getName()] = new Kronolith_Calendar_Internal(array('share' => $share));
$this->_displayCalendars[] = $share->getName();
$prefs->setValue('default_share', $share->getName());
// Calendar auto-sharing with the user's groups
if ($conf['autoshare']['shareperms'] != 'none') {
$perm_value = 0;
switch ($conf['autoshare']['shareperms']) {
case 'read':
$perm_value = Horde_Perms::READ | Horde_Perms::SHOW;
break;
case 'edit':
$perm_value = Horde_Perms::READ | Horde_Perms::SHOW | Horde_Perms::EDIT;
break;
case 'full':
$perm_value = Horde_Perms::READ | Horde_Perms::SHOW | Horde_Perms::EDIT | Horde_Perms::DELETE;
break;
}
try {
$group_list = $GLOBALS['injector']
->getInstance('Horde_Group')
->listGroups($registry->getAuth());
if (count($group_list)) {
$perm = $share->getPermission();
// Add the default perm, not added otherwise
foreach (array_keys($group_list) as $group_id) {
$perm->addGroupPermission($group_id, $perm_value, false);
}
$share->setPermission($perm);
$GLOBALS['notification']->push(sprintf(_("New calendar created and automatically shared with the following group(s): %s."), implode(', ', $group_list)), 'horde.success');
}
} catch (Horde_Group_Exception $e) {}
}
$prefs->setValue('display_cals', serialize($this->_displayCalendars));
}
}
/**
* Return all known external calendars.
*
* @return array
*/
protected function _getAllExternal()
{
global $registry, $session;
$this->_allExternal = array();
// Make sure all task lists exist.
if (Kronolith::hasApiPermission('tasks') &&
$registry->hasMethod('tasks/listTimeObjects')) {
try {
$tasklists = $registry->tasks->listTasklists();
$categories = $registry->call('tasks/listTimeObjectCategories');
foreach ($categories as $name => $description) {
if (!isset($tasklists[$name])) {
continue;
}
$this->_allExternal['tasks/' . $name] = new Kronolith_Calendar_External_Tasks(array('api' => 'tasks', 'name' => $description['title'], 'share' => $tasklists[$name], 'type' => 'share'));
}
} catch (Horde_Exception $e) {
Horde::log($e, 'DEBUG');
}
}
if ($session->exists('kronolith', 'all_external_calendars')) {
foreach ($session->get('kronolith', 'all_external_calendars') as $calendar) {
if (!Kronolith::hasApiPermission($calendar['a']) ||
$calendar['a'] == 'tasks') {
continue;
}
$this->_allExternal[$calendar['a'] . '/' . $calendar['n']] = new Kronolith_Calendar_External(array('api' => $calendar['a'], 'name' => $calendar['d'], 'id' => $calendar['n'], 'type' => $calendar['t'], 'background' => $calendar['b']));
}
} else {
$apis = array_unique($registry->listAPIs());
$ext_cals = array();
foreach ($apis as $api) {
if ($api == 'tasks' ||
!Kronolith::hasApiPermission($api) ||
!$registry->hasMethod($api . '/listTimeObjects')) {
continue;
}
try {
$categories = $registry->call($api . '/listTimeObjectCategories');
} catch (Horde_Exception $e) {
Horde::log($e, 'DEBUG');
continue;
}
foreach ($categories as $name => $description) {
if (empty($description['background'])) {
$description['background'] = '#dddddd';
}
$this->_allExternal[$api . '/' . $name] = new Kronolith_Calendar_External(array(
'api' => $api,
'name' => $description['title'],
'id' => $name,
'type' => $description['type'],
'background' => $description['background']));
$ext_cals[] = array(
'a' => $api,
'n' => $name,
'd' => $description['title'],
't' => $description['type'],
'b' => $description['background']
);
}
}
$session->set('kronolith', 'all_external_calendars', $ext_cals);
}
return $this->_allExternal;
}
/**
* Return all external calendars selected for display.
*
* @return array
*/
protected function _getDisplayExternal()
{
global $registry, $prefs;
// Make sure all the external calendars still exist.
$_tasklists = $_temp = $this->_displayExternal;
if (Kronolith::hasApiPermission('tasks')) {
try {
$_tasklists = $registry->tasks->getDisplayedTasklists();
} catch (Horde_Exception $e) {
}
}
$this->_displayExternal = array();
foreach ($this->get(Kronolith::ALL_EXTERNAL_CALENDARS) as $id => $calendar) {
if ((substr($id, 0, 6) == 'tasks/' &&
in_array(substr($id, 6), $_tasklists)) ||
in_array($id, $_temp)) {
$this->_displayExternal[] = $id;
}
}
$prefs->setValue('display_external_cals', serialize($this->_displayExternal));
return $this->_displayExternal;
}
/**
* Return list of all available holidays drivers.
*
* @return array The available holidays.
*/
protected function _getAllHolidays()
{
$this->_allHolidays = array();
if (!empty($GLOBALS['conf']['holidays']['enable'])) {
if (class_exists('Date_Holidays')) {
$dh = new Date_Holidays();
foreach ($dh->getInstalledDrivers() as $driver) {
if ($driver['id'] == 'Composite') {
continue;
}
$this->_allHolidays[$driver['id']] = new Kronolith_Calendar_Holiday(array('driver' => $driver));
ksort($this->_allHolidays);
}
}
}
return $this->_allHolidays;
}
/**
* Return list of holiday calendars to be displayed.
*
* @return array The holiday calendars to display.
*/
protected function _getDisplayHolidays()
{
$this->_displayHolidays = array();
foreach (array_keys($this->get(Kronolith::ALL_HOLIDAYS)) as $id) {
if (in_array($id, $this->_displayHolidaysInternal)) {
$this->_displayHolidays[] = $id;
}
}
$GLOBALS['prefs']->setValue('holiday_drivers', serialize($this->_displayHolidays));
return $this->_displayHolidays;
}
/**
* Return list of all resource calendars.
*
* @return array Resource calendars, keyed by calendar id.
*/
protected function _getAllResource()
{
$this->_allResource = array();
if (!empty($GLOBALS['conf']['resource']['driver'])) {
foreach (Kronolith::getDriver('Resource')->listResources(Horde_Perms::READ, array('type' => Kronolith_Resource::TYPE_SINGLE)) as $resource) {
$rcal = new Kronolith_Calendar_Resource(array(
'resource' => $resource
));
$this->_allResource[$resource->get('calendar')] = $rcal;
}
}
return $this->_allResource;
}
protected function _getRemoteCalendars()
{
if ($this->_allRemote === false) {
// Check that all selected remote calendars are still configured.
$tmp = $this->_displayRemote;
$this->_allRemote = $this->_displayRemote = array();
$calendars = @unserialize($GLOBALS['prefs']->getValue('remote_cals'));
if (!is_array($calendars)) {
$calendars = array();
}
foreach ($calendars as $calendar) {
$this->_allRemote[$calendar['url']] = new Kronolith_Calendar_Remote($calendar);
if (in_array($calendar['url'], $tmp)) {
$this->_displayRemote[] = $calendar['url'];
}
}
$GLOBALS['prefs']->setValue('display_remote_cals', serialize($this->_displayRemote));
}
return $this->_allRemote;
}
}