diff --git a/calendar/inc/class.calendar_bo.inc.php b/calendar/inc/class.calendar_bo.inc.php index 609c69166a..cd63ca2b2d 100644 --- a/calendar/inc/class.calendar_bo.inc.php +++ b/calendar/inc/class.calendar_bo.inc.php @@ -348,6 +348,7 @@ class calendar_bo // Email list $contacts_obj = new Api\Contacts(); + $bo = new calendar_bo(); foreach($ids as $id) { $list = $contacts_obj->read_list((int)$id); @@ -356,6 +357,7 @@ class calendar_bo 'res_id' => $id, 'rights' => self::ACL_READ_FOR_PARTICIPANTS, 'name' => $list['list_name'], + 'resources' => $bo->enum_mailing_list('l'.$id, false, false) ); } @@ -465,6 +467,22 @@ class calendar_bo { if ($user && !in_array($user,$users)) // already added? { + // General expansion check + if (!is_numeric($user) && $this->resources[$user[0]]['info']) + { + $info = $this->resource_info($user); + if($info && $info['resources']) + { + foreach($info['resources'] as $_user) + { + if($_user && !in_array($_user, $users)) + { + $users[] = $_user; + } + } + continue; + } + } $users[] = $user; } } diff --git a/calendar/inc/class.calendar_owner_etemplate_widget.inc.php b/calendar/inc/class.calendar_owner_etemplate_widget.inc.php index 8ce445808c..c6d234f79f 100644 --- a/calendar/inc/class.calendar_owner_etemplate_widget.inc.php +++ b/calendar/inc/class.calendar_owner_etemplate_widget.inc.php @@ -78,9 +78,14 @@ class calendar_owner_etemplate_widget extends Etemplate\Widget\Taglist foreach($value as &$owner) { $label = self::get_owner_label($owner); + $info = array(); if(!is_numeric($owner)) { $resource = $bo->resources[substr($owner, 0,1)]; + if($resource['info']) + { + $info = $bo->resource_info($owner); + } } else if (!in_array($owner, array_keys($accounts))) { @@ -90,7 +95,7 @@ class calendar_owner_etemplate_widget extends Etemplate\Widget\Taglist { continue; } - $sel_options[] = array('value' => $owner, 'label' => $label, 'app' => lang($resource['app'])); + $sel_options[] = array('value' => $owner, 'label' => $label, 'app' => lang($resource['app'])) + $info; } } @@ -135,6 +140,7 @@ class calendar_owner_etemplate_widget extends Etemplate\Widget\Taglist $bo = new calendar_bo(); $query = $_REQUEST['query']; + // Arbitrarily limited to 50 / resource $options = array('start' => 0, 'num_rows' => 50) + array_diff_key($_REQUEST, array_flip(array('menuaction','query'))); @@ -156,6 +162,10 @@ class calendar_owner_etemplate_widget extends Etemplate\Widget\Taglist $_results = array_intersect_key($_results, $GLOBALS['egw']->acl->get_grants('calendar')); } } + else if ($data['app'] && $data['search']) + { + $_results = call_user_func_array($data['search'], array($query, $options)); + } else if ($data['app'] && Link::get_registry($data['app'], 'query')) { $_results = Link::query($data['app'], $query,$options); diff --git a/calendar/js/et2_widget_event.js b/calendar/js/et2_widget_event.js index 28773edf44..8a3e17e9f2 100644 --- a/calendar/js/et2_widget_event.js +++ b/calendar/js/et2_widget_event.js @@ -918,18 +918,36 @@ et2_calendar_event.owner_check = function owner_check(event, parent, owner_too) { owner_too = app.calendar.state.status_filter === 'owner'; } + var options = false + if(app.calendar && app.calendar.sidebox_et2 && app.calendar.sidebox_et2.getWidgetById('owner')) + { + options = app.calendar.sidebox_et2.getWidgetById('owner').taglist.getSelection(); + } + else + { + options = this.getArrayMgr("sel_options").getRoot().getEntry('owner'); + } if(event.participants && parent.options.owner) { - var parent_owner = typeof parent.options.owner !== 'object' ? + var parent_owner = jQuery.extend([], typeof parent.options.owner !== 'object' ? [parent.options.owner] : - parent.options.owner; + parent.options.owner); owner_match = false; var length = parent_owner.length; for(var i = 0; i < length; i++ ) { - // Exception for mailing lists, they won't match and we don't have the - // list client side. - if(parent_owner[i][0] === 'l') return true; + // Handle grouped resources like mailing lists, they won't match so + // we need the list - pull it from sidebox owner + if(isNaN(parent_owner[i]) && options && options.find) + { + var resource = options.find(function(element) {return element.id == parent_owner[i];}) || {}; + if(resource && resource.resources) + { + parent_owner.splice(i,1); + parent_owner = parent_owner.concat(resource.resources); + continue; + } + } if (parseInt(parent_owner[i]) < 0) { diff --git a/resources/inc/class.resources_bo.inc.php b/resources/inc/class.resources_bo.inc.php index 83169666f8..08b47bd725 100755 --- a/resources/inc/class.resources_bo.inc.php +++ b/resources/inc/class.resources_bo.inc.php @@ -519,21 +519,113 @@ class resources_bo return $acc_list; } + /** + * Search for resources for calendar to select as participants + * + * Search and options match Link::query() + * + * Resources return actual resources as well as categories that match + * + * @param String $search - Search string + * @param Array $options - search options + * @see Link::query() + * + * @return Array List of ID => Title entries matching search string + */ + public static function calendar_search($search, $options) + { + // Resources + $list = Link::query('resources', $search, $options); + + // Categories + $bo = new resources_bo(); + $cats = $bo->acl->get_cats(Acl::READ); + foreach($cats as $cat_id => $cat) + { + if($cat && stripos($cat, $search) !== FALSE) + { + // Get resources for that category + $resources = $bo->get_resources_by_category($cat_id); + + // Edit dialog sends exec as an option, don't add categories + if(count($resources) && !$options['exec']) + { + $list['cat-'.$cat_id] = array( + 'label' => $cat, + 'resources' => $resources, + ); + } + else if ($resources && $options['exec']) + { + array_map( + function($id,$name) use (&$list) { $list[''+$id] = $name;}, + array_keys($resources), $resources + ); + } + } + } + + return $list; + } + + /** + * Get a list of resources (ID => name) matching a single category ID + * @param int $cat_id + * @return array() + */ + public function get_resources_by_category($cat_id) + { + $resources = array(); + $filter = array( + 'cat_id' => $cat_id, + //'accessory_of' => '-1' + 'deleted' => null + ); + $only_keys = 'res_id,name'; + $data = $this->so->search(array(),$only_keys,$order_by='name',$extra_cols='',$wildcard='%',$empty,$op='OR',$limit,$filter); + foreach($data as $resource) + { + $resources[$resource['res_id']] = $resource['name']; + } + + return $resources; + } + /** * returns info about resource for calender * @author Cornelius Weiss - * @param int|array $res_id single id or array $num => $res_id + * @param int|array|string $res_id single id, array $num => $res_id or + * 'cat-' for the whole category * @return array */ function get_calendar_info($res_id) { - //echo "

resources_bo::get_calendar_info(".print_r($res_id,true).")

\n"; + //error_log(__METHOD__ . "(".print_r($res_id,true).")"); + + // Resource category + if(is_string($res_id) && strpos($res_id, 'cat-') === 0) + { + $cat_id = (int)substr($res_id, 4); + if(!$this->acl->is_permitted($cat_id, Acl::READ)) + { + return array(); + } + return array( array( + 'name' => $this->acl->get_cat_name($cat_id), + 'rights' => $this->acl->get_permissions($cat_id), + 'resources' => array_map( + function($id) { return 'r'.$id;}, + array_keys($this->get_resources_by_category($cat_id)) + ) + )); + } + if(!is_array($res_id) && $res_id < 1) return; $data = $this->so->search(array('res_id' => $res_id),self::TITLE_COLS.',useable'); if (!is_array($data)) { - error_log(__METHOD__." No Calendar Data found for Resource with id $res_id"); + //error_log(__METHOD__." No Calendar Data found for Resource with id $res_id"); return array(); } foreach($data as $num => &$resource) @@ -611,10 +703,11 @@ class resources_bo { $filter['accessory_of'] = $options['accessory_of']; } + $list = array(); $data = $this->so->search($criteria,$only_keys,$order_by='name',$extra_cols='',$wildcard='%',$empty,$op='OR',$limit,$filter); // maybe we need to check disponibility of the searched resources in the calendar if $pattern ['exec'] contains some extra args $show_conflict=False; - if ($options['exec'] && $GLOBALS['egw_info']['preferences']['calendar']['defaultresource_sel'] !== 'resources') + if ($data && $options['exec'] && $GLOBALS['egw_info']['preferences']['calendar']['defaultresource_sel'] !== 'resources') { // we'll use a cache for resources info taken from database static $res_info_cache = array(); diff --git a/resources/inc/class.resources_hooks.inc.php b/resources/inc/class.resources_hooks.inc.php index 57f41d360d..3eb73def35 100644 --- a/resources/inc/class.resources_hooks.inc.php +++ b/resources/inc/class.resources_hooks.inc.php @@ -101,7 +101,7 @@ class resources_hooks function calendar_resources($args) { return array( - 'widget' => 'resources_select',// widget to use for the selection of resources + 'search' => 'resources_bo::calendar_search',// method to use for the selection of resources, otherwise Link system is used 'info' => 'resources.resources_bo.get_calendar_info',// info method, returns array with id, type & name for a given id 'max_quantity' => 'useable',// if set, key for max. quantity in array returned by info method 'new_status' => 'resources.resources_bo.get_calendar_new_status',// method returning the status for new items, else 'U' is used