Begin with event attendees and free/busy implementation
This commit is contained in:
parent
6994d3d38f
commit
d210f1c023
10 changed files with 356 additions and 9 deletions
|
@ -108,6 +108,8 @@ class calendar extends rcube_plugin
|
||||||
$this->register_action('export_events', array($this, 'export_events'));
|
$this->register_action('export_events', array($this, 'export_events'));
|
||||||
$this->register_action('upload', array($this, 'attachment_upload'));
|
$this->register_action('upload', array($this, 'attachment_upload'));
|
||||||
$this->register_action('get-attachment', array($this, 'attachment_get'));
|
$this->register_action('get-attachment', array($this, 'attachment_get'));
|
||||||
|
$this->register_action('freebusy-status', array($this, 'freebusy_status'));
|
||||||
|
$this->register_action('freebusy-times', array($this, 'freebusy_times'));
|
||||||
$this->register_action('randomdata', array($this, 'generate_randomdata'));
|
$this->register_action('randomdata', array($this, 'generate_randomdata'));
|
||||||
}
|
}
|
||||||
else if ($this->rc->task == 'settings') {
|
else if ($this->rc->task == 'settings') {
|
||||||
|
@ -169,10 +171,12 @@ class calendar extends rcube_plugin
|
||||||
$this->register_handler('plugin.recurrence_form', array($this->ui, 'recurrence_form'));
|
$this->register_handler('plugin.recurrence_form', array($this->ui, 'recurrence_form'));
|
||||||
$this->register_handler('plugin.attachments_form', array($this->ui, 'attachments_form'));
|
$this->register_handler('plugin.attachments_form', array($this->ui, 'attachments_form'));
|
||||||
$this->register_handler('plugin.attachments_list', array($this->ui, 'attachments_list'));
|
$this->register_handler('plugin.attachments_list', array($this->ui, 'attachments_list'));
|
||||||
|
$this->register_handler('plugin.attendees_list', array($this->ui, 'attendees_list'));
|
||||||
|
$this->register_handler('plugin.attendees_form', array($this->ui, 'attendees_form'));
|
||||||
$this->register_handler('plugin.edit_recurring_warning', array($this->ui, 'recurring_event_warning'));
|
$this->register_handler('plugin.edit_recurring_warning', array($this->ui, 'recurring_event_warning'));
|
||||||
$this->register_handler('plugin.searchform', array($this->rc->output, 'search_form')); // use generic method from rcube_template
|
$this->register_handler('plugin.searchform', array($this->rc->output, 'search_form')); // use generic method from rcube_template
|
||||||
|
|
||||||
$this->rc->output->add_label('low','normal','high','delete','cancel','uploading');
|
$this->rc->output->add_label('low','normal','high','delete','cancel','uploading','noemailwarning');
|
||||||
|
|
||||||
$this->rc->output->send("calendar.calendar");
|
$this->rc->output->send("calendar.calendar");
|
||||||
}
|
}
|
||||||
|
@ -442,29 +446,41 @@ class calendar extends rcube_plugin
|
||||||
case "new":
|
case "new":
|
||||||
// create UID for new event
|
// create UID for new event
|
||||||
$event['uid'] = $this->generate_uid();
|
$event['uid'] = $this->generate_uid();
|
||||||
|
|
||||||
|
// set current user as organizer
|
||||||
|
if (!$event['attendees']) {
|
||||||
|
$identity = $this->rc->user->get_identity();
|
||||||
|
$event['attendees'][] = array('role' => 'OWNER', 'name' => $identity['name'], 'email' => $identity['email']);
|
||||||
|
}
|
||||||
|
|
||||||
$this->prepare_event($event);
|
$this->prepare_event($event);
|
||||||
if ($success = $this->driver->new_event($event))
|
if ($success = $this->driver->new_event($event))
|
||||||
$this->cleanup_event($event);
|
$this->cleanup_event($event);
|
||||||
$reload = true;
|
$reload = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "edit":
|
case "edit":
|
||||||
$this->prepare_event($event);
|
$this->prepare_event($event);
|
||||||
if ($success = $this->driver->edit_event($event))
|
if ($success = $this->driver->edit_event($event))
|
||||||
$this->cleanup_event($event);
|
$this->cleanup_event($event);
|
||||||
$reload = true;
|
$reload = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "resize":
|
case "resize":
|
||||||
$success = $this->driver->resize_event($event);
|
$success = $this->driver->resize_event($event);
|
||||||
$reload = true;
|
$reload = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "move":
|
case "move":
|
||||||
$success = $this->driver->move_event($event);
|
$success = $this->driver->move_event($event);
|
||||||
$reload = true;
|
$reload = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "remove":
|
case "remove":
|
||||||
$removed = $this->driver->remove_event($event);
|
$removed = $this->driver->remove_event($event);
|
||||||
$reload = true;
|
$reload = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "dismiss":
|
case "dismiss":
|
||||||
foreach (explode(',', $event['id']) as $id)
|
foreach (explode(',', $event['id']) as $id)
|
||||||
$success |= $this->driver->dismiss_alarm($id, $event['snooze']);
|
$success |= $this->driver->dismiss_alarm($id, $event['snooze']);
|
||||||
|
@ -607,6 +623,10 @@ class calendar extends rcube_plugin
|
||||||
// user prefs
|
// user prefs
|
||||||
$settings['hidden_calendars'] = array_filter(explode(',', $this->rc->config->get('hidden_calendars', '')));
|
$settings['hidden_calendars'] = array_filter(explode(',', $this->rc->config->get('hidden_calendars', '')));
|
||||||
|
|
||||||
|
// get user identity to create default attendee
|
||||||
|
$identity = $this->rc->user->get_identity();
|
||||||
|
$settings['event_owner'] = array('name' => $identity['name'], 'email' => $identity['email']);
|
||||||
|
|
||||||
return $settings;
|
return $settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1114,4 +1134,58 @@ class calendar extends rcube_plugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Echo simple free/busy status text for the given user and time range
|
||||||
|
*/
|
||||||
|
public function freebusy_status()
|
||||||
|
{
|
||||||
|
$email = get_input_value('email', RCUBE_INPUT_GPC);
|
||||||
|
$start = get_input_value('start', RCUBE_INPUT_GET);
|
||||||
|
$end = get_input_value('end', RCUBE_INPUT_GET);
|
||||||
|
|
||||||
|
if (!$start) $start = time();
|
||||||
|
if (!$end) $end = $start + 3600;
|
||||||
|
|
||||||
|
$status = 'UNKNOWN';
|
||||||
|
|
||||||
|
// if the backend has free-busy information
|
||||||
|
$fblist = $this->driver->get_freebusy_list($email, $start, $end);
|
||||||
|
if (is_array($fblist)) {
|
||||||
|
$status = 'FREE';
|
||||||
|
|
||||||
|
foreach ($fblist as $slot) {
|
||||||
|
list($from, $to) = $slot;
|
||||||
|
if ($from <= $end && $to >= $start) {
|
||||||
|
$status = 'BUSY';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo $status;
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a list of free/busy time slots within the given period
|
||||||
|
* Echo data in JSON encoding
|
||||||
|
*/
|
||||||
|
public function freebusy_times()
|
||||||
|
{
|
||||||
|
$email = get_input_value('email', RCUBE_INPUT_GPC);
|
||||||
|
$start = get_input_value('start', RCUBE_INPUT_GET);
|
||||||
|
$end = get_input_value('end', RCUBE_INPUT_GET);
|
||||||
|
|
||||||
|
if (!$start) $start = time();
|
||||||
|
if (!$end) $end = $start + 86400 * 30;
|
||||||
|
|
||||||
|
$fblist = $this->driver->get_freebusy_list($email, $start, $end);
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
// TODO: build a list from $start till $end with blocks representing the fb-status
|
||||||
|
|
||||||
|
echo json_encode($result);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,8 @@ function rcube_calendar_ui(settings)
|
||||||
var gmt_offset = (new Date().getTimezoneOffset() / -60) - (settings.timezone || 0);
|
var gmt_offset = (new Date().getTimezoneOffset() / -60) - (settings.timezone || 0);
|
||||||
var day_clicked = day_clicked_ts = 0;
|
var day_clicked = day_clicked_ts = 0;
|
||||||
var ignore_click = false;
|
var ignore_click = false;
|
||||||
|
var event_attendees = null;
|
||||||
|
var attendees_list;
|
||||||
|
|
||||||
// general datepicker settings
|
// general datepicker settings
|
||||||
var datepicker_settings = {
|
var datepicker_settings = {
|
||||||
|
@ -67,6 +69,27 @@ function rcube_calendar_ui(settings)
|
||||||
return String(str).replace(/\n/g, "<br/>");
|
return String(str).replace(/\n/g, "<br/>");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
var explode_quoted_string = function(str, delimiter)
|
||||||
|
{
|
||||||
|
var result = [],
|
||||||
|
strlen = str.length,
|
||||||
|
q, p, i;
|
||||||
|
|
||||||
|
for (q = p = i = 0; i < strlen; i++) {
|
||||||
|
if (str[i] == '"' && str[i-1] != '\\') {
|
||||||
|
q = !q;
|
||||||
|
}
|
||||||
|
else if (!q && str[i] == delimiter) {
|
||||||
|
result.push(str.substring(p, i));
|
||||||
|
p = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(str.substr(p));
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
// from time and date strings to a real date object
|
// from time and date strings to a real date object
|
||||||
var parse_datetime = function(time, date)
|
var parse_datetime = function(time, date)
|
||||||
{
|
{
|
||||||
|
@ -391,6 +414,14 @@ function rcube_calendar_ui(settings)
|
||||||
else
|
else
|
||||||
$('#edit-recurring-warning').hide();
|
$('#edit-recurring-warning').hide();
|
||||||
|
|
||||||
|
// attendees
|
||||||
|
event_attendees = [];
|
||||||
|
attendees_list = $('#edit-attendees-table > tbody').html('');
|
||||||
|
if (calendar.attendees && event.attendees) {
|
||||||
|
for (var j=0; j < event.attendees.length; j++)
|
||||||
|
add_attendee(event.attendees[j]);
|
||||||
|
}
|
||||||
|
|
||||||
// attachments
|
// attachments
|
||||||
if (calendar.attachments) {
|
if (calendar.attachments) {
|
||||||
rcmail.enable_command('remove-attachment', !calendar.readonly);
|
rcmail.enable_command('remove-attachment', !calendar.readonly);
|
||||||
|
@ -436,6 +467,7 @@ function rcube_calendar_ui(settings)
|
||||||
sensitivity: sensitivity.val(),
|
sensitivity: sensitivity.val(),
|
||||||
recurrence: '',
|
recurrence: '',
|
||||||
alarms: '',
|
alarms: '',
|
||||||
|
attendees: event_attendees,
|
||||||
deleted_attachments: rcmail.env.deleted_attachments
|
deleted_attachments: rcmail.env.deleted_attachments
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -531,18 +563,87 @@ function rcube_calendar_ui(settings)
|
||||||
$dialog.dialog({
|
$dialog.dialog({
|
||||||
modal: true,
|
modal: true,
|
||||||
resizable: true,
|
resizable: true,
|
||||||
|
closeOnEscape: false,
|
||||||
title: rcmail.gettext((action == 'edit' ? 'edit_event' : 'new_event'), 'calendar'),
|
title: rcmail.gettext((action == 'edit' ? 'edit_event' : 'new_event'), 'calendar'),
|
||||||
close: function() {
|
close: function() {
|
||||||
$dialog.dialog("destroy").hide();
|
$dialog.dialog("destroy").hide();
|
||||||
},
|
},
|
||||||
buttons: buttons,
|
buttons: buttons,
|
||||||
minWidth: 440,
|
minWidth: 500,
|
||||||
width: 480
|
width: 580
|
||||||
}).show();
|
}).show();
|
||||||
|
|
||||||
title.select();
|
title.select();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// add the given list of participants
|
||||||
|
var add_attendees = function(names)
|
||||||
|
{
|
||||||
|
names = explode_quoted_string(names.replace(/,\s*$/, ''), ',');
|
||||||
|
|
||||||
|
// parse name/email pairs
|
||||||
|
var item, email, name, success = false;
|
||||||
|
for (var i=0; i < names.length; i++) {
|
||||||
|
email = name = null;
|
||||||
|
item = $.trim(names[i]);
|
||||||
|
|
||||||
|
if (!item.length) {
|
||||||
|
continue;
|
||||||
|
} // address in brackets without name (do nothing)
|
||||||
|
else if (item.match(/^<[^@]+@[^>]+>$/)) {
|
||||||
|
email = item.replace(/[<>]/g, '');
|
||||||
|
} // address without brackets and without name (add brackets)
|
||||||
|
else if (rcube_check_email(item)) {
|
||||||
|
email = item;
|
||||||
|
} // address with name
|
||||||
|
else if (item.match(/([^\s<@]+@[^>]+)>*$/)) {
|
||||||
|
email = RegExp.$1;
|
||||||
|
name = item.replace(email, '').replace(/^["\s<>]+/, '').replace(/["\s<>]+$/, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (email) {
|
||||||
|
add_attendee({ email:email, name:name, role:'REQUIRED', status:'unknown' });
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
alert(rcmail.gettext('noemailwarning'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
};
|
||||||
|
|
||||||
|
// add the given attendee to the list
|
||||||
|
var add_attendee = function(data)
|
||||||
|
{
|
||||||
|
var dispname = (data.email && data.name) ? data.name + ' <' + data.email + '>' : (data.email || data.name);
|
||||||
|
|
||||||
|
// delete icon
|
||||||
|
var icon = rcmail.env.deleteicon ? '<img src="' + rcmail.env.deleteicon + '" alt="" />' : rcmail.gettext('delete');
|
||||||
|
var dellink = '<a href="#delete" class="deletelink" title="' + Q(rcmail.gettext('delete')) + '">' + icon + '</a>';
|
||||||
|
|
||||||
|
var html = '<td class="role"></td>' +
|
||||||
|
'<td class="name">' + Q(dispname) + '</td>' +
|
||||||
|
'<td class="availability">' + '' + '</td>' +
|
||||||
|
'<td class="confirmstate">' + Q(data.status) + '</td>' +
|
||||||
|
'<td class="options">' + (data.role != 'OWNER' ? dellink : '') + '</td>';
|
||||||
|
|
||||||
|
$('<tr>')
|
||||||
|
.addClass(String(data.role).toLowerCase())
|
||||||
|
.html(html)
|
||||||
|
.appendTo(attendees_list)
|
||||||
|
.find('a.deletelink').click({ id:(data.email || data.name) }, function(e) { remove_attendee(this, e.data.id); return false; });
|
||||||
|
|
||||||
|
event_attendees.push(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
// remove an attendee from the list
|
||||||
|
var remove_attendee = function(elem, id)
|
||||||
|
{
|
||||||
|
$(elem).closest('tr').hide();
|
||||||
|
event_attendees = $.grep(event_attendees, function(data){ return (data.name != id && data.email != id) });
|
||||||
|
};
|
||||||
|
|
||||||
// post the given event data to server
|
// post the given event data to server
|
||||||
var update_event = function(action, data)
|
var update_event = function(action, data)
|
||||||
{
|
{
|
||||||
|
@ -1098,7 +1199,12 @@ function rcube_calendar_ui(settings)
|
||||||
};
|
};
|
||||||
|
|
||||||
// init event dialog
|
// init event dialog
|
||||||
$('#eventtabs').tabs();
|
$('#eventtabs').tabs({
|
||||||
|
show: function(event, ui) {
|
||||||
|
if (ui.panel.id == 'event-tab-3')
|
||||||
|
$('#edit-attendee-name').select();
|
||||||
|
}
|
||||||
|
});
|
||||||
$('#edit-enddate, input.edit-alarm-date').datepicker(datepicker_settings);
|
$('#edit-enddate, input.edit-alarm-date').datepicker(datepicker_settings);
|
||||||
$('#edit-startdate').datepicker(datepicker_settings).datepicker('option', 'onSelect', shift_enddate).change(function(){ shift_enddate(this.value); });
|
$('#edit-startdate').datepicker(datepicker_settings).datepicker('option', 'onSelect', shift_enddate).change(function(){ shift_enddate(this.value); });
|
||||||
$('#edit-allday').click(function(){ $('#edit-starttime, #edit-endtime')[(this.checked?'hide':'show')](); });
|
$('#edit-allday').click(function(){ $('#edit-starttime, #edit-endtime')[(this.checked?'hide':'show')](); });
|
||||||
|
@ -1176,6 +1282,16 @@ function rcube_calendar_ui(settings)
|
||||||
});
|
});
|
||||||
$('#edit-recurrence-enddate').datepicker(datepicker_settings).click(function(){ $("#edit-recurrence-repeat-until").prop('checked', true) });
|
$('#edit-recurrence-enddate').datepicker(datepicker_settings).click(function(){ $("#edit-recurrence-repeat-until").prop('checked', true) });
|
||||||
|
|
||||||
|
// init attendees autocompletion
|
||||||
|
rcmail.init_address_input_events($('#edit-attendee-name'));
|
||||||
|
rcmail.addEventListener('autocomplete_insert', function(e){ $('#edit-attendee-add').click(); });
|
||||||
|
|
||||||
|
$('#edit-attendee-add').click(function(){
|
||||||
|
var input = $('#edit-attendee-name');
|
||||||
|
if (add_attendees(input.val()))
|
||||||
|
input.val('');
|
||||||
|
});
|
||||||
|
|
||||||
// add proprietary css styles if not IE
|
// add proprietary css styles if not IE
|
||||||
if (!bw.ie)
|
if (!bw.ie)
|
||||||
$('div.fc-content').addClass('rcube-fc-content');
|
$('div.fc-content').addClass('rcube-fc-content');
|
||||||
|
@ -1208,7 +1324,6 @@ window.rcmail && rcmail.addEventListener('init', function(evt) {
|
||||||
rcmail.addEventListener('plugin.destroy_source', function(p){ cal.calendar_destroy_source(p.id); });
|
rcmail.addEventListener('plugin.destroy_source', function(p){ cal.calendar_destroy_source(p.id); });
|
||||||
rcmail.addEventListener('plugin.unlock_saving', function(p){ rcmail.set_busy(false, null, cal.saving_lock); });
|
rcmail.addEventListener('plugin.unlock_saving', function(p){ rcmail.set_busy(false, null, cal.saving_lock); });
|
||||||
|
|
||||||
|
|
||||||
// let's go
|
// let's go
|
||||||
var cal = new rcube_calendar_ui(rcmail.env.calendar_settings);
|
var cal = new rcube_calendar_ui(rcmail.env.calendar_settings);
|
||||||
|
|
||||||
|
|
|
@ -274,10 +274,15 @@ abstract class calendar_driver
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch free/busy information from a person within the given range
|
* Fetch free/busy information from a person within the given range
|
||||||
|
*
|
||||||
|
* @param string E-mail address of attendee
|
||||||
|
* @param integer Requested period start date/time as unix timestamp
|
||||||
|
* @param integer Requested period end date/time as unix timestamp
|
||||||
|
* @return array List of busy timeslots within the requested range
|
||||||
*/
|
*/
|
||||||
public function get_freebusy_list($email, $start, $end)
|
public function get_freebusy_list($email, $start, $end)
|
||||||
{
|
{
|
||||||
return array();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -442,6 +442,24 @@ class kolab_calendar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($rec['organizer']) {
|
||||||
|
$attendees[] = array(
|
||||||
|
'role' => 'OWNER',
|
||||||
|
'name' => $rec['organizer']['display-name'],
|
||||||
|
'email' => $rec['organizer']['smtp-address'],
|
||||||
|
'status' => 'accepted',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ((array)$rec['attendee'] as $attendee) {
|
||||||
|
$attendees[] = array(
|
||||||
|
'role' => strtoupper($attendee['role']),
|
||||||
|
'name' => $attendee['display-name'],
|
||||||
|
'email' => $attendee['smtp-address'],
|
||||||
|
'status' => $attendee['status'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'id' => $rec['uid'],
|
'id' => $rec['uid'],
|
||||||
'uid' => $rec['uid'],
|
'uid' => $rec['uid'],
|
||||||
|
@ -455,6 +473,7 @@ class kolab_calendar
|
||||||
'alarms' => $alarm_value . $alarm_unit,
|
'alarms' => $alarm_value . $alarm_unit,
|
||||||
'categories' => $rec['categories'],
|
'categories' => $rec['categories'],
|
||||||
'attachments' => $attachments,
|
'attachments' => $attachments,
|
||||||
|
'attendees' => $attendees,
|
||||||
'free_busy' => $rec['show-time-as'],
|
'free_busy' => $rec['show-time-as'],
|
||||||
'priority' => isset($priority_map[$rec['priority']]) ? $priority_map[$rec['priority']] : 1,
|
'priority' => isset($priority_map[$rec['priority']]) ? $priority_map[$rec['priority']] : 1,
|
||||||
'sensitivity' => $sensitivity_map[$rec['sensitivity']],
|
'sensitivity' => $sensitivity_map[$rec['sensitivity']],
|
||||||
|
@ -602,6 +621,25 @@ class kolab_calendar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// process event attendees
|
||||||
|
foreach ((array)$event['attendees'] as $attendee) {
|
||||||
|
$role = $attendee['role'];
|
||||||
|
if ($role == 'OWNER') {
|
||||||
|
$object['organizer'] = array(
|
||||||
|
'display-name' => $attendee['name'],
|
||||||
|
'smtp-address' => $attendee['email'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$object['attendee'][] = array(
|
||||||
|
'display-name' => $attendee['name'],
|
||||||
|
'smtp-address' => $attendee['email'],
|
||||||
|
'status' => $attendee['status'],
|
||||||
|
'role' => strtolower($role),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $object;
|
return $object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -645,7 +645,29 @@ class kolab_driver extends calendar_driver
|
||||||
*/
|
*/
|
||||||
public function get_freebusy_list($email, $start, $end)
|
public function get_freebusy_list($email, $start, $end)
|
||||||
{
|
{
|
||||||
return array();
|
require_once('Horde/iCalendar.php');
|
||||||
|
|
||||||
|
if (empty($email) || $end < time())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// load and parse free-busy information using Horde classes
|
||||||
|
$fburl = rcube_kolab::get_freebusy_url($email);
|
||||||
|
if ($fbdata = file_get_contents($fburl)) {
|
||||||
|
$fbcal = new Horde_iCalendar;
|
||||||
|
$fbcal->parsevCalendar($fbdata);
|
||||||
|
if ($fb = $fbcal->findComponent('vfreebusy')) {
|
||||||
|
$result = array();
|
||||||
|
foreach ($fb->getBusyPeriods() as $from => $to) {
|
||||||
|
if ($to == null) // no information, assume free
|
||||||
|
break;
|
||||||
|
$result[] = array($from, $to);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -561,4 +561,30 @@ class calendar_ui
|
||||||
return html::tag('form', array('action' => "#", 'method' => "get"), $html);
|
return html::tag('form', array('action' => "#", 'method' => "get"), $html);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function attendees_list($attrib = array())
|
||||||
|
{
|
||||||
|
$table = new html_table(array('cols' => 5, 'border' => 0, 'cellpadding' => 0, 'class' => 'rectable'));
|
||||||
|
$table->add_header('role', $this->calendar->gettext('role'));
|
||||||
|
$table->add_header('name', $this->calendar->gettext('attendee'));
|
||||||
|
$table->add_header('availability', $this->calendar->gettext('availability'));
|
||||||
|
$table->add_header('confirmstate', $this->calendar->gettext('confirmstate'));
|
||||||
|
$table->add_header('options', '');
|
||||||
|
|
||||||
|
return $table->show($attrib);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function attendees_form($attrib = array())
|
||||||
|
{
|
||||||
|
$input = new html_inputfield(array('name' => 'participant', 'id' => 'edit-attendee-name', 'size' => 30));
|
||||||
|
|
||||||
|
return html::div($attrib, $input->show() . " " .
|
||||||
|
html::tag('input', array('type' => 'button', 'class' => 'button', 'id' => 'edit-attendee-add', 'value' => $this->calendar->gettext('addattendee'))));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,13 @@ $labels['repeattomorrow'] = 'Repeat tomorrow';
|
||||||
$labels['repeatinweek'] = 'Repeat in a week';
|
$labels['repeatinweek'] = 'Repeat in a week';
|
||||||
$labels['alarmtitle'] = 'Upcoming events';
|
$labels['alarmtitle'] = 'Upcoming events';
|
||||||
|
|
||||||
|
// attendees
|
||||||
|
$labels['attendee'] = 'Participant';
|
||||||
|
$labels['role'] = 'Role';
|
||||||
|
$labels['availability'] = 'Avail.';
|
||||||
|
$labels['confirmstate'] = 'Confirmed';
|
||||||
|
$labels['addattendee'] = 'Add participant';
|
||||||
|
|
||||||
// event dialog tabs
|
// event dialog tabs
|
||||||
$labels['tabsummary'] = 'Summary';
|
$labels['tabsummary'] = 'Summary';
|
||||||
$labels['tabrecurrence'] = 'Recurrence';
|
$labels['tabrecurrence'] = 'Recurrence';
|
||||||
|
|
|
@ -467,6 +467,53 @@ td.topalign {
|
||||||
min-width: 5em;
|
min-width: 5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#edit-attendees-table {
|
||||||
|
width: 100%;
|
||||||
|
display: table;
|
||||||
|
table-layout: fixed;
|
||||||
|
border-collapse: collapse;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#edit-attendees-table td {
|
||||||
|
padding: 3px;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#edit-attendees-table tr.owner td {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
#edit-attendees-table td.role,
|
||||||
|
#edit-attendees-table td.availability {
|
||||||
|
width: 4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#edit-attendees-table td.confirmstate {
|
||||||
|
width: 6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#edit-attendees-table td.options {
|
||||||
|
width: 3em;
|
||||||
|
text-align: right;
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#edit-attendees-table td.name {
|
||||||
|
width: auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
#edit-attendees-table thead td {
|
||||||
|
background: url(images/listheader.gif) top left repeat-x #CCC;
|
||||||
|
}
|
||||||
|
|
||||||
|
#edit-attendees-form {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
span.edit-alarm-set {
|
span.edit-alarm-set {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
@ -623,7 +670,8 @@ div.fc-event-location {
|
||||||
}
|
}
|
||||||
|
|
||||||
.fc-view-list div.fc-list-header,
|
.fc-view-list div.fc-list-header,
|
||||||
.fc-view-table td.fc-list-header {
|
.fc-view-table td.fc-list-header,
|
||||||
|
#edit-attendees-table thead td {
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
background: #dddddd;
|
background: #dddddd;
|
||||||
background-image: -moz-linear-gradient(center top, #f4f4f4, #d2d2d2);
|
background-image: -moz-linear-gradient(center top, #f4f4f4, #d2d2d2);
|
||||||
|
|
|
@ -166,7 +166,8 @@
|
||||||
</div>
|
</div>
|
||||||
<!-- attendees list -->
|
<!-- attendees list -->
|
||||||
<div id="event-tab-3">
|
<div id="event-tab-3">
|
||||||
|
<roundcube:object name="plugin.attendees_list" id="edit-attendees-table" cellspacing="0" cellpadding="0" border="0" />
|
||||||
|
<roundcube:object name="plugin.attendees_form" id="edit-attendees-form" />
|
||||||
</div>
|
</div>
|
||||||
<!-- attachments list (with upload form) -->
|
<!-- attachments list (with upload form) -->
|
||||||
<div id="event-tab-4">
|
<div id="event-tab-4">
|
||||||
|
|
|
@ -27,6 +27,7 @@ require_once 'Horde/Perms.php';
|
||||||
class rcube_kolab
|
class rcube_kolab
|
||||||
{
|
{
|
||||||
private static $horde_auth;
|
private static $horde_auth;
|
||||||
|
private static $config;
|
||||||
private static $ready = false;
|
private static $ready = false;
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,6 +75,7 @@ class rcube_kolab
|
||||||
|
|
||||||
$conf['kolab']['ldap'] = array_merge($ldap, (array)$conf['kolab']['ldap']);
|
$conf['kolab']['ldap'] = array_merge($ldap, (array)$conf['kolab']['ldap']);
|
||||||
$conf['kolab']['imap'] = array_merge($imap, (array)$conf['kolab']['imap']);
|
$conf['kolab']['imap'] = array_merge($imap, (array)$conf['kolab']['imap']);
|
||||||
|
self::$config = &$conf;
|
||||||
|
|
||||||
// pass the current IMAP authentication credentials to the Horde auth system
|
// pass the current IMAP authentication credentials to the Horde auth system
|
||||||
self::$horde_auth = Auth::singleton('kolab');
|
self::$horde_auth = Auth::singleton('kolab');
|
||||||
|
@ -147,6 +149,15 @@ class rcube_kolab
|
||||||
return self::$ready ? $kolab->getFolder($folder)->getData($data_type) : null;
|
return self::$ready ? $kolab->getFolder($folder)->getData($data_type) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compose an URL to query the free/busy status for the given user
|
||||||
|
*/
|
||||||
|
public static function get_freebusy_url($email)
|
||||||
|
{
|
||||||
|
$host = self::$config['kolab']['freebusy']['server'] ? self::$config['kolab']['freebusy']['server'] : self::$config['kolab']['imap']['server'];
|
||||||
|
return 'https://' . $host . '/freebusy/' . $email . '.ifb';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleanup session data when done
|
* Cleanup session data when done
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Reference in a new issue