mirror of
https://github.com/YunoHost-Apps/agendav_ynh.git
synced 2024-09-03 20:36:12 +02:00
850 lines
30 KiB
PHP
850 lines
30 KiB
PHP
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
|
|
|
|
/*
|
|
* Copyright 2011-2012 Jorge López Pérez <jorge@adobo.org>
|
|
*
|
|
* This file is part of AgenDAV.
|
|
*
|
|
* AgenDAV is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* any later version.
|
|
*
|
|
* AgenDAV is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with AgenDAV. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
class Event extends CI_Controller {
|
|
|
|
private $time_format;
|
|
private $date_format;
|
|
|
|
private $tz;
|
|
private $tz_utc;
|
|
|
|
private $prefs;
|
|
|
|
function __construct() {
|
|
parent::__construct();
|
|
|
|
if (!$this->auth->is_authenticated()) {
|
|
$this->extended_logs->message('INFO',
|
|
'Anonymous access attempt to '
|
|
. uri_string());
|
|
$this->output->set_status_header('401');
|
|
$this->output->_display();
|
|
die();
|
|
}
|
|
|
|
$this->date_format = $this->dates->date_format_string('date');
|
|
$this->time_format = $this->dates->time_format_string('date');
|
|
|
|
$this->tz = $this->timezonemanager->getTz(
|
|
$this->config->item('default_timezone'));
|
|
$this->tz_utc = $this->timezonemanager->getTz('UTC');
|
|
|
|
$this->prefs =
|
|
Preferences::singleton($this->session->userdata('prefs'));
|
|
|
|
$this->load->library('caldav');
|
|
|
|
$this->output->set_content_type('application/json');
|
|
}
|
|
|
|
function index() {
|
|
}
|
|
|
|
function all() {
|
|
$returned_events = array();
|
|
$err = 0;
|
|
|
|
// For benchmarking
|
|
$time_start = microtime(TRUE);
|
|
$time_end = $time_fetch = -1;
|
|
$total_fetch = $total_parse = -1;
|
|
|
|
$calendar = $this->input->get('calendar');
|
|
if ($calendar === FALSE) {
|
|
$this->extended_logs->message('ERROR',
|
|
'Calendar events request with no calendar name');
|
|
$err = 400;
|
|
}
|
|
|
|
$start = $this->input->get('start');
|
|
$end = $this->input->get('end');
|
|
|
|
if ($err == 0 && $start === FALSE) {
|
|
// Something is wrong here
|
|
$this->extended_logs->message('ERROR',
|
|
'Calendar events request for ' . $calendar
|
|
.' with no start timestamp');
|
|
$err = 400;
|
|
} else if ($err == 0) {
|
|
$start =
|
|
$this->dates->datetime2idt(
|
|
$this->dates->ts2datetime(
|
|
$start,
|
|
$this->tz_utc));
|
|
|
|
if ($end === FALSE) {
|
|
$this->extended_logs->message('ERROR',
|
|
'Calendar events request for ' . $calendar
|
|
.' with no end timestamp');
|
|
$err = 400;
|
|
} else {
|
|
$end =
|
|
$this->dates->datetime2idt(
|
|
$this->dates->ts2datetime(
|
|
$end,
|
|
$this->tz_utc));
|
|
|
|
$returned_events = $this->caldav->fetch_events(
|
|
$this->auth->get_user(),
|
|
$this->auth->get_passwd(),
|
|
$start, $end,
|
|
$calendar);
|
|
|
|
$time_fetch = microtime(TRUE);
|
|
|
|
if ($returned_events === FALSE) {
|
|
// Something went wrong
|
|
$err = 500;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($err == 0) {
|
|
$parsed =
|
|
$this->icshelper->expand_and_parse_events($returned_events,
|
|
$start, $end, $calendar);
|
|
|
|
$time_end = microtime(TRUE);
|
|
|
|
$total_fetch = sprintf('%.4F', $time_fetch - $time_start);
|
|
$total_parse = sprintf('%.4F', $time_end - $time_fetch);
|
|
$total_time = sprintf('%.4F', $time_end - $time_start);
|
|
|
|
|
|
$this->extended_logs->message('INTERNALS', 'Sending to client ' .
|
|
count($parsed) . ' event(s) on calendar ' . $calendar
|
|
.' ['.$total_fetch.'/'.$total_parse.'/'.$total_time.']');
|
|
|
|
$this->output->set_header("X-Fetch-Time: " . $total_fetch);
|
|
$this->output->set_header("X-Parse-Time: " . $total_parse);
|
|
$this->output->set_output(json_encode($parsed));
|
|
} else {
|
|
$this->output->set_status_header($err, 'Error');
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Deletes an event
|
|
* TODO: control whether we want to remove a single recurrence-id
|
|
* instead of the whole event
|
|
*/
|
|
function delete() {
|
|
$calendar = $this->input->post('calendar');
|
|
$uid = $this->input->post('uid');
|
|
$href = $this->input->post('href');
|
|
$etag = $this->input->post('etag');
|
|
|
|
$response = array();
|
|
|
|
if ($calendar === FALSE || $uid === FALSE || $href === FALSE ||
|
|
$etag === FALSE || empty($calendar) || empty($uid) ||
|
|
empty($href) || empty($calendar) || empty($etag)) {
|
|
$this->extended_logs->message('ERROR',
|
|
'Call to delete_event() with no calendar, uid, href or etag');
|
|
$this->_throw_error($this->i18n->_('messages',
|
|
'error_interfacefailure'));
|
|
} else {
|
|
$this->load->library('caldav');
|
|
$res = $this->caldav->delete_resource(
|
|
$this->auth->get_user(),
|
|
$this->auth->get_passwd(),
|
|
$href,
|
|
$calendar,
|
|
$etag);
|
|
if ($res === TRUE) {
|
|
$this->_throw_success();
|
|
} else {
|
|
// There was an error
|
|
$msg = $this->i18n->_('messages', $res[0],
|
|
$res[1]);
|
|
$this->_throw_exception($msg);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates or modifies an existing event
|
|
* TODO: detect if we are defining a new recurrence-id
|
|
*/
|
|
function modify() {
|
|
// Important data to be filled later
|
|
$etag = '';
|
|
$href = '';
|
|
$calendar = '';
|
|
$resource = null;
|
|
// Default new properties. To be cleaned
|
|
// on Icshelper library
|
|
$p = $this->input->post(null, TRUE); // XSS
|
|
|
|
$this->load->library('form_validation');
|
|
$this->form_validation
|
|
->set_rules('calendar', $this->i18n->_('labels', 'calendar'), 'required');
|
|
$this->form_validation
|
|
->set_rules('summary', $this->i18n->_('labels', 'summary'), 'required');
|
|
$this->form_validation
|
|
->set_rules('start_date', $this->i18n->_('labels', 'startdate'),
|
|
'required|callback__valid_date');
|
|
$this->form_validation
|
|
->set_rules('end_date', $this->i18n->_('labels', 'enddate'),
|
|
'required|callback__valid_date');
|
|
$this->form_validation
|
|
->set_rules('recurrence_count', $this->i18n->_('labels',
|
|
'repeatcount'),
|
|
'callback__empty_or_natural_no_zero');
|
|
$this->form_validation
|
|
->set_rules('recurrence_until', $this->i18n->_('labels',
|
|
'repeatuntil'),
|
|
'callback__empty_or_valid_date');
|
|
|
|
if ($this->form_validation->run() === FALSE) {
|
|
$this->_throw_exception(validation_errors());
|
|
}
|
|
|
|
$this->load->library('caldav');
|
|
|
|
// DateTime objects
|
|
$start = null;
|
|
$end = null;
|
|
|
|
$tz = isset($p['timezone']) ?
|
|
$this->timezonemanager->getTz($p['timezone']) :
|
|
$this->timezonemanager->getTz(
|
|
$this->config->item('default_timezone'));
|
|
|
|
|
|
// Additional validations
|
|
|
|
// 1. All day? If all day, require start_time, end_date and end_time
|
|
// If not, generate our own values
|
|
if (isset($p['allday']) && $p['allday'] == 'true') {
|
|
// Start and end days, 00:00
|
|
$start = $this->dates->frontend2datetime($p['start_date']
|
|
. ' ' . date($this->time_format, mktime(0,0)),
|
|
$this->tz_utc);
|
|
$end = $this->dates->frontend2datetime($p['end_date']
|
|
. ' ' . date($this->time_format, mktime(0, 0)),
|
|
$this->tz_utc);
|
|
// Add 1 day (iCalendar needs this)
|
|
$end->add(new DateInterval('P1D'));
|
|
} else {
|
|
// Create new form validation rules
|
|
$this->form_validation
|
|
->set_rules('start_time', $this->i18n->_('labels',
|
|
'starttime'),
|
|
'required|callback__valid_time');
|
|
$this->form_validation
|
|
->set_rules('end_time', $this->i18n->_('labels',
|
|
'endtime'),
|
|
'required|callback__valid_time');
|
|
|
|
if ($this->form_validation->run() === FALSE) {
|
|
$this->_throw_exception(validation_errors());
|
|
}
|
|
|
|
// 2. Check if start date <= end date
|
|
$start = $this->dates->frontend2datetime($p['start_date']
|
|
. ' ' . $p['start_time'], $tz);
|
|
$end = $this->dates->frontend2datetime($p['end_date']
|
|
. ' ' . $p['end_time'], $tz);
|
|
if ($end->getTimestamp() < $start->getTimestamp()) {
|
|
$this->_throw_exception($this->i18n->_('messages',
|
|
'error_startgreaterend'));
|
|
}
|
|
}
|
|
|
|
$p['dtstart'] = $start;
|
|
$p['dtend'] = $end;
|
|
|
|
// Recurrence checks
|
|
unset($p['rrule']);
|
|
|
|
if (isset($p['recurrence_type'])) {
|
|
if ($p['recurrence_type'] != 'none') {
|
|
if (isset($p['recurrence_until']) &&
|
|
!empty($p['recurrence_until'])) {
|
|
$p['recurrence_until'] .= date($this->time_format,
|
|
mktime(0, 0)); // Tricky
|
|
}
|
|
|
|
$rrule = $this->recurrence->build($p, $rrule_err);
|
|
if (FALSE === $rrule) {
|
|
// Couldn't build rrule
|
|
$this->extended_logs->message('ERROR',
|
|
'Error building RRULE ('
|
|
. $rrule_err .')');
|
|
$this->_throw_exception($this->i18n->_('messages',
|
|
'error_bogusrepeatrule') . ': ' . $rrule_err);
|
|
}
|
|
} else {
|
|
// Deleted RRULE
|
|
// TODO in the future, consider recurrence-id and so
|
|
$rrule = '';
|
|
}
|
|
|
|
$p['rrule'] = $rrule;
|
|
}
|
|
|
|
|
|
// Reminders
|
|
$reminders = array();
|
|
|
|
// Contains a list of old parseable (visible on UI) reminders.
|
|
// Used to remove reminders that were deleted by user
|
|
$visible_reminders = isset($p['visible_reminders']) ?
|
|
$p['visible_reminders'] : array();
|
|
|
|
if (isset($p['reminders']) && is_array($p['reminders'])) {
|
|
$data_reminders = $p['reminders'];
|
|
$num_reminders = count($data_reminders['is_absolute']);
|
|
|
|
for($i=0;$i<$num_reminders;$i++) {
|
|
$this_reminder = null;
|
|
$data_reminders['is_absolute'][$i] =
|
|
($data_reminders['is_absolute'][$i] == 'true' ? TRUE :
|
|
FALSE);
|
|
|
|
if ($data_reminders['is_absolute'][$i]) {
|
|
$when =
|
|
$this->dates->frontend2datetime($data_reminders['tdate'][$i]
|
|
. ' ' . $data_reminders['ttime'][$i],
|
|
$this->tz);
|
|
$when->setTimezone($this->tz_utc);
|
|
$this_reminder = Reminder::createFrom($when);
|
|
} else {
|
|
$when = array(
|
|
'before' => ($data_reminders['before'][$i] ==
|
|
'true'),
|
|
'relatedStart' =>
|
|
($data_reminders['relatedStart'][$i] == 'true'),
|
|
);
|
|
$interval = $data_reminders['interval'][$i];
|
|
$when[$interval] = $data_reminders['qty'][$i];
|
|
|
|
$this_reminder = Reminder::createFrom($when);
|
|
}
|
|
|
|
if (!empty($data_reminders['order'][$i])) {
|
|
$this_reminder->order = $data_reminders['order'][$i];
|
|
}
|
|
|
|
log_message('INTERNALS', 'Adding reminder ' .
|
|
$this_reminder);
|
|
$reminders[] = $this_reminder;
|
|
}
|
|
}
|
|
|
|
|
|
// Is this a new event or a modification?
|
|
|
|
// Valid destination calendar?
|
|
if (!$this->caldav->is_valid_calendar(
|
|
$this->auth->get_user(),
|
|
$this->auth->get_passwd(),
|
|
$p['calendar'])) {
|
|
$this->_throw_exception(
|
|
$this->i18n->_('messages', 'error_calendarnotfound',
|
|
array('%calendar' => $p['calendar'])));
|
|
} else {
|
|
$calendar = $p['calendar'];
|
|
}
|
|
|
|
if (!isset($p['modification'])) {
|
|
// New event (resource)
|
|
$new_uid = $this->icshelper->new_resource($p,
|
|
$resource, $this->tz, $reminders);
|
|
$href = $new_uid . '.ics';
|
|
$etag = '*';
|
|
} else {
|
|
// Load existing resource
|
|
|
|
// Valid original calendar?
|
|
if (!isset($p['original_calendar'])) {
|
|
$this->_throw_exception($this->i18n->_('messages',
|
|
'error_interfacefailure'));
|
|
} else {
|
|
$original_calendar = $p['original_calendar'];
|
|
}
|
|
|
|
if (!$this->caldav->is_valid_calendar(
|
|
$this->auth->get_user(),
|
|
$this->auth->get_passwd(),
|
|
$original_calendar)) {
|
|
$this->_throw_exception(
|
|
$this->i18n->_('messages', 'error_calendarnotfound',
|
|
array('%calendar' => $original_calendar)));
|
|
}
|
|
|
|
$uid = $p['uid'];
|
|
$href = $p['href'];
|
|
$etag = $p['etag'];
|
|
|
|
$res = $this->caldav->fetch_resource_by_uid(
|
|
$this->auth->get_user(),
|
|
$this->auth->get_passwd(),
|
|
$uid,
|
|
$original_calendar);
|
|
|
|
if (is_null($res)) {
|
|
$this->_throw_error(
|
|
$this->i18n->_('messages', 'error_eventnotfound'));
|
|
}
|
|
|
|
if ($etag != $res['etag']) {
|
|
$this->_throw_error(
|
|
$this->i18n->_('messages', 'error_eventchanged'));
|
|
}
|
|
|
|
|
|
$resource = $this->icshelper->parse_icalendar($res['data']);
|
|
$timezones = $this->icshelper->get_timezones($resource);
|
|
$vevent = null;
|
|
// TODO: recurrence-id?
|
|
$modify_pos =
|
|
$this->icshelper->find_component_position($resource,
|
|
'VEVENT', array(), $vevent);
|
|
if (is_null($vevent)) {
|
|
$this->_throw_error(
|
|
$this->i18n->_('messages', 'error_eventnofound'));
|
|
}
|
|
|
|
$tz = $this->icshelper->detect_tz($vevent, $timezones);
|
|
|
|
// Change every property
|
|
$force_new_value =
|
|
(isset($p['allday']) && $p['allday'] == 'true') ?
|
|
'DATE' : 'DATE-TIME';
|
|
|
|
$vevent = $this->icshelper->make_start($vevent, $tz,
|
|
$start, null,
|
|
$force_new_value);
|
|
$vevent = $this->icshelper->make_end($vevent, $tz,
|
|
$end, null,
|
|
$force_new_value);
|
|
|
|
$properties = array(
|
|
'summary' => $p['summary'],
|
|
'location' => $p['location'],
|
|
'description' => $p['description'],
|
|
);
|
|
|
|
// Only change RRULE when we are able to
|
|
if (isset($p['rrule'])) {
|
|
$properties['rrule'] = $p['rrule'];
|
|
}
|
|
|
|
// CLASS and TRANSP
|
|
if (isset($p['class'])) {
|
|
$properties['class'] = $p['class'];
|
|
}
|
|
|
|
if (isset($p['transp'])) {
|
|
$properties['transp'] = strtoupper($p['transp']);
|
|
}
|
|
|
|
$vevent = $this->icshelper->change_properties($vevent,
|
|
$properties);
|
|
|
|
// Add/change/remove reminders
|
|
$vevent = $this->icshelper->set_valarms($vevent,
|
|
$reminders, $visible_reminders);
|
|
|
|
$vevent = $this->icshelper->set_last_modified($vevent);
|
|
$resource = $this->icshelper->replace_component($resource,
|
|
'vevent', $modify_pos, $vevent);
|
|
if ($resource === FALSE) {
|
|
$this->_throw_error(
|
|
$this->i18n->_('messages', 'error_internalgen'));
|
|
}
|
|
|
|
// Moving event between calendars
|
|
if ($original_calendar != $calendar) {
|
|
// We will need this etag later
|
|
$original_etag = $etag;
|
|
$etag = '*';
|
|
}
|
|
}
|
|
|
|
// PUT on server
|
|
$new_etag = $this->caldav->put_resource(
|
|
$this->auth->get_user(),
|
|
$this->auth->get_passwd(),
|
|
$href,
|
|
$calendar,
|
|
$resource,
|
|
$etag);
|
|
|
|
if (FALSE === $new_etag) {
|
|
$code = $this->caldav->get_last_response();
|
|
switch ($code[0]) {
|
|
case '412':
|
|
// TODO new events + already used UIDs!
|
|
if (isset($p['modification'])) {
|
|
$this->_throw_exception(
|
|
$this->i18n->_('messages', 'error_eventchanged'));
|
|
} else {
|
|
// Already used UID on new event. What a bad luck!
|
|
// TODO propose a solution
|
|
$this->_throw_error('Bad luck'
|
|
.' Repeated UID');
|
|
}
|
|
break;
|
|
case '403':
|
|
$this->_throw_error($this->i18n->_('messages',
|
|
'error_denied'));
|
|
break;
|
|
default:
|
|
$this->_throw_error( $this->i18n->_('messages',
|
|
'error_unknownhttpcode',
|
|
array('%res' => $code[0])));
|
|
break;
|
|
}
|
|
} else {
|
|
// Remove original event
|
|
if (isset($p['modification']) && $original_calendar != $calendar) {
|
|
$res = $this->caldav->delete_resource(
|
|
$this->auth->get_user(),
|
|
$this->auth->get_passwd(),
|
|
$href,
|
|
$original_calendar,
|
|
$original_etag);
|
|
if ($res === TRUE) {
|
|
$this->extended_logs->message('INTERNALS',
|
|
'Deleted event (moved) with uid=' . $uid
|
|
.' from calendar ' . $original_calendar);
|
|
} else {
|
|
// There was an error
|
|
$this->extended_logs->message('INTERNALS',
|
|
'Error deleting event (moved) with uid=' . $uid
|
|
.' from calendar ' . $original_calendar . ': '
|
|
. $res);
|
|
$this->_throw_exception($res);
|
|
}
|
|
}
|
|
|
|
// Return a list of affected calendars (original_calendar, new
|
|
// calendar)
|
|
$affected_calendars = array($calendar);
|
|
if (isset($original_calendar) && $original_calendar !=
|
|
$calendar) {
|
|
$affected_calendars[] = $original_calendar;
|
|
}
|
|
|
|
$this->_throw_success($affected_calendars);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Resizing of an event
|
|
*/
|
|
function alter() {
|
|
$uid = $this->input->post('uid');
|
|
$calendar = $this->input->post('calendar');
|
|
$etag = $this->input->post('etag');
|
|
$dayDelta = $this->input->post('dayDelta');
|
|
$minuteDelta = $this->input->post('minuteDelta');
|
|
$allday = $this->input->post('allday');
|
|
$was_allday = $this->input->post('was_allday');
|
|
$view = $this->input->post('view');
|
|
$type = $this->input->post('type');
|
|
|
|
if ($uid === FALSE || $calendar === FALSE ||
|
|
$etag === FALSE || $dayDelta === FALSE ||
|
|
$minuteDelta === FALSE ||
|
|
$view === FALSE || $allday === FALSE ||
|
|
$type === FALSE || $was_allday === FALSE) {
|
|
$this->_throw_error($this->i18n->_('messages',
|
|
'error_interfacefailure'));
|
|
}
|
|
|
|
// Generate a duration string
|
|
$pattern = '/^(-)?([0-9]+)$/';
|
|
if ($view == 'month') {
|
|
$dur_string = preg_replace($pattern, '\1P\2D', $dayDelta);
|
|
} else {
|
|
// Going the easy way O:) 1D = 1440M
|
|
$val = intval($minuteDelta) + intval($dayDelta)*1440;
|
|
$minuteDelta = strval($val);
|
|
$dur_string = preg_replace($pattern, '\1PT\2M', $minuteDelta);
|
|
}
|
|
|
|
// Load resource
|
|
$resource = $this->caldav->fetch_resource_by_uid(
|
|
$this->auth->get_user(),
|
|
$this->auth->get_passwd(),
|
|
$uid,
|
|
$calendar);
|
|
|
|
|
|
if (is_null($resource)) {
|
|
$this->_throw_error(
|
|
$this->i18n->_('messages', 'error_eventnotfound'));
|
|
}
|
|
|
|
if ($etag != $resource['etag']) {
|
|
$this->_throw_error(
|
|
$this->i18n->_('messages', 'error_eventchanged'));
|
|
}
|
|
|
|
// We're prepared to modify the event
|
|
$href = $resource['href'];
|
|
$ical = $this->icshelper->parse_icalendar($resource['data']);
|
|
$timezones = $this->icshelper->get_timezones($ical);
|
|
$vevent = null;
|
|
// TODO: recurrence-id?
|
|
$modify_pos = $this->icshelper->find_component_position($ical,
|
|
'VEVENT', array(), $vevent);
|
|
|
|
if (is_null($vevent)) {
|
|
$this->_throw_error(
|
|
$this->i18n->_('messages', 'error_eventnotfound'));
|
|
}
|
|
|
|
$tz = $this->icshelper->detect_tz($vevent, $timezones);
|
|
|
|
/*
|
|
log_message('INTERNALS', 'PRE: ['.$tz.'] '
|
|
. $vevent->createComponent($x));
|
|
*/
|
|
|
|
// Distinguish between these two options
|
|
if ($type == 'drag') {
|
|
// 4 Posibilities
|
|
if ($was_allday == 'true') {
|
|
if ($allday == 'true') {
|
|
// From all day to all day
|
|
$tz = $this->tz_utc;
|
|
$new_vevent = $this->icshelper->make_start($vevent,
|
|
$tz, null, $dur_string, 'DATE');
|
|
$new_vevent = $this->icshelper->make_end($new_vevent,
|
|
$tz, null, $dur_string, 'DATE');
|
|
} else {
|
|
// From all day to normal event
|
|
// Use default timezone
|
|
$tz = $this->tz;
|
|
|
|
// Add VTIMEZONE
|
|
$this->icshelper->add_vtimezone($ical, $tz->getName(),
|
|
$timezones);
|
|
|
|
// Set start date using default timezone instead of UTC
|
|
$start = $this->icshelper->extract_date($vevent,
|
|
'DTSTART', $tz);
|
|
$start_obj = $start['result'];
|
|
$start_obj->add($this->dates->duration2di($dur_string));
|
|
$new_vevent = $this->icshelper->make_start($vevent,
|
|
$tz, $start_obj, null, 'DATE-TIME',
|
|
$tz->getName());
|
|
$new_vevent = $this->icshelper->make_end($new_vevent,
|
|
$tz, $start_obj, 'PT1H', 'DATE-TIME',
|
|
$tz->getName());
|
|
}
|
|
} else {
|
|
// was_allday = false
|
|
$force = ($allday == 'true' ? 'DATE' : null);
|
|
$new_vevent = $this->icshelper->make_start($vevent, $tz,
|
|
null, $dur_string, $force);
|
|
if ($allday == 'true') {
|
|
$new_start = $this->icshelper->extract_date($new_vevent,
|
|
'DTSTART', $tz);
|
|
$new_vevent = $this->icshelper->make_end($new_vevent,
|
|
$tz, $new_start['result'], 'P1D', $force);
|
|
} else {
|
|
$new_vevent = $this->icshelper->make_end($new_vevent,
|
|
$tz, null, $dur_string, $force);
|
|
}
|
|
}
|
|
} else {
|
|
$new_vevent = $this->icshelper->make_end($vevent,
|
|
$tz, null, $dur_string);
|
|
|
|
// Check if DTSTART == DTEND
|
|
$new_dtstart = $this->icshelper->extract_date($new_vevent,
|
|
'DTSTART', $tz);
|
|
$new_dtend = $this->icshelper->extract_date($new_vevent,
|
|
'DTEND', $tz);
|
|
if ($new_dtstart['result'] == $new_dtend['result']) {
|
|
// Avoid this
|
|
$new_vevent = $this->icshelper->make_end($vevent,
|
|
$tz, null, ($new_dtend['value'] == 'DATE' ? 'P1D' :
|
|
'PT60M'));
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// Apply LAST-MODIFIED update
|
|
$new_vevent = $this->icshelper->set_last_modified($new_vevent);
|
|
|
|
/*
|
|
log_message('INTERNALS', 'POS: ' .
|
|
$new_vevent->createComponent($x));
|
|
*/
|
|
|
|
|
|
$ical = $this->icshelper->replace_component($ical, 'vevent',
|
|
$modify_pos, $new_vevent);
|
|
if ($ical === FALSE) {
|
|
$this->_throw_error($this->i18n->_('messages',
|
|
'error_internalgen'));
|
|
}
|
|
|
|
// PUT on server
|
|
$new_etag = $this->caldav->put_resource(
|
|
$this->auth->get_user(),
|
|
$this->auth->get_passwd(),
|
|
$href,
|
|
$calendar,
|
|
$ical,
|
|
$etag);
|
|
|
|
|
|
if (FALSE === $new_etag) {
|
|
$code = $this->caldav->get_last_response();
|
|
switch ($code[0]) {
|
|
case '412':
|
|
$this->_throw_exception(
|
|
$this->i18n->_('messages', 'error_eventchanged'));
|
|
break;
|
|
default:
|
|
$this->_throw_error( $this->i18n->_('messages',
|
|
'error_unknownhttpcode',
|
|
array('%res' => $code[0])));
|
|
break;
|
|
}
|
|
} else {
|
|
// Send new information about this event
|
|
|
|
$info = $this->icshelper->parse_vevent_fullcalendar(
|
|
$new_vevent, $href, $new_etag, $calendar, $tz,
|
|
$timezones);
|
|
$this->_throw_success($info);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Searchs a principal using provided data
|
|
*/
|
|
function principal_search() {
|
|
$result = array();
|
|
$term = $this->input->get('term');
|
|
|
|
if (!empty($term)) {
|
|
$caldav_res = $this->caldav->principal_property_search(
|
|
$this->auth->get_user(),
|
|
$this->auth->get_passwd(),
|
|
$term, $term);
|
|
|
|
if ($caldav_res[0] != '207') {
|
|
$this->extended_logs->message('ERROR',
|
|
'principal-property-search for '
|
|
. $term . ' answer was HTTP code '
|
|
. $caldav_res[0]);
|
|
} else {
|
|
$result = array_values($caldav_res[1]);
|
|
}
|
|
}
|
|
|
|
$this->output->set_output(json_encode($result));
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Input validators
|
|
*/
|
|
|
|
// Validate date format
|
|
function _valid_date($d) {
|
|
$obj = $this->dates->frontend2datetime($d .' ' .
|
|
date($this->time_format));
|
|
if (FALSE === $obj) {
|
|
$this->form_validation->set_message('_valid_date',
|
|
$this->i18n->_('messages', 'error_invaliddate'));
|
|
return FALSE;
|
|
} else {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// Validate date format (or empty string)
|
|
function _empty_or_valid_date($d) {
|
|
return empty($d) || $this->_valid_date($d);
|
|
}
|
|
|
|
// Validate empty or > 0
|
|
function _empty_or_natural_no_zero($n) {
|
|
return empty($n) || intval($n) > 0;
|
|
}
|
|
|
|
// Validate time format
|
|
function _valid_time($t) {
|
|
$obj = $this->dates->frontend2datetime(date($this->date_format) .' '. $t);
|
|
if (FALSE === $obj) {
|
|
$this->form_validation->set_message('_valid_time',
|
|
$this->i18n->_('messages', 'error_invalidtime'));
|
|
return FALSE;
|
|
} else {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Throws an exception message
|
|
*/
|
|
function _throw_exception($message) {
|
|
$this->output->set_output(json_encode(array(
|
|
'result' => 'EXCEPTION',
|
|
'message' => $message)));
|
|
$this->output->_display();
|
|
die();
|
|
}
|
|
|
|
/**
|
|
* Throws an error message
|
|
*/
|
|
function _throw_error($message) {
|
|
$this->output->set_output(json_encode(array(
|
|
'result' => 'ERROR',
|
|
'message' => $message)));
|
|
$this->output->_display();
|
|
die();
|
|
}
|
|
|
|
/**
|
|
* Throws a success message
|
|
*/
|
|
function _throw_success($message = '') {
|
|
$this->output->set_output(json_encode(array(
|
|
'result' => 'SUCCESS',
|
|
'message' => $message)));
|
|
$this->output->_display();
|
|
die();
|
|
}
|
|
|
|
|
|
|
|
}
|