From 55fc673dc5eee80dcb0ff116987097ee97886331 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Thu, 19 Nov 2009 18:56:04 +0000 Subject: [PATCH] - new configurable invitation ACL: Require an ACL grant to invite other users and groups: * No: Every user can invite other users and groups (default and old behavior) * Groups: other users can allways be invited, only groups require an invite_grant * Users + groups: inviting both allways requires an invite grant One need to keep in mind, that setting an invitation ACL via a group, gives each groupmember the right to invite the group / create a group event. So the last option propable only works, if users manage invitations grants on their own, or admin only sets it in small working groups, where every member is allowed to invite the whole group. --> calendar backend code removes participants a user is not allowed to invite - new "only groupevents" filter, showing only real groupenvents not events of groupmembers (added tooltips to explain filters) --- calendar/inc/class.calendar_bo.inc.php | 22 ++++- calendar/inc/class.calendar_boupdate.inc.php | 85 +++++++++++++++---- calendar/inc/class.calendar_ui.inc.php | 28 +++--- calendar/inc/class.calendar_uiforms.inc.php | 31 +++++-- calendar/setup/egw_de.lang | 31 ++++++- calendar/setup/egw_en.lang | 29 +++++++ calendar/templates/default/config.tpl | 12 ++- .../templates/default/preference_acl_row.tpl | 1 + .../templates/default/preference_colspan.tpl | 1 + 9 files changed, 203 insertions(+), 37 deletions(-) diff --git a/calendar/inc/class.calendar_bo.inc.php b/calendar/inc/class.calendar_bo.inc.php index 365ff4ed1c..8b8f438419 100644 --- a/calendar/inc/class.calendar_bo.inc.php +++ b/calendar/inc/class.calendar_bo.inc.php @@ -22,6 +22,10 @@ if (!defined('ACL_TYPE_IDENTIFER')) // used to mark ACL-values for the debug_mes */ define('EGW_ACL_READ_FOR_PARTICIPANTS',EGW_ACL_CUSTOM_1); define('EGW_ACL_FREEBUSY',EGW_ACL_CUSTOM_2); +/** + * Allows to invite an other user (if configured to be used!) + */ +define('EGW_ACL_INVITE',EGW_ACL_CUSTOM_3); /** * Required (!) include, as we use the MCAL_* constants, BEFORE instanciating (and therefore autoloading) the class @@ -154,6 +158,13 @@ class calendar_bo */ var $datetime; + /** + * Does a user require an extra invite grant, to be able to invite an other user, default no + * + * @var boolean + */ + public $require_acl_invite = false; + /** * Constructor */ @@ -196,7 +207,9 @@ class calendar_bo } //echo "registered resources="; _debug_array($this->resources); - $this->config = config::read('calendar'); + $this->config = config::read('calendar'); // only used for horizont, regular calendar config is under phpgwapi + + $this->require_acl_invite = $GLOBALS['egw_info']['server']['require_acl_invite']; } /** @@ -333,6 +346,8 @@ class calendar_bo // for groups we have to include the members if ($GLOBALS['egw']->accounts->get_type($user) == 'g') { + if ($params['filter'] == 'no-enum-groups') continue; + $members = $GLOBALS['egw']->accounts->member($user); if (is_array($members)) { @@ -362,6 +377,11 @@ class calendar_bo } } } + // replace (by so not understood filter 'no-enum-groups' with 'default' filter + if ($params['filter'] == 'no-enum-groups') + { + $params['filter'] = 'default'; + } // if we have no grants from the given user(s), we directly return no events / an empty array, // as calling the so-layer without users would give the events of all users (!) if (!count($users)) diff --git a/calendar/inc/class.calendar_boupdate.inc.php b/calendar/inc/class.calendar_boupdate.inc.php index 6718b68561..995ed61116 100644 --- a/calendar/inc/class.calendar_boupdate.inc.php +++ b/calendar/inc/class.calendar_boupdate.inc.php @@ -119,7 +119,23 @@ class calendar_boupdate extends calendar_bo { return false; } - + if (!($new_event = !(int)$event['id'])) + { + $old_event = $this->read((int)$event['id'],null,$ignore_acl); + // if no participants are set, set them from the old event, as we might need them to update recuring events + if (!isset($event['participants'])) $event['participants'] = $old_event['participants']; + //echo "old $event[id]="; _debug_array($old_event); + } + else + { + $event['created'] = $this->now_su; + $event['creator'] = $GLOBALS['egw_info']['user']['account_id']; + } + // do we need to check, if user is allowed to invite the invited participants + if ($this->require_acl_invite && ($removed = $this->remove_no_acl_invite($event,$old_event))) + { + // todo: report removed participants back to user + } // check for conflicts only happens !$ignore_conflicts AND if start + end date are given if (!$ignore_conflicts && !$event['non_blocking'] && isset($event['start']) && isset($event['end'])) { @@ -250,18 +266,6 @@ class calendar_boupdate extends calendar_bo $event['modified'] = $this->now_su; // we are still in user-time $event['modifier'] = $GLOBALS['egw_info']['user']['account_id']; } - if (!($new_event = !(int)$event['id'])) - { - $old_event = $this->read((int)$event['id'],null,$ignore_acl); - // if no participants are set, set them from the old event, as we might need them to update recuring events - if (!isset($event['participants'])) $event['participants'] = $old_event['participants']; - //echo "old $event[id]="; _debug_array($old_event); - } - else - { - $event['created'] = $this->now_su; - $event['creator'] = $GLOBALS['egw_info']['user']['account_id']; - } //echo "saving $event[id]="; _debug_array($event); $event2save = $event; @@ -293,6 +297,53 @@ class calendar_boupdate extends calendar_bo return $cal_id; } + /** + * Remove participants current user has no right to invite + * + * @param array &$event new event + * @param array $old_event=null old event with already invited participants + * @return array removed participants because of missing invite grants + */ + public function remove_no_acl_invite(array &$event,array $old_event=null) + { + if (!$this->require_acl_invite) + { + return array(); // nothing to check, everyone can invite everyone else + } + if ($event['id'] && is_null($old_event)) + { + $old_event = $this->read($event['id']); + } + $removed = array(); + foreach($event['participants'] as $uid => $status) + { + if ((is_null($old_event) || !in_array($old_event['participants'][$uid])) && !$this->check_acl_invite($uid)) + { + unset($event['participants'][$uid]); // remove participant + $removed[] = $uid; + } + } + echo "

".__METHOD__."($event[title],".($old_event?'$old_event':'NULL').") returning ".array2string($removed)."

"; + return $removed; + } + + /** + * Check if current user is allowed to invite a given participant + * + * @param int|string $uid + * @return boolean + */ + public function check_acl_invite($uid) + { + if (!is_numeric($uid)) return true; // nothing implemented for resources so far + + if ($this->require_acl_invite == 'group' && $GLOBALS['egw']->accounts->get_type($uid) != 'g') + { + return true; // grant only required for groups + } + return $this->check_perms(EGW_ACL_INVITE,0,$uid); + } + /** * Check for added, modified or deleted participants AND notify them * @@ -1080,7 +1131,7 @@ class calendar_boupdate extends calendar_bo { $this->categories = new categories($this->user,'calendar'); } - + if($cal_id && $cal_id > 0) { // preserve categories without users read access @@ -1104,7 +1155,7 @@ class calendar_boupdate extends calendar_bo { $cat_name = trim($cat_name); $cat_id = $this->categories->name2id($cat_name, 'X-'); - + if (!$cat_id) { // some SyncML clients (mostly phones) add an X- to the category names @@ -1120,7 +1171,7 @@ class calendar_boupdate extends calendar_bo $cat_id_list[] = $cat_id; } } - + if(is_array($old_cats_preserve) && count($old_cats_preserve) > 0) { $cat_id_list = array_merge($cat_id_list, $old_cats_preserve); @@ -1149,7 +1200,7 @@ class calendar_boupdate extends calendar_bo $cat_list = array(); foreach($cat_id_list as $cat_id) { - if ($cat_id && $this->categories->check_perms(EGW_ACL_READ, $cat_id) && + if ($cat_id && $this->categories->check_perms(EGW_ACL_READ, $cat_id) && ($cat_name = $this->categories->id2name($cat_id)) && $cat_name != '--') { $cat_list[] = $cat_name; diff --git a/calendar/inc/class.calendar_ui.inc.php b/calendar/inc/class.calendar_ui.inc.php index 10183541b6..b3e1512c67 100644 --- a/calendar/inc/class.calendar_ui.inc.php +++ b/calendar/inc/class.calendar_ui.inc.php @@ -578,6 +578,13 @@ class calendar_ui } $views .= "\n"; + // hack to disable invite ACL column, if not enabled in config + if ($_GET['menuaction'] == 'preferences.uiaclprefs.index' && + (!$this->bo->require_acl_invite || $this->bo->require_acl_invite == 'groups' && !($_REQUEST['owner'] < 0))) + { + $views .= "\n"; + } + $file[++$n] = array('text' => $views,'no_lang' => True,'link' => False,'icon' => False); // special views and view-options menu @@ -696,17 +703,19 @@ class calendar_ui // Filter all or hideprivate $options = ''; foreach(array( - 'default' => lang('Not rejected'), - 'accepted' => lang('Accepted'), - 'unknown' => lang('Invitations'), - 'tentative' => lang('Tentative'), - 'rejected' => lang('Rejected'), - 'owner' => lang('Owner too'), - 'all' => lang('All incl. rejected'), - 'hideprivate' => lang('Hide private infos'), + 'default' => array(lang('Not rejected'), lang('Show all status, but rejected')), + 'accepted' => array(lang('Accepted'), lang('Show only accepted events')), + 'unknown' => array(lang('Invitations'), lang('Show only invitations, not yet accepted or rejected')), + 'tentative' => array(lang('Tentative'), lang('Show only tentative accepted events')), + 'rejected' => array(lang('Rejected'),lang('Show only rejected events')), + 'owner' => array(lang('Owner too'),lang('Show also events just owned by selected user')), + 'all' => array(lang('All incl. rejected'),lang('Show all status incl. rejected events')), + 'hideprivate' => array(lang('Hide private infos'),lang('Show all events, as if they were private')), + 'no-enum-groups' => array(lang('only group-events'),lang('Do not include events of group members')), ) as $value => $label) { - $options .= '