872 lines
33 KiB
PHP
872 lines
33 KiB
PHP
<?php
|
|
/**
|
|
* Kronolith application API.
|
|
*
|
|
* This file defines Horde's core API interface. Other core Horde libraries
|
|
* can interact with Kronolith through this API.
|
|
*
|
|
* Copyright 2010-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.
|
|
*
|
|
* @package Kronolith
|
|
*/
|
|
|
|
/* Determine the base directories. */
|
|
if (!defined('KRONOLITH_BASE')) {
|
|
define('KRONOLITH_BASE', realpath(__DIR__ . '/..'));
|
|
}
|
|
|
|
if (!defined('HORDE_BASE')) {
|
|
/* If Horde does not live directly under the app directory, the HORDE_BASE
|
|
* constant should be defined in config/horde.local.php. */
|
|
if (file_exists(KRONOLITH_BASE . '/config/horde.local.php')) {
|
|
include KRONOLITH_BASE . '/config/horde.local.php';
|
|
} else {
|
|
define('HORDE_BASE', realpath(KRONOLITH_BASE . '/..'));
|
|
}
|
|
}
|
|
|
|
/* Load the Horde Framework core (needed to autoload
|
|
* Horde_Registry_Application::). */
|
|
require_once HORDE_BASE . '/lib/core.php';
|
|
|
|
use Sabre\CalDAV;
|
|
|
|
class Kronolith_Application extends Horde_Registry_Application
|
|
{
|
|
/**
|
|
*/
|
|
public $features = array(
|
|
'alarmHandler' => true,
|
|
'dynamicView' => true,
|
|
'smartmobileView' => true,
|
|
'modseq' => true
|
|
);
|
|
|
|
/**
|
|
*/
|
|
public $version = 'H5 (4.2.29)';
|
|
|
|
/**
|
|
* Global variables defined:
|
|
* - $kronolith_shares: TODO
|
|
*/
|
|
protected function _init()
|
|
{
|
|
/* For now, autoloading the Content_* classes depend on there being a
|
|
* registry entry for the 'content' application that contains at least
|
|
* the fileroot entry. */
|
|
$GLOBALS['injector']->getInstance('Horde_Autoloader')
|
|
->addClassPathMapper(
|
|
new Horde_Autoloader_ClassPathMapper_Prefix('/^Content_/', $GLOBALS['registry']->get('fileroot', 'content') . '/lib/'));
|
|
|
|
if (!class_exists('Content_Tagger')) {
|
|
throw new Horde_Exception(_("The Content_Tagger class could not be found. Make sure the Content application is installed."));
|
|
}
|
|
|
|
$GLOBALS['injector']->bindFactory('Kronolith_Geo', 'Kronolith_Factory_Geo', 'create');
|
|
$GLOBALS['injector']->bindFactory('Kronolith_Shares', 'Kronolith_Factory_Shares', 'create');
|
|
|
|
/* Set the timezone variable, if available. */
|
|
$GLOBALS['registry']->setTimeZone();
|
|
|
|
/* Store the request timestamp if it's not already present. */
|
|
if (!isset($_SERVER['REQUEST_TIME'])) {
|
|
$_SERVER['REQUEST_TIME'] = time();
|
|
}
|
|
|
|
if (!$GLOBALS['prefs']->getValue('dynamic_view')) {
|
|
$this->features['dynamicView'] = false;
|
|
}
|
|
if ($GLOBALS['registry']->getView() != Horde_Registry::VIEW_DYNAMIC ||
|
|
!$GLOBALS['prefs']->getValue('dynamic_view') ||
|
|
empty($this->initParams['nodynamicinit'])) {
|
|
Kronolith::initialize();
|
|
}
|
|
}
|
|
|
|
/**
|
|
*/
|
|
public function perms()
|
|
{
|
|
return array(
|
|
'max_events' => array(
|
|
'title' => _("Maximum Number of Events"),
|
|
'type' => 'int'
|
|
),
|
|
'resource_management' => array(
|
|
'title' => _("Resource Management"),
|
|
'type' => 'boolean')
|
|
);
|
|
}
|
|
|
|
/**
|
|
*/
|
|
public function menu($menu)
|
|
{
|
|
global $browser, $conf, $notification, $page_output, $registry, $session;
|
|
|
|
/* Check here for guest calendars so that we don't get multiple
|
|
* messages after redirects, etc. */
|
|
if (!$registry->getAuth() && !count(Kronolith::listCalendars())) {
|
|
$notification->push(_("No calendars are available to guests."));
|
|
}
|
|
|
|
if ($browser->hasFeature('dom')) {
|
|
Horde_Core_Ui_JsCalendar::init(array(
|
|
'click_month' => true,
|
|
'click_week' => true,
|
|
'click_year' => true,
|
|
'full_weekdays' => true
|
|
));
|
|
$page_output->addScriptFile('goto.js');
|
|
$page_output->addInlineJsVars(array(
|
|
'KronolithGoto.dayurl' => strval(Horde::url('day.php')),
|
|
'KronolithGoto.monthurl' => strval(Horde::url('month.php')),
|
|
'KronolithGoto.weekurl' => strval(Horde::url('week.php')),
|
|
'KronolithGoto.yearurl' => strval(Horde::url('year.php'))
|
|
));
|
|
$menu->add(new Horde_Url(''), _("_Goto"), 'kronolith-icon-goto', null, '', null, 'kgotomenu');
|
|
}
|
|
$menu->add(Horde::url('search.php'), _("_Search"), 'kronolith-icon-search');
|
|
|
|
/* Import/Export. */
|
|
if ($conf['menu']['import_export'] &&
|
|
!Kronolith::showAjaxView()) {
|
|
$menu->add(Horde::url('data.php'), _("_Import/Export"), 'horde-data');
|
|
}
|
|
|
|
if (strlen($session->get('kronolith', 'display_cal'))) {
|
|
$menu->add(Horde::selfUrl(true)->add('display_cal', ''),
|
|
$registry->getAuth()
|
|
? _("Return to my calendars")
|
|
: _("Return to calendars"),
|
|
'kronolith-icon-back',
|
|
null, null, null, '__noselection');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds additional items to the sidebar.
|
|
*
|
|
* This is for the traditional view. For the dynamic view, see
|
|
* Kronolith_View_Sidebar.
|
|
*
|
|
* @param Horde_View_Sidebar $sidebar The sidebar object.
|
|
*/
|
|
public function sidebar($sidebar)
|
|
{
|
|
$perms = $GLOBALS['injector']->getInstance('Horde_Core_Perms');
|
|
if (Kronolith::getDefaultCalendar(Horde_Perms::EDIT) &&
|
|
($perms->hasAppPermission('max_events') === true ||
|
|
$perms->hasAppPermission('max_events') > Kronolith::countEvents())) {
|
|
$sidebar->addNewButton(_("_New Event"), Horde::url('new.php')->add('url', Horde::signUrl(Horde::selfUrl(true, false, true))));
|
|
}
|
|
|
|
if (strlen($GLOBALS['session']->get('kronolith', 'display_cal'))) {
|
|
$calendars = Kronolith::displayedCalendars();
|
|
$sidebar->containers['calendars'] = array(
|
|
'header' => array(
|
|
'id' => 'kronolith-toggle-calendars',
|
|
'label' => ngettext("Showing calendar:", "Showing calendars:", count($calendars)),
|
|
'collapsed' => false,
|
|
),
|
|
);
|
|
foreach ($calendars as $calendar) {
|
|
$row = array(
|
|
'label' => $calendar->name(),
|
|
'color' => $calendar->background(),
|
|
'type' => 'checkbox',
|
|
);
|
|
$sidebar->addRow($row, 'calendars');
|
|
}
|
|
return;
|
|
}
|
|
|
|
$user = $GLOBALS['registry']->getAuth();
|
|
$url = Horde::selfUrl();
|
|
$edit = Horde::url('calendars/edit.php');
|
|
|
|
$sidebar->containers['my'] = array(
|
|
'header' => array(
|
|
'id' => 'kronolith-toggle-my',
|
|
'label' => _("My Calendars"),
|
|
'collapsed' => false,
|
|
),
|
|
);
|
|
if (!$GLOBALS['prefs']->isLocked('default_share')) {
|
|
$sidebar->containers['my']['header']['add'] = array(
|
|
'url' => Horde::url('calendars/create.php'),
|
|
'label' => _("Create a new Local Calendar"),
|
|
);
|
|
}
|
|
if ($GLOBALS['registry']->isAdmin()) {
|
|
$sidebar->containers['system'] = array(
|
|
'header' => array(
|
|
'id' => 'kronolith-toggle-system',
|
|
'label' => _("System Calendars"),
|
|
'collapsed' => true,
|
|
),
|
|
);
|
|
$sidebar->containers['system']['header']['add'] = array(
|
|
'url' => Horde::url('calendars/create.php')->add('system', 1),
|
|
'label' => _("Create a new System Calendar"),
|
|
);
|
|
}
|
|
$sidebar->containers['shared'] = array(
|
|
'header' => array(
|
|
'id' => 'kronolith-toggle-shared',
|
|
'label' => _("Shared Calendars"),
|
|
'collapsed' => true,
|
|
),
|
|
);
|
|
foreach (Kronolith::listInternalCalendars() as $id => $calendar) {
|
|
$row = array(
|
|
'selected' => in_array($id, $GLOBALS['calendar_manager']->get(Kronolith::DISPLAY_CALENDARS)),
|
|
'url' => $url->copy()->add('toggle_calendar', $id),
|
|
'label' => Kronolith::getLabel($calendar),
|
|
'color' => Kronolith::backgroundColor($calendar),
|
|
'edit' => $edit->add('c', $calendar->getName()),
|
|
'type' => 'checkbox',
|
|
);
|
|
if ($calendar->get('owner') && $calendar->get('owner') == $user) {
|
|
$sidebar->addRow($row, 'my');
|
|
} else {
|
|
$sidebar->addRow($row, 'shared');
|
|
}
|
|
}
|
|
|
|
if ($GLOBALS['registry']->isAdmin()) {
|
|
foreach ($GLOBALS['injector']->getInstance('Kronolith_Shares')->listSystemShares() as $id => $calendar) {
|
|
$row = array(
|
|
'selected' => in_array($id, $GLOBALS['calendar_manager']->get(Kronolith::DISPLAY_CALENDARS)),
|
|
'url' => $url->copy()->add('toggle_calendar', $id),
|
|
'label' => $calendar->get('name'),
|
|
'color' => Kronolith::backgroundColor($calendar),
|
|
'edit' => $edit->add('c', $calendar->getName()),
|
|
'type' => 'checkbox',
|
|
);
|
|
$sidebar->addRow($row, 'system');
|
|
}
|
|
}
|
|
if (!empty($GLOBALS['conf']['resource']['driver']) &&
|
|
($GLOBALS['registry']->isAdmin() || $GLOBALS['injector']->getInstance('Horde_Core_Perms')->hasAppPermission('resource_management'))) {
|
|
|
|
$sidebar->containers['groups'] = array(
|
|
'header' => array(
|
|
'id' => 'kronolith-toggle-groups',
|
|
'label' => _("Resource Groups"),
|
|
'collapsed' => true,
|
|
'add' => array(
|
|
'url' => Horde::url('resources/groups/create.php'),
|
|
'label' => _("Create a new Resource Group"),
|
|
),
|
|
),
|
|
);
|
|
$editGroups = Horde::url('resources/groups/edit.php');
|
|
$sidebar->containers['resources'] = array(
|
|
'header' => array(
|
|
'id' => 'kronolith-toggle-resources',
|
|
'label' => _("Resources"),
|
|
'collapsed' => true,
|
|
'add' => array(
|
|
'url' => Horde::url('resources/create.php'),
|
|
'label' => _("Create a new Resource"),
|
|
),
|
|
),
|
|
);
|
|
$edit = Horde::url('resources/edit.php');
|
|
foreach (Kronolith::getDriver('Resource')->listResources() as $resource) {
|
|
if ($resource->get('type') == Kronolith_Resource::TYPE_GROUP) {
|
|
$row = array(
|
|
'label' => $resource->get('name'),
|
|
'color' => '#dddddd',
|
|
'edit' => $editGroups->add('c', $resource->getId()),
|
|
'type' => 'radiobox',
|
|
);
|
|
$sidebar->addRow($row, 'groups');
|
|
} else {
|
|
$calendar = new Kronolith_Calendar_Resource(array(
|
|
'resource' => $resource
|
|
));
|
|
$row = array(
|
|
'selected' => in_array($resource->get('calendar'), $GLOBALS['calendar_manager']->get(Kronolith::DISPLAY_RESOURCE_CALENDARS)),
|
|
'url' => $url->copy()->add('toggle_calendar', 'resource_' . $resource->get('calendar')),
|
|
'label' => $calendar->name(),
|
|
'color' => $calendar->background(),
|
|
'edit' => $edit->add('c', $resource->getId()),
|
|
'type' => 'checkbox',
|
|
);
|
|
$sidebar->addRow($row, 'resources');
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($GLOBALS['calendar_manager']->get(Kronolith::ALL_EXTERNAL_CALENDARS) as $id => $calendar) {
|
|
if (!$calendar->display()) {
|
|
continue;
|
|
}
|
|
$app = $GLOBALS['registry']->get(
|
|
'name',
|
|
$GLOBALS['registry']->hasInterface($calendar->api()));
|
|
if (!strlen($app)) {
|
|
$app = _("Other events");
|
|
}
|
|
$container = 'external_' . $app;
|
|
if (!isset($sidebar->containers[$container])) {
|
|
$sidebar->containers[$container] = array(
|
|
'header' => array(
|
|
'id' => 'kronolith-toggle-external-' . $calendar->api(),
|
|
'label' => $app,
|
|
'collapsed' => true,
|
|
),
|
|
);
|
|
}
|
|
$row = array(
|
|
'selected' => in_array($id, $GLOBALS['calendar_manager']->get(Kronolith::DISPLAY_EXTERNAL_CALENDARS)),
|
|
'url' => $url->copy()->add('toggle_calendar', 'external_' . $id),
|
|
'label' => $calendar->name(),
|
|
'color' => $calendar->background(),
|
|
'type' => 'checkbox',
|
|
);
|
|
$sidebar->addRow($row, $container);
|
|
}
|
|
|
|
$sidebar->containers['remote'] = array(
|
|
'header' => array(
|
|
'id' => 'kronolith-toggle-remote',
|
|
'label' => _("Remote Calendars"),
|
|
'collapsed' => true,
|
|
'add' => array(
|
|
'url' => Horde::url('calendars/remote_subscribe.php'),
|
|
'label' => _("Subscribe to a Remote Calendar"),
|
|
),
|
|
),
|
|
);
|
|
$edit = Horde::url('calendars/remote_edit.php');
|
|
foreach ($GLOBALS['calendar_manager']->get(Kronolith::ALL_REMOTE_CALENDARS) as $calendar) {
|
|
$row = array(
|
|
'selected' => in_array($calendar->url(), $GLOBALS['calendar_manager']->get(Kronolith::DISPLAY_REMOTE_CALENDARS)),
|
|
'url' => $url->copy()->add('toggle_calendar', 'remote_' . $calendar->url()),
|
|
'label' => $calendar->name(),
|
|
'color' => $calendar->background(),
|
|
'edit' => $edit->add('url', $calendar->url()),
|
|
'type' => 'checkbox',
|
|
);
|
|
$sidebar->addRow($row, 'remote');
|
|
}
|
|
|
|
if (!empty($GLOBALS['conf']['holidays']['enable'])) {
|
|
$sidebar->containers['holidays'] = array(
|
|
'header' => array(
|
|
'id' => 'kronolith-toggle-holidays',
|
|
'label' => _("Holidays"),
|
|
'collapsed' => true,
|
|
),
|
|
);
|
|
foreach ($GLOBALS['calendar_manager']->get(Kronolith::ALL_HOLIDAYS) as $id => $calendar) {
|
|
$row = array(
|
|
'selected' => in_array($id, $GLOBALS['calendar_manager']->get(Kronolith::DISPLAY_HOLIDAYS)),
|
|
'url' => $url->copy()->add('toggle_calendar', 'holiday_' . $id),
|
|
'label' => $calendar->name(),
|
|
'color' => $calendar->background(),
|
|
'type' => 'checkbox',
|
|
);
|
|
$sidebar->addRow($row, 'holidays');
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
*/
|
|
public function hasPermission($permission, $allowed, $opts = array())
|
|
{
|
|
if (is_array($allowed)) {
|
|
switch ($permission) {
|
|
case 'max_events':
|
|
$allowed = max($allowed);
|
|
break;
|
|
}
|
|
}
|
|
return $allowed;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
public function removeUserData($user)
|
|
{
|
|
$error = false;
|
|
|
|
// Remove all events owned by the user in all calendars.
|
|
try {
|
|
Kronolith::removeUserEvents($user);
|
|
} catch (Exception $e) {
|
|
Horde::log($e, 'NOTICE');
|
|
$error = true;
|
|
}
|
|
|
|
// Get the shares owned by the user being deleted.
|
|
try {
|
|
$kronolith_shares = $GLOBALS['injector']->getInstance('Kronolith_Shares');
|
|
$shares = $kronolith_shares->listShares(
|
|
$user,
|
|
array('attributes' => $user)
|
|
);
|
|
foreach ($shares as $share) {
|
|
$kronolith_shares->removeShare($share);
|
|
}
|
|
} catch (Exception $e) {
|
|
Horde::log($e, 'NOTICE');
|
|
$error = true;
|
|
}
|
|
|
|
/* Get a list of all shares this user has perms to and remove the
|
|
* perms */
|
|
try {
|
|
$shares = $kronolith_shares->listShares($user);
|
|
foreach ($shares as $share) {
|
|
$share->removeUser($user);
|
|
}
|
|
} catch (Horde_Share_Exception $e) {
|
|
Horde::log($e, 'NOTICE');
|
|
$error = true;
|
|
}
|
|
|
|
if ($error) {
|
|
throw new Kronolith_Exception(sprintf(_("There was an error removing calendars for %s. Details have been logged."), $user));
|
|
}
|
|
}
|
|
|
|
/* Topbar method. */
|
|
|
|
/**
|
|
*/
|
|
public function topbarCreate(Horde_Tree_Renderer_Base $tree, $parent = null,
|
|
array $params = array())
|
|
{
|
|
switch ($params['id']) {
|
|
case 'menu':
|
|
$menus = array(
|
|
array('new', _("New Event"), 'new.png', Horde::url('new.php')),
|
|
array('day', _("Day"), 'dayview.png', Horde::url('day.php')),
|
|
array('work', _("Work Week"), 'workweekview.png', Horde::url('workweek.php')),
|
|
array('week', _("Week"), 'weekview.png', Horde::url('week.php')),
|
|
array('month', _("Month"), 'monthview.png', Horde::url('month.php')),
|
|
array('year', _("Year"), 'yearview.png', Horde::url('year.php'))
|
|
);
|
|
// Dynamic view has no dedicated search page.
|
|
if (!Kronolith::showAjaxView()) {
|
|
$menus[] = array('search', _("Search"), 'search.png', Horde::url('search.php'));
|
|
}
|
|
foreach ($menus as $menu) {
|
|
$tree->addNode(array(
|
|
'id' => $parent . $menu[0],
|
|
'parent' => $parent,
|
|
'label' => $menu[1],
|
|
'expanded' => false,
|
|
'params' => array(
|
|
'icon' => Horde_Themes::img($menu[2]),
|
|
'url' => $menu[3]
|
|
)
|
|
));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Alarm method. */
|
|
|
|
/**
|
|
*/
|
|
public function listAlarms($time, $user = null)
|
|
{
|
|
$current_user = $GLOBALS['registry']->getAuth();
|
|
if ((empty($user) || $user != $current_user) && !$GLOBALS['registry']->isAdmin()) {
|
|
throw new Horde_Exception_PermissionDenied();
|
|
}
|
|
|
|
$group = $GLOBALS['injector']->getInstance('Horde_Group');
|
|
$kronolith_shares = $GLOBALS['injector']->getInstance('Kronolith_Shares');
|
|
|
|
$alarm_list = array();
|
|
$time = new Horde_Date($time);
|
|
$calendars = is_null($user)
|
|
? array_keys($kronolith_shares->listAllShares())
|
|
: $GLOBALS['calendar_manager']->get(Kronolith::DISPLAY_CALENDARS);
|
|
$alarms = Kronolith::listAlarms($time, $calendars, true);
|
|
foreach ($alarms as $calendar => $cal_alarms) {
|
|
if (!$cal_alarms) {
|
|
continue;
|
|
}
|
|
try {
|
|
$share = $kronolith_shares->getShare($calendar);
|
|
} catch (Exception $e) {
|
|
continue;
|
|
}
|
|
if (empty($user)) {
|
|
$users = $share->listUsers(Horde_Perms::READ);
|
|
$groups = $share->listGroups(Horde_Perms::READ);
|
|
foreach ($groups as $gid) {
|
|
try {
|
|
$users = array_merge($users, $group->listUsers($gid));
|
|
} catch (Horde_Group_Exception $e) {}
|
|
}
|
|
$users = array_unique($users);
|
|
} else {
|
|
$users = array($user);
|
|
}
|
|
$owner = $share->get('owner');
|
|
foreach ($cal_alarms as $event) {
|
|
foreach ($users as $alarm_user) {
|
|
if ($alarm_user == $current_user) {
|
|
$prefs = $GLOBALS['prefs'];
|
|
} else {
|
|
$prefs = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Prefs')->create('kronolith', array(
|
|
'cache' => false,
|
|
'user' => $alarm_user
|
|
));
|
|
}
|
|
// Don't show alarms for private events if not the owner.
|
|
if ($event->isPrivate($alarm_user)) {
|
|
continue;
|
|
}
|
|
$shown_calendars = unserialize($prefs->getValue('display_cals'));
|
|
$reminder = $prefs->getValue('event_reminder');
|
|
if (($reminder == 'owner' && $alarm_user == $owner) ||
|
|
($reminder == 'show' && in_array($calendar, $shown_calendars)) ||
|
|
$reminder == 'read') {
|
|
$GLOBALS['registry']->setLanguageEnvironment($prefs->getValue('language'));
|
|
$alarm = $event->toAlarm($time, $alarm_user, $prefs);
|
|
if ($alarm) {
|
|
$alarm_list[] = $alarm;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $alarm_list;
|
|
}
|
|
|
|
/* Download data. */
|
|
|
|
/**
|
|
* @throws Kronolith_Exception
|
|
*/
|
|
public function download(Horde_Variables $vars)
|
|
{
|
|
global $display_calendars, $injector;
|
|
|
|
switch ($vars->actionID) {
|
|
case 'export':
|
|
if ($vars->all_events) {
|
|
$end = $start = null;
|
|
} else {
|
|
$start = new Horde_Date(
|
|
$vars->start_year,
|
|
$vars->start_month,
|
|
$vars->start_day
|
|
);
|
|
$end = new Horde_Date(
|
|
$vars->end_year,
|
|
$vars->end_month,
|
|
$vars->end_day
|
|
);
|
|
}
|
|
|
|
$calendars = $vars->get('exportCal', $display_calendars);
|
|
if (!is_array($calendars)) {
|
|
$calendars = array($calendars);
|
|
}
|
|
$events = array();
|
|
|
|
foreach ($calendars as $calendar) {
|
|
list($type, $cal) = explode('_', $calendar, 2);
|
|
$kronolith_driver = Kronolith::getDriver($type, $cal);
|
|
$calendarObject = Kronolith::getCalendar($kronolith_driver);
|
|
if (!$calendarObject ||
|
|
!$calendarObject->hasPermission(Horde_Perms::READ)) {
|
|
throw new Horde_Exception_PermissionDenied();
|
|
}
|
|
$events[$calendar] = $kronolith_driver->listEvents(
|
|
$start,
|
|
$end,
|
|
array(
|
|
'cover_dates' => false,
|
|
'hide_exceptions' => ($vars->exportID == Horde_Data::EXPORT_ICALENDAR)
|
|
)
|
|
);
|
|
}
|
|
|
|
switch ($vars->exportID) {
|
|
case Horde_Data::EXPORT_CSV:
|
|
$data = array();
|
|
foreach ($events as $calevents) {
|
|
foreach ($calevents as $dayevents) {
|
|
foreach ($dayevents as $event) {
|
|
$row = array(
|
|
'alarm' => $event->alarm,
|
|
'description' => $event->description,
|
|
'end_date' => $event->end->format('Y-m-d'),
|
|
'end_time' => $event->end->format('H:i:s'),
|
|
'location' => $event->location,
|
|
'private' => intval($event->private),
|
|
'recur_type' => null,
|
|
'recur_end_date' => null,
|
|
'recur_interval' => null,
|
|
'recur_data' => null,
|
|
'start_date' => $event->start->format('Y-m-d'),
|
|
'start_time' => $event->start->format('H:i:s'),
|
|
'tags' => implode(', ', $event->tags),
|
|
'title' => $event->getTitle()
|
|
);
|
|
|
|
if ($event->recurs()) {
|
|
$row['recur_type'] = $event->recurrence->getRecurType();
|
|
if ($event->recurrence->hasRecurEnd()) {
|
|
$row['recur_end_date'] = $event->recurrence->recurEnd->format('Y-m-d');
|
|
}
|
|
$row['recur_interval'] = $event->recurrence->getRecurInterval();
|
|
$row['recur_data'] = $event->recurrence->recurData;
|
|
}
|
|
|
|
$data[] = $row;
|
|
}
|
|
}
|
|
}
|
|
|
|
$injector->getInstance('Horde_Core_Factory_Data')
|
|
->create('Csv', array('cleanup' => array($this, 'cleanupData')))
|
|
->exportFile(_("events.csv"), $data, true);
|
|
exit;
|
|
|
|
case Horde_Data::EXPORT_ICALENDAR:
|
|
$calNames = array();
|
|
$iCal = new Horde_Icalendar();
|
|
|
|
foreach ($events as $calevents) {
|
|
foreach ($calevents as $dayevents) {
|
|
foreach ($dayevents as $event) {
|
|
$calNames[Kronolith::getCalendar($event->getDriver())->name()] = true;
|
|
$iCal->addComponent($event->toiCalendar($iCal));
|
|
}
|
|
}
|
|
}
|
|
|
|
$iCal->setAttribute('X-WR-CALNAME', implode(', ', array_keys($calNames)));
|
|
|
|
return array(
|
|
'data' => $iCal->exportvCalendar(),
|
|
'name' => _("events.ics"),
|
|
'type' => 'text/calendar'
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
*/
|
|
public function cleanupData()
|
|
{
|
|
$GLOBALS['import_step'] = 1;
|
|
return Horde_Data::IMPORT_FILE;
|
|
}
|
|
|
|
/* DAV methods. */
|
|
|
|
/**
|
|
*/
|
|
public function davGetCollections($user)
|
|
{
|
|
global $calendar_manager, $injector, $registry;
|
|
|
|
$hordeUser = $registry->convertUsername($user, true);
|
|
$shares = $injector->getInstance('Kronolith_Shares')
|
|
->listShares($hordeUser);
|
|
$dav = $injector->getInstance('Horde_Dav_Storage');
|
|
$calendars = array();
|
|
foreach ($shares as $id => $share) {
|
|
if ($user == '-system-' && $share->get('owner')) {
|
|
continue;
|
|
}
|
|
if (!$calendar = $calendar_manager->getEntry(Kronolith::ALL_CALENDARS, $id)) {
|
|
Horde::log(sprintf('Unable to find share id: %s', $id));
|
|
continue;
|
|
}
|
|
$calendar = $calendar->toHash();
|
|
try {
|
|
$id = $dav->getExternalCollectionId($id, 'calendar');
|
|
} catch (Horde_Dav_Exception $e) {
|
|
}
|
|
$calendars[] = array(
|
|
'id' => $id,
|
|
'uri' => $id,
|
|
'{' . CalDAV\Plugin::NS_CALENDARSERVER . '}shared-url' =>
|
|
$calendar['caldav'],
|
|
'principaluri' => 'principals/' . $user,
|
|
'{http://sabredav.org/ns}owner-principal' =>
|
|
'principals/'
|
|
. ($share->get('owner')
|
|
? $registry->convertUsername($share->get('owner'), false)
|
|
: '-system-'
|
|
),
|
|
'{DAV:}displayname' => Kronolith::getLabel($share),
|
|
'{' . CalDAV\Plugin::NS_CALDAV . '}calendar-description' =>
|
|
$share->get('desc'),
|
|
'{http://apple.com/ns/ical/}calendar-color' =>
|
|
$share->get('color') . 'ff',
|
|
'{' . CalDAV\Plugin::NS_CALDAV . '}supported-calendar-component-set' => new CalDAV\Property\SupportedCalendarComponentSet(array('VEVENT')),
|
|
'{http://sabredav.org/ns}read-only' => !$share->hasPermission($hordeUser, Horde_Perms::EDIT),
|
|
);
|
|
}
|
|
return $calendars;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
public function davGetObjects($collection)
|
|
{
|
|
$dav = $GLOBALS['injector']
|
|
->getInstance('Horde_Dav_Storage');
|
|
|
|
$internal = $dav->getInternalCollectionId($collection, 'calendar') ?: $collection;
|
|
if (!Kronolith::hasPermission($internal, Horde_Perms::SHOW)) {
|
|
throw new Kronolith_Exception(_("Calendar does not exist or no permission to edit"));
|
|
}
|
|
|
|
$kronolith_driver = Kronolith::getDriver(null, $internal);
|
|
$allEvents = $kronolith_driver->listEvents(
|
|
null,
|
|
null,
|
|
array('cover_dates' => false, 'hide_exceptions' => true)
|
|
);
|
|
$events = array();
|
|
foreach ($allEvents as $dayevents) {
|
|
foreach ($dayevents as $event) {
|
|
$id = $event->id;
|
|
$event->loadHistory();
|
|
$modified = $event->modified ?: $event->created;
|
|
try {
|
|
$id = $dav->getExternalObjectId($id, $internal) ?: $id . '.ics';
|
|
} catch (Horde_Dav_Exception $e) {
|
|
}
|
|
$events[] = array(
|
|
'id' => $id,
|
|
'uri' => $id,
|
|
'lastmodified' => $modified,
|
|
'etag' => '"' . md5($event->id . '|' . $modified) . '"',
|
|
'calendarid' => $collection,
|
|
);
|
|
}
|
|
}
|
|
|
|
return $events;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
public function davGetObject($collection, $object)
|
|
{
|
|
$dav = $GLOBALS['injector']
|
|
->getInstance('Horde_Dav_Storage');
|
|
|
|
$internal = $dav->getInternalCollectionId($collection, 'calendar') ?: $collection;
|
|
if (!Kronolith::hasPermission($internal, Horde_Perms::SHOW)) {
|
|
throw new Kronolith_Exception(_("Calendar does not exist or no permission to edit"));
|
|
}
|
|
|
|
$kronolith_driver = Kronolith::getDriver(null, $internal);
|
|
try {
|
|
$object = $dav->getInternalObjectId($object, $internal) ?: preg_replace('/\.ics$/', '', $object);
|
|
} catch (Horde_Dav_Exception $e) {
|
|
}
|
|
$event = $kronolith_driver->getEvent($object);
|
|
$id = $event->id;
|
|
try {
|
|
$id = $dav->getExternalObjectId($id, $internal) ?: $id . '.ics';
|
|
} catch (Horde_Dav_Exception $e) {
|
|
}
|
|
|
|
$event->loadHistory();
|
|
$modified = $event->modified ?: $event->created;
|
|
|
|
$share = $GLOBALS['injector']
|
|
->getInstance('Kronolith_Shares')
|
|
->getShare($event->calendar);
|
|
$ical = new Horde_Icalendar('2.0');
|
|
$ical->setAttribute('X-WR-CALNAME', $share->get('name'));
|
|
$ical->addComponent($event->toiCalendar($ical));
|
|
$data = $ical->exportvCalendar();
|
|
|
|
return array(
|
|
'id' => $id,
|
|
'calendardata' => $data,
|
|
'uri' => $id,
|
|
'lastmodified' => $modified,
|
|
'etag' => '"' . md5($event->id . '|' . $modified) . '"',
|
|
'calendarid' => $collection,
|
|
'size' => strlen($data),
|
|
);
|
|
}
|
|
|
|
/**
|
|
*/
|
|
public function davPutObject($collection, $object, $data)
|
|
{
|
|
$dav = $GLOBALS['injector']
|
|
->getInstance('Horde_Dav_Storage');
|
|
|
|
$internal = $dav->getInternalCollectionId($collection, 'calendar') ?: $collection;
|
|
if (!Kronolith::hasPermission($internal, Horde_Perms::EDIT)) {
|
|
throw new Kronolith_Exception(_("Calendar does not exist or no permission to edit"));
|
|
}
|
|
|
|
$ical = new Horde_Icalendar();
|
|
if (!$ical->parsevCalendar($data)) {
|
|
throw new Kronolith_Exception(_("There was an error importing the iCalendar data."));
|
|
}
|
|
$importer = new Kronolith_Icalendar_Handler_Dav(
|
|
$ical, Kronolith::getDriver(null, $internal), array('object' => $object)
|
|
);
|
|
$importer->process();
|
|
}
|
|
|
|
/**
|
|
*/
|
|
public function davDeleteObject($collection, $object)
|
|
{
|
|
$dav = $GLOBALS['injector']->getInstance('Horde_Dav_Storage');
|
|
|
|
$internal = $dav->getInternalCollectionId($collection, 'calendar') ?: $collection;
|
|
if (!Kronolith::hasPermission($internal, Horde_Perms::DELETE)) {
|
|
throw new Kronolith_Exception(_("Calendar does not exist or no permission to delete"));
|
|
}
|
|
|
|
try {
|
|
$object = $dav->getInternalObjectId($object, $internal)
|
|
?: preg_replace('/\.ics$/', '', $object);
|
|
} catch (Horde_Dav_Exception $e) {
|
|
}
|
|
|
|
$kronolith_driver = Kronolith::getDriver(null, $internal);
|
|
$event = $kronolith_driver->getEvent($object);
|
|
$kronolith_driver->deleteEvent($object);
|
|
|
|
try {
|
|
$dav->deleteExternalObjectId($object, $internal);
|
|
} catch (Horde_Dav_Exception $e) {
|
|
}
|
|
|
|
// Send iTip messages.
|
|
// Notifications will get lost, there is no way to return messages to
|
|
// clients.
|
|
Kronolith::sendITipNotifications(
|
|
$event,
|
|
new Horde_Notification_Handler(new Horde_Notification_Storage_Object()),
|
|
Kronolith::ITIP_CANCEL
|
|
);
|
|
}
|
|
}
|