276 lines
10 KiB
PHP
Executable File
276 lines
10 KiB
PHP
Executable File
#!/usr/bin/env php
|
|
<?php
|
|
/**
|
|
* This script imports Open-Xchange calendars into Kronolith.
|
|
*
|
|
* The first argument must be the API endpoint of an Open-Xchange servers,
|
|
* usually something like http://servername/ajax.
|
|
*
|
|
* If called with three arguments, the further arguments must be the user name
|
|
* (usually "Administrator") and password of an administrator user to import
|
|
* public calendars.
|
|
*
|
|
* If called with two arguments, the second argument must be a file with user
|
|
* names and cleartext passwords separated by spaces.
|
|
*
|
|
* Copyright 2014-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 Jan Schneider <jan@horde.org>
|
|
*/
|
|
|
|
// Init application.
|
|
if (file_exists(__DIR__ . '/../../kronolith/lib/Application.php')) {
|
|
$baseDir = __DIR__ . '/../';
|
|
} else {
|
|
require_once 'PEAR/Config.php';
|
|
$baseDir = PEAR_Config::singleton()
|
|
->get('horde_dir', null, 'pear.horde.org') . '/kronolith/';
|
|
}
|
|
require_once $baseDir . 'lib/Application.php';
|
|
Horde_Registry::appInit('kronolith', array('cli' => true, 'user_admin' => true));
|
|
|
|
// Read command line parameters.
|
|
if ($argc < 3 || $argc > 4) {
|
|
$cli->message('Too many or too few parameters.', 'cli.error');
|
|
$cli->writeln('Usage: kronolith-import-openxchange url [ file | user password ]');
|
|
$cli->writeln($cli->indent('url is the URL of an Open-Xchange AJAX endpoint'));
|
|
$cli->writeln($cli->indent('file is a file with space separated user names and passwords to import'));
|
|
$cli->writeln($cli->indent('personal calendars.'));
|
|
$cli->writeln($cli->indent('user and password are credentials of an administrator user to import public'));
|
|
$cli->writeln($cli->indent('calendars.'));
|
|
exit;
|
|
}
|
|
$admin = $argc == 4;
|
|
|
|
// Basic objects and variables.
|
|
$endpoint = parse_url($argv[1]);
|
|
$cli->message('Opening endpoint ' . $argv[1]);
|
|
$ox = new Horde_OpenXchange_Events(array('endpoint' => $argv[1]));
|
|
$users = array();
|
|
|
|
// Prepare handle on user/password list.
|
|
if ($admin) {
|
|
$fp = fopen('php://temp', 'r+');
|
|
fwrite($fp, $argv[2] . ' ' . $argv[3]);
|
|
rewind($fp);
|
|
} else {
|
|
if (!is_readable($argv[2]) || !filesize($argv[2])) {
|
|
$cli->message($argv[2] . ' is not readable or empty', 'cli.error');
|
|
exit(1);
|
|
}
|
|
$fp = fopen($argv[2], 'r');
|
|
}
|
|
if (!$fp) {
|
|
exit(1);
|
|
}
|
|
|
|
// Loop through all users.
|
|
while ($row = fgetcsv($fp, 0, ' ')) {
|
|
$user = $row[0];
|
|
if (is_null($user)) {
|
|
continue;
|
|
}
|
|
$ox->logout();
|
|
$ox->login($user, $row[1]);
|
|
|
|
$registry->setAuth($user, array());
|
|
$cli->message('Importing ' . $user . '\'s calendars');
|
|
|
|
// Reset user prefs
|
|
$prefs = $injector->getInstance('Horde_Core_Factory_Prefs')
|
|
->create('kronolith', array(
|
|
'cache' => false,
|
|
'user' => $user
|
|
)
|
|
);
|
|
$calendar_manager = $injector->createInstance('Kronolith_CalendarsManager');
|
|
|
|
// Load calendars for current user.
|
|
$targets = Kronolith::listInternalCalendars(true, Horde_Perms::EDIT);
|
|
|
|
$count = 0;
|
|
$calendars = $ox->listResources(
|
|
$admin
|
|
? Horde_OpenXchange_Events::RESOURCE_PUBLIC
|
|
: Horde_OpenXchange_Events::RESOURCE_PRIVATE
|
|
);
|
|
$default = $ox->getConfig('folder/calendar');
|
|
|
|
// Loop through all calendars.
|
|
foreach ($calendars as $folderId => $calendar) {
|
|
// Check if we already have an calendar matching the name.
|
|
$target = null;
|
|
foreach ($targets as $id => $info) {
|
|
if ($calendar['label'] == $info->get('name')) {
|
|
$target = $id;
|
|
break;
|
|
}
|
|
}
|
|
if ($target) {
|
|
$cli->message('Calendar "' . $calendar['label'] . '" found, updating...');
|
|
} else {
|
|
// Create new calendar.
|
|
$cli->message('Calendar "' . $calendar['label'] . '" not found, creating...');
|
|
$params = array(
|
|
'name' => $calendar['label'],
|
|
'color' => Kronolith::randomColor(),
|
|
'description' => '',
|
|
'system' => $admin,
|
|
'tags' => array(),
|
|
);
|
|
$share = Kronolith::addShare($params);
|
|
foreach ($calendar['hordePermission']['group'] as $group => $perm) {
|
|
$share->addGroupPermission($group, $perm);
|
|
}
|
|
foreach ($calendar['hordePermission']['user'] as $user => $perm) {
|
|
$share->addUserPermission($user, $perm);
|
|
}
|
|
$target = $share->getName();
|
|
}
|
|
|
|
if ($folderId == $default) {
|
|
$prefs->setValue('default_share', $target);
|
|
}
|
|
|
|
// Initiate driver.
|
|
try {
|
|
$calendar = $calendar_manager->getEntry(
|
|
Kronolith::ALL_CALENDARS,
|
|
$target
|
|
);
|
|
$driver = Kronolith::getDriver(null, $calendar->share()->getName());
|
|
} catch (Kronolith_Exception $e) {
|
|
$cli->message(' ' . sprintf(_("Connection failed: %s"), $e->getMessage()), 'cli.error');
|
|
continue;
|
|
}
|
|
|
|
$events = $ox->listEvents($folderId);
|
|
|
|
// Loop through all events.
|
|
foreach ($events as $event) {
|
|
if ($event['recur_id'] && ($event['recur_id'] == $event['id'])) {
|
|
// Workaround because recurrence_master parameter doesn't work
|
|
// as advertised.
|
|
if ($event['recur_position'] > 1) {
|
|
continue;
|
|
}
|
|
|
|
switch ($event['recur_type']) {
|
|
case 3:
|
|
if ($event['day_in_month']) {
|
|
$event['recur_type'] = Horde_Date_Recurrence::RECUR_MONTHLY_DATE;
|
|
} else {
|
|
$event['recur_type'] = Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY;
|
|
}
|
|
break;
|
|
case 4:
|
|
if ($event['day_in_month']) {
|
|
$event['recur_type'] = Horde_Date_Recurrence::RECUR_YEARLY_DATE;
|
|
} else {
|
|
$event['recur_type'] = Horde_Date_Recurrence::RECUR_YEARLY_WEEKDAY;
|
|
}
|
|
break;
|
|
}
|
|
if ($event['recur_end']) {
|
|
$end = new Horde_Date($event['recur_end'] / 1000, 'UTC');
|
|
$end->mday++;
|
|
$event['recur_end_date'] = $end->format('Y-m-d');
|
|
}
|
|
$event['recur_data'] = $event['recur_days'];
|
|
$exceptions = array_merge(
|
|
(array)$event['recur_delete_exceptions'],
|
|
(array)$event['recur_change_exceptions']
|
|
);
|
|
$event['recur_exceptions'] = array();
|
|
foreach ($exceptions as $exception) {
|
|
$exception = new Horde_Date($exception / 1000, 'UTC');
|
|
$event['recur_exceptions'][] = $exception->format('Y-m-d');
|
|
}
|
|
}
|
|
|
|
$start = new Horde_Date($event['start'] / 1000, 'UTC');
|
|
$event['start_date'] = $start->format('Y-m-d');
|
|
$event['start_time'] = $start->format('H:i:s');
|
|
$end = new Horde_Date($event['end'] / 1000, 'UTC');
|
|
$event['end_date'] = $end->format('Y-m-d');
|
|
$event['end_time'] = $end->format('H:i:s');
|
|
$event['tags'] == $event['categories'];
|
|
|
|
$newEvent = $driver->getEvent();
|
|
$newEvent->fromHash($event);
|
|
|
|
if ($event['recur_id'] && ($event['recur_id'] != $event['id'])) {
|
|
$base = $ox->getEvent($folderId, $event['recur_id']);
|
|
$baseStart = new Horde_Date($base['start_date'] / 1000, 'UTC');
|
|
$baseStart->setTimezone($base['timezone']);
|
|
$newEvent->baseid = $base['uid'];
|
|
$newEvent->exceptionoriginaldate = new Horde_Date(
|
|
$event['recur_change_exceptions'][0] / 1000, 'UTC'
|
|
);
|
|
$newEvent->exceptionoriginaldate->setTimezone($base['timezone']);
|
|
// This is a hack that will probably break if recurrences span
|
|
// DST changes. Correct, but also more complex would be to
|
|
// calculate the actual time of this recurrence.
|
|
// recur_change_exception only contains the date.
|
|
$newEvent->exceptionoriginaldate->hour = $baseStart->hour;
|
|
$newEvent->exceptionoriginaldate->min = $baseStart->min;
|
|
$newEvent->exceptionoriginaldate->sec = $baseStart->sec;
|
|
$newEvent->uid = null;
|
|
}
|
|
$newEvent->timezone = $timezone;
|
|
switch ($event['status']) {
|
|
case 1:
|
|
$newEvent->status = Kronolith::STATUS_CONFIRMED;
|
|
break;
|
|
case 2:
|
|
$newEvent->status = Kronolith::STATUS_TENTATIVE;
|
|
break;
|
|
case 3:
|
|
$newEvent->status = Kronolith::STATUS_CONFIRMED;
|
|
break;
|
|
case 4:
|
|
$newEvent->status = Kronolith::STATUS_FREE;
|
|
break;
|
|
}
|
|
if ($event['attendees']) {
|
|
foreach ($event['users'] as $attendee) {
|
|
if (!isset($users[$attendee['id']])) {
|
|
$users[$attendee['id']] = $ox->getUser($attendee['id']);
|
|
}
|
|
if (count($event['attendees']) == 1 &&
|
|
$users[$attendee['id']]['login_info'] == $user) {
|
|
break;
|
|
}
|
|
$newEvent->addAttendee(
|
|
$users[$attendee['id']]['email1'],
|
|
Kronolith::PART_REQUIRED,
|
|
$attendee['confirmation'] + 1,
|
|
$users[$attendee['id']]['display_name']
|
|
);
|
|
}
|
|
foreach ($event['confirmations'] as $attendee) {
|
|
$newEvent->addAttendee(
|
|
$attendee['mail'],
|
|
Kronolith::PART_REQUIRED,
|
|
$attendee['status'] + 1,
|
|
$attendee['display_name']
|
|
);
|
|
}
|
|
}
|
|
|
|
try {
|
|
$newEvent->save();
|
|
$count++;
|
|
} catch (Kronolith_Exception $e) {
|
|
$cli->message(' ' . $e->getMessage(), 'cli.error');
|
|
}
|
|
}
|
|
}
|
|
|
|
$cli->message(' Added ' . $count . ' events', 'cli.success');
|
|
$count = 0;
|
|
}
|