- Require delete permission for a calendar to be writeable (#4827)

- Introduce 'insert' permission which allows the creation of new events but no subsequent editing
- Replace 'readonly' with '!writeable' properties for consistency reasons
This commit is contained in:
Thomas Bruederli 2015-03-11 12:22:01 +01:00
parent a32690ad38
commit 6f97b9ff71
9 changed files with 62 additions and 40 deletions

View file

@ -265,7 +265,7 @@ class calendar extends rcube_plugin
$default_id = $this->rc->config->get('calendar_default_calendar'); $default_id = $this->rc->config->get('calendar_default_calendar');
$calendars = $this->driver->list_calendars(calendar_driver::FILTER_PERSONAL); $calendars = $this->driver->list_calendars(calendar_driver::FILTER_PERSONAL);
$calendar = $calendars[$default_id] ?: null; $calendar = $calendars[$default_id] ?: null;
if (!$calendar || $confidential || ($writeable && $calendar['readonly'])) { if (!$calendar || $confidential || ($writeable && !$calendar['writeable'])) {
foreach ($calendars as $cal) { foreach ($calendars as $cal) {
if ($confidential && $cal['subtype'] == 'confidential') { if ($confidential && $cal['subtype'] == 'confidential') {
$calendar = $cal; $calendar = $cal;
@ -276,7 +276,7 @@ class calendar extends rcube_plugin
if (!$confidential) if (!$confidential)
break; break;
} }
if (!$writeable || !$cal['readonly']) { if (!$writeable || $cal['writeable']) {
$first = $cal; $first = $cal;
} }
} }
@ -2459,7 +2459,7 @@ class calendar extends rcube_plugin
$calendar_select->add('--', ''); $calendar_select->add('--', '');
$numcals = 0; $numcals = 0;
foreach ($calendars as $calendar) { foreach ($calendars as $calendar) {
if (!$calendar['readonly']) { if ($calendar['writeable']) {
$calendar_select->add($calendar['name'], $calendar['id']); $calendar_select->add($calendar['name'], $calendar['id']);
$numcals++; $numcals++;
} }
@ -2840,7 +2840,7 @@ class calendar extends rcube_plugin
} }
// save to calendar // save to calendar
if ($calendar && !$calendar['readonly']) { if ($calendar && $calendar['writeable']) {
// check for existing event with the same UID // check for existing event with the same UID
$existing = $this->driver->get_event($event, calendar_driver::FILTER_WRITEABLE | calendar_driver::FILTER_PERSONAL); $existing = $this->driver->get_event($event, calendar_driver::FILTER_WRITEABLE | calendar_driver::FILTER_PERSONAL);
@ -3107,7 +3107,7 @@ class calendar extends rcube_plugin
foreach ($events as $event) { foreach ($events as $event) {
// save to calendar // save to calendar
$calendar = $calendars[$cal_id] ?: $this->get_default_calendar(true, $event['sensitivity'] == 'confidential'); $calendar = $calendars[$cal_id] ?: $this->get_default_calendar(true, $event['sensitivity'] == 'confidential');
if ($calendar && !$calendar['readonly'] && $event['_type'] == 'event') { if ($calendar && $calendar['writeable'] && $event['_type'] == 'event') {
$event['calendar'] = $calendar['id']; $event['calendar'] = $calendar['id'];
if (!$this->driver->get_event($event['uid'], calendar_driver::FILTER_WRITEABLE)) { if (!$this->driver->get_event($event['uid'], calendar_driver::FILTER_WRITEABLE)) {

View file

@ -63,7 +63,7 @@ function rcube_calendar_ui(settings)
var resources_data = {}; var resources_data = {};
var resources_index = []; var resources_index = [];
var resource_owners = {}; var resource_owners = {};
var resources_events_source = { url:null, editable:false }; var resources_events_source = { url:null, editable:false, insertable:false };
var freebusy_ui = { workinhoursonly:false, needsupdate:false }; var freebusy_ui = { workinhoursonly:false, needsupdate:false };
var freebusy_data = {}; var freebusy_data = {};
var current_view = null; var current_view = null;
@ -392,7 +392,7 @@ function rcube_calendar_ui(settings)
var event_show_dialog = function(event, ev, temp) var event_show_dialog = function(event, ev, temp)
{ {
var $dialog = $("#eventshow"); var $dialog = $("#eventshow");
var calendar = event.calendar && me.calendars[event.calendar] ? me.calendars[event.calendar] : { editable:false }; var calendar = event.calendar && me.calendars[event.calendar] ? me.calendars[event.calendar] : { editable:false, insertable:false };
if (!temp) if (!temp)
me.selected_event = event; me.selected_event = event;
@ -687,7 +687,7 @@ function rcube_calendar_ui(settings)
$("#eventshow:ui-dialog").data('opener', null).dialog('close'); $("#eventshow:ui-dialog").data('opener', null).dialog('close');
var $dialog = $('<div>'); var $dialog = $('<div>');
var calendar = event.calendar && me.calendars[event.calendar] ? me.calendars[event.calendar] : { editable:action=='new' }; var calendar = event.calendar && me.calendars[event.calendar] ? me.calendars[event.calendar] : { insertable:action=='new' };
me.selected_event = $.extend($.extend({}, event_defaults), event); // clone event object (with defaults) me.selected_event = $.extend($.extend({}, event_defaults), event); // clone event object (with defaults)
event = me.selected_event; // change reference to clone event = me.selected_event; // change reference to clone
freebusy_ui.needsupdate = false; freebusy_ui.needsupdate = false;
@ -734,6 +734,12 @@ function rcube_calendar_ui(settings)
allday.checked = false; allday.checked = false;
} }
// set calendar selection according to permissions
calendars.find('option').each(function(i, opt) {
var cal = me.calendars[opt.value] || {};
$(opt).prop('disabled', !(cal.editable || (action == 'new' && cal.insertable)))
});
// set alarm(s) // set alarm(s)
me.set_alarms_edit('#edit-alarms', action != 'new' && event.valarms && calendar.alarms ? event.valarms : []); me.set_alarms_edit('#edit-alarms', action != 'new' && event.valarms && calendar.alarms ? event.valarms : []);
@ -808,7 +814,7 @@ function rcube_calendar_ui(settings)
// attachments // attachments
var load_attachments_tab = function() var load_attachments_tab = function()
{ {
rcmail.enable_command('remove-attachment', !calendar.readonly && !event.recurrence_id); rcmail.enable_command('remove-attachment', calendar.editable && !event.recurrence_id);
rcmail.env.deleted_attachments = []; rcmail.env.deleted_attachments = [];
// we're sharing some code for uploads handling with app.js // we're sharing some code for uploads handling with app.js
rcmail.env.attachments = []; rcmail.env.attachments = [];
@ -3553,7 +3559,8 @@ function rcube_calendar_ui(settings)
me.calendars[id] = $.extend({ me.calendars[id] = $.extend({
url: rcmail.url('calendar/load_events', { source: id }), url: rcmail.url('calendar/load_events', { source: id }),
editable: !cal.readonly, editable: cal.writeable || false,
insertable: cal.insert || false,
className: 'fc-event-cal-'+id, className: 'fc-event-cal-'+id,
id: id id: id
}, cal); }, cal);
@ -3583,7 +3590,7 @@ function rcube_calendar_ui(settings)
// insert to #calendar-select options if writeable // insert to #calendar-select options if writeable
select = $('#edit-calendar'); select = $('#edit-calendar');
if (fc && !cal.readonly && select.length && !select.find('option[value="'+id+'"]').length) { if (fc && (cal.writeable || cal.insert) && select.length && !select.find('option[value="'+id+'"]').length) {
$('<option>').attr('value', id).html(cal.name).appendTo(select); $('<option>').attr('value', id).html(cal.name).appendTo(select);
} }
} }
@ -3618,7 +3625,7 @@ function rcube_calendar_ui(settings)
count_sources.push(id); count_sources.push(id);
} }
if (!cal.readonly && !this.selected_calendar) { if (cal.writeable && !this.selected_calendar) {
this.selected_calendar = id; this.selected_calendar = id;
rcmail.enable_command('addevent', true); rcmail.enable_command('addevent', true);
} }
@ -3640,7 +3647,7 @@ function rcube_calendar_ui(settings)
if (node && node.id && me.calendars[node.id]) { if (node && node.id && me.calendars[node.id]) {
me.select_calendar(node.id, true); me.select_calendar(node.id, true);
rcmail.enable_command('calendar-edit', 'calendar-showurl', true); rcmail.enable_command('calendar-edit', 'calendar-showurl', true);
rcmail.enable_command('calendar-delete', !me.calendars[node.id].readonly); rcmail.enable_command('calendar-delete', me.calendars[node.id].editable);
rcmail.enable_command('calendar-remove', me.calendars[node.id] && me.calendars[node.id].removable); rcmail.enable_command('calendar-remove', me.calendars[node.id] && me.calendars[node.id].removable);
} }
}); });
@ -3751,7 +3758,7 @@ function rcube_calendar_ui(settings)
}); });
// select default calendar // select default calendar
if (settings.default_calendar && this.calendars[settings.default_calendar] && !this.calendars[settings.default_calendar].readonly) if (settings.default_calendar && this.calendars[settings.default_calendar] && this.calendars[settings.default_calendar].editable)
this.selected_calendar = settings.default_calendar; this.selected_calendar = settings.default_calendar;
if (this.selected_calendar) if (this.selected_calendar)
@ -3769,6 +3776,8 @@ function rcube_calendar_ui(settings)
color: '#fff', color: '#fff',
textColor: '#333', textColor: '#333',
editable: false, editable: false,
writeable: false,
insertable: false,
attendees: true attendees: true
}; };
event_sources.push(me.calendars['--invitation--itip']); event_sources.push(me.calendars['--invitation--itip']);

View file

@ -96,10 +96,11 @@ abstract class calendar_driver
{ {
const FILTER_ALL = 0; const FILTER_ALL = 0;
const FILTER_WRITEABLE = 1; const FILTER_WRITEABLE = 1;
const FILTER_ACTIVE = 2; const FILTER_INSERTABLE = 2;
const FILTER_PERSONAL = 4; const FILTER_ACTIVE = 4;
const FILTER_PRIVATE = 8; const FILTER_PERSONAL = 8;
const FILTER_CONFIDENTIAL = 16; const FILTER_PRIVATE = 16;
const FILTER_CONFIDENTIAL = 32;
const BIRTHDAY_CALENDAR_ID = '__bdays__'; const BIRTHDAY_CALENDAR_ID = '__bdays__';
// features supported by backend // features supported by backend

View file

@ -89,6 +89,8 @@ class database_driver extends calendar_driver
$arr['active'] = !in_array($arr['id'], $hidden); $arr['active'] = !in_array($arr['id'], $hidden);
$arr['name'] = html::quote($arr['name']); $arr['name'] = html::quote($arr['name']);
$arr['listname'] = html::quote($arr['name']); $arr['listname'] = html::quote($arr['name']);
$arr['insert'] = true;
$arr['writeable'] = true;
$this->calendars[$arr['calendar_id']] = $arr; $this->calendars[$arr['calendar_id']] = $arr;
$calendar_ids[] = $this->rc->db->quote($arr['calendar_id']); $calendar_ids[] = $this->rc->db->quote($arr['calendar_id']);
} }
@ -139,7 +141,7 @@ class database_driver extends calendar_driver
'showalarms' => (bool)$this->rc->config->get('calendar_birthdays_alarm_type'), 'showalarms' => (bool)$this->rc->config->get('calendar_birthdays_alarm_type'),
'active' => !in_array($id, $hidden), 'active' => !in_array($id, $hidden),
'group' => 'x-birthdays', 'group' => 'x-birthdays',
'readonly' => true, 'writeable' => false,
'default' => false, 'default' => false,
'children' => false, 'children' => false,
); );

View file

@ -27,7 +27,8 @@
class kolab_calendar extends kolab_storage_folder_api class kolab_calendar extends kolab_storage_folder_api
{ {
public $ready = false; public $ready = false;
public $readonly = true; public $writeable = false;
public $insert = false;
public $attachments = true; public $attachments = true;
public $alarms = false; public $alarms = false;
public $history = false; public $history = false;
@ -78,17 +79,20 @@ class kolab_calendar extends kolab_storage_folder_api
$this->storage = kolab_storage::get_folder($this->name); $this->storage = kolab_storage::get_folder($this->name);
$this->ready = $this->storage && $this->storage->valid; $this->ready = $this->storage && $this->storage->valid;
// Set readonly and alarms flags according to folder permissions // Set writeable and alarms flags according to folder permissions
if ($this->ready) { if ($this->ready) {
if ($this->storage->get_namespace() == 'personal') { if ($this->storage->get_namespace() == 'personal') {
$this->readonly = false; $this->writeable = true;
$this->insert = true;
$this->alarms = true; $this->alarms = true;
} }
else { else {
$rights = $this->storage->get_myrights(); $rights = $this->storage->get_myrights();
if ($rights && !PEAR::isError($rights)) { if ($rights && !PEAR::isError($rights)) {
if (strpos($rights, 'i') !== false) if (strpos($rights, 'i') !== false || strpos($rights, 'w') !== false)
$this->readonly = false; $this->insert = true;
if (strpos($rights, 't') !== false || strpos($rights, 'd') !== false)
$this->writeable = $this->insert;
} }
} }

View file

@ -103,7 +103,7 @@ class kolab_driver extends calendar_driver
if ($calendar->ready) { if ($calendar->ready) {
$this->calendars[$calendar->id] = $calendar; $this->calendars[$calendar->id] = $calendar;
if (!$calendar->readonly) if ($calendar->writeable)
$this->has_writeable = true; $this->has_writeable = true;
} }
} }
@ -173,7 +173,7 @@ class kolab_driver extends calendar_driver
'owner' => $cal->get_owner(), 'owner' => $cal->get_owner(),
'history' => false, 'history' => false,
'virtual' => false, 'virtual' => false,
'readonly' => true, 'writeable' => false,
'group' => 'other', 'group' => 'other',
'class' => 'user', 'class' => 'user',
'removable' => true, 'removable' => true,
@ -186,7 +186,7 @@ class kolab_driver extends calendar_driver
'listname' => $listname, 'listname' => $listname,
'editname' => $cal->get_foldername(), 'editname' => $cal->get_foldername(),
'virtual' => true, 'virtual' => true,
'readonly' => true, 'writeable' => false,
'group' => $cal->get_namespace(), 'group' => $cal->get_namespace(),
'class' => 'folder', 'class' => 'folder',
); );
@ -199,7 +199,8 @@ class kolab_driver extends calendar_driver
'editname' => $cal->get_foldername(), 'editname' => $cal->get_foldername(),
'title' => $cal->get_title(), 'title' => $cal->get_title(),
'color' => $cal->get_color(), 'color' => $cal->get_color(),
'readonly' => $cal->readonly, 'writeable' => $cal->writeable,
'insert' => $cal->insert,
'showalarms' => $cal->alarms, 'showalarms' => $cal->alarms,
'history' => !empty($this->bonnie_api), 'history' => !empty($this->bonnie_api),
'group' => $cal->get_namespace(), 'group' => $cal->get_namespace(),
@ -232,7 +233,8 @@ class kolab_driver extends calendar_driver
'editname' => $cal->get_foldername(), 'editname' => $cal->get_foldername(),
'title' => $cal->get_title(), 'title' => $cal->get_title(),
'color' => $cal->get_color(), 'color' => $cal->get_color(),
'readonly' => $cal->readonly, 'writeable' => $cal->writeable,
'insert' => $cal->insert,
'showalarms' => $cal->alarms, 'showalarms' => $cal->alarms,
'history' => !empty($this->bonnie_api), 'history' => !empty($this->bonnie_api),
'group' => 'x-invitations', 'group' => 'x-invitations',
@ -266,7 +268,7 @@ class kolab_driver extends calendar_driver
'active' => (bool)$prefs[$id]['active'], 'active' => (bool)$prefs[$id]['active'],
'showalarms' => (bool)$this->rc->config->get('calendar_birthdays_alarm_type'), 'showalarms' => (bool)$this->rc->config->get('calendar_birthdays_alarm_type'),
'group' => 'x-birthdays', 'group' => 'x-birthdays',
'readonly' => true, 'writeable' => false,
'default' => false, 'default' => false,
'children' => false, 'children' => false,
'history' => false, 'history' => false,
@ -293,6 +295,7 @@ class kolab_driver extends calendar_driver
'calendars' => $calendars, 'calendars' => $calendars,
'filter' => $filter, 'filter' => $filter,
'writeable' => ($filter & self::FILTER_WRITEABLE), 'writeable' => ($filter & self::FILTER_WRITEABLE),
'insert' => ($filter & self::FILTER_INSERTABLE),
'active' => ($filter & self::FILTER_ACTIVE), 'active' => ($filter & self::FILTER_ACTIVE),
'personal' => ($filter & self::FILTER_PERSONAL), 'personal' => ($filter & self::FILTER_PERSONAL),
)); ));
@ -305,7 +308,10 @@ class kolab_driver extends calendar_driver
if (!$cal->ready) { if (!$cal->ready) {
continue; continue;
} }
if (($filter & self::FILTER_WRITEABLE) && $cal->readonly) { if (($filter & self::FILTER_WRITEABLE) && !$cal->writeable) {
continue;
}
if (($filter & self::FILTER_INSERTABLE) && !$cal->insert) {
continue; continue;
} }
if (($filter & self::FILTER_ACTIVE) && !$cal->is_active()) { if (($filter & self::FILTER_ACTIVE) && !$cal->is_active()) {

View file

@ -26,7 +26,7 @@ class kolab_invitation_calendar
public $id = '__invitation__'; public $id = '__invitation__';
public $ready = true; public $ready = true;
public $alarms = false; public $alarms = false;
public $readonly = true; public $writeable = false;
public $attachments = false; public $attachments = false;
public $subscriptions = false; public $subscriptions = false;
public $partstats = array('unknown'); public $partstats = array('unknown');

View file

@ -25,7 +25,7 @@ class kolab_user_calendar extends kolab_calendar
{ {
public $id = 'unknown'; public $id = 'unknown';
public $ready = false; public $ready = false;
public $readonly = true; public $writeable = false;
public $attachments = false; public $attachments = false;
public $subscriptions = false; public $subscriptions = false;

View file

@ -294,7 +294,7 @@ class calendar_ui
if ($prop['virtual']) if ($prop['virtual'])
$classes[] = 'virtual'; $classes[] = 'virtual';
else if ($prop['readonly']) else if (!$prop['writeable'])
$classes[] = 'readonly'; $classes[] = 'readonly';
if ($prop['subscribed']) if ($prop['subscribed'])
$classes[] = 'subscribed'; $classes[] = 'subscribed';
@ -361,7 +361,7 @@ class calendar_ui
$select = new html_select($attrib); $select = new html_select($attrib);
foreach ((array)$this->cal->driver->list_calendars() as $id => $prop) { foreach ((array)$this->cal->driver->list_calendars() as $id => $prop) {
if (!$prop['readonly']) if (!empty($prop['insert']))
$select->add($prop['name'], $id); $select->add($prop['name'], $id);
} }