1 | <?php |
||||||
2 | /** |
||||||
3 | * EGroupware - Addressbook - user interface |
||||||
4 | * |
||||||
5 | * @link www.egroupware.org |
||||||
6 | * @author Cornelius Weiss <[email protected]> |
||||||
7 | * @author Ralf Becker <RalfBecker-AT-outdoor-training.de> |
||||||
8 | * @copyright (c) 2005-19 by Ralf Becker <RalfBecker-AT-outdoor-training.de> |
||||||
9 | * @copyright (c) 2005/6 by Cornelius Weiss <[email protected]> |
||||||
10 | * @package addressbook |
||||||
11 | * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License |
||||||
12 | */ |
||||||
13 | |||||||
14 | use EGroupware\Api; |
||||||
15 | use EGroupware\Api\Link; |
||||||
16 | use EGroupware\Api\Framework; |
||||||
17 | use EGroupware\Api\Egw; |
||||||
18 | use EGroupware\Api\Acl; |
||||||
19 | use EGroupware\Api\Vfs; |
||||||
20 | use EGroupware\Api\Etemplate; |
||||||
21 | |||||||
22 | /** |
||||||
23 | * General user interface object of the adressbook |
||||||
24 | */ |
||||||
25 | class addressbook_ui extends addressbook_bo |
||||||
26 | { |
||||||
27 | public $public_functions = array( |
||||||
28 | 'search' => True, |
||||||
29 | 'edit' => True, |
||||||
30 | 'view' => True, |
||||||
31 | 'index' => True, |
||||||
32 | 'photo' => True, |
||||||
33 | 'emailpopup'=> True, |
||||||
34 | 'migrate2ldap' => True, |
||||||
35 | 'admin_set_fileas' => True, |
||||||
36 | 'admin_set_all_cleanup' => True, |
||||||
37 | 'cat_add' => True, |
||||||
38 | ); |
||||||
39 | protected $org_views; |
||||||
40 | |||||||
41 | /** |
||||||
42 | * Addressbook configuration (stored as phpgwapi = general server config) |
||||||
43 | * |
||||||
44 | * @var array |
||||||
45 | */ |
||||||
46 | protected $config; |
||||||
47 | |||||||
48 | /** |
||||||
49 | * Fields to copy, default if nothing specified in config |
||||||
50 | * |
||||||
51 | * @var array |
||||||
52 | */ |
||||||
53 | static public $copy_fields = array( |
||||||
54 | 'org_name', |
||||||
55 | 'org_unit', |
||||||
56 | 'adr_one_street', |
||||||
57 | 'adr_one_street2', |
||||||
58 | 'adr_one_locality', |
||||||
59 | 'adr_one_region', |
||||||
60 | 'adr_one_postalcode', |
||||||
61 | 'adr_one_countryname', |
||||||
62 | 'adr_one_countrycode', |
||||||
63 | 'email', |
||||||
64 | 'url', |
||||||
65 | 'tel_work', |
||||||
66 | 'cat_id' |
||||||
67 | ); |
||||||
68 | |||||||
69 | /** |
||||||
70 | * Instance of eTemplate class |
||||||
71 | * |
||||||
72 | * @var Etemplate |
||||||
73 | */ |
||||||
74 | protected $tmpl; |
||||||
75 | |||||||
76 | /** |
||||||
77 | * Constructor |
||||||
78 | * |
||||||
79 | * @param string $contact_app |
||||||
80 | */ |
||||||
81 | function __construct($contact_app='addressbook') |
||||||
82 | { |
||||||
83 | parent::__construct($contact_app); |
||||||
84 | |||||||
85 | $this->tmpl = new Etemplate(); |
||||||
86 | |||||||
87 | $this->grouped_views = array( |
||||||
0 ignored issues
–
show
Bug
Best Practice
introduced
by
![]() |
|||||||
88 | 'org_name' => lang('Organisations'), |
||||||
89 | 'org_name,adr_one_locality' => lang('Organisations by location'), |
||||||
90 | 'org_name,org_unit' => lang('Organisations by departments'), |
||||||
91 | 'duplicates' => lang('Duplicates') |
||||||
92 | ); |
||||||
93 | |||||||
94 | // make sure the hook for export_limit is registered |
||||||
95 | if (!Api\Hooks::exists('export_limit','addressbook')) Api\Hooks::read(true); |
||||||
96 | |||||||
97 | $this->config =& $GLOBALS['egw_info']['server']; |
||||||
98 | |||||||
99 | // check if a contact specific export limit is set, if yes use it also for etemplate's csv export |
||||||
100 | $this->config['export_limit'] = $this->config['contact_export_limit'] = Api\Storage\Merge::getExportLimit($app='addressbook'); |
||||||
101 | |||||||
102 | if ($this->config['copy_fields'] && ($fields = is_array($this->config['copy_fields']) ? |
||||||
103 | $this->config['copy_fields'] : unserialize($this->config['copy_fields']))) |
||||||
104 | { |
||||||
105 | // Set country code if country name is selected |
||||||
106 | $supported_fields = $this->get_fields('supported',null,0); |
||||||
107 | if(in_array('adr_one_countrycode', $supported_fields) && in_array('adr_one_countryname',$fields)) |
||||||
108 | { |
||||||
109 | $fields[] = 'adr_one_countrycode'; |
||||||
110 | } |
||||||
111 | if(in_array('adr_two_countrycode', $supported_fields) && in_array('adr_two_countryname',$fields)) |
||||||
112 | { |
||||||
113 | $fields[] = 'adr_two_countrycode'; |
||||||
114 | } |
||||||
115 | |||||||
116 | self::$copy_fields = $fields; |
||||||
117 | } |
||||||
118 | } |
||||||
119 | |||||||
120 | /** |
||||||
121 | * List contacts of an addressbook |
||||||
122 | * |
||||||
123 | * @param array $_content =null submitted content |
||||||
124 | * @param string $msg =null message to show |
||||||
125 | */ |
||||||
126 | function index($_content=null,$msg=null) |
||||||
127 | { |
||||||
128 | //echo "<p>uicontacts::index(".print_r($_content,true).",'$msg')</p>\n"; |
||||||
129 | if (($re_submit = is_array($_content))) |
||||||
0 ignored issues
–
show
|
|||||||
130 | { |
||||||
131 | |||||||
132 | if (isset($_content['nm']['rows']['delete'])) // handle a single delete like delete with the checkboxes |
||||||
133 | { |
||||||
134 | $id = @key($_content['nm']['rows']['delete']); |
||||||
135 | $_content['nm']['action'] = 'delete'; |
||||||
136 | $_content['nm']['selected'] = array($id); |
||||||
137 | } |
||||||
138 | if (isset($_content['nm']['rows']['document'])) // handle insert in default document button like an action |
||||||
139 | { |
||||||
140 | $id = @key($_content['nm']['rows']['document']); |
||||||
141 | $_content['nm']['action'] = 'document'; |
||||||
142 | $_content['nm']['selected'] = array($id); |
||||||
143 | } |
||||||
144 | if ($_content['nm']['action'] !== '' && $_content['nm']['action'] !== null) |
||||||
145 | { |
||||||
146 | if (!count($_content['nm']['selected']) && !$_content['nm']['select_all'] && $_content['nm']['action'] != 'delete_list') |
||||||
147 | { |
||||||
148 | $msg = lang('You need to select some contacts first'); |
||||||
149 | } |
||||||
150 | elseif ($_content['nm']['action'] == 'view_org' || $_content['nm']['action'] == 'view_duplicates') |
||||||
151 | { |
||||||
152 | // grouped view via context menu |
||||||
153 | $_content['nm']['grouped_view'] = array_shift($_content['nm']['selected']); |
||||||
154 | } |
||||||
155 | else |
||||||
156 | { |
||||||
157 | $success = $failed = $action_msg = null; |
||||||
158 | if ($this->action($_content['nm']['action'],$_content['nm']['selected'],$_content['nm']['select_all'], |
||||||
159 | $success,$failed,$action_msg,'index',$msg,$_content['nm']['checkboxes'])) |
||||||
160 | { |
||||||
161 | $msg .= lang('%1 contact(s) %2',$success,$action_msg); |
||||||
0 ignored issues
–
show
The call to
lang() has too many arguments starting with $success .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||||
162 | Framework::message($msg); |
||||||
163 | } |
||||||
164 | elseif(is_null($msg)) |
||||||
165 | { |
||||||
166 | $msg .= lang('%1 contact(s) %2, %3 failed because of insufficent rights !!!',$success,$action_msg,$failed); |
||||||
167 | Framework::message($msg,'error'); |
||||||
168 | } |
||||||
169 | $msg = ''; |
||||||
170 | } |
||||||
171 | } |
||||||
172 | if ($_content['nm']['rows']['infolog']) |
||||||
173 | { |
||||||
174 | $org = key($_content['nm']['rows']['infolog']); |
||||||
175 | return $this->infolog_org_view($org); |
||||||
0 ignored issues
–
show
Are you sure the usage of
$this->infolog_org_view($org) targeting addressbook_ui::infolog_org_view() seems to always return null.
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() |
|||||||
176 | } |
||||||
177 | if ($_content['nm']['rows']['view']) // show all contacts of an organisation |
||||||
178 | { |
||||||
179 | $grouped_view = key($_content['nm']['rows']['view']); |
||||||
180 | } |
||||||
181 | else |
||||||
182 | { |
||||||
183 | $grouped_view = $_content['nm']['grouped_view']; |
||||||
184 | } |
||||||
185 | $typeselection = $_content['nm']['col_filter']['tid']; |
||||||
186 | } |
||||||
187 | elseif($_GET['add_list']) |
||||||
188 | { |
||||||
189 | $list = $this->add_list($_GET['add_list'],$_GET['owner']?$_GET['owner']:$this->user); |
||||||
190 | if ($list === true) |
||||||
0 ignored issues
–
show
|
|||||||
191 | { |
||||||
192 | $msg = lang('List already exists!'); |
||||||
193 | } |
||||||
194 | elseif ($list) |
||||||
0 ignored issues
–
show
|
|||||||
195 | { |
||||||
196 | $msg = lang('List created'); |
||||||
197 | } |
||||||
198 | else |
||||||
199 | { |
||||||
200 | $msg = lang('List creation failed, no rights!'); |
||||||
201 | } |
||||||
202 | } |
||||||
203 | $preserv = array(); |
||||||
204 | $content = array(); |
||||||
205 | if($msg || $_GET['msg']) |
||||||
206 | { |
||||||
207 | Framework::message($msg ? $msg : $_GET['msg']); |
||||||
208 | } |
||||||
209 | |||||||
210 | $content['nm'] = Api\Cache::getSession('addressbook', 'index'); |
||||||
211 | if (!is_array($content['nm'])) |
||||||
212 | { |
||||||
213 | $content['nm'] = array( |
||||||
214 | 'get_rows' => 'addressbook.addressbook_ui.get_rows', // I method/callback to request the data for the rows eg. 'notes.bo.get_rows' |
||||||
215 | 'bottom_too' => false, // I show the nextmatch-line (arrows, filters, search, ...) again after the rows |
||||||
216 | 'never_hide' => True, // I never hide the nextmatch-line if less then maxmatch entrie |
||||||
217 | 'start' => 0, // IO position in list |
||||||
218 | 'cat_id' => '', // IO category, if not 'no_cat' => True |
||||||
219 | 'search' => '', // IO search pattern |
||||||
220 | 'order' => 'n_family', // IO name of the column to sort after (optional for the sortheaders) |
||||||
221 | 'sort' => 'ASC', // IO direction of the sort: 'ASC' or 'DESC' |
||||||
222 | 'col_filter' => array(), // IO array of column-name value pairs (optional for the filterheaders) |
||||||
223 | //'cat_id_label' => lang('Categories'), |
||||||
224 | //'filter_label' => lang('Addressbook'), // I label for filter (optional) |
||||||
225 | 'filter' => '', // =All // IO filter, if not 'no_filter' => True |
||||||
226 | 'filter_no_lang' => True, // I set no_lang for filter (=dont translate the options) |
||||||
227 | 'no_filter2' => True, // I disable the 2. filter (params are the same as for filter) |
||||||
228 | //'filter2_label'=> lang('Distribution lists'), // IO filter2, if not 'no_filter2' => True |
||||||
229 | 'filter2' => '', // IO filter2, if not 'no_filter2' => True |
||||||
230 | 'filter2_no_lang'=> True, // I set no_lang for filter2 (=dont translate the options) |
||||||
231 | 'lettersearch' => true, |
||||||
232 | // using a positiv list now, as we constantly adding new columns in addressbook, but not removing them from default |
||||||
233 | 'default_cols' => 'type,n_fileas_n_given_n_family_n_family_n_given_org_name_n_family_n_given_n_fileas,'. |
||||||
234 | 'number,org_name,org_unit,'. |
||||||
235 | 'business_adr_one_countrycode_adr_one_postalcode,tel_work_tel_cell_tel_home,url_email_email_home', |
||||||
236 | /* old negative list |
||||||
237 | 'default_cols' => '!cat_id,contact_created_contact_modified,distribution_list,contact_id,owner,room',*/ |
||||||
238 | 'filter2_onchange' => "return app.addressbook.filter2_onchange();", |
||||||
239 | 'filter2_tags' => true, |
||||||
240 | //'actions' => $this->get_actions(), // set on each request, as it depends on some filters |
||||||
241 | 'row_id' => 'id', |
||||||
242 | 'row_modified' => 'modified', |
||||||
243 | 'is_parent' => 'group_count', |
||||||
244 | 'parent_id' => 'parent_id', |
||||||
245 | 'favorites' => true, |
||||||
246 | ); |
||||||
247 | |||||||
248 | // use the state of the last session stored in the user prefs |
||||||
249 | if (($state = @unserialize($this->prefs['index_state']))) |
||||||
250 | { |
||||||
251 | $content['nm'] = array_merge($content['nm'],$state); |
||||||
252 | } |
||||||
253 | } |
||||||
254 | $sel_options['cat_id'] = array('' => lang('All categories'), '0' => lang('None')); |
||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||
255 | |||||||
256 | $content['nm']['placeholder_actions'] = array('add'); |
||||||
257 | // Edit and delete list actions depends on permissions |
||||||
258 | if($this->get_lists(Acl::EDIT)) |
||||||
259 | { |
||||||
260 | $content['nm']['placeholder_actions'][] = 'rename_list'; |
||||||
261 | $content['nm']['placeholder_actions'][] = 'delete_list'; |
||||||
262 | } |
||||||
263 | |||||||
264 | // Search parameter passed in |
||||||
265 | if ($_GET['search']) { |
||||||
266 | $content['nm']['search'] = $_GET['search']; |
||||||
267 | } |
||||||
268 | if (isset($typeselection)) $content['nm']['col_filter']['tid'] = $typeselection; |
||||||
269 | // save the tid for use in creating new addressbook entrys via UI. Current tid is to be used as type of new entrys |
||||||
270 | //error_log(__METHOD__.__LINE__.' '.$content['nm']['col_filter']['tid']); |
||||||
271 | Api\Cache::setSession('addressbook','active_tid',$content['nm']['col_filter']['tid']); |
||||||
272 | if ($this->lists_available()) |
||||||
273 | { |
||||||
274 | $sel_options['filter2'] = $this->get_lists(Acl::READ,array('' => lang('No distribution list'))); |
||||||
275 | $sel_options['filter2']['add'] = lang('Add a new list').'...'; // put it at the end |
||||||
276 | } |
||||||
277 | |||||||
278 | // Organisation stuff is not (yet) availible with ldap |
||||||
279 | if($GLOBALS['egw_info']['server']['contact_repository'] != 'ldap') |
||||||
280 | { |
||||||
281 | $content['nm']['header_left'] = 'addressbook.index.left'; |
||||||
282 | } |
||||||
283 | $sel_options['filter'] = $sel_options['owner'] = $this->get_addressbooks(Acl::READ, lang('All addressbooks')); |
||||||
284 | $sel_options['to'] = array( |
||||||
285 | 'to' => 'To', |
||||||
286 | 'cc' => 'Cc', |
||||||
287 | 'bcc' => 'Bcc', |
||||||
288 | ); |
||||||
289 | $sel_options['adr_one_countrycode']['-custom-'] = lang('No country selected'); |
||||||
290 | |||||||
291 | // if there is any export limit set, pass it on to the nextmatch, to be evaluated by the export |
||||||
292 | if (isset($this->config['contact_export_limit']) && (int)$this->config['contact_export_limit']) $content['nm']['export_limit']=$this->config['contact_export_limit']; |
||||||
293 | |||||||
294 | // Merge to email dialog needs the infolog types |
||||||
295 | $infolog = new infolog_bo(); |
||||||
296 | $sel_options['info_type'] = $infolog->enums['type']; |
||||||
297 | |||||||
298 | // dont show tid-selection if we have only one content_type |
||||||
299 | // be a bit more sophisticated about it |
||||||
300 | $availabletypes = array_keys($this->content_types); |
||||||
301 | if ($content['nm']['col_filter']['tid'] && !in_array($content['nm']['col_filter']['tid'],$availabletypes)) |
||||||
302 | { |
||||||
303 | //_debug_array(array('Typefilter:'=> $content['nm']['col_filter']['tid'],'Available Types:'=>$availabletypes,'action:'=>'remove invalid filter')); |
||||||
304 | unset($content['nm']['col_filter']['tid']); |
||||||
305 | } |
||||||
306 | if (!isset($content['nm']['col_filter']['tid'])) $content['nm']['col_filter']['tid'] = $availabletypes[0]; |
||||||
307 | if (count($this->content_types) > 1) |
||||||
308 | { |
||||||
309 | foreach($this->content_types as $tid => $data) |
||||||
310 | { |
||||||
311 | $sel_options['tid'][$tid] = $data['name']; |
||||||
312 | } |
||||||
313 | } |
||||||
314 | else |
||||||
315 | { |
||||||
316 | $this->tmpl->disableElement('nm[col_filter][tid]'); |
||||||
317 | } |
||||||
318 | // get the availible grouped-views plus the label of the contacts view of one group |
||||||
319 | $sel_options['grouped_view'] = $this->grouped_views; |
||||||
320 | if (isset($grouped_view)) |
||||||
321 | { |
||||||
322 | $content['nm']['grouped_view'] = $grouped_view; |
||||||
323 | } |
||||||
324 | |||||||
325 | $content['nm']['actions'] = $this->get_actions($content['nm']['col_filter']['tid']); |
||||||
326 | |||||||
327 | if (!isset($sel_options['grouped_view'][(string) $content['nm']['grouped_view']])) |
||||||
328 | { |
||||||
329 | $sel_options['grouped_view'] += $this->_get_grouped_name((string)$content['nm']['grouped_view']); |
||||||
330 | } |
||||||
331 | // unset the filters regarding grouped views, when there is no group selected |
||||||
332 | if (empty($sel_options['grouped_view'][(string) $content['nm']['grouped_view']]) || stripos($grouped_view,":") === false ) |
||||||
333 | { |
||||||
334 | $this->unset_grouped_filters($content['nm']); |
||||||
335 | } |
||||||
336 | $content['nm']['grouped_view_label'] = $sel_options['grouped_view'][(string) $content['nm']['grouped_view']]; |
||||||
337 | |||||||
338 | $this->tmpl->read('addressbook.index'); |
||||||
339 | return $this->tmpl->exec('addressbook.addressbook_ui.index', |
||||||
340 | $content,$sel_options,array(),$preserv); |
||||||
341 | } |
||||||
342 | |||||||
343 | /** |
||||||
344 | * Get actions / context menu items |
||||||
345 | * |
||||||
346 | * @param string $tid_filter =null |
||||||
347 | * @return array see Etemplate\Widget\Nextmatch::get_actions() |
||||||
348 | */ |
||||||
349 | public function get_actions($tid_filter=null) |
||||||
350 | { |
||||||
351 | // Contact view |
||||||
352 | $actions = array( |
||||||
353 | 'view' => array( |
||||||
354 | 'caption' => 'CRM-View', |
||||||
355 | 'default' => $GLOBALS['egw_info']['user']['preferences']['addressbook']['crm_list'] != '~edit~', |
||||||
356 | 'allowOnMultiple' => false, |
||||||
357 | 'group' => $group=1, |
||||||
358 | 'onExecute' => 'javaScript:app.addressbook.view', |
||||||
359 | 'enableClass' => 'contact_contact', |
||||||
360 | 'hideOnDisabled' => true, |
||||||
361 | // Children added below |
||||||
362 | 'children' => array(), |
||||||
363 | 'hideOnMobile' => true |
||||||
364 | ), |
||||||
365 | 'open' => array( |
||||||
366 | 'caption' => 'Open', |
||||||
367 | 'default' => $GLOBALS['egw_info']['user']['preferences']['addressbook']['crm_list'] == '~edit~', |
||||||
368 | 'allowOnMultiple' => false, |
||||||
369 | 'enableClass' => 'contact_contact', |
||||||
370 | 'hideOnDisabled' => true, |
||||||
371 | 'url' => 'menuaction=addressbook.addressbook_ui.edit&contact_id=$id', |
||||||
372 | 'popup' => Link::get_registry('addressbook', 'edit_popup'), |
||||||
373 | 'group' => $group, |
||||||
374 | ), |
||||||
375 | 'add' => array( |
||||||
376 | 'caption' => 'Add', |
||||||
377 | 'group' => $group, |
||||||
378 | 'hideOnDisabled' => true, |
||||||
379 | 'children' => array( |
||||||
380 | 'new' => array( |
||||||
381 | 'caption' => 'New', |
||||||
382 | 'url' => 'menuaction=addressbook.addressbook_ui.edit', |
||||||
383 | 'popup' => Link::get_registry('addressbook', 'add_popup'), |
||||||
384 | 'icon' => 'new', |
||||||
385 | ), |
||||||
386 | 'copy' => array( |
||||||
387 | 'caption' => 'Copy', |
||||||
388 | 'url' => 'menuaction=addressbook.addressbook_ui.edit&makecp=1&contact_id=$id', |
||||||
389 | 'popup' => Link::get_registry('addressbook', 'add_popup'), |
||||||
390 | 'enableClass' => 'contact_contact', |
||||||
391 | 'allowOnMultiple' => false, |
||||||
392 | 'icon' => 'copy', |
||||||
393 | ), |
||||||
394 | ), |
||||||
395 | 'hideOnMobile' => true |
||||||
396 | ), |
||||||
397 | ); |
||||||
398 | // CRM view options |
||||||
399 | $crm_count = 0; |
||||||
400 | $crm_apps = array('infolog','tracker'); |
||||||
401 | foreach($crm_apps as $app) |
||||||
402 | { |
||||||
403 | if ($GLOBALS['egw_info']['user']['apps'][$app]) $crm_count++; |
||||||
404 | } |
||||||
405 | if($GLOBALS['egw_info']['user']['apps']['infolog']) |
||||||
406 | { |
||||||
407 | array_splice($crm_apps, 1, 0, 'infolog-organisation'); |
||||||
408 | } |
||||||
409 | if($crm_count > 1) |
||||||
410 | { |
||||||
411 | foreach($crm_apps as $app) |
||||||
412 | { |
||||||
413 | $actions['view']['children']["view-$app"] = array( |
||||||
414 | 'caption' => $app, |
||||||
415 | 'icon' => "$app/navbar" |
||||||
416 | ); |
||||||
417 | } |
||||||
418 | } |
||||||
419 | |||||||
420 | // org view |
||||||
421 | $actions += array( |
||||||
422 | 'view_org' => array( |
||||||
423 | 'caption' => 'View', |
||||||
424 | 'default' => true, |
||||||
425 | 'allowOnMultiple' => false, |
||||||
426 | 'group' => $group=1, |
||||||
427 | 'enableClass' => 'contact_organisation', |
||||||
428 | 'hideOnDisabled' => true |
||||||
429 | ), |
||||||
430 | 'add_org' => array( |
||||||
431 | 'caption' => 'Add', |
||||||
432 | 'group' => $group, |
||||||
433 | 'allowOnMultiple' => false, |
||||||
434 | 'enableClass' => 'contact_organisation', |
||||||
435 | 'hideOnDisabled' => true, |
||||||
436 | 'url' => 'menuaction=addressbook.addressbook_ui.edit&org=$id', |
||||||
437 | 'popup' => Link::get_registry('addressbook', 'add_popup'), |
||||||
438 | ), |
||||||
439 | ); |
||||||
440 | |||||||
441 | // Duplicates view |
||||||
442 | $actions += array( |
||||||
443 | 'view_duplicates' => array( |
||||||
444 | 'caption' => 'View', |
||||||
445 | 'default' => true, |
||||||
446 | 'allowOnMultiple' => false, |
||||||
447 | 'group' => $group=1, |
||||||
448 | 'enableClass' => 'contact_duplicate', |
||||||
449 | 'hideOnDisabled' => true |
||||||
450 | ) |
||||||
451 | ); |
||||||
452 | |||||||
453 | ++$group; // other AB related stuff group: lists, AB's, categories |
||||||
454 | // categories submenu |
||||||
455 | $actions['cat'] = array( |
||||||
456 | 'caption' => 'Categories', |
||||||
457 | 'group' => $group, |
||||||
458 | 'children' => array( |
||||||
459 | 'cat_add' => Etemplate\Widget\Nextmatch::category_action( |
||||||
460 | 'addressbook',$group,'Add category', 'cat_add_', |
||||||
461 | true, 0,Etemplate\Widget\Nextmatch::DEFAULT_MAX_MENU_LENGTH,false |
||||||
0 ignored issues
–
show
The call to
EGroupware\Api\Etemplate...atch::category_action() has too many arguments starting with false .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||||
462 | )+array( |
||||||
463 | 'icon' => 'foldertree_nolines_plus', |
||||||
464 | 'disableClass' => 'rowNoEdit', |
||||||
465 | ), |
||||||
466 | 'cat_del' => Etemplate\Widget\Nextmatch::category_action( |
||||||
467 | 'addressbook',$group,'Delete category', 'cat_del_', |
||||||
468 | true, 0,Etemplate\Widget\Nextmatch::DEFAULT_MAX_MENU_LENGTH,false |
||||||
469 | )+array( |
||||||
470 | 'icon' => 'foldertree_nolines_minus', |
||||||
471 | 'disableClass' => 'rowNoEdit', |
||||||
472 | ), |
||||||
473 | ), |
||||||
474 | ); |
||||||
475 | if (!$GLOBALS['egw_info']['user']['apps']['preferences']) unset($actions['cats']['children']['cat_edit']); |
||||||
476 | // Submenu for all distributionlist stuff |
||||||
477 | $actions['lists'] = array( |
||||||
478 | 'caption' => 'Distribution lists', |
||||||
479 | 'children' => array( |
||||||
480 | 'list_add' => array( |
||||||
481 | 'caption' => 'Add a new list', |
||||||
482 | 'icon' => 'new', |
||||||
483 | 'onExecute' => 'javaScript:app.addressbook.add_new_list', |
||||||
484 | ), |
||||||
485 | ), |
||||||
486 | 'group' => $group, |
||||||
487 | ); |
||||||
488 | if (($add_lists = $this->get_lists(Acl::EDIT))) // do we have distribution lists?, and are we allowed to edit them |
||||||
489 | { |
||||||
490 | $actions['lists']['children'] += array( |
||||||
491 | 'to_list' => array( |
||||||
492 | 'caption' => 'Add to distribution list', |
||||||
493 | 'children' => $add_lists, |
||||||
494 | 'prefix' => 'to_list_', |
||||||
495 | 'icon' => 'foldertree_nolines_plus', |
||||||
496 | 'enabled' => ($add_lists?true:false), // if there are editable lists, allow to add a contact to one of them, |
||||||
0 ignored issues
–
show
|
|||||||
497 | //'disableClass' => 'rowNoEdit', // wether you are allowed to edit the contact or not, as you alter a list, not the contact |
||||||
498 | ), |
||||||
499 | 'remove_from_list' => array( |
||||||
500 | 'caption' => 'Remove from distribution list', |
||||||
501 | 'confirm' => 'Remove selected contacts from distribution list', |
||||||
502 | 'icon' => 'foldertree_nolines_minus', |
||||||
503 | 'enabled' => 'javaScript:app.addressbook.nm_compare_field', |
||||||
504 | 'fieldId' => 'exec[nm][filter2]', |
||||||
505 | 'fieldValue' => '!', // enable if list != '' |
||||||
506 | ), |
||||||
507 | 'rename_list' => array( |
||||||
508 | 'caption' => 'Rename selected distribution list', |
||||||
509 | 'icon' => 'edit', |
||||||
510 | 'enabled' => 'javaScript:app.addressbook.nm_compare_field', |
||||||
511 | 'fieldId' => 'exec[nm][filter2]', |
||||||
512 | 'fieldValue' => '!', // enable if list != '' |
||||||
513 | 'onExecute' => 'javaScript:app.addressbook.rename_list' |
||||||
514 | ), |
||||||
515 | 'delete_list' => array( |
||||||
516 | 'caption' => 'Delete selected distribution list!', |
||||||
517 | 'confirm' => 'Delete selected distribution list!', |
||||||
518 | 'icon' => 'delete', |
||||||
519 | 'enabled' => 'javaScript:app.addressbook.nm_compare_field', |
||||||
520 | 'fieldId' => 'exec[nm][filter2]', |
||||||
521 | 'fieldValue' => '!', // enable if list != '' |
||||||
522 | ), |
||||||
523 | ); |
||||||
524 | if(is_subclass_of('etemplate', 'etemplate_new')) |
||||||
525 | { |
||||||
526 | $actions['lists']['children']['remove_from_list']['fieldId'] = 'filter2'; |
||||||
527 | $actions['lists']['children']['rename_list']['fieldId'] = 'filter2'; |
||||||
528 | $actions['lists']['children']['delete_list']['fieldId'] = 'filter2'; |
||||||
529 | } |
||||||
530 | } |
||||||
531 | // move to AB |
||||||
532 | if (($move2addressbooks = $this->get_addressbooks(Acl::ADD))) // do we have addressbooks, we should |
||||||
533 | { |
||||||
534 | unset($move2addressbooks[0]); // do not offer action to move contact to an account, as we dont support that currrently |
||||||
535 | foreach($move2addressbooks as $owner => $label) |
||||||
536 | { |
||||||
537 | $icon = $type_label = null; |
||||||
538 | $this->type_icon((int)$owner, substr($owner,-1) == 'p', 'n', $icon, $type_label); |
||||||
539 | $move2addressbooks[$owner] = array( |
||||||
540 | 'icon' => $icon, |
||||||
541 | 'caption' => $label, |
||||||
542 | ); |
||||||
543 | } |
||||||
544 | // copy checkbox |
||||||
545 | $move2addressbooks= array( |
||||||
546 | 'copy' =>array( |
||||||
547 | 'id' => 'move_to_copy', |
||||||
548 | 'caption' => 'Copy instead of move', |
||||||
549 | 'checkbox' => true, |
||||||
550 | )) + $move2addressbooks; |
||||||
551 | $actions['move_to'] = array( |
||||||
552 | 'caption' => 'Move to addressbook', |
||||||
553 | 'children' => $move2addressbooks, |
||||||
554 | 'prefix' => 'move_to_', |
||||||
555 | 'group' => $group, |
||||||
556 | 'disableClass' => 'rowNoDelete', |
||||||
557 | 'hideOnMobile' => true |
||||||
558 | ); |
||||||
559 | } |
||||||
560 | $actions['merge'] = array( |
||||||
561 | 'caption' => 'Merge contacts', |
||||||
562 | 'confirm' => 'Merge into first or account, deletes all other!', |
||||||
563 | 'hint' => 'Merge into first or account, deletes all other!', |
||||||
564 | 'allowOnMultiple' => 'only', |
||||||
565 | 'group' => $group, |
||||||
566 | 'hideOnMobile' => true, |
||||||
567 | 'enabled' => 'javaScript:app.addressbook.can_merge' |
||||||
568 | ); |
||||||
569 | // Duplicates view |
||||||
570 | $actions['merge_duplicates'] = array( |
||||||
571 | 'caption' => 'Merge duplicates', |
||||||
572 | 'group' => $group, |
||||||
573 | 'allowOnMultiple' => true, |
||||||
574 | 'enableClass' => 'contact_duplicate', |
||||||
575 | 'hideOnDisabled' => true |
||||||
576 | ); |
||||||
577 | |||||||
578 | ++$group; // integration with other apps: infolog, calendar, filemanager, messenger |
||||||
579 | |||||||
580 | // Integrate Messenger app actions for adding new buddy into roster list |
||||||
581 | if ($GLOBALS['egw_info']['user']['apps']['messenger']) |
||||||
582 | { |
||||||
583 | $actions['messenger_app'] = array( |
||||||
584 | 'caption' => 'Messenger', |
||||||
585 | 'icon' => 'messenger/navbar', |
||||||
586 | 'group' => $group, |
||||||
587 | 'children' => array( |
||||||
588 | 'addBuddy' => array( |
||||||
589 | 'caption' => lang('Add contact'), |
||||||
590 | 'icon' => 'add', |
||||||
591 | 'allowOnMultiple' => true, |
||||||
592 | 'onExecute' => 'javaScript:app.messenger.addBuddy', |
||||||
593 | 'enabled' => 'javaScript:app.messenger.addBuddyEnabaled' |
||||||
594 | ) |
||||||
595 | ) |
||||||
596 | ); |
||||||
597 | } |
||||||
598 | |||||||
599 | if ($GLOBALS['egw_info']['user']['apps']['infolog']) |
||||||
600 | { |
||||||
601 | $actions['infolog_app'] = array( |
||||||
602 | 'caption' => 'InfoLog', |
||||||
603 | 'icon' => 'infolog/navbar', |
||||||
604 | 'group' => $group, |
||||||
605 | 'children' => array( |
||||||
606 | 'infolog' => array( |
||||||
607 | 'caption' => lang('View linked InfoLog entries'), |
||||||
608 | 'icon' => 'infolog/navbar', |
||||||
609 | 'onExecute' => 'javaScript:app.addressbook.view_infolog', |
||||||
610 | 'disableClass' => 'contact_duplicate', |
||||||
611 | 'allowOnMultiple' => true, |
||||||
612 | 'hideOnDisabled' => true, |
||||||
613 | ), |
||||||
614 | 'infolog_add' => array( |
||||||
615 | 'caption' => 'Add a new Infolog', |
||||||
616 | 'icon' => 'new', |
||||||
617 | 'url' => 'menuaction=infolog.infolog_ui.edit&type=task&action=addressbook&action_id=$id', |
||||||
618 | 'popup' => Link::get_registry('infolog', 'add_popup'), |
||||||
619 | 'onExecute' => 'javaScript:app.addressbook.add_task', // call server for org-view only |
||||||
620 | ), |
||||||
621 | ), |
||||||
622 | 'hideOnMobile' => true |
||||||
623 | ); |
||||||
624 | } |
||||||
625 | if ($GLOBALS['egw_info']['user']['apps']['calendar']) |
||||||
626 | { |
||||||
627 | $actions['calendar'] = array( |
||||||
628 | 'icon' => 'calendar/navbar', |
||||||
629 | 'caption' => 'Calendar', |
||||||
630 | 'group' => $group, |
||||||
631 | 'enableClass' => 'contact_contact', |
||||||
632 | 'children' => array( |
||||||
633 | 'calendar_view' => array( |
||||||
634 | 'caption' => 'Show', |
||||||
635 | 'icon' => 'view', |
||||||
636 | 'onExecute' => 'javaScript:app.addressbook.view_calendar', |
||||||
637 | 'targetapp' => 'calendar', // open in calendar tab, |
||||||
638 | 'hideOnDisabled' => true, |
||||||
639 | ), |
||||||
640 | 'calendar_add' => array( |
||||||
641 | 'caption' => 'Add appointment', |
||||||
642 | 'icon' => 'new', |
||||||
643 | 'popup' => Link::get_registry('calendar', 'add_popup'), |
||||||
644 | 'onExecute' => 'javaScript:app.addressbook.add_cal', |
||||||
645 | ), |
||||||
646 | ), |
||||||
647 | 'hideOnMobile' => true |
||||||
648 | ); |
||||||
649 | } |
||||||
650 | //Send to email |
||||||
651 | $actions['email'] = array( |
||||||
652 | 'caption' => 'Email', |
||||||
653 | 'icon' => 'mail/navbar', |
||||||
654 | 'enableClass' => 'contact_contact', |
||||||
655 | 'hideOnDisabled' => true, |
||||||
656 | 'group' => $group, |
||||||
657 | 'children' => array( |
||||||
658 | 'add_to_to' => array( |
||||||
659 | 'caption' => lang('Add to To'), |
||||||
660 | 'no_lang' => true, |
||||||
661 | 'onExecute' => 'javaScript:app.addressbook.addEmail', |
||||||
662 | |||||||
663 | ), |
||||||
664 | 'add_to_cc' => array( |
||||||
665 | 'caption' => lang('Add to Cc'), |
||||||
666 | 'no_lang' => true, |
||||||
667 | 'onExecute' => 'javaScript:app.addressbook.addEmail', |
||||||
668 | |||||||
669 | ), |
||||||
670 | 'add_to_bcc' => array( |
||||||
671 | 'caption' => lang('Add to BCc'), |
||||||
672 | 'no_lang' => true, |
||||||
673 | 'onExecute' => 'javaScript:app.addressbook.addEmail', |
||||||
674 | |||||||
675 | ), |
||||||
676 | 'email_business' => array( |
||||||
677 | 'caption' => lang('Business email'), |
||||||
678 | 'no_lang' => true, |
||||||
679 | 'checkbox' => true, |
||||||
680 | 'group' => $group, |
||||||
681 | 'onExecute' => 'javaScript:app.addressbook.mailCheckbox', |
||||||
682 | 'checked' => $this->prefs['preferredMail']['business'], |
||||||
683 | ), |
||||||
684 | 'email_home' => array( |
||||||
685 | 'caption' => lang('Home email'), |
||||||
686 | 'no_lang' => true, |
||||||
687 | 'checkbox' => true, |
||||||
688 | 'group' => $group, |
||||||
689 | 'onExecute' => 'javaScript:app.addressbook.mailCheckbox', |
||||||
690 | 'checked' => $this->prefs['preferredMail']['private'], |
||||||
691 | ), |
||||||
692 | ), |
||||||
693 | |||||||
694 | ); |
||||||
695 | if (!$this->prefs['preferredMail']) |
||||||
696 | $actions['email']['children']['email_business']['checked'] = true; |
||||||
697 | |||||||
698 | if ($GLOBALS['egw_info']['user']['apps']['filemanager']) |
||||||
699 | { |
||||||
700 | $actions['filemanager'] = array( |
||||||
701 | 'icon' => 'filemanager/navbar', |
||||||
702 | 'caption' => 'Filemanager', |
||||||
703 | 'url' => 'menuaction=filemanager.filemanager_ui.index&path=/apps/addressbook/$id&ajax=true', |
||||||
704 | 'allowOnMultiple' => false, |
||||||
705 | 'group' => $group, |
||||||
706 | // disable for for group-views, as it needs contact-ids |
||||||
707 | 'enableClass' => 'contact_contact', |
||||||
708 | 'hideOnMobile' => true |
||||||
709 | ); |
||||||
710 | } |
||||||
711 | |||||||
712 | $actions['geolocation'] = array( |
||||||
713 | 'caption' => 'GeoLocation', |
||||||
714 | 'icon' => 'map', |
||||||
715 | 'group' => ++$group, |
||||||
716 | 'enableClass' => 'contact_contact', |
||||||
717 | 'children' => array ( |
||||||
718 | 'private' => array( |
||||||
719 | 'caption' => 'Private Address', |
||||||
720 | 'enabled' => 'javaScript:app.addressbook.geoLocation_enabled', |
||||||
721 | 'onExecute' => 'javaScript:app.addressbook.geoLocationExec', |
||||||
722 | |||||||
723 | ), |
||||||
724 | 'business' => array( |
||||||
725 | 'caption' => 'Business Address', |
||||||
726 | 'enabled' => 'javaScript:app.addressbook.geoLocation_enabled', |
||||||
727 | 'onExecute' => 'javaScript:app.addressbook.geoLocationExec', |
||||||
728 | |||||||
729 | ) |
||||||
730 | ) |
||||||
731 | ); |
||||||
732 | $actions += EGroupware\Api\Link\Sharing::get_actions('addressbook', $group); |
||||||
733 | |||||||
734 | // check if user is an admin or the export is not generally turned off (contact_export_limit is non-numerical, eg. no) |
||||||
735 | $exception = Api\Storage\Merge::is_export_limit_excepted(); |
||||||
736 | if ((isset($GLOBALS['egw_info']['user']['apps']['admin']) || $exception) || !$this->config['contact_export_limit'] || (int)$this->config['contact_export_limit']) |
||||||
737 | { |
||||||
738 | $actions['export'] = array( |
||||||
739 | 'caption' => 'Export', |
||||||
740 | 'icon' => 'filesave', |
||||||
741 | 'enableClass' => 'contact_contact', |
||||||
742 | 'group' => ++$group, |
||||||
743 | 'children' => array( |
||||||
744 | 'csv' => array( |
||||||
745 | 'caption' => 'Export as CSV', |
||||||
746 | 'allowOnMultiple' => true, |
||||||
747 | 'url' => 'menuaction=importexport.importexport_export_ui.export_dialog&appname=addressbook&plugin=addressbook_export_contacts_csv&selection=$id&select_all=$select_all', |
||||||
748 | 'popup' => '850x440' |
||||||
749 | ), |
||||||
750 | 'vcard' => array( |
||||||
751 | 'caption' => 'Export as VCard', |
||||||
752 | 'postSubmit' => true, // download needs post submit (not Ajax) to work |
||||||
753 | 'icon' => Vfs::mime_icon('text/vcard'), |
||||||
754 | ), |
||||||
755 | ), |
||||||
756 | 'hideOnMobile' => true |
||||||
757 | ); |
||||||
758 | } |
||||||
759 | |||||||
760 | $actions['documents'] = Api\Contacts\Merge::document_action( |
||||||
761 | $this->prefs['document_dir'], $group, 'Insert in document', 'document_', |
||||||
762 | $this->prefs['default_document'], $this->config['contact_export_limit'] |
||||||
763 | ); |
||||||
764 | if ($GLOBALS['egw_info']['user']['apps']['felamimail']||$GLOBALS['egw_info']['user']['apps']['mail']) |
||||||
765 | { |
||||||
766 | $actions['mail'] = array( |
||||||
767 | 'caption' => lang('Mail VCard'), |
||||||
768 | 'icon' => 'filemanager/mail_post_to', |
||||||
769 | 'group' => $group, |
||||||
770 | 'onExecute' => 'javaScript:app.addressbook.adb_mail_vcard', |
||||||
771 | 'enableClass' => 'contact_contact', |
||||||
772 | 'hideOnDisabled' => true, |
||||||
773 | 'hideOnMobile' => true, |
||||||
774 | 'disableIfNoEPL' => true |
||||||
775 | ); |
||||||
776 | } |
||||||
777 | ++$group; |
||||||
778 | if (!($tid_filter == 'D' && !$GLOBALS['egw_info']['user']['apps']['admin'] && $this->config['history'] != 'userpurge')) |
||||||
779 | { |
||||||
780 | $actions['delete'] = array( |
||||||
781 | 'caption' => 'Delete', |
||||||
782 | 'confirm' => 'Delete this contact', |
||||||
783 | 'confirm_multiple' => 'Delete these entries', |
||||||
784 | 'group' => $group, |
||||||
785 | 'disableClass' => 'rowNoDelete', |
||||||
786 | ); |
||||||
787 | } |
||||||
788 | if ($this->grants[0] & Acl::DELETE) |
||||||
789 | { |
||||||
790 | $actions['delete_account'] = array( |
||||||
791 | 'caption' => 'Delete', |
||||||
792 | 'icon' => 'delete', |
||||||
793 | 'group' => $group, |
||||||
794 | 'enableClass' => 'rowAccount', |
||||||
795 | 'hideOnDisabled' => true, |
||||||
796 | 'popup' => '400x200', |
||||||
797 | 'url' => 'menuaction=admin.admin_account.delete&contact_id=$id', |
||||||
798 | ); |
||||||
799 | $actions['delete']['hideOnDisabled'] = true; |
||||||
800 | } |
||||||
801 | if($tid_filter == 'D') |
||||||
802 | { |
||||||
803 | $actions['undelete'] = array( |
||||||
804 | 'caption' => 'Un-delete', |
||||||
805 | 'icon' => 'revert', |
||||||
806 | 'group' => $group, |
||||||
807 | 'disableClass' => 'rowNoEdit', |
||||||
808 | ); |
||||||
809 | } |
||||||
810 | if (isset($actions['export']['children']['csv']) && |
||||||
811 | (!isset($GLOBALS['egw_info']['user']['apps']['importexport']) || |
||||||
812 | !importexport_helper_functions::has_definitions('addressbook','export'))) |
||||||
813 | { |
||||||
814 | unset($actions['export']['children']['csv']); |
||||||
815 | } |
||||||
816 | // Intercept open action in order to open entry into view mode instead of edit |
||||||
817 | if (Api\Header\UserAgent::mobile()) |
||||||
818 | { |
||||||
819 | $actions['open']['onExecute'] = 'javaScript:app.addressbook.viewEntry'; |
||||||
820 | $actions['open']['mobileViewTemplate'] = 'view?'.filemtime(Api\Etemplate\Widget\Template::rel2path('/addressbook/templates/mobile/view.xet')); |
||||||
821 | $actions['view']['default'] = false; |
||||||
822 | $actions['open']['default'] = true; |
||||||
823 | } |
||||||
824 | // Allow contacts to be dragged |
||||||
825 | /* |
||||||
826 | $actions['drag'] = array( |
||||||
827 | 'type' => 'drag', |
||||||
828 | 'dragType' => 'addressbook' |
||||||
829 | ); |
||||||
830 | */ |
||||||
831 | return $actions; |
||||||
832 | } |
||||||
833 | |||||||
834 | /** |
||||||
835 | * Get a nice name for the given grouped view ID |
||||||
836 | * |
||||||
837 | * @param String $view_id Some kind of indicator for a specific group, either |
||||||
838 | * organisation or duplicate. It looks like key:value pairs seperated by |||. |
||||||
839 | * |
||||||
840 | * @return Array(ID => name), where ID is the $view_id passed in |
||||||
841 | */ |
||||||
842 | protected function _get_grouped_name($view_id) |
||||||
843 | { |
||||||
844 | $group_name = array(); |
||||||
845 | if (strpos($view_id,'*AND*')!== false) $view_id = str_replace('*AND*','&',$view_id); |
||||||
846 | foreach(explode('|||',$view_id) as $part) |
||||||
847 | { |
||||||
848 | list(,$name) = explode(':',$part,2); |
||||||
849 | if ($name) $group_name[] = $name; |
||||||
850 | } |
||||||
851 | $name = implode(': ',$group_name); |
||||||
852 | return $name ? array($view_id => $name) : array(); |
||||||
853 | } |
||||||
854 | |||||||
855 | /** |
||||||
856 | * Unset the relevant column filters to clear a grouped view |
||||||
857 | * |
||||||
858 | * @param Array $query |
||||||
859 | */ |
||||||
860 | protected function unset_grouped_filters(&$query) |
||||||
861 | { |
||||||
862 | unset($query['col_filter']['org_name']); |
||||||
863 | unset($query['col_filter']['org_unit']); |
||||||
864 | unset($query['col_filter']['adr_one_locality']); |
||||||
865 | foreach(array_keys(static::$duplicate_fields) as $field) |
||||||
866 | { |
||||||
867 | unset($query['col_filter'][$field]); |
||||||
868 | } |
||||||
869 | } |
||||||
870 | |||||||
871 | /** |
||||||
872 | * Adjust the query as needed and get the rows for the grouped views (organisation |
||||||
873 | * or duplicate contacts) |
||||||
874 | * |
||||||
875 | * @param Array $query Nextmatch query |
||||||
876 | * @return array rows found |
||||||
877 | */ |
||||||
878 | protected function get_grouped_rows(&$query) |
||||||
879 | { |
||||||
880 | // Query doesn't like empties |
||||||
881 | unset($query['col_filter']['parent_id']); |
||||||
882 | |||||||
883 | if($query['actions'] && $query['actions']['open']) |
||||||
884 | { |
||||||
885 | // Just switched from contact view, update actions |
||||||
886 | $query['actions'] = $this->get_actions($query['col_filter']['tid']); |
||||||
887 | } |
||||||
888 | |||||||
889 | $query['template'] = $query['grouped_view'] == 'duplicates' ? 'addressbook.index.duplicate_rows' : 'addressbook.index.org_rows'; |
||||||
890 | |||||||
891 | if ($query['advanced_search']) |
||||||
892 | { |
||||||
893 | $query['op'] = $query['advanced_search']['operator']; |
||||||
894 | unset($query['advanced_search']['operator']); |
||||||
895 | $query['wildcard'] = $query['advanced_search']['meth_select']; |
||||||
896 | unset($query['advanced_search']['meth_select']); |
||||||
897 | $original_search = $query['search']; |
||||||
898 | $query['search'] = $query['advanced_search']; |
||||||
899 | } |
||||||
900 | |||||||
901 | switch ($query['template']) |
||||||
902 | { |
||||||
903 | case 'addressbook.index.org_rows': |
||||||
904 | if ($query['order'] != 'org_name') |
||||||
905 | { |
||||||
906 | $query['sort'] = 'ASC'; |
||||||
907 | $query['order'] = 'org_name'; |
||||||
908 | } |
||||||
909 | $query['org_view'] = $query['grouped_view']; |
||||||
910 | // switch the distribution list selection off for ldap |
||||||
911 | if($this->contact_repository != 'sql') |
||||||
912 | { |
||||||
913 | $query['no_filter2'] = true; |
||||||
914 | unset($query['col_filter']['list']); // does not work here |
||||||
915 | } |
||||||
916 | else |
||||||
917 | { |
||||||
918 | $rows = parent::organisations($query); |
||||||
919 | } |
||||||
920 | break; |
||||||
921 | case 'addressbook.index.duplicate_rows': |
||||||
922 | $query['no_filter2'] = true; // switch the distribution list selection off |
||||||
923 | unset($query['col_filter']['list']); // does not work for duplicates |
||||||
924 | $rows = parent::duplicates($query); |
||||||
925 | break; |
||||||
926 | } |
||||||
927 | |||||||
928 | if ($query['advanced_search']) |
||||||
929 | { |
||||||
930 | $query['search'] = $original_search; |
||||||
931 | unset($query['wildcard']); |
||||||
932 | unset($query['op']); |
||||||
933 | } |
||||||
934 | $GLOBALS['egw_info']['flags']['params']['manual'] = array('page' => 'ManualAddressbookIndexOrga'); |
||||||
935 | |||||||
936 | return $rows; |
||||||
937 | } |
||||||
938 | |||||||
939 | /** |
||||||
940 | * Return the contacts in an organisation via AJAX |
||||||
941 | * |
||||||
942 | * @param string|string[] $org Organisation ID |
||||||
943 | * @param mixed $_query Query filters (category, etc) to use, or null to use session |
||||||
944 | * @return array |
||||||
945 | */ |
||||||
946 | public function ajax_organisation_contacts($org, $_query = null) |
||||||
947 | { |
||||||
948 | $org_contacts = array(); |
||||||
949 | $query = !$_query ? Api\Cache::getSession('addressbook', 'index') : $_query; |
||||||
950 | $query['num_rows'] = -1; // all |
||||||
951 | if(!is_array($query['col_filter'])) $query['col_filter'] = array(); |
||||||
952 | |||||||
953 | if(!is_array($org)) $org = array($org); |
||||||
954 | foreach($org as $org_name) |
||||||
955 | { |
||||||
956 | $query['grouped_view'] = $org_name; |
||||||
957 | $checked = array(); |
||||||
958 | $readonlys = null; |
||||||
959 | $this->get_rows($query,$checked,$readonlys,true); // true = only return the id's |
||||||
960 | if($checked[0]) |
||||||
961 | { |
||||||
962 | $org_contacts = array_merge($org_contacts,$checked); |
||||||
963 | } |
||||||
964 | } |
||||||
965 | Api\Json\Response::get()->data(array_unique($org_contacts)); |
||||||
966 | } |
||||||
967 | |||||||
968 | /** |
||||||
969 | * Show the infologs of an whole organisation |
||||||
970 | * |
||||||
971 | * @param string $org |
||||||
972 | */ |
||||||
973 | function infolog_org_view($org) |
||||||
974 | { |
||||||
975 | $query = Api\Cache::getSession('addressbook', 'index'); |
||||||
976 | $query['num_rows'] = -1; // all |
||||||
977 | $query['grouped_view'] = $org; |
||||||
978 | $query['searchletter'] = ''; |
||||||
979 | $checked = $readonlys = null; |
||||||
980 | $this->get_rows($query,$checked,$readonlys,true); // true = only return the id's |
||||||
981 | |||||||
982 | if (count($checked) > 1) // use a nicely formatted org-name as title in infolog |
||||||
983 | { |
||||||
984 | $parts = array(); |
||||||
985 | if (strpos($org,'*AND*')!== false) $org = str_replace('*AND*','&',$org); |
||||||
986 | foreach(explode('|||',$org) as $part) |
||||||
987 | { |
||||||
988 | list(,$part) = explode(':',$part,2); |
||||||
989 | if ($part) $parts[] = $part; |
||||||
990 | } |
||||||
991 | $org = implode(', ',$parts); |
||||||
992 | } |
||||||
993 | else |
||||||
994 | { |
||||||
995 | $org = ''; // use infolog default of link-title |
||||||
996 | } |
||||||
997 | Egw::redirect_link('/index.php',array( |
||||||
998 | 'menuaction' => 'infolog.infolog_ui.index', |
||||||
999 | 'action' => 'addressbook', |
||||||
1000 | 'action_id' => implode(',',$checked), |
||||||
1001 | 'action_title' => $org, |
||||||
1002 | ),'infolog'); |
||||||
1003 | } |
||||||
1004 | |||||||
1005 | /** |
||||||
1006 | * Create or rename an existing email list |
||||||
1007 | * |
||||||
1008 | * @param int $list_id ID of existing list, or 0 for a new one |
||||||
1009 | * @param string $new_name List name |
||||||
1010 | * @param int $_owner List owner, or empty for current user |
||||||
1011 | * @param string[] [$contacts] List of contacts to add to the array |
||||||
0 ignored issues
–
show
|
|||||||
1012 | * @return boolean|string |
||||||
1013 | */ |
||||||
1014 | function ajax_set_list($list_id, $new_name, $_owner = false, $contacts = array()) |
||||||
1015 | { |
||||||
1016 | // Set owner to current user, if not set |
||||||
1017 | $owner = $_owner ? $_owner : $GLOBALS['egw_info']['user']['account_id']; |
||||||
1018 | // if admin forced or set default for add_default pref |
||||||
1019 | // consider default_addressbook as owner which already |
||||||
1020 | // covered all cases in contacts class. |
||||||
1021 | if ($owner == (int)$GLOBALS['egw']->preferences->default['addressbook']['add_default'] || |
||||||
1022 | $owner == (int)$GLOBALS['egw']->preferences->forced['addressbook']['add_default']) |
||||||
1023 | { |
||||||
1024 | $owner = $this->default_addressbook; |
||||||
1025 | } |
||||||
1026 | // Check for valid list & permissions |
||||||
1027 | if(!(int)$list_id && !$this->check_list(null,EGW_ACL_ADD|EGW_ACL_EDIT,$owner)) |
||||||
1028 | { |
||||||
1029 | Api\Json\Response::get()->apply('egw.message', array( lang('List creation failed, no rights!'),'error')); |
||||||
1030 | return; |
||||||
1031 | } |
||||||
1032 | if ((int)$list_id && !$this->check_list((int)$list_id, Acl::EDIT, $owner)) |
||||||
1033 | { |
||||||
1034 | Api\Json\Response::get()->apply('egw.message', array( lang('Insufficent rights to edit this list!'),'error')); |
||||||
1035 | return; |
||||||
1036 | } |
||||||
1037 | |||||||
1038 | $list = array('list_owner' => $owner); |
||||||
1039 | |||||||
1040 | // Rename |
||||||
1041 | if($list_id) |
||||||
1042 | { |
||||||
1043 | $list = $this->read_list((int)$list_id); |
||||||
1044 | } |
||||||
1045 | $list['list_name'] = $new_name; |
||||||
1046 | |||||||
1047 | $new_id = $this->add_list(array('list_id' => (int)$list_id), $list['list_owner'],array(),$list); |
||||||
1048 | |||||||
1049 | if($contacts) |
||||||
1050 | { |
||||||
1051 | $this->add2list($contacts,$new_id); |
||||||
1052 | } |
||||||
1053 | Api\Json\Response::get()->apply('egw.message', array( |
||||||
1054 | $new_id == $list_id ? lang('Distribution list renamed') : lang('List created'), |
||||||
1055 | 'success' |
||||||
1056 | )); |
||||||
1057 | // Success, just update selectbox to new value |
||||||
1058 | Api\Json\Response::get()->data($new_id == $list_id ? "true" : $new_id); |
||||||
1059 | } |
||||||
1060 | |||||||
1061 | /** |
||||||
1062 | * Ajax function to get contact data out of provided account_id |
||||||
1063 | * |
||||||
1064 | * @param string $account_id |
||||||
1065 | */ |
||||||
1066 | function ajax_get_contact ($account_id) |
||||||
1067 | { |
||||||
1068 | $bo = new Api\Contacts(); |
||||||
1069 | $contact = $bo->read('account:'.$account_id); |
||||||
1070 | Api\Json\Response::get()->data($contact); |
||||||
1071 | } |
||||||
1072 | |||||||
1073 | /** |
||||||
1074 | * Disable / clear advanced search |
||||||
1075 | * |
||||||
1076 | * Advanced search is stored server side in session no matter what the nextmatch |
||||||
1077 | * sends, so we have to clear it here. |
||||||
1078 | */ |
||||||
1079 | public static function ajax_clear_advanced_search() |
||||||
1080 | { |
||||||
1081 | $query = Api\Cache::getSession('addressbook', 'index'); |
||||||
1082 | unset($query['advanced_search']); |
||||||
1083 | Api\Cache::setSession('addressbook','index',$query); |
||||||
1084 | Api\Cache::setSession('addressbook', 'advanced_search', false); |
||||||
1085 | } |
||||||
1086 | |||||||
1087 | /** |
||||||
1088 | * apply an action to multiple contacts |
||||||
1089 | * |
||||||
1090 | * @param string/int $action 'delete', 'vcard', 'csv' or nummerical account_id to move contacts to that addessbook |
||||||
0 ignored issues
–
show
|
|||||||
1091 | * @param array $checked contact id's to use if !$use_all |
||||||
1092 | * @param boolean $use_all if true use all contacts of the current selection (in the session) |
||||||
1093 | * @param int &$success number of succeded actions |
||||||
1094 | * @param int &$failed number of failed actions (not enought permissions) |
||||||
1095 | * @param string &$action_msg translated verb for the actions, to be used in a message like %1 contacts 'deleted' |
||||||
1096 | * @param string/array $session_name 'index' or array with session-data depending if we are in the main list or the popup |
||||||
1097 | * @return boolean true if all actions succeded, false otherwise |
||||||
1098 | */ |
||||||
1099 | function action($action,$checked,$use_all,&$success,&$failed,&$action_msg,$session_name,&$msg, $checkboxes = NULL) |
||||||
1100 | { |
||||||
1101 | //echo "<p>uicontacts::action('$action',".print_r($checked,true).','.(int)$use_all.",...)</p>\n"; |
||||||
1102 | $success = $failed = 0; |
||||||
1103 | if ($use_all || in_array($action,array('remove_from_list','delete_list'))) |
||||||
1104 | { |
||||||
1105 | // get the whole selection |
||||||
1106 | $query = is_array($session_name) ? $session_name : Api\Cache::getSession('addressbook', $session_name); |
||||||
1107 | |||||||
1108 | if ($use_all) |
||||||
1109 | { |
||||||
1110 | @set_time_limit(0); // switch off the execution time limit, as it's for big selections to small |
||||||
0 ignored issues
–
show
It seems like you do not handle an error condition for
set_time_limit() . This can introduce security issues, and is generally not recommended.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||||||
1111 | $query['num_rows'] = -1; // all |
||||||
1112 | $readonlys = null; |
||||||
1113 | $this->get_rows($query,$checked,$readonlys,true); // true = only return the id's |
||||||
1114 | } |
||||||
1115 | } |
||||||
1116 | // replace org_name:* id's with all id's of that org |
||||||
1117 | $grouped_contacts = $this->find_grouped_ids($action, $checked, $use_all, $success,$failed,$action_msg,$session_name, $msg); |
||||||
1118 | if ($grouped_contacts) $checked = array_unique($checked ? array_merge($checked,$grouped_contacts) : $grouped_contacts); |
||||||
1119 | //_debug_array($checked); exit; |
||||||
1120 | |||||||
1121 | if (substr($action,0,8) == 'move_to_') |
||||||
1122 | { |
||||||
1123 | $action = (int)substr($action,8).(substr($action,-1) == 'p' ? 'p' : ''); |
||||||
1124 | } |
||||||
1125 | elseif (substr($action,0,8) == 'to_list_') |
||||||
1126 | { |
||||||
1127 | $to_list = (int)substr($action,8); |
||||||
1128 | $action = 'to_list'; |
||||||
1129 | } |
||||||
1130 | elseif (substr($action,0,9) == 'document_') |
||||||
1131 | { |
||||||
1132 | $document = substr($action,9); |
||||||
1133 | $action = 'document'; |
||||||
1134 | } |
||||||
1135 | elseif(substr($action,0,4) == 'cat_') // cat_add_123 or cat_del_456 |
||||||
1136 | { |
||||||
1137 | $cat_id = (int)substr($action, 8); |
||||||
1138 | $action = substr($action,0,7); |
||||||
1139 | } |
||||||
1140 | // Security: stop non-admins to export more then the configured number of contacts |
||||||
1141 | if (in_array($action,array('csv','vcard')) && $this->config['contact_export_limit'] && !Api\Storage\Merge::is_export_limit_excepted() && |
||||||
1142 | (!is_numeric($this->config['contact_export_limit']) || count($checked) > $this->config['contact_export_limit'])) |
||||||
1143 | { |
||||||
1144 | $action_msg = lang('exported'); |
||||||
1145 | $failed = count($checked); |
||||||
1146 | return false; |
||||||
1147 | } |
||||||
1148 | switch($action) |
||||||
1149 | { |
||||||
1150 | case 'vcard': |
||||||
1151 | $action_msg = lang('exported'); |
||||||
1152 | $vcard = new addressbook_vcal('addressbook','text/vcard'); |
||||||
1153 | $vcard->export($checked); |
||||||
1154 | // does not return! |
||||||
1155 | $Ok = false; |
||||||
1156 | break; |
||||||
1157 | |||||||
1158 | case 'merge': |
||||||
1159 | $error_msg = null; |
||||||
1160 | $success = $this->merge($checked,$error_msg); |
||||||
0 ignored issues
–
show
The call to
EGroupware\Api\Contacts::merge() has too many arguments starting with $error_msg .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||||
1161 | $failed = count($checked) - (int)$success; |
||||||
1162 | $action_msg = lang('merged'); |
||||||
1163 | $checked = array(); // to not start the single actions |
||||||
1164 | break; |
||||||
1165 | |||||||
1166 | case 'delete_list': |
||||||
1167 | if (!$query['filter2']) |
||||||
1168 | { |
||||||
1169 | $msg = lang('You need to select a distribution list'); |
||||||
1170 | } |
||||||
1171 | elseif($this->delete_list($query['filter2']) === false) |
||||||
0 ignored issues
–
show
|
|||||||
1172 | { |
||||||
1173 | $msg = lang('Insufficent rights to delete this list!'); |
||||||
1174 | } |
||||||
1175 | else |
||||||
1176 | { |
||||||
1177 | $msg = lang('Distribution list deleted'); |
||||||
1178 | unset($query['filter2']); |
||||||
1179 | Api\Cache::setSession('addressbook', $session_name, $query); |
||||||
1180 | } |
||||||
1181 | return false; |
||||||
1182 | |||||||
1183 | case 'document': |
||||||
1184 | if (!$document) $document = $this->prefs['default_document']; |
||||||
1185 | $document_merge = new Api\Contacts\Merge(); |
||||||
1186 | $msg = $document_merge->download($document, $checked, '', $this->prefs['document_dir']); |
||||||
1187 | $failed = count($checked); |
||||||
1188 | return false; |
||||||
1189 | |||||||
1190 | case 'infolog_add': |
||||||
1191 | Framework::popup(Egw::link('/index.php',array( |
||||||
1192 | 'menuaction' => 'infolog.infolog_ui.edit', |
||||||
1193 | 'type' => 'task', |
||||||
1194 | 'action' => 'addressbook', |
||||||
1195 | 'action_id' => implode(',',$checked), |
||||||
1196 | )),'_blank',Link::get_registry('infolog', 'add_popup')); |
||||||
1197 | $msg = ''; // no message, as we send none in javascript too and users sees opening popup |
||||||
1198 | return false; |
||||||
1199 | |||||||
1200 | case 'calendar_add': // add appointment for org-views, other views are handled directly in javascript |
||||||
1201 | Framework::popup(Egw::link('/index.php',array( |
||||||
1202 | 'menuaction' => 'calendar.calendar_uiforms.edit', |
||||||
1203 | 'participants' => 'c'.implode(',c',$checked), |
||||||
1204 | )),'_blank',Link::get_registry('calendar', 'add_popup')); |
||||||
1205 | $msg = ''; // no message, as we send none in javascript too and users sees opening popup |
||||||
1206 | return false; |
||||||
1207 | |||||||
1208 | case 'calendar_view': // show calendar for org-views, although all views are handled directly in javascript |
||||||
1209 | Egw::redirect_link('/index.php',array( |
||||||
1210 | 'menuaction' => 'calendar.calendar_uiviews.index', |
||||||
1211 | 'owner' => 'c'.implode(',c',$checked), |
||||||
1212 | )); |
||||||
1213 | } |
||||||
1214 | foreach($checked as $id) |
||||||
1215 | { |
||||||
1216 | switch($action) |
||||||
1217 | { |
||||||
1218 | case 'cat_add': |
||||||
1219 | case 'cat_del': |
||||||
1220 | if (($Ok = !!($contact = $this->read($id)) && $this->check_perms(Acl::EDIT,$contact))) |
||||||
1221 | { |
||||||
1222 | $action_msg = $action == 'cat_add' ? lang('categorie added') : lang('categorie delete'); |
||||||
1223 | $cat_ids = $contact['cat_id'] ? explode(',', $contact['cat_id']) : array(); //existing Api\Categories |
||||||
1224 | if ($action == 'cat_add') |
||||||
1225 | { |
||||||
1226 | $cat_ids[] = $cat_id; |
||||||
1227 | $cat_ids = array_unique($cat_ids); |
||||||
1228 | } |
||||||
1229 | elseif ((($key = array_search($cat_id,$cat_ids))) !== false) |
||||||
1230 | { |
||||||
1231 | unset($cat_ids[$key]); |
||||||
1232 | } |
||||||
1233 | $ids = $cat_ids ? implode(',',$cat_ids) : null; |
||||||
1234 | if ($ids !== $contact['cat_id']) |
||||||
1235 | { |
||||||
1236 | $contact['cat_id'] = $ids; |
||||||
1237 | $Ok = $this->save($contact); |
||||||
1238 | } |
||||||
1239 | } |
||||||
1240 | break; |
||||||
1241 | |||||||
1242 | case 'delete': |
||||||
1243 | $action_msg = lang('deleted'); |
||||||
1244 | if (($Ok = !!($contact = $this->read($id)) && $this->check_perms(Acl::DELETE,$contact))) |
||||||
1245 | { |
||||||
1246 | if ($contact['owner'] || // regular contact or |
||||||
1247 | empty($contact['account_id']) || // accounts without account_id |
||||||
1248 | // already deleted account (should no longer happen, but needed to allow for cleanup) |
||||||
1249 | $contact['tid'] == self::DELETED_TYPE) |
||||||
1250 | { |
||||||
1251 | $Ok = $this->delete($id, $contact['tid'] != self::DELETED_TYPE && $contact['account_id']); |
||||||
1252 | } |
||||||
1253 | // delete single account --> redirect to admin |
||||||
1254 | elseif (count($checked) == 1 && $contact['account_id']) |
||||||
1255 | { |
||||||
1256 | Egw::redirect_link('/index.php',array( |
||||||
1257 | 'menuaction' => 'admin.admin_account.delete', |
||||||
1258 | 'account_id' => $contact['account_id'], |
||||||
1259 | )); |
||||||
1260 | // this does NOT return! |
||||||
1261 | } |
||||||
1262 | else // no mass delete of Api\Accounts |
||||||
1263 | { |
||||||
1264 | $Ok = false; |
||||||
1265 | } |
||||||
1266 | } |
||||||
1267 | break; |
||||||
1268 | |||||||
1269 | case 'undelete': |
||||||
1270 | $action_msg = lang('recovered'); |
||||||
1271 | if (($contact = $this->read($id))) |
||||||
1272 | { |
||||||
1273 | $contact['tid'] = 'n'; |
||||||
1274 | $Ok = $this->save($contact); |
||||||
1275 | } |
||||||
1276 | break; |
||||||
1277 | |||||||
1278 | case 'email': |
||||||
1279 | case 'email_home': |
||||||
1280 | /* this cant work anymore, as Framework::set_onload does not longer exist |
||||||
1281 | $action_fallback = $action == 'email' ? 'email_home' : 'email'; |
||||||
1282 | $action_msg = lang('added'); |
||||||
1283 | if(($contact = $this->read($id))) |
||||||
1284 | { |
||||||
1285 | if(strpos($contact[$action],'@') !== false) |
||||||
1286 | { |
||||||
1287 | $email = $contact[$action]; |
||||||
1288 | } |
||||||
1289 | elseif(strpos($contact[$action_fallback],'@') !== false) |
||||||
1290 | { |
||||||
1291 | $email = $contact[$action_fallback]; |
||||||
1292 | } |
||||||
1293 | else |
||||||
1294 | { |
||||||
1295 | $Ok = $email = false; |
||||||
1296 | } |
||||||
1297 | if($email) |
||||||
1298 | { |
||||||
1299 | $contact['n_fn'] = str_replace(array(',','@'),' ',$contact['n_fn']); |
||||||
1300 | Framework::set_onload("addEmail('".addslashes( |
||||||
1301 | $contact['n_fn'] ? $contact['n_fn'].' <'.trim($email).'>' : trim($email))."');"); |
||||||
1302 | //error_log(__METHOD__.__LINE__."addEmail('".addslashes( |
||||||
1303 | // $contact['n_fn'] ? $contact['n_fn'].' <'.trim($email).'>' : trim($email))."');"); |
||||||
1304 | $Ok = true; |
||||||
1305 | } |
||||||
1306 | }*/ |
||||||
1307 | break; |
||||||
1308 | |||||||
1309 | case 'remove_from_list': |
||||||
1310 | $action_msg = lang('removed from distribution list'); |
||||||
1311 | if (!$query['filter2']) |
||||||
1312 | { |
||||||
1313 | $msg = lang('You need to select a distribution list'); |
||||||
1314 | return false; |
||||||
1315 | } |
||||||
1316 | else |
||||||
1317 | { |
||||||
1318 | $Ok = $this->remove_from_list($id,$query['filter2']) !== false; |
||||||
1319 | } |
||||||
1320 | break; |
||||||
1321 | |||||||
1322 | case 'to_list': |
||||||
1323 | $action_msg = lang('added to distribution list'); |
||||||
1324 | if (!$to_list) |
||||||
1325 | { |
||||||
1326 | $msg = lang('You need to select a distribution list'); |
||||||
1327 | return false; |
||||||
1328 | } |
||||||
1329 | else |
||||||
1330 | { |
||||||
1331 | $Ok = $this->add2list($id,$to_list) !== false; |
||||||
1332 | } |
||||||
1333 | break; |
||||||
1334 | |||||||
1335 | default: // move to an other addressbook |
||||||
1336 | if (!(int)$action || !($this->grants[(string) (int) $action] & Acl::EDIT)) // might be ADD in the future |
||||||
1337 | { |
||||||
1338 | return false; |
||||||
1339 | } |
||||||
1340 | if (!$checkboxes['move_to_copy']) |
||||||
1341 | { |
||||||
1342 | $action_msg = lang('moved'); |
||||||
1343 | if (($Ok = !!($contact = $this->read($id)) && $this->check_perms(Acl::DELETE,$contact))) |
||||||
1344 | { |
||||||
1345 | if (!$contact['owner']) // no (mass-)move of Api\Accounts |
||||||
1346 | { |
||||||
1347 | $Ok = false; |
||||||
1348 | } |
||||||
1349 | elseif ($contact['owner'] != (int)$action || $contact['private'] != (int)(substr($action,-1) == 'p')) |
||||||
1350 | { |
||||||
1351 | $contact['owner'] = (int) $action; |
||||||
1352 | $contact['private'] = (int)(substr($action,-1) == 'p'); |
||||||
1353 | $Ok = $this->save($contact); |
||||||
1354 | } |
||||||
1355 | } |
||||||
1356 | } |
||||||
1357 | else |
||||||
1358 | { |
||||||
1359 | $action_msg = lang('copied'); |
||||||
1360 | if (($Ok = !!($contact = $this->read($id)) && $this->check_perms(Acl::READ,$contact))) |
||||||
1361 | { |
||||||
1362 | if ($contact['owner'] != (int)$action || $contact['private'] != (int)(substr($action,-1) == 'p')) |
||||||
1363 | { |
||||||
1364 | $this->copy_contact($contact, false); // do NOT use self::$copy_fields, copy everything but uid etc. |
||||||
1365 | $links = $contact['link_to']['to_id']; |
||||||
1366 | $contact['owner'] = (int) $action; |
||||||
1367 | $contact['private'] = (int)(substr($action,-1) == 'p'); |
||||||
1368 | $Ok = $this->save($contact); |
||||||
1369 | if ($Ok && is_array($links)) |
||||||
1370 | { |
||||||
1371 | Link::link('addressbook', $contact['id'], $links); |
||||||
1372 | } |
||||||
1373 | } |
||||||
1374 | } |
||||||
1375 | } |
||||||
1376 | break; |
||||||
1377 | } |
||||||
1378 | if ($Ok) |
||||||
1379 | { |
||||||
1380 | ++$success; |
||||||
1381 | } |
||||||
1382 | elseif ($action != 'email' && $action != 'email_home') |
||||||
1383 | { |
||||||
1384 | ++$failed; |
||||||
1385 | } |
||||||
1386 | } |
||||||
1387 | return !$failed; |
||||||
1388 | } |
||||||
1389 | |||||||
1390 | /** |
||||||
1391 | * Find the individual contact IDs for a list of grouped contacts |
||||||
1392 | * |
||||||
1393 | * Successful lookups are removed from the checked array. |
||||||
1394 | * |
||||||
1395 | * Used for action on organisation and duplicate views |
||||||
1396 | * @param string/int $action 'delete', 'vcard', 'csv' or nummerical account_id to move contacts to that addessbook |
||||||
0 ignored issues
–
show
|
|||||||
1397 | * @param array $checked contact id's to use if !$use_all |
||||||
1398 | * @param boolean $use_all if true use all contacts of the current selection in the session (NOT used!) |
||||||
1399 | * @param int &$success number of succeded actions |
||||||
1400 | * @param int &$failed number of failed actions (not enought permissions) |
||||||
1401 | * @param string &$action_msg translated verb for the actions, to be used in a message like %1 contacts 'deleted' |
||||||
1402 | * @param string/array $session_name 'index' or 'email', or array with session-data depending if we are in the main list or the popup |
||||||
1403 | * |
||||||
1404 | * @return array List of contact IDs in the provided groups |
||||||
1405 | */ |
||||||
1406 | protected function find_grouped_ids($action,&$checked,$use_all,&$success,&$failed,&$action_msg,$session_name,&$msg) |
||||||
1407 | { |
||||||
1408 | unset($use_all); |
||||||
1409 | $grouped_contacts = array(); |
||||||
1410 | foreach((array)$checked as $n => $id) |
||||||
1411 | { |
||||||
1412 | if (substr($id,0,9) == 'org_name:' || substr($id, 0,10) == 'duplicate:') |
||||||
1413 | { |
||||||
1414 | if (count($checked) == 1 && !count($grouped_contacts) && $action == 'infolog') |
||||||
1415 | { |
||||||
1416 | return $this->infolog_org_view($id); // uses the org-name, instead of 'selected contacts' |
||||||
0 ignored issues
–
show
Are you sure the usage of
$this->infolog_org_view($id) targeting addressbook_ui::infolog_org_view() seems to always return null.
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. ![]() |
|||||||
1417 | } |
||||||
1418 | unset($checked[$n]); |
||||||
1419 | $query = Api\Cache::getSession('addressbook', $session_name); |
||||||
1420 | $query['num_rows'] = -1; // all |
||||||
1421 | $query['grouped_view'] = $id; |
||||||
1422 | unset($query['filter2']); |
||||||
1423 | $extra = $readonlys = null; |
||||||
1424 | $this->get_rows($query,$extra,$readonlys,true); // true = only return the id's |
||||||
1425 | |||||||
1426 | // Merge them here, so we only merge the ones that are duplicates, |
||||||
1427 | // not merge all selected together |
||||||
1428 | if($action == 'merge_duplicates') |
||||||
1429 | { |
||||||
1430 | $loop_success = $loop_fail = 0; |
||||||
1431 | $this->action('merge', $extra, false, $loop_success, $loop_fail, $action_msg,$session_name,$msg); |
||||||
1432 | $success += $loop_success; |
||||||
1433 | $failed += $loop_fail; |
||||||
1434 | } |
||||||
1435 | if ($extra[0]) |
||||||
1436 | { |
||||||
1437 | $grouped_contacts = array_merge($grouped_contacts,$extra); |
||||||
1438 | } |
||||||
1439 | } |
||||||
1440 | } |
||||||
1441 | return $grouped_contacts; |
||||||
1442 | } |
||||||
1443 | |||||||
1444 | /** |
||||||
1445 | * Copy a given contact (not storing it!) |
||||||
1446 | * |
||||||
1447 | * Taken care only configured fields get copied and certain fields never to copy (uid etc.). |
||||||
1448 | * |
||||||
1449 | * @param array& $content |
||||||
1450 | * @param boolean $only_copy_fields =true true: only copy fields configured for copying (eg. no name), |
||||||
1451 | * false: copy everything, but never to copy fields |
||||||
1452 | */ |
||||||
1453 | function copy_contact(array &$content, $only_copy_fields=true) |
||||||
1454 | { |
||||||
1455 | $content['link_to']['to_id'] = 0; |
||||||
1456 | Link::link('addressbook',$content['link_to']['to_id'],'addressbook',$content['id'], |
||||||
1457 | lang('Copied by %1, from record #%2.',Api\Accounts::format_username('', |
||||||
0 ignored issues
–
show
The call to
lang() has too many arguments starting with EGroupware\Api\Accounts:...']['account_lastname']) .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||||
1458 | $GLOBALS['egw_info']['user']['account_firstname'],$GLOBALS['egw_info']['user']['account_lastname']), |
||||||
1459 | $content['id'])); |
||||||
1460 | // create a new contact with the content of the old |
||||||
1461 | foreach(array_keys($content) as $key) |
||||||
1462 | { |
||||||
1463 | if($only_copy_fields && !in_array($key, self::$copy_fields) || in_array($key, array('id','etag','carddav_name','uid'))) |
||||||
0 ignored issues
–
show
|
|||||||
1464 | { |
||||||
1465 | unset($content[$key]); |
||||||
1466 | } |
||||||
1467 | } |
||||||
1468 | if(!isset($content['owner'])) |
||||||
1469 | { |
||||||
1470 | $content['owner'] = $this->default_private ? $this->user.'p' : $this->default_addressbook; |
||||||
1471 | } |
||||||
1472 | $content['creator'] = $this->user; |
||||||
1473 | $content['created'] = $this->now_su; |
||||||
1474 | } |
||||||
1475 | |||||||
1476 | /** |
||||||
1477 | * rows callback for index nextmatch |
||||||
1478 | * |
||||||
1479 | * @internal |
||||||
1480 | * @param array &$query |
||||||
1481 | * @param array &$rows returned rows/cups |
||||||
1482 | * @param array &$readonlys eg. to disable buttons based on Acl |
||||||
1483 | * @param boolean $id_only =false if true only return (via $rows) an array of contact-ids, dont save state to session |
||||||
1484 | * @return int total number of contacts matching the selection |
||||||
1485 | */ |
||||||
1486 | function get_rows(&$query,&$rows,&$readonlys,$id_only=false) |
||||||
1487 | { |
||||||
1488 | $what = $query['sitemgr_display'] ? $query['sitemgr_display'] : 'index'; |
||||||
1489 | |||||||
1490 | if (!$id_only && !$query['csv_export']) // do NOT store state for csv_export or querying id's (no regular view) |
||||||
1491 | { |
||||||
1492 | $store_query = $query; |
||||||
1493 | // Do not store these |
||||||
1494 | foreach(array('options-cat_id','actions','action_links','placeholder_actions') as $key) |
||||||
1495 | { |
||||||
1496 | unset($store_query[$key]); |
||||||
1497 | } |
||||||
1498 | $old_state = $store_query; |
||||||
1499 | Api\Cache::setSession('addressbook', $what, $store_query); |
||||||
1500 | } |
||||||
1501 | else |
||||||
1502 | { |
||||||
1503 | $old_state = Api\Cache::getSession('addressbook', $what); |
||||||
1504 | } |
||||||
1505 | $GLOBALS['egw']->session->commit_session(); |
||||||
1506 | if (!isset($this->grouped_views[(string) $query['grouped_view']]) || strpos($query['grouped_view'],':') === false) |
||||||
1507 | { |
||||||
1508 | // we don't have a grouped view, unset the according col_filters |
||||||
1509 | $this->unset_grouped_filters($query); |
||||||
1510 | } |
||||||
1511 | |||||||
1512 | if (isset($this->grouped_views[(string) $query['grouped_view']])) |
||||||
1513 | { |
||||||
1514 | // we have a grouped view, reset the advanced search |
||||||
1515 | if(!$query['search'] && $old_state['advanced_search']) $query['advanced_search'] = $old_state['advanced_search']; |
||||||
1516 | } |
||||||
1517 | elseif(!$query['search'] && array_key_exists('advanced_search',$old_state)) // eg. paging in an advanced search |
||||||
1518 | { |
||||||
1519 | $query['advanced_search'] = $old_state['advanced_search']; |
||||||
1520 | } |
||||||
1521 | |||||||
1522 | // Make sure old lettersearch filter doesn't stay - current letter filter will be added later |
||||||
1523 | foreach($query['col_filter'] as $key => $col_filter) |
||||||
1524 | { |
||||||
1525 | if(!is_numeric($key)) continue; |
||||||
1526 | if(preg_match('/'.$GLOBALS['egw']->db->capabilities['case_insensitive_like']. |
||||||
1527 | ' '.$GLOBALS['egw']->db->quote('[a-z]%').'$/i',$col_filter) == 1 |
||||||
1528 | ) |
||||||
1529 | { |
||||||
1530 | unset($query['col_filter'][$key]); |
||||||
1531 | } |
||||||
1532 | } |
||||||
1533 | |||||||
1534 | //echo "<p>uicontacts::get_rows(".print_r($query,true).")</p>\n"; |
||||||
1535 | if (!$id_only) |
||||||
1536 | { |
||||||
1537 | // check if accounts are stored in ldap, which does NOT yet support the org-views |
||||||
1538 | if ($this->so_accounts && $query['filter'] === '0' && $query['grouped_view']) |
||||||
1539 | { |
||||||
1540 | if ($old_state['filter'] === '0') // user changed to org_view |
||||||
1541 | { |
||||||
1542 | $query['filter'] = ''; // --> change filter to all contacts |
||||||
1543 | } |
||||||
1544 | else // user changed to accounts |
||||||
1545 | { |
||||||
1546 | $query['grouped_view'] = ''; // --> change to regular contacts view |
||||||
1547 | } |
||||||
1548 | } |
||||||
1549 | if ($query['grouped_view'] && isset($this->grouped_views[$old_state['grouped_view']]) && !isset($this->grouped_views[$query['grouped_view']])) |
||||||
1550 | { |
||||||
1551 | $query['searchletter'] = ''; // reset lettersearch if viewing the contacts of one group (org or duplicates) |
||||||
1552 | } |
||||||
1553 | // save the state of the index in the user prefs |
||||||
1554 | $state = serialize(array( |
||||||
1555 | 'filter' => $query['filter'], |
||||||
1556 | 'cat_id' => $query['cat_id'], |
||||||
1557 | 'order' => $query['order'], |
||||||
1558 | 'sort' => $query['sort'], |
||||||
1559 | 'col_filter' => array('tid' => $query['col_filter']['tid']), |
||||||
1560 | 'grouped_view' => $query['grouped_view'], |
||||||
1561 | )); |
||||||
1562 | if ($state != $this->prefs[$what.'_state'] && !$query['csv_export']) |
||||||
1563 | { |
||||||
1564 | $GLOBALS['egw']->preferences->add('addressbook',$what.'_state',$state); |
||||||
1565 | // save prefs, but do NOT invalid the cache (unnecessary) |
||||||
1566 | $GLOBALS['egw']->preferences->save_repository(false,'user',false); |
||||||
1567 | } |
||||||
1568 | } |
||||||
1569 | unset($old_state); |
||||||
1570 | |||||||
1571 | if ((string)$query['cat_id'] != '') |
||||||
1572 | { |
||||||
1573 | $query['col_filter']['cat_id'] = $query['cat_id'] ? $query['cat_id'] : null; |
||||||
1574 | } |
||||||
1575 | else |
||||||
1576 | { |
||||||
1577 | unset($query['col_filter']['cat_id']); |
||||||
1578 | } |
||||||
1579 | if ($query['filter'] !== '') // not all addressbooks |
||||||
1580 | { |
||||||
1581 | $query['col_filter']['owner'] = (string) (int) $query['filter']; |
||||||
1582 | |||||||
1583 | if ($this->private_addressbook) |
||||||
1584 | { |
||||||
1585 | $query['col_filter']['private'] = substr($query['filter'],-1) == 'p' ? 1 : 0; |
||||||
1586 | } |
||||||
1587 | } |
||||||
1588 | else |
||||||
1589 | { |
||||||
1590 | unset($query['col_filter']['owner']); |
||||||
1591 | unset($query['col_filter']['private']); |
||||||
1592 | } |
||||||
1593 | if ((int)$query['filter2']) // not no distribution list |
||||||
1594 | { |
||||||
1595 | $query['col_filter']['list'] = (string) (int) $query['filter2']; |
||||||
1596 | } |
||||||
1597 | else |
||||||
1598 | { |
||||||
1599 | unset($query['col_filter']['list']); |
||||||
1600 | } |
||||||
1601 | if ($GLOBALS['egw_info']['user']['preferences']['addressbook']['hide_accounts'] === '1') |
||||||
1602 | { |
||||||
1603 | $query['col_filter']['account_id'] = null; |
||||||
1604 | } |
||||||
1605 | else |
||||||
1606 | { |
||||||
1607 | unset($query['col_filter']['account_id']); |
||||||
1608 | } |
||||||
1609 | |||||||
1610 | // all backends allow now at least to use groups as distribution lists |
||||||
1611 | $query['no_filter2'] = false; |
||||||
1612 | |||||||
1613 | // Grouped view |
||||||
1614 | if (isset($this->grouped_views[(string) $query['grouped_view']]) && !$query['col_filter']['parent_id']) |
||||||
1615 | { |
||||||
1616 | $query['grouped_view_label'] = ''; |
||||||
1617 | $rows = $this->get_grouped_rows($query); |
||||||
1618 | } |
||||||
1619 | else // contacts view |
||||||
1620 | { |
||||||
1621 | if ($query['sitemgr_display']) |
||||||
1622 | { |
||||||
1623 | $query['template'] = $query['sitemgr_display'].'.rows'; |
||||||
1624 | } |
||||||
1625 | else |
||||||
1626 | { |
||||||
1627 | $query['template'] = 'addressbook.index.rows'; |
||||||
1628 | } |
||||||
1629 | if($query['col_filter']['parent_id']) |
||||||
1630 | { |
||||||
1631 | $query['grouped_view'] = $query['col_filter']['parent_id']; |
||||||
1632 | $query['template'] = strpos($query['grouped_view'], 'duplicate') === 0 ? |
||||||
1633 | 'addressbook.index.duplicate_rows' : 'addressbook.index.org_rows'; |
||||||
1634 | } |
||||||
1635 | // Query doesn't like parent_id |
||||||
1636 | unset($query['col_filter']['parent_id']); |
||||||
1637 | if ($query['grouped_view']) // view the contacts of one organisation only |
||||||
1638 | { |
||||||
1639 | if (strpos($query['grouped_view'],'*AND*') !== false) $query['grouped_view'] = str_replace('*AND*','&',$query['grouped_view']); |
||||||
1640 | $fields = explode(',',$GLOBALS['egw_info']['user']['preferences']['addressbook']['duplicate_fields']); |
||||||
1641 | foreach(explode('|||',$query['grouped_view']) as $part) |
||||||
1642 | { |
||||||
1643 | list($name,$value) = explode(':',$part,2); |
||||||
1644 | // do NOT set invalid column, as this gives an SQL error ("AND AND" in sql) |
||||||
1645 | if (static::$duplicate_fields[$name] && $value && ( |
||||||
1646 | strpos($query['grouped_view'], 'duplicate:') === 0 && in_array($name, $fields) || |
||||||
1647 | strpos($query['grouped_view'], 'duplicate:') !== 0 |
||||||
1648 | )) |
||||||
1649 | { |
||||||
1650 | $query['col_filter'][$name] = $value; |
||||||
1651 | } |
||||||
1652 | } |
||||||
1653 | } |
||||||
1654 | else if($query['actions'] && !$query['actions']['edit']) |
||||||
1655 | { |
||||||
1656 | // Just switched from grouped view, update actions |
||||||
1657 | $query['actions'] = $this->get_actions($query['col_filter']['tid']); |
||||||
1658 | } |
||||||
1659 | // translate the select order to the really used over all 3 columns |
||||||
1660 | $sort = $query['sort']; |
||||||
1661 | switch($query['order']) // "xxx<>'' DESC" sorts contacts with empty order-criteria always at the end |
||||||
1662 | { // we don't exclude them, as the total would otherwise depend on the order-criteria |
||||||
1663 | case 'org_name': |
||||||
1664 | $order = "egw_addressbook.org_name<>''DESC,egw_addressbook.org_name $sort,n_family $sort,n_given $sort"; |
||||||
1665 | break; |
||||||
1666 | default: |
||||||
1667 | if ($query['order'][0] == '#') // we order by a custom field |
||||||
1668 | { |
||||||
1669 | $order = "{$query['order']} $sort,org_name $sort,n_family $sort,n_given $sort"; |
||||||
1670 | break; |
||||||
1671 | } |
||||||
1672 | $query['order'] = 'n_family'; |
||||||
1673 | case 'n_family': |
||||||
1674 | $order = "n_family<>'' DESC,n_family $sort,n_given $sort,org_name $sort"; |
||||||
1675 | break; |
||||||
1676 | case 'n_given': |
||||||
1677 | $order = "n_given<>'' DESC,n_given $sort,n_family $sort,org_name $sort"; |
||||||
1678 | break; |
||||||
1679 | case 'n_fileas': |
||||||
1680 | $order = "n_fileas<>'' DESC,n_fileas $sort"; |
||||||
1681 | break; |
||||||
1682 | case 'adr_one_postalcode': |
||||||
1683 | case 'adr_two_postalcode': |
||||||
1684 | $order = $query['order']."<>'' DESC,".$query['order']." $sort,org_name $sort,n_family $sort,n_given $sort"; |
||||||
1685 | break; |
||||||
1686 | case 'contact_modified': |
||||||
1687 | case 'contact_created': |
||||||
1688 | $order = "$query[order] IS NULL,$query[order] $sort,org_name $sort,n_family $sort,n_given $sort"; |
||||||
1689 | break; |
||||||
1690 | case 'contact_id': |
||||||
1691 | $order = "egw_addressbook.$query[order] $sort"; |
||||||
1692 | } |
||||||
1693 | if ($query['searchletter']) // only show contacts if the order-criteria starts with the given letter |
||||||
1694 | { |
||||||
1695 | $no_letter_search = array('adr_one_postalcode', 'adr_two_postalcode', 'contact_id', 'contact_created','contact_modified'); |
||||||
1696 | $query['col_filter'][] = (in_array($query['order'],$no_letter_search) ? 'org_name' : (substr($query['order'],0,1)=='#'?'':'egw_addressbook.').$query['order']).' '. |
||||||
1697 | $GLOBALS['egw']->db->capabilities['case_insensitive_like'].' '.$GLOBALS['egw']->db->quote($query['searchletter'].'%'); |
||||||
1698 | } |
||||||
1699 | $wildcard = '%'; |
||||||
1700 | $op = 'OR'; |
||||||
1701 | if ($query['advanced_search']) |
||||||
1702 | { |
||||||
1703 | // Make sure op & wildcard are only valid options |
||||||
1704 | $op = $query['advanced_search']['operator'] == $op ? $op : 'AND'; |
||||||
1705 | unset($query['advanced_search']['operator']); |
||||||
1706 | $wildcard = $query['advanced_search']['meth_select'] == $wildcard ? $wildcard : ''; |
||||||
1707 | unset($query['advanced_search']['meth_select']); |
||||||
1708 | } |
||||||
1709 | |||||||
1710 | $rows = parent::search($query['advanced_search'] ? $query['advanced_search'] : $query['search'],$id_only, |
||||||
1711 | $order,'',$wildcard,false,$op,array((int)$query['start'],(int) $query['num_rows']),$query['col_filter']); |
||||||
1712 | |||||||
1713 | // do we need to read the custom fields, depends on the column is enabled and customfields |
||||||
1714 | $columsel = $this->prefs['nextmatch-addressbook.index.rows']; |
||||||
1715 | $available_distib_lists=$this->get_lists(Acl::READ); |
||||||
1716 | $columselection = $columsel ? explode(',',$columsel) : array(); |
||||||
1717 | $ids = $calendar_participants = array(); |
||||||
1718 | if (!$id_only && $rows) |
||||||
0 ignored issues
–
show
The expression
$rows of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||||
1719 | { |
||||||
1720 | $show_custom_fields = (in_array('customfields',$columselection) || $this->config['index_load_cfs']) && $this->customfields; |
||||||
0 ignored issues
–
show
The expression
$this->customfields of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||||
1721 | $show_calendar = $this->config['disable_event_column'] != 'True' && in_array('calendar_calendar',$columselection); |
||||||
1722 | $show_distributionlist = in_array('distrib_lists',$columselection) || count($available_distib_lists); |
||||||
1723 | if ($show_calendar || $show_custom_fields || $show_distributionlist) |
||||||
1724 | { |
||||||
1725 | foreach($rows as $val) |
||||||
1726 | { |
||||||
1727 | $ids[] = $val['id']; |
||||||
1728 | $calendar_participants[$val['id']] = $val['account_id'] ? $val['account_id'] : 'c'.$val['id']; |
||||||
1729 | } |
||||||
1730 | if ($show_custom_fields) |
||||||
1731 | { |
||||||
1732 | $selected_cfs = array(); |
||||||
1733 | if(in_array('customfields',$columselection)) |
||||||
1734 | { |
||||||
1735 | foreach($columselection as $col) |
||||||
1736 | { |
||||||
1737 | if ($col[0] == '#') $selected_cfs[] = substr($col,1); |
||||||
1738 | } |
||||||
1739 | } |
||||||
1740 | $selected_cfs = array_unique(array_merge($selected_cfs, (array)$this->config['index_load_cfs'])); |
||||||
1741 | $customfields = $this->read_customfields($ids,$selected_cfs); |
||||||
1742 | } |
||||||
1743 | if ($show_calendar && !empty($ids)) $calendar = $this->read_calendar($calendar_participants); |
||||||
1744 | // distributionlist memership for the entrys |
||||||
1745 | //_debug_array($this->get_lists(Acl::EDIT)); |
||||||
1746 | if ($show_distributionlist && $available_distib_lists) |
||||||
1747 | { |
||||||
1748 | $distributionlist = $this->read_distributionlist($ids,array_keys($available_distib_lists)); |
||||||
1749 | } |
||||||
1750 | } |
||||||
1751 | } |
||||||
1752 | } |
||||||
1753 | if (!$rows) $rows = array(); |
||||||
0 ignored issues
–
show
The expression
$rows of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||||
1754 | |||||||
1755 | if ($id_only) |
||||||
1756 | { |
||||||
1757 | foreach($rows as $n => $row) |
||||||
1758 | { |
||||||
1759 | $rows[$n] = $row['id']; |
||||||
1760 | } |
||||||
1761 | return $this->total; // no need to set other fields or $readonlys |
||||||
1762 | } |
||||||
1763 | $order = $query['order']; |
||||||
1764 | |||||||
1765 | $readonlys = array(); |
||||||
1766 | foreach($rows as $n => &$row) |
||||||
1767 | { |
||||||
1768 | $given = $row['n_given'] ? $row['n_given'] : ($row['n_prefix'] ? $row['n_prefix'] : ''); |
||||||
1769 | |||||||
1770 | switch($order) |
||||||
1771 | { |
||||||
1772 | default: // postalcode, created, modified, ... |
||||||
1773 | case 'org_name': |
||||||
1774 | $row['line1'] = $row['org_name']; |
||||||
1775 | $row['line2'] = $row['n_family'].($given ? ', '.$given : ''); |
||||||
1776 | break; |
||||||
1777 | case 'n_family': |
||||||
1778 | $row['line1'] = $row['n_family'].($given ? ', '.$given : ''); |
||||||
1779 | $row['line2'] = $row['org_name']; |
||||||
1780 | break; |
||||||
1781 | case 'n_given': |
||||||
1782 | $row['line1'] = $given.' '.$row['n_family']; |
||||||
1783 | $row['line2'] = $row['org_name']; |
||||||
1784 | break; |
||||||
1785 | case 'n_fileas': |
||||||
1786 | if (!$row['n_fileas']) $row['n_fileas'] = $this->fileas($row); |
||||||
1787 | list($row['line1'],$row['line2']) = explode(': ',$row['n_fileas']); |
||||||
1788 | break; |
||||||
1789 | } |
||||||
1790 | if (isset($this->grouped_views[(string) $query['grouped_view']])) |
||||||
1791 | { |
||||||
1792 | $row['type'] = 'home'; |
||||||
1793 | $row['type_label'] = $query['grouped_view'] == 'duplicate' ? lang('Duplicates') : lang('Organisation'); |
||||||
1794 | |||||||
1795 | if ($query['filter'] && !($this->grants[(int)$query['filter']] & Acl::DELETE)) |
||||||
1796 | { |
||||||
1797 | $row['class'] .= 'rowNoDelete '; |
||||||
1798 | } |
||||||
1799 | $row['class'] .= 'rowNoEdit '; // no edit in OrgView |
||||||
1800 | $row['class'] .= $query['grouped_view'] == 'duplicates' ? 'contact_duplicate' : 'contact_organisation '; |
||||||
1801 | } |
||||||
1802 | else |
||||||
1803 | { |
||||||
1804 | $this->type_icon($row['owner'],$row['private'],$row['tid'],$row['type'],$row['type_label']); |
||||||
1805 | |||||||
1806 | static $tel2show = array('tel_work','tel_cell','tel_home','tel_fax'); |
||||||
1807 | static $prefer_marker = null; |
||||||
1808 | if (is_null($prefer_marker)) |
||||||
1809 | { |
||||||
1810 | // as et2 adds options with .text(), it can't be entities, but php knows no string literals with utf-8 |
||||||
1811 | $prefer_marker = html_entity_decode(' ☆', ENT_NOQUOTES, 'utf-8'); |
||||||
1812 | } |
||||||
1813 | foreach($tel2show as $name) |
||||||
1814 | { |
||||||
1815 | $row[$name] .= ' '.($row['tel_prefer'] == $name ? $prefer_marker : ''); // .' ' to NOT remove the field |
||||||
1816 | } |
||||||
1817 | // allways show the prefered phone, if not already shown |
||||||
1818 | if (!in_array($row['tel_prefer'],$tel2show) && $row[$row['tel_prefer']]) |
||||||
1819 | { |
||||||
1820 | $row['tel_prefered'] = $row[$row['tel_prefer']].$prefer_marker; |
||||||
1821 | } |
||||||
1822 | // Show nice name as status text |
||||||
1823 | if($row['tel_prefer']) |
||||||
1824 | { |
||||||
1825 | $row['tel_prefer_label'] = $this->contact_fields[$row['tel_prefer']]; |
||||||
1826 | } |
||||||
1827 | if (!$row['owner'] && $row['account_id'] > 0) |
||||||
1828 | { |
||||||
1829 | $row['class'] .= 'rowAccount rowNoDelete '; |
||||||
1830 | } |
||||||
1831 | elseif (!$this->check_perms(Acl::DELETE,$row) || (!$GLOBALS['egw_info']['user']['apps']['admin'] && $this->config['history'] != 'userpurge' && $query['col_filter']['tid'] == self::DELETED_TYPE)) |
||||||
1832 | { |
||||||
1833 | $row['class'] .= 'rowNoDelete '; |
||||||
1834 | } |
||||||
1835 | if (!$this->check_perms(Acl::EDIT,$row)) |
||||||
1836 | { |
||||||
1837 | $row['class'] .= 'rowNoEdit '; |
||||||
1838 | } |
||||||
1839 | $row['class'] .= 'contact_contact '; |
||||||
1840 | |||||||
1841 | unset($row['jpegphoto']); // unused and messes up json encoding (not utf-8) |
||||||
1842 | |||||||
1843 | if (isset($customfields[$row['id']])) |
||||||
1844 | { |
||||||
1845 | foreach($this->customfields as $name => $data) |
||||||
1846 | { |
||||||
1847 | $row['#'.$name] = $customfields[$row['id']]['#'.$name]; |
||||||
1848 | } |
||||||
1849 | } |
||||||
1850 | if (isset($distributionlist[$row['id']])) |
||||||
1851 | { |
||||||
1852 | $row['distrib_lists'] = implode("\n",array_values($distributionlist[$row['id']])); |
||||||
1853 | //if ($show_distributionlist) $readonlys['distrib_lists'] =true; |
||||||
1854 | } |
||||||
1855 | if (isset($calendar[$calendar_participants[$row['id']]])) |
||||||
1856 | { |
||||||
1857 | foreach($calendar[$calendar_participants[$row['id']]] as $name => $data) |
||||||
1858 | { |
||||||
1859 | $row[$name] = $data; |
||||||
1860 | } |
||||||
1861 | } |
||||||
1862 | } |
||||||
1863 | |||||||
1864 | // hide region for address format 'postcode_city' |
||||||
1865 | if (($row['addr_format'] = $this->addr_format_by_country($row['adr_one_countryname']))=='postcode_city') unset($row['adr_one_region']); |
||||||
1866 | if (($row['addr_format2'] = $this->addr_format_by_country($row['adr_two_countryname']))=='postcode_city') unset($row['adr_two_region']); |
||||||
1867 | |||||||
1868 | // respect category permissions |
||||||
1869 | if(!empty($row['cat_id'])) |
||||||
1870 | { |
||||||
1871 | $row['cat_id'] = $this->categories->check_list(Acl::READ,$row['cat_id']); |
||||||
1872 | } |
||||||
1873 | } |
||||||
1874 | $rows['no_distribution_list'] = (bool)$query['filter2']; |
||||||
1875 | |||||||
1876 | // disable customfields column, if we have no customefield(s) |
||||||
1877 | if (!$this->customfields) |
||||||
0 ignored issues
–
show
The expression
$this->customfields of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||||
1878 | { |
||||||
1879 | $rows['no_customfields'] = true; |
||||||
1880 | } |
||||||
1881 | |||||||
1882 | // Disable next/last date if so configured |
||||||
1883 | if($this->config['disable_event_column'] == 'True') |
||||||
1884 | { |
||||||
1885 | $rows['no_event_column'] = true; |
||||||
1886 | } |
||||||
1887 | |||||||
1888 | $rows['order'] = $order; |
||||||
1889 | $rows['call_popup'] = $this->config['call_popup']; |
||||||
1890 | $rows['customfields'] = array_values($this->customfields); |
||||||
1891 | |||||||
1892 | // full app-header with all search criteria specially for the print |
||||||
1893 | $header = array(); |
||||||
1894 | if ($query['filter'] !== '' && !isset($this->grouped_views[$query['grouped_view']])) |
||||||
1895 | { |
||||||
1896 | $header[] = ($query['filter'] == '0' ? lang('accounts') : |
||||||
1897 | ($GLOBALS['egw']->accounts->get_type($query['filter']) == 'g' ? |
||||||
1898 | lang('Group %1',$GLOBALS['egw']->accounts->id2name($query['filter'])) : |
||||||
0 ignored issues
–
show
The call to
lang() has too many arguments starting with $GLOBALS['egw']->account...2name($query['filter']) .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||||
1899 | Api\Accounts::username((int)$query['filter']). |
||||||
1900 | (substr($query['filter'],-1) == 'p' ? ' ('.lang('private').')' : ''))); |
||||||
1901 | } |
||||||
1902 | if ($query['grouped_view']) |
||||||
1903 | { |
||||||
1904 | $header[] = $query['grouped_view_label']; |
||||||
1905 | // Make sure option is there |
||||||
1906 | if(!array_key_exists($query['grouped_view'], $this->grouped_views)) |
||||||
1907 | { |
||||||
1908 | $this->grouped_views += $this->_get_grouped_name($query['grouped_view']); |
||||||
1909 | $rows['sel_options']['grouped_view'] = $this->grouped_views; |
||||||
1910 | } |
||||||
1911 | } |
||||||
1912 | if($query['advanced_search']) |
||||||
1913 | { |
||||||
1914 | $header[] = lang('Advanced search'); |
||||||
1915 | } |
||||||
1916 | if ($query['cat_id']) |
||||||
1917 | { |
||||||
1918 | $header[] = lang('Category').' '.$GLOBALS['egw']->categories->id2name($query['cat_id']); |
||||||
1919 | } |
||||||
1920 | if ($query['searchletter']) |
||||||
1921 | { |
||||||
1922 | $order = $order == 'n_given' ? lang('first name') : ($order == 'n_family' ? lang('last name') : lang('Organisation')); |
||||||
1923 | $header[] = lang("%1 starts with '%2'",$order,$query['searchletter']); |
||||||
1924 | } |
||||||
1925 | if ($query['search'] && !$query['advanced_search']) // do not add that, if we have advanced search active |
||||||
1926 | { |
||||||
1927 | $header[] = lang("Search for '%1'",$query['search']); |
||||||
1928 | } |
||||||
1929 | $GLOBALS['egw_info']['flags']['app_header'] = implode(': ', $header); |
||||||
1930 | |||||||
1931 | return $this->total; |
||||||
1932 | } |
||||||
1933 | |||||||
1934 | /** |
||||||
1935 | * Get addressbook type icon from owner, private and tid |
||||||
1936 | * |
||||||
1937 | * @param int $owner user- or group-id or 0 for Api\Accounts |
||||||
1938 | * @param boolean $private |
||||||
1939 | * @param string $tid 'n' for regular addressbook |
||||||
1940 | * @param string &$icon icon-name |
||||||
1941 | * @param string &$label translated label |
||||||
1942 | */ |
||||||
1943 | function type_icon($owner,$private,$tid,&$icon,&$label) |
||||||
1944 | { |
||||||
1945 | if (!$owner) |
||||||
1946 | { |
||||||
1947 | $icon = 'accounts'; |
||||||
1948 | $label = lang('accounts'); |
||||||
1949 | } |
||||||
1950 | elseif ($private) |
||||||
1951 | { |
||||||
1952 | $icon = 'private'; |
||||||
1953 | $label = lang('private'); |
||||||
1954 | } |
||||||
1955 | elseif ($GLOBALS['egw']->accounts->get_type($owner) == 'g') |
||||||
1956 | { |
||||||
1957 | $icon = 'group'; |
||||||
1958 | $label = lang('group %1',$GLOBALS['egw']->accounts->id2name($owner)); |
||||||
0 ignored issues
–
show
The call to
lang() has too many arguments starting with $GLOBALS['egw']->accounts->id2name($owner) .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||||
1959 | } |
||||||
1960 | else |
||||||
1961 | { |
||||||
1962 | $icon = 'personal'; |
||||||
1963 | $label = $owner == $this->user ? lang('personal') : Api\Accounts::username($owner); |
||||||
1964 | } |
||||||
1965 | // show tid icon for tid!='n' AND only if one is defined |
||||||
1966 | if ($tid != 'n' && Api\Image::find('addressbook',$this->content_types[$tid]['name'])) |
||||||
1967 | { |
||||||
1968 | $icon = Api\Image::find('addressbook',$this->content_types[$tid]['name']); |
||||||
1969 | } |
||||||
1970 | |||||||
1971 | // Legacy - from when icons could be anywhere |
||||||
1972 | if ($tid != 'n' && $this->content_types[$tid]['options']['icon']) |
||||||
1973 | { |
||||||
1974 | $icon = $this->content_types[$tid]['options']['icon']; |
||||||
1975 | $label = $this->content_types[$tid]['name'].' ('.$label.')'; |
||||||
1976 | } |
||||||
1977 | } |
||||||
1978 | |||||||
1979 | /** |
||||||
1980 | * Edit a contact |
||||||
1981 | * |
||||||
1982 | * @param array $content=null submitted content |
||||||
1983 | * @param int $_GET['contact_id'] contact_id mainly for popup use |
||||||
1984 | * @param bool $_GET['makecp'] true if you want to copy the contact given by $_GET['contact_id'] |
||||||
1985 | */ |
||||||
1986 | function edit($content=null) |
||||||
1987 | { |
||||||
1988 | if (is_array($content)) |
||||||
1989 | { |
||||||
1990 | $button = @key($content['button']); |
||||||
1991 | unset($content['button']); |
||||||
1992 | $content['private'] = (int) ($content['owner'] && substr($content['owner'],-1) == 'p'); |
||||||
1993 | $content['owner'] = (string) (int) $content['owner']; |
||||||
1994 | $content['cat_id'] = $this->config['cat_tab'] === 'Tree' ? $content['cat_id_tree'] : $content['cat_id']; |
||||||
1995 | if ($this->config['private_cf_tab']) $content = (array)$content['private_cfs'] + $content; |
||||||
1996 | unset($content['private_cfs']); |
||||||
1997 | |||||||
1998 | switch($button) |
||||||
1999 | { |
||||||
2000 | case 'save': |
||||||
2001 | case 'apply': |
||||||
2002 | if ($content['presets_fields']) |
||||||
2003 | { |
||||||
2004 | // unset the duplicate_filed after submit because we don't need to warn user for second time about contact duplication |
||||||
2005 | unset($content['presets_fields']); |
||||||
2006 | } |
||||||
2007 | // photo might be changed by ajax_upload_photo |
||||||
2008 | if (!array_key_exists('jpegphoto', $content)) |
||||||
2009 | { |
||||||
2010 | $content['photo_unchanged'] = true; // hint no need to store photo |
||||||
2011 | } |
||||||
2012 | $links = false; |
||||||
2013 | if (!$content['id'] && is_array($content['link_to']['to_id'])) |
||||||
2014 | { |
||||||
2015 | $links = $content['link_to']['to_id']; |
||||||
2016 | } |
||||||
2017 | $fullname = $old_fullname = parent::fullname($content); |
||||||
2018 | if ($content['id'] && $content['org_name'] && $content['change_org']) |
||||||
2019 | { |
||||||
2020 | $old_org_entry = $this->read($content['id']); |
||||||
2021 | $old_fullname = ($old_org_entry['n_fn'] ? $old_org_entry['n_fn'] : parent::fullname($old_org_entry)); |
||||||
2022 | } |
||||||
2023 | if ( $content['n_fn'] != $fullname || $fullname != $old_fullname) |
||||||
2024 | { |
||||||
2025 | unset($content['n_fn']); |
||||||
2026 | } |
||||||
2027 | // Country codes |
||||||
2028 | foreach(array('adr_one', 'adr_two') as $c_prefix) |
||||||
2029 | { |
||||||
2030 | if ($content[$c_prefix.'_countrycode'] == '-custom-') |
||||||
2031 | { |
||||||
2032 | $content[$c_prefix.'_countrycode'] = null; |
||||||
2033 | } |
||||||
2034 | } |
||||||
2035 | $content['msg'] = ''; |
||||||
2036 | $this->error = false; |
||||||
2037 | foreach((array)$content['pre_save_callbacks'] as $callback) |
||||||
2038 | { |
||||||
2039 | try { |
||||||
2040 | if (($success_msg = call_user_func_array($callback, array(&$content)))) |
||||||
2041 | { |
||||||
2042 | $content['msg'] .= ($content['msg'] ? ', ' : '').$success_msg; |
||||||
2043 | } |
||||||
2044 | } |
||||||
2045 | catch (Exception $ex) { |
||||||
2046 | $content['msg'] .= ($content['msg'] ? ', ' : '').$ex->getMessage(); |
||||||
2047 | $button = 'apply'; // do not close dialog |
||||||
2048 | $this->error = true; |
||||||
2049 | break; |
||||||
2050 | } |
||||||
2051 | } |
||||||
2052 | if ($this->error) |
||||||
2053 | { |
||||||
2054 | // error in pre_save_callbacks |
||||||
2055 | } |
||||||
2056 | elseif ($this->save($content)) |
||||||
2057 | { |
||||||
2058 | $content['msg'] .= ($content['msg'] ? ', ' : '').lang('Contact saved'); |
||||||
2059 | |||||||
2060 | unset($content['jpegphoto'], $content['photo_unchanged']); |
||||||
2061 | |||||||
2062 | foreach((array)$content['post_save_callbacks'] as $callback) |
||||||
2063 | { |
||||||
2064 | try { |
||||||
2065 | if (($success_msg = call_user_func_array($callback, array(&$content)))) |
||||||
2066 | { |
||||||
2067 | $content['msg'] .= ', '.$success_msg; |
||||||
2068 | } |
||||||
2069 | } |
||||||
2070 | catch(Api\Exception\Redirect $r) |
||||||
2071 | { |
||||||
2072 | // catch it to continue execution and rethrow it later |
||||||
2073 | } |
||||||
2074 | catch (Exception $ex) { |
||||||
2075 | $content['msg'] .= ', '.$ex->getMessage(); |
||||||
2076 | $button = 'apply'; // do not close dialog |
||||||
2077 | $this->error = true; |
||||||
2078 | break; |
||||||
2079 | } |
||||||
2080 | } |
||||||
2081 | |||||||
2082 | if ($content['change_org'] && $old_org_entry && ($changed = $this->changed_fields($old_org_entry,$content,true)) && |
||||||
2083 | ($members = $this->org_similar($old_org_entry['org_name'],$changed))) |
||||||
2084 | { |
||||||
2085 | //foreach($changed as $name => $old_value) echo "<p>$name: '$old_value' --> '{$content[$name]}'</p>\n"; |
||||||
2086 | list($changed_members,$changed_fields,$failed_members) = $this->change_org($old_org_entry['org_name'],$changed,$content,$members); |
||||||
2087 | if ($changed_members) |
||||||
2088 | { |
||||||
2089 | $content['msg'] .= ', '.lang('%1 fields in %2 other organisation member(s) changed',$changed_fields,$changed_members); |
||||||
0 ignored issues
–
show
The call to
lang() has too many arguments starting with $changed_fields .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||||
2090 | } |
||||||
2091 | if ($failed_members) |
||||||
2092 | { |
||||||
2093 | $content['msg'] .= ', '.lang('failed to change %1 organisation member(s) (insufficent rights) !!!',$failed_members); |
||||||
2094 | } |
||||||
2095 | } |
||||||
2096 | } |
||||||
2097 | elseif($this->error === true) |
||||||
0 ignored issues
–
show
|
|||||||
2098 | { |
||||||
2099 | $content['msg'] = lang('Error: the entry has been updated since you opened it for editing!').'<br />'. |
||||||
2100 | lang('Copy your changes to the clipboard, %1reload the entry%2 and merge them.','<a href="'. |
||||||
2101 | htmlspecialchars(Egw::link('/index.php',array( |
||||||
2102 | 'menuaction' => 'addressbook.addressbook_ui.edit', |
||||||
2103 | 'contact_id' => $content['id'], |
||||||
2104 | ))).'">','</a>'); |
||||||
2105 | break; // dont refresh the list |
||||||
2106 | } |
||||||
2107 | else |
||||||
2108 | { |
||||||
2109 | $content['msg'] = lang('Error saving the contact !!!'). |
||||||
2110 | ($this->error ? ' '.$this->error : ''); |
||||||
2111 | $button = 'apply'; // to not leave the dialog |
||||||
2112 | } |
||||||
2113 | // writing links for new entry, existing ones are handled by the widget itself |
||||||
2114 | if ($links && $content['id']) |
||||||
2115 | { |
||||||
2116 | Link::link('addressbook',$content['id'],$links); |
||||||
2117 | } |
||||||
2118 | // Update client side global datastore |
||||||
2119 | $response = Api\Json\Response::get(); |
||||||
2120 | $response->generic('data', array('uid' => 'addressbook::'.$content['id'], 'data' => $content)); |
||||||
2121 | Framework::refresh_opener($content['msg'], 'addressbook', $content['id'], $content['id'] ? 'edit' : 'add', |
||||||
2122 | null, null, null, $this->error ? 'error' : 'success'); |
||||||
2123 | |||||||
2124 | // re-throw redirect exception, if there's no error |
||||||
2125 | if (!$this->error && isset($r)) |
||||||
2126 | { |
||||||
2127 | throw $r; |
||||||
2128 | } |
||||||
2129 | if ($button == 'save') |
||||||
2130 | { |
||||||
2131 | Framework::window_close(); |
||||||
2132 | } |
||||||
2133 | else |
||||||
2134 | { |
||||||
2135 | Framework::message($content['msg'], $this->error ? 'error' : 'success'); |
||||||
2136 | unset($content['msg']); |
||||||
2137 | } |
||||||
2138 | $content['link_to']['to_id'] = $content['id']; |
||||||
2139 | break; |
||||||
2140 | |||||||
2141 | case 'delete': |
||||||
2142 | $success = $failed = $action_msg = null; |
||||||
2143 | if($this->action('delete',array($content['id']),false,$success,$failed,$action_msg,'',$content['msg'])) |
||||||
2144 | { |
||||||
2145 | if ($GLOBALS['egw']->currentapp == 'addressbook') |
||||||
2146 | { |
||||||
2147 | Framework::refresh_opener(lang('Contact deleted'), 'addressbook', $content['id'], 'delete' ); |
||||||
2148 | Framework::window_close(); |
||||||
2149 | } |
||||||
2150 | else |
||||||
2151 | { |
||||||
2152 | Framework::refresh_opener(lang('Contact deleted'), 'addressbook', $content['id'], null, 'addressbook'); |
||||||
2153 | Framework::window_close(); |
||||||
2154 | } |
||||||
2155 | } |
||||||
2156 | else |
||||||
2157 | { |
||||||
2158 | $content['msg'] = lang('Error deleting the contact !!!'); |
||||||
2159 | } |
||||||
2160 | break; |
||||||
2161 | } |
||||||
2162 | $view = !$this->check_perms(Acl::EDIT, $content); |
||||||
2163 | } |
||||||
2164 | else |
||||||
2165 | { |
||||||
2166 | $content = array(); |
||||||
2167 | $contact_id = $_GET['contact_id'] ? $_GET['contact_id'] : ((int)$_GET['account_id'] ? 'account:'.(int)$_GET['account_id'] : 0); |
||||||
2168 | $view = (boolean)$_GET['view']; |
||||||
2169 | // new contact --> set some defaults |
||||||
2170 | if ($contact_id && is_array($content = $this->read($contact_id))) |
||||||
2171 | { |
||||||
2172 | $contact_id = $content['id']; // it could have been: "account:$account_id" |
||||||
2173 | if (!$this->check_perms(Acl::EDIT, $content)) |
||||||
2174 | { |
||||||
2175 | $view = true; |
||||||
2176 | } |
||||||
2177 | } |
||||||
2178 | else // not found |
||||||
2179 | { |
||||||
2180 | $state = Api\Cache::getSession('addressbook', 'index'); |
||||||
2181 | // check if we create the new contact in an existing org |
||||||
2182 | if (($org = $_GET['org'])) |
||||||
2183 | { |
||||||
2184 | // arguments containing a comma get quoted by etemplate/js/nextmatch_action.js |
||||||
2185 | // leading to error in Api\Db::column_data_implode, if not unquoted |
||||||
2186 | if ($org[0] == '"') $org = substr($org, 1, -1); |
||||||
2187 | $content = $this->read_org($org); |
||||||
2188 | } |
||||||
2189 | elseif ($state['grouped_view'] && !isset($this->grouped_views[$state['grouped_view']])) |
||||||
2190 | { |
||||||
2191 | $content = $this->read_org($state['grouped_view']); |
||||||
2192 | } |
||||||
2193 | else |
||||||
2194 | { |
||||||
2195 | if ($GLOBALS['egw_info']['user']['preferences']['common']['country']) |
||||||
2196 | { |
||||||
2197 | $content['adr_one_countrycode'] = |
||||||
2198 | $GLOBALS['egw_info']['user']['preferences']['common']['country']; |
||||||
2199 | $content['adr_one_countryname'] = |
||||||
2200 | $GLOBALS['egw']->country->get_full_name($GLOBALS['egw_info']['user']['preferences']['common']['country']); |
||||||
2201 | $content['adr_two_countrycode'] = |
||||||
2202 | $GLOBALS['egw_info']['user']['preferences']['common']['country']; |
||||||
2203 | $content['adr_two_countryname'] = |
||||||
2204 | $GLOBALS['egw']->country->get_full_name($GLOBALS['egw_info']['user']['preferences']['common']['country']); |
||||||
2205 | } |
||||||
2206 | if ($this->prefs['fileas_default']) $content['fileas_type'] = $this->prefs['fileas_default']; |
||||||
2207 | } |
||||||
2208 | if (isset($_GET['owner']) && $_GET['owner'] !== '') |
||||||
2209 | { |
||||||
2210 | $content['owner'] = $_GET['owner']; |
||||||
2211 | } |
||||||
2212 | else |
||||||
2213 | { |
||||||
2214 | $content['owner'] = (string)($state['filter'] == 0 ? '' : $state['filter']); |
||||||
2215 | } |
||||||
2216 | $content['private'] = (int) ($content['owner'] && substr($content['owner'],-1) == 'p'); |
||||||
2217 | if ($content['owner'] === '' || !($this->grants[$content['owner'] = (string) (int) $content['owner']] & Acl::ADD)) |
||||||
2218 | { |
||||||
2219 | $content['owner'] = $this->default_addressbook; |
||||||
2220 | $content['private'] = (int)$this->default_private; |
||||||
2221 | |||||||
2222 | if (!($this->grants[$content['owner'] = (string) (int) $content['owner']] & Acl::ADD)) |
||||||
2223 | { |
||||||
2224 | $content['owner'] = (string) $this->user; |
||||||
2225 | $content['private'] = 0; |
||||||
2226 | } |
||||||
2227 | } |
||||||
2228 | $new_type = array_keys($this->content_types); |
||||||
2229 | // fetch active type to preset the type, if param typeid is not passed |
||||||
2230 | $active_tid = Api\Cache::getSession('addressbook','active_tid'); |
||||||
2231 | if ($active_tid && strtoupper($active_tid) === 'D') unset($active_tid); |
||||||
2232 | $content['tid'] = $_GET['typeid'] ? $_GET['typeid'] : ($active_tid?$active_tid:$new_type[0]); |
||||||
2233 | foreach($this->get_contact_columns() as $field) |
||||||
2234 | { |
||||||
2235 | if ($_GET['presets'][$field]) |
||||||
2236 | { |
||||||
2237 | if ($field=='email'||$field=='email_home') |
||||||
2238 | { |
||||||
2239 | $singleAddress = imap_rfc822_parse_adrlist($_GET['presets'][$field],''); |
||||||
2240 | //error_log(__METHOD__.__LINE__.' Address:'.$singleAddress[0]->mailbox."@".$singleAddress[0]->host.", ".$singleAddress[0]->personal); |
||||||
2241 | if (!(!is_array($singleAddress) || count($singleAddress)<1)) |
||||||
2242 | { |
||||||
2243 | $content[$field] = $singleAddress[0]->mailbox."@".$singleAddress[0]->host; |
||||||
2244 | if (!empty($singleAddress[0]->personal)) |
||||||
2245 | { |
||||||
2246 | if (strpos($singleAddress[0]->personal,',')===false) |
||||||
2247 | { |
||||||
2248 | list($P_n_given,$P_n_family,$P_org_name)=explode(' ',$singleAddress[0]->personal,3); |
||||||
2249 | if (strlen(trim($P_n_given))>0) $content['n_given'] = trim($P_n_given); |
||||||
2250 | if (strlen(trim($P_n_family))>0) $content['n_family'] = trim($P_n_family); |
||||||
2251 | if (strlen(trim($P_org_name))>0) $content['org_name'] = trim($P_org_name); |
||||||
2252 | } |
||||||
2253 | else |
||||||
2254 | { |
||||||
2255 | list($P_n_family,$P_other)=explode(',',$singleAddress[0]->personal,2); |
||||||
2256 | if (strlen(trim($P_n_family))>0) $content['n_family'] = trim($P_n_family); |
||||||
2257 | if (strlen(trim($P_other))>0) |
||||||
2258 | { |
||||||
2259 | list($P_n_given,$P_org_name)=explode(',',$P_other,2); |
||||||
2260 | if (strlen(trim($P_n_given))>0) $content['n_given'] = trim($P_n_given); |
||||||
2261 | if (strlen(trim($P_org_name))>0) $content['org_name'] = trim($P_org_name); |
||||||
2262 | } |
||||||
2263 | } |
||||||
2264 | } |
||||||
2265 | } |
||||||
2266 | else |
||||||
2267 | { |
||||||
2268 | $content[$field] = $_GET['presets'][$field]; |
||||||
2269 | } |
||||||
2270 | } |
||||||
2271 | else |
||||||
2272 | { |
||||||
2273 | $content[$field] = $_GET['presets'][$field]; |
||||||
2274 | } |
||||||
2275 | } |
||||||
2276 | } |
||||||
2277 | if (isset($_GET['presets'])) |
||||||
2278 | { |
||||||
2279 | foreach(array('email','email_home','n_family','n_given','org_name') as $field) |
||||||
2280 | { |
||||||
2281 | if (!empty($content[$field])) |
||||||
2282 | { |
||||||
2283 | //Set the presets fields in content in order to be able to use them later in client side for checking duplication only on first time load |
||||||
2284 | // after save/apply we unset them |
||||||
2285 | $content['presets_fields'][]= $field; |
||||||
2286 | break; |
||||||
2287 | } |
||||||
2288 | } |
||||||
2289 | if (empty($content['n_fn'])) $content['n_fn'] = $this->fullname($content); |
||||||
2290 | } |
||||||
2291 | $content['creator'] = $this->user; |
||||||
2292 | $content['created'] = $this->now_su; |
||||||
2293 | unset($state); |
||||||
2294 | //_debug_array($content); |
||||||
2295 | } |
||||||
2296 | |||||||
2297 | if ($_GET['msg']) $content['msg'] = strip_tags($_GET['msg']); // dont allow HTML! |
||||||
2298 | |||||||
2299 | if($content && $_GET['makecp']) // copy the contact |
||||||
2300 | { |
||||||
2301 | $this->copy_contact($content); |
||||||
2302 | $content['msg'] = lang('%1 copied - the copy can now be edited', lang(Link::get_registry('addressbook','entry'))); |
||||||
2303 | $view = false; |
||||||
2304 | } |
||||||
2305 | else |
||||||
2306 | { |
||||||
2307 | if ($contact_id && is_numeric($contact_id)) $content['link_to']['to_id'] = $contact_id; |
||||||
2308 | } |
||||||
2309 | // automatic link new entries to entries specified in the url |
||||||
2310 | if (!$contact_id && isset($_REQUEST['link_app']) && isset($_REQUEST['link_id']) && !is_array($content['link_to']['to_id'])) |
||||||
2311 | { |
||||||
2312 | $link_ids = is_array($_REQUEST['link_id']) ? $_REQUEST['link_id'] : array($_REQUEST['link_id']); |
||||||
2313 | foreach(is_array($_REQUEST['link_app']) ? $_REQUEST['link_app'] : array($_REQUEST['link_app']) as $n => $link_app) |
||||||
2314 | { |
||||||
2315 | $link_id = $link_ids[$n]; |
||||||
2316 | if (preg_match('/^[a-z_0-9-]+:[:a-z_0-9-]+$/i',$link_app.':'.$link_id)) // gard against XSS |
||||||
2317 | { |
||||||
2318 | Link::link('addressbook',$content['link_to']['to_id'],$link_app,$link_id); |
||||||
2319 | } |
||||||
2320 | } |
||||||
2321 | } |
||||||
2322 | } |
||||||
2323 | if ($content['id']) |
||||||
2324 | { |
||||||
2325 | // last and next calendar date |
||||||
2326 | $dates = current($this->read_calendar(array($content['account_id'] ? $content['account_id'] : 'c'.$content['id']),false)); |
||||||
2327 | if(is_array($dates)) $content += $dates; |
||||||
2328 | } |
||||||
2329 | |||||||
2330 | // Registry has view_id as contact_id, so set it (custom fields uses it) |
||||||
2331 | $content['contact_id'] = $content['id']; |
||||||
2332 | |||||||
2333 | // Avoid ID conflict with tree & selectboxes |
||||||
2334 | $content['cat_id_tree'] = $content['cat_id']; |
||||||
2335 | |||||||
2336 | // Avoid setting conflicts with private custom fields |
||||||
2337 | $content['private_cfs'] = array(); |
||||||
2338 | foreach(Api\Storage\Customfields::get('addressbook', true) as $name => $cf) |
||||||
2339 | { |
||||||
2340 | if ($this->config['private_cf_tab'] && $cf['private'] && isset($content['#'.$name])) |
||||||
2341 | { |
||||||
2342 | $content['private_cfs']['#'.$name] = $content['#'.$name]; |
||||||
2343 | } |
||||||
2344 | } |
||||||
2345 | |||||||
2346 | // how to display addresses |
||||||
2347 | $content['addr_format'] = $this->addr_format_by_country($content['adr_one_countryname']); |
||||||
2348 | $content['addr_format2'] = $this->addr_format_by_country($content['adr_two_countryname']); |
||||||
2349 | |||||||
2350 | //_debug_array($content); |
||||||
2351 | $readonlys['button[delete]'] = !$content['owner'] || !$this->check_perms(Acl::DELETE,$content); |
||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||
2352 | $readonlys['button[copy]'] = $readonlys['button[edit]'] = $readonlys['button[vcard]'] = true; |
||||||
2353 | $readonlys['button[save]'] = $readonlys['button[apply]'] = $view; |
||||||
2354 | if ($view) |
||||||
2355 | { |
||||||
2356 | $readonlys['__ALL__'] = true; |
||||||
2357 | $readonlys['button[cancel]'] = false; |
||||||
2358 | } |
||||||
2359 | |||||||
2360 | $sel_options['fileas_type'] = $this->fileas_options($content); |
||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||
2361 | $sel_options['adr_one_countrycode']['-custom-'] = lang('Custom'); |
||||||
2362 | $sel_options['owner'] = $this->get_addressbooks(Acl::ADD); |
||||||
2363 | if ($content['owner']) unset($sel_options['owner'][0]); // do not offer to switch to accounts, as we do not support moving contacts to accounts |
||||||
2364 | if ((string) $content['owner'] !== '') |
||||||
2365 | { |
||||||
2366 | if (!isset($sel_options['owner'][(int)$content['owner']])) |
||||||
2367 | { |
||||||
2368 | $sel_options['owner'][(int)$content['owner']] = !$content['owner'] ? lang('Accounts') : |
||||||
2369 | Api\Accounts::username($content['owner']); |
||||||
2370 | } |
||||||
2371 | $readonlys['owner'] = !$content['owner'] || // dont allow to move accounts, as this mean deleting the user incl. all content he owns |
||||||
2372 | $content['id'] && !$this->check_perms(Acl::DELETE,$content); // you need delete rights to move an existing contact into an other addressbook |
||||||
2373 | } |
||||||
2374 | // set the unsupported fields from the backend to readonly |
||||||
2375 | foreach($this->get_fields('unsupported',$content['id'],$content['owner']) as $field) |
||||||
2376 | { |
||||||
2377 | $readonlys[$field] = true; |
||||||
2378 | } |
||||||
2379 | // for editing own account, make all fields not allowed by own_account_acl readonly |
||||||
2380 | if (!$this->is_admin() && !$content['owner'] && $content['account_id'] == $this->user && $this->own_account_acl && !$view) |
||||||
0 ignored issues
–
show
The expression
$this->own_account_acl of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||||
2381 | { |
||||||
2382 | $readonlys['__ALL__'] = true; |
||||||
2383 | $readonlys['button[cancel]'] = false; |
||||||
2384 | |||||||
2385 | foreach($this->own_account_acl as $field) |
||||||
2386 | { |
||||||
2387 | $readonlys[$field] = false; |
||||||
2388 | } |
||||||
2389 | if (!$readonlys['jpegphoto']) |
||||||
2390 | { |
||||||
2391 | $readonlys = array_merge($readonlys, array( |
||||||
2392 | 'upload_photo' => false, |
||||||
2393 | 'delete_photo' => false, |
||||||
2394 | 'addressbook.edit.upload' => false |
||||||
2395 | )); |
||||||
2396 | } |
||||||
2397 | if (!$readonlys['pubkey']) |
||||||
2398 | { |
||||||
2399 | $readonlys['addressbook:'.$content['id'].':.files/pgp-pubkey.asc'] = |
||||||
2400 | $readonlys['addressbook:'.$content['id'].':.files/smime-pubkey.crt'] = false; |
||||||
2401 | } |
||||||
2402 | } |
||||||
2403 | |||||||
2404 | if (isset($readonlys['n_fileas'])) $readonlys['fileas_type'] = $readonlys['n_fileas']; |
||||||
2405 | // disable not needed tabs |
||||||
2406 | $readonlys['tabs']['cats'] = !($content['cat_tab'] = $this->config['cat_tab']); |
||||||
2407 | $readonlys['tabs']['custom'] = !$this->customfields || $this->get_backend($content['id'],$content['owner']) == $this->so_accounts; |
||||||
0 ignored issues
–
show
The expression
$this->customfields of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||||
2408 | $readonlys['tabs']['custom_private'] = $readonlys['tabs']['custom'] || !$this->config['private_cf_tab']; |
||||||
2409 | $readonlys['tabs']['distribution_list'] = !$content['distrib_lists'];#false; |
||||||
2410 | $readonlys['tabs']['history'] = $this->contact_repository != 'sql' || !$content['id'] || |
||||||
2411 | $this->account_repository != 'sql' && $content['account_id']; |
||||||
2412 | if (!$content['id']) $readonlys['button[delete]'] = !$content['id']; |
||||||
2413 | if ($this->config['private_cf_tab']) $content['no_private_cfs'] = 0; |
||||||
2414 | $readonlys['change_org'] = empty($content['org_name']) || $view; |
||||||
2415 | |||||||
2416 | // for editing the own account (by a non-admin), enable only the fields allowed via the "own_account_acl" |
||||||
2417 | if (!$content['owner'] && !$this->check_perms(Acl::EDIT, $content)) |
||||||
2418 | { |
||||||
2419 | $this->_set_readonlys_for_own_account_acl($readonlys, $content['id']); |
||||||
2420 | } |
||||||
2421 | for($i = -23; $i<=23; $i++) |
||||||
2422 | { |
||||||
2423 | $tz[$i] = ($i > 0 ? '+' : '').$i; |
||||||
2424 | } |
||||||
2425 | $sel_options['tz'] = $tz; |
||||||
2426 | $content['tz'] = $content['tz'] ? $content['tz'] : '0'; |
||||||
2427 | if (count($this->content_types) > 1) |
||||||
2428 | { |
||||||
2429 | foreach($this->content_types as $type => $data) |
||||||
2430 | { |
||||||
2431 | $sel_options['tid'][$type] = $data['name']; |
||||||
2432 | } |
||||||
2433 | $content['typegfx'] = Api\Html::image('addressbook',$this->content_types[$content['tid']]['options']['icon'],'',' width="16px" height="16px"'); |
||||||
2434 | } |
||||||
2435 | else |
||||||
2436 | { |
||||||
2437 | $content['no_tid'] = true; |
||||||
2438 | } |
||||||
2439 | |||||||
2440 | $content['view'] = false; |
||||||
2441 | $content['link_to'] = array( |
||||||
2442 | 'to_app' => 'addressbook', |
||||||
2443 | 'to_id' => $content['link_to']['to_id'], |
||||||
2444 | ); |
||||||
2445 | |||||||
2446 | // Links for deleted entries |
||||||
2447 | if($content['tid'] == self::DELETED_TYPE) |
||||||
2448 | { |
||||||
2449 | $content['link_to']['show_deleted'] = true; |
||||||
2450 | if(!$GLOBALS['egw_info']['user']['apps']['admin'] && $this->config['history'] != 'userpurge') |
||||||
2451 | { |
||||||
2452 | $readonlys['button[delete]'] = true; |
||||||
2453 | } |
||||||
2454 | } |
||||||
2455 | |||||||
2456 | // Enable history |
||||||
2457 | $this->setup_history($content, $sel_options); |
||||||
2458 | |||||||
2459 | $content['photo'] = $this->photo_src($content['id'],$content['jpegphoto'],'',$content['etag']); |
||||||
2460 | |||||||
2461 | if ($content['private']) $content['owner'] .= 'p'; |
||||||
2462 | |||||||
2463 | // for custom types, check if we have a custom edit template named "addressbook.edit.$type", $type is the name |
||||||
2464 | if (in_array($content['tid'], array('n',self::DELETED_TYPE)) || !$this->tmpl->read('addressbook.edit.'.$this->content_types[$content['tid']]['name'])) |
||||||
2465 | { |
||||||
2466 | $this->tmpl->read('addressbook.edit'); |
||||||
2467 | } |
||||||
2468 | |||||||
2469 | // allow other apps to add tabs to addressbook edit |
||||||
2470 | $preserve = $content; |
||||||
2471 | $preserve['old_owner'] = $content['owner']; |
||||||
2472 | unset($preserve['jpegphoto'], $content['jpegphoto']); // unused and messes up json encoding (not utf-8) |
||||||
2473 | $this->tmpl->setElementAttribute('tabs', 'add_tabs', true); |
||||||
2474 | $tabs =& $this->tmpl->getElementAttribute('tabs', 'tabs'); |
||||||
2475 | if (($first_call = !isset($tabs))) |
||||||
2476 | { |
||||||
2477 | $tabs = array(); |
||||||
2478 | } |
||||||
2479 | //error_log(__LINE__.': '.__METHOD__."() first_call=$first_call"); |
||||||
2480 | $hook_data = Api\Hooks::process(array('location' => 'addressbook_edit')+$content); |
||||||
2481 | //error_log(__METHOD__."() hook_data=".array2string($hook_data)); |
||||||
2482 | foreach($hook_data as $extra_tabs) |
||||||
2483 | { |
||||||
2484 | if (!$extra_tabs) continue; |
||||||
2485 | |||||||
2486 | foreach(isset($extra_tabs[0]) ? $extra_tabs : array($extra_tabs) as $extra_tab) |
||||||
2487 | { |
||||||
2488 | if ($extra_tab['data'] && is_array($extra_tab['data'])) |
||||||
2489 | { |
||||||
2490 | $content = array_merge($content, $extra_tab['data']); |
||||||
2491 | } |
||||||
2492 | if ($extra_tab['preserve'] && is_array($extra_tab['preserve'])) |
||||||
2493 | { |
||||||
2494 | $preserve = array_merge($preserve, $extra_tab['preserve']); |
||||||
2495 | } |
||||||
2496 | if ($extra_tab['readonlys'] && is_array($extra_tab['readonlys'])) |
||||||
2497 | { |
||||||
2498 | $readonlys = array_merge($readonlys, $extra_tab['readonlys']); |
||||||
2499 | } |
||||||
2500 | // we must NOT add tabs and callbacks more then once! |
||||||
2501 | if (!$first_call) continue; |
||||||
2502 | |||||||
2503 | if (!empty($extra_tab['pre_save_callback'])) |
||||||
2504 | { |
||||||
2505 | $preserve['pre_save_callbacks'][] = $extra_tab['pre_save_callback']; |
||||||
2506 | } |
||||||
2507 | if (!empty($extra_tab['post_save_callback'])) |
||||||
2508 | { |
||||||
2509 | $preserve['post_save_callbacks'][] = $extra_tab['post_save_callback']; |
||||||
2510 | } |
||||||
2511 | if (!empty($extra_tab['label']) && !empty($extra_tab['name'])) |
||||||
2512 | { |
||||||
2513 | $tabs[] = array( |
||||||
2514 | 'label' => $extra_tab['label'], |
||||||
2515 | 'template' => $extra_tab['name'], |
||||||
2516 | 'prepend' => $extra_tab['prepend'], |
||||||
2517 | ); |
||||||
2518 | } |
||||||
2519 | //error_log(__METHOD__."() changed tabs=".array2string($tabs)); |
||||||
2520 | } |
||||||
2521 | } |
||||||
2522 | return $this->tmpl->exec('addressbook.addressbook_ui.edit', $content, $sel_options, $readonlys, $preserve, 2); |
||||||
2523 | } |
||||||
2524 | |||||||
2525 | /** |
||||||
2526 | * Set the readonlys for non-admins editing their own account |
||||||
2527 | * |
||||||
2528 | * @param array &$readonlys |
||||||
2529 | * @param int $id |
||||||
2530 | */ |
||||||
2531 | function _set_readonlys_for_own_account_acl(&$readonlys,$id) |
||||||
2532 | { |
||||||
2533 | // regular fields depending on the backend |
||||||
2534 | foreach($this->get_fields('supported',$id,0) as $field) |
||||||
2535 | { |
||||||
2536 | if (!$this->own_account_acl || !in_array($field,$this->own_account_acl)) |
||||||
0 ignored issues
–
show
The expression
$this->own_account_acl of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||||
2537 | { |
||||||
2538 | $readonlys[$field] = true; |
||||||
2539 | switch($field) |
||||||
2540 | { |
||||||
2541 | case 'tel_work': |
||||||
2542 | case 'tel_cell': |
||||||
2543 | case 'tel_home': |
||||||
2544 | $readonlys[$field.'2'] = true; |
||||||
2545 | break; |
||||||
2546 | case 'n_fileas': |
||||||
2547 | $readonlys['fileas_type'] = true; |
||||||
2548 | break; |
||||||
2549 | } |
||||||
2550 | } |
||||||
2551 | } |
||||||
2552 | // custom fields |
||||||
2553 | if ($this->customfields) |
||||||
0 ignored issues
–
show
The expression
$this->customfields of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||||
2554 | { |
||||||
2555 | foreach(array_keys($this->customfields) as $name) |
||||||
2556 | { |
||||||
2557 | if (!$this->own_account_acl || !in_array('#'.$name,$this->own_account_acl)) |
||||||
0 ignored issues
–
show
The expression
$this->own_account_acl of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||||
2558 | { |
||||||
2559 | $readonlys['#'.$name] = true; |
||||||
2560 | } |
||||||
2561 | } |
||||||
2562 | } |
||||||
2563 | // links |
||||||
2564 | if (!$this->own_account_acl || !in_array('link_to',$this->own_account_acl)) |
||||||
0 ignored issues
–
show
The expression
$this->own_account_acl of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||||
2565 | { |
||||||
2566 | $readonlys['link_to'] = true; |
||||||
2567 | } |
||||||
2568 | } |
||||||
2569 | |||||||
2570 | /** |
||||||
2571 | * Doublicate check: returns similar contacts: same email or 2 of name, firstname, org |
||||||
2572 | * |
||||||
2573 | * Also update/return fileas options, if necessary. |
||||||
2574 | * |
||||||
2575 | * @param array $values contact values from form |
||||||
2576 | * @param string $name name of changed value, eg. "email" |
||||||
2577 | * @param int $own_id =0 own contact id, to not check against it |
||||||
2578 | * @return array with keys 'msg' => "EMail address exists, do you want to open contact?" (or null if not existing) |
||||||
2579 | * 'data' => array of id => "full name (addressbook)" pairs |
||||||
2580 | * 'fileas_options' |
||||||
2581 | */ |
||||||
2582 | public function ajax_check_values($values, $name, $own_id=0) |
||||||
2583 | { |
||||||
2584 | $fields = explode(',',$GLOBALS['egw_info']['user']['preferences']['addressbook']['duplicate_fields']); |
||||||
2585 | $threshold = (int)$GLOBALS['egw_info']['user']['preferences']['addressbook']['duplicate_threshold']; |
||||||
2586 | |||||||
2587 | $ret = array('doublicates' => array(), 'msg' => null); |
||||||
2588 | |||||||
2589 | // if email changed, check for doublicates |
||||||
2590 | if (in_array($name, array('email', 'email_home')) && in_array('contact_'.$name, $fields)) |
||||||
2591 | { |
||||||
2592 | if (preg_match(Etemplate\Widget\Url::EMAIL_PREG, $values[$name])) // only search for real email addresses, to not return to many contacts |
||||||
2593 | { |
||||||
2594 | $contacts = parent::search(array( |
||||||
2595 | 'email' => $values[$name], |
||||||
2596 | 'email_home' => $values[$name], |
||||||
2597 | ), false, '', '', '', false, 'OR'); |
||||||
2598 | } |
||||||
2599 | } |
||||||
2600 | else |
||||||
2601 | { |
||||||
2602 | // only set fileas-options if other then email changed |
||||||
2603 | $ret['fileas_options'] = array_values($this->fileas_options($values)); |
||||||
2604 | // Full options for et2 |
||||||
2605 | $ret['fileas_sel_options'] = $this->fileas_options($values); |
||||||
2606 | |||||||
2607 | // if name, firstname or org changed and enough are specified, check for doublicates |
||||||
2608 | $specified_count = 0; |
||||||
2609 | foreach($fields as $field) |
||||||
2610 | { |
||||||
2611 | if($values[trim($field)]) |
||||||
2612 | { |
||||||
2613 | $specified_count++; |
||||||
2614 | } |
||||||
2615 | } |
||||||
2616 | if (in_array($name,$fields) && $specified_count >= $threshold) |
||||||
2617 | { |
||||||
2618 | $filter = array(); |
||||||
2619 | foreach($fields as $n) // use email too, to exclude obvious false positives |
||||||
2620 | { |
||||||
2621 | if (!empty($values[$n])) $filter[$n] = $values[$n]; |
||||||
2622 | } |
||||||
2623 | $contacts = parent::search('', false, '', '', '', false, 'AND', false, $filter); |
||||||
2624 | } |
||||||
2625 | } |
||||||
2626 | if ($contacts) |
||||||
2627 | { |
||||||
2628 | foreach($contacts as $contact) |
||||||
2629 | { |
||||||
2630 | if ($own_id && $contact['id'] == $own_id) continue; |
||||||
2631 | |||||||
2632 | $ret['doublicates'][$contact['id']] = $this->fileas($contact).' ('. |
||||||
2633 | (!$contact['owner'] ? lang('Accounts') : ($contact['owner'] == $this->user ? |
||||||
2634 | ($contact['private'] ? lang('Private') : lang('Personal')) : Api\Accounts::username($contact['owner']))).')'; |
||||||
2635 | } |
||||||
2636 | if ($ret['doublicates']) |
||||||
2637 | { |
||||||
2638 | $ret['msg'] = lang('Similar contacts found:'). |
||||||
2639 | "\n\n".implode("\n", $ret['doublicates'])."\n\n". |
||||||
2640 | lang('Open for editing?'); |
||||||
2641 | } |
||||||
2642 | } |
||||||
2643 | //error_log(__METHOD__.'('.array2string($values).", '$name', $own_id) doublicates found ".array2string($ret['doublicates'])); |
||||||
2644 | Api\Json\Response::get()->data($ret); |
||||||
2645 | } |
||||||
2646 | |||||||
2647 | /** |
||||||
2648 | * CRM view |
||||||
2649 | * |
||||||
2650 | * @param array $content |
||||||
2651 | */ |
||||||
2652 | function view(array $content=null) |
||||||
2653 | { |
||||||
2654 | // CRM list comes from content, request, or preference |
||||||
2655 | $crm_list = $content['crm_list'] ? $content['crm_list'] : |
||||||
2656 | ($_GET['crm_list'] ? $_GET['crm_list'] : $GLOBALS['egw_info']['user']['preferences']['addressbook']['crm_list']); |
||||||
2657 | if(!$crm_list || $crm_list == '~edit~') $crm_list = 'infolog'; |
||||||
2658 | |||||||
2659 | if(is_array($content)) |
||||||
2660 | { |
||||||
2661 | $button = key($content['button']); |
||||||
2662 | switch ($content['toolbar'] ? $content['toolbar'] : $button) |
||||||
2663 | { |
||||||
2664 | case 'vcard': |
||||||
2665 | Egw::redirect_link('/index.php','menuaction=addressbook.uivcard.out&ab_id=' .$content['id']); |
||||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||||||
2666 | |||||||
2667 | case 'cancel': |
||||||
2668 | Egw::redirect_link('/index.php','menuaction=addressbook.addressbook_ui.index&ajax=true'); |
||||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||||||
2669 | |||||||
2670 | case 'delete': |
||||||
2671 | Egw::redirect_link('/index.php',array( |
||||||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
|
|||||||
2672 | 'menuaction' => 'addressbook.addressbook_ui.index', |
||||||
2673 | 'msg' => $this->delete($content) ? lang('Contact deleted') : lang('Error deleting the contact !!!'), |
||||||
2674 | )); |
||||||
2675 | |||||||
2676 | case 'next': |
||||||
2677 | $inc = 1; |
||||||
2678 | // fall through |
||||||
2679 | case 'back': |
||||||
2680 | if (!isset($inc)) $inc = -1; |
||||||
2681 | // get next/previous contact in selection |
||||||
2682 | $query = Api\Cache::getSession('addressbook', 'index'); |
||||||
2683 | $query['start'] = $content['index'] + $inc; |
||||||
2684 | $query['num_rows'] = 1; |
||||||
2685 | $rows = $readonlys = array(); |
||||||
2686 | $num_rows = $this->get_rows($query, $rows, $readonlys, true); |
||||||
2687 | //error_log(__METHOD__."() get_rows()=$num_rows rows=".array2string($rows)); |
||||||
2688 | $contact_id = $rows[0]; |
||||||
2689 | if(!$contact_id || !is_array($content = $this->read($contact_id))) |
||||||
2690 | { |
||||||
2691 | Egw::redirect_link('/index.php',array( |
||||||
2692 | 'menuaction' => 'addressbook.addressbook_ui.index', |
||||||
2693 | 'msg' => $content, |
||||||
2694 | 'ajax' => 'true' |
||||||
2695 | )); |
||||||
2696 | } |
||||||
2697 | $content['index'] = $query['start']; |
||||||
2698 | |||||||
2699 | // List nextmatch is already there, just update the filter |
||||||
2700 | if($contact_id && Api\Json\Request::isJSONRequest()) |
||||||
2701 | { |
||||||
2702 | switch($crm_list) |
||||||
2703 | { |
||||||
2704 | case 'infolog-organisation': |
||||||
2705 | $contact_id = $this->get_all_org_contacts($contact_id); |
||||||
2706 | // Fall through |
||||||
2707 | case 'infolog': |
||||||
2708 | case 'tracker': |
||||||
2709 | default: |
||||||
2710 | Api\Json\Response::get()->apply('app.addressbook.view_set_list',Array(Array('action'=>'addressbook', 'action_id' => $contact_id))); |
||||||
2711 | break; |
||||||
2712 | } |
||||||
2713 | |||||||
2714 | // Clear contact_id, it's used as a flag to send the list |
||||||
2715 | unset($contact_id); |
||||||
2716 | } |
||||||
2717 | break; |
||||||
2718 | } |
||||||
2719 | } |
||||||
2720 | else |
||||||
2721 | { |
||||||
2722 | // allow to search eg. for a phone number |
||||||
2723 | if (isset($_GET['search'])) |
||||||
2724 | { |
||||||
2725 | $query = Api\Cache::getSession('addressbook', 'index'); |
||||||
2726 | $query['search'] = $_GET['search']; |
||||||
2727 | unset($_GET['search']); |
||||||
2728 | // reset all filters |
||||||
2729 | unset($query['advanced_search']); |
||||||
2730 | $query['col_filter'] = array(); |
||||||
2731 | $query['filter'] = $query['filter2'] = $query['cat_id'] = ''; |
||||||
2732 | Api\Cache::setSession('addressbook', 'index', $query); |
||||||
2733 | $query['start'] = 0; |
||||||
2734 | $query['num_rows'] = 1; |
||||||
2735 | $rows = $readonlys = array(); |
||||||
2736 | $num_rows = $this->get_rows($query, $rows, $readonlys, true); |
||||||
2737 | $_GET['contact_id'] = array_shift($rows); |
||||||
2738 | $_GET['index'] = 0; |
||||||
2739 | } |
||||||
2740 | $contact_id = $_GET['contact_id'] ? $_GET['contact_id'] : ((int)$_GET['account_id'] ? 'account:'.(int)$_GET['account_id'] : 0); |
||||||
2741 | if(!$contact_id || !is_array($content = $this->read($contact_id))) |
||||||
2742 | { |
||||||
2743 | Egw::redirect_link('/index.php',array( |
||||||
2744 | 'menuaction' => 'addressbook.addressbook_ui.index', |
||||||
2745 | 'msg' => $content, |
||||||
2746 | 'ajax' => 'true' |
||||||
2747 | )+(isset($_GET['search']) ? array('search' => $_GET['search']) : array())); |
||||||
2748 | } |
||||||
2749 | if (isset($_GET['index'])) |
||||||
2750 | { |
||||||
2751 | $content['index'] = (int)$_GET['index']; |
||||||
2752 | // get number of rows to determine if we can have a next button |
||||||
2753 | $query = Api\Cache::getSession('addressbook', 'index'); |
||||||
2754 | $query['start'] = $content['index']; |
||||||
2755 | $query['num_rows'] = 1; |
||||||
2756 | $rows = $readonlys = array(); |
||||||
2757 | $num_rows = $this->get_rows($query, $rows, $readonlys, true); |
||||||
2758 | } |
||||||
2759 | } |
||||||
2760 | $content['jpegphoto'] = !empty($content['jpegphoto']); // unused and messes up json encoding (not utf-8) |
||||||
2761 | |||||||
2762 | // make everything not explicit mentioned readonly |
||||||
2763 | $readonlys['__ALL__'] = true; |
||||||
2764 | $readonlys['photo'] = $readonlys['button[cancel]'] = $readonlys['button[copy]'] = |
||||||
2765 | $readonlys['button[ok]'] = $readonlys['button[more]'] = $readonlys['toolbar'] = false; |
||||||
2766 | |||||||
2767 | foreach(array_keys($this->contact_fields) as $key) |
||||||
2768 | { |
||||||
2769 | if (in_array($key,array('tel_home','tel_work','tel_cell','tel_fax'))) |
||||||
2770 | { |
||||||
2771 | $content[$key.'2'] = $content[$key]; |
||||||
2772 | } |
||||||
2773 | } |
||||||
2774 | |||||||
2775 | // respect category permissions |
||||||
2776 | if(!empty($content['cat_id'])) |
||||||
2777 | { |
||||||
2778 | $content['cat_id'] = $this->categories->check_list(Acl::READ,$content['cat_id']); |
||||||
2779 | } |
||||||
2780 | $content['cat_id_tree'] = $content['cat_id']; |
||||||
2781 | |||||||
2782 | $content['view'] = true; |
||||||
2783 | $content['link_to'] = array( |
||||||
2784 | 'to_app' => 'addressbook', |
||||||
2785 | 'to_id' => $content['id'], |
||||||
2786 | ); |
||||||
2787 | // Links for deleted entries |
||||||
2788 | if($content['tid'] == self::DELETED_TYPE) |
||||||
2789 | { |
||||||
2790 | $content['link_to']['show_deleted'] = true; |
||||||
2791 | } |
||||||
2792 | $readonlys['button[delete]'] = !$content['owner'] || !$this->check_perms(Acl::DELETE,$content); |
||||||
2793 | $readonlys['button[edit]'] = !$this->check_perms(Acl::EDIT,$content); |
||||||
2794 | |||||||
2795 | // how to display addresses |
||||||
2796 | $content['addr_format'] = $this->addr_format_by_country($content['adr_one_countryname']); |
||||||
2797 | $content['addr_format2'] = $this->addr_format_by_country($content['adr_two_countryname']); |
||||||
2798 | |||||||
2799 | $sel_options['fileas_type'][$content['fileas_type']] = $this->fileas($content); |
||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||
2800 | $sel_options['owner'] = $this->get_addressbooks(); |
||||||
2801 | for($i = -23; $i<=23; $i++) |
||||||
2802 | { |
||||||
2803 | $tz[$i] = ($i > 0 ? '+' : '').$i; |
||||||
2804 | } |
||||||
2805 | $sel_options['tz'] = $tz; |
||||||
2806 | $content['tz'] = $content['tz'] ? $content['tz'] : 0; |
||||||
2807 | if (count($this->content_types) > 1) |
||||||
2808 | { |
||||||
2809 | foreach($this->content_types as $type => $data) |
||||||
2810 | { |
||||||
2811 | $sel_options['tid'][$type] = $data['name']; |
||||||
2812 | } |
||||||
2813 | $content['typegfx'] = Api\Html::image('addressbook',$this->content_types[$content['tid']]['options']['icon'],'',' width="16px" height="16px"'); |
||||||
2814 | } |
||||||
2815 | else |
||||||
2816 | { |
||||||
2817 | $content['no_tid'] = true; |
||||||
2818 | } |
||||||
2819 | $this->tmpl->read('addressbook.view'); |
||||||
2820 | /*if (!$this->tmpl->read($this->content_types[$content['tid']]['options']['template'] ? $this->content_types[$content['tid']]['options']['template'] : 'addressbook.edit')) |
||||||
2821 | { |
||||||
2822 | $content['msg'] = lang('WARNING: Template "%1" not found, using default template instead.', $this->content_types[$content['tid']]['options']['template'])."\n"; |
||||||
2823 | $content['msg'] .= lang('Please update the templatename in your customfields section!'); |
||||||
2824 | $this->tmpl->read('addressbook.edit'); |
||||||
2825 | }*/ |
||||||
2826 | if ($this->private_addressbook && $content['private'] && $content['owner'] == $this->user) |
||||||
2827 | { |
||||||
2828 | $content['owner'] .= 'p'; |
||||||
2829 | } |
||||||
2830 | $this->tmpl->set_cell_attribute('change_org','disabled',true); |
||||||
0 ignored issues
–
show
The function
EGroupware\Api\Etemplate::set_cell_attribute() has been deprecated: use setElementAttribute($name, $attr, $val)
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||||
2831 | |||||||
2832 | // Prevent double countries - invalid code blanks it, disabling doesn't work |
||||||
2833 | $content['adr_one_countrycode'] = '-'; |
||||||
2834 | $content['adr_two_countrycode'] = '-'; |
||||||
2835 | |||||||
2836 | // Enable history |
||||||
2837 | $this->setup_history($content, $sel_options); |
||||||
2838 | |||||||
2839 | // disable not needed tabs |
||||||
2840 | $readonlys['tabs']['cats'] = !($content['cat_tab'] = $this->config['cat_tab']); |
||||||
2841 | $readonlys['tabs']['custom'] = !$this->customfields; |
||||||
2842 | $readonlys['tabs']['custom_private'] = !$this->customfields || !$this->config['private_cf_tab']; |
||||||
0 ignored issues
–
show
The expression
$this->customfields of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||||
2843 | $readonlys['tabs']['distribution_list'] = !$content['distrib_lists'];#false; |
||||||
2844 | $readonlys['tabs']['history'] = $this->contact_repository != 'sql' || !$content['id'] || |
||||||
2845 | $this->account_repository != 'sql' && $content['account_id']; |
||||||
2846 | if ($this->config['private_cf_tab']) $content['no_private_cfs'] = 0; |
||||||
2847 | |||||||
2848 | // last and next calendar date |
||||||
2849 | if (!empty($content['id'])) $dates = current($this->read_calendar(array($content['account_id'] ? $content['account_id'] : 'c'.$content['id']),false)); |
||||||
2850 | if(is_array($dates)) $content += $dates; |
||||||
2851 | |||||||
2852 | // Disable importexport |
||||||
2853 | $GLOBALS['egw_info']['flags']['disable_importexport']['export'] = true; |
||||||
2854 | $GLOBALS['egw_info']['flags']['disable_importexport']['merge'] = true; |
||||||
2855 | |||||||
2856 | // set id for automatic linking via quick add |
||||||
2857 | $GLOBALS['egw_info']['flags']['currentid'] = $content['id']; |
||||||
2858 | |||||||
2859 | // load app.css for addressbook explicit, as addressbook_view hooks changes currentapp! |
||||||
2860 | Framework::includeCSS('addressbook', 'app'); |
||||||
2861 | |||||||
2862 | // dont show an app-header |
||||||
2863 | $GLOBALS['egw_info']['flags']['app_header'] = ''; |
||||||
2864 | |||||||
2865 | $actions = array( |
||||||
2866 | 'open' => array( |
||||||
2867 | 'caption' => 'Open', |
||||||
2868 | 'toolbarDefault' => true, |
||||||
2869 | ), |
||||||
2870 | 'copy' => 'Copy', |
||||||
2871 | 'delete' => array( |
||||||
2872 | 'caption' => 'Delete', |
||||||
2873 | 'confirm' => 'Delete this entry', |
||||||
2874 | ), |
||||||
2875 | 'cancel' => array( |
||||||
2876 | 'caption' => 'Cancel', |
||||||
2877 | 'toolbarDefault' => true, |
||||||
2878 | 'icon' => 'close' |
||||||
2879 | ), |
||||||
2880 | 'back' => array( |
||||||
2881 | 'caption' => 'Back', |
||||||
2882 | 'toolbarDefault' => true, |
||||||
2883 | ), |
||||||
2884 | 'next' => array( |
||||||
2885 | 'caption' => 'Next', |
||||||
2886 | 'toolbarDefault' => true, |
||||||
2887 | ), |
||||||
2888 | ); |
||||||
2889 | if (!isset($content['index']) || !$content['index']) |
||||||
2890 | { |
||||||
2891 | unset($actions['back']); |
||||||
2892 | } |
||||||
2893 | if (!isset($content['index']) || $content['index'] >= $num_rows-1) |
||||||
2894 | { |
||||||
2895 | unset($actions['next']); |
||||||
2896 | } |
||||||
2897 | $this->tmpl->setElementAttribute('toolbar', 'actions', $actions); |
||||||
2898 | |||||||
2899 | // always show sidebox, as it contains contact-data |
||||||
2900 | unset($GLOBALS['egw_info']['user']['preferences']['common']['auto_hide_sidebox']); |
||||||
2901 | |||||||
2902 | // need to load list's app.js now, as exec calls header before other app can include it |
||||||
2903 | Framework::includeJS('/'.$crm_list.'/js/app.js'); |
||||||
2904 | |||||||
2905 | $this->tmpl->exec('addressbook.addressbook_ui.view',$content,$sel_options,$readonlys,array( |
||||||
2906 | 'id' => $content['id'], |
||||||
2907 | 'index' => $content['index'], |
||||||
2908 | 'crm_list' => $crm_list |
||||||
2909 | )); |
||||||
2910 | |||||||
2911 | // Only load this on first time - we're using AJAX, so it stays there through submits. |
||||||
2912 | // Sending it again (via ajax) will break the addressbook.view etemplate2 |
||||||
2913 | if($contact_id) |
||||||
2914 | { |
||||||
2915 | // Show for whole organisation, not just selected contact |
||||||
2916 | if($crm_list == 'infolog-organisation') |
||||||
2917 | { |
||||||
2918 | $crm_list = str_replace('-organisation','',$crm_list); |
||||||
2919 | $_query = Api\Cache::getSession('addressbook', 'index'); |
||||||
0 ignored issues
–
show
|
|||||||
2920 | $content['id'] = $this->get_all_org_contacts($content['id']); |
||||||
2921 | } |
||||||
2922 | Api\Hooks::single(array( |
||||||
2923 | 'location' => 'addressbook_view', |
||||||
2924 | 'ab_id' => $content['id'] |
||||||
2925 | ),$crm_list); |
||||||
2926 | } |
||||||
2927 | } |
||||||
2928 | |||||||
2929 | /** |
||||||
2930 | * Get all the contact IDs in the given contact's organisation |
||||||
2931 | * |
||||||
2932 | * @param int $contact_id |
||||||
2933 | * @param Array $query Optional base query |
||||||
2934 | * |
||||||
2935 | * @return array of contact IDs in the organisation |
||||||
2936 | */ |
||||||
2937 | function get_all_org_contacts($contact_id, $query = array()) |
||||||
2938 | { |
||||||
2939 | $contact = $this->read($contact_id); |
||||||
2940 | |||||||
2941 | // No org name, early return with just the contact |
||||||
2942 | if(!$contact['org_name']) |
||||||
2943 | { |
||||||
2944 | return array($contact_id); |
||||||
2945 | } |
||||||
2946 | |||||||
2947 | $query['num_rows'] = -1; |
||||||
2948 | $query['start'] = 0; |
||||||
2949 | if(!array_key_exists('filter', $query)) |
||||||
2950 | { |
||||||
2951 | $query['filter'] = ''; |
||||||
2952 | } |
||||||
2953 | if(!is_array($query['col_filter'])) |
||||||
2954 | { |
||||||
2955 | $query['col_filter'] = array(); |
||||||
2956 | } |
||||||
2957 | $query['grouped_view'] = 'org_name:'.$contact['org_name']; |
||||||
2958 | |||||||
2959 | $org_contacts = array(); |
||||||
2960 | $readonlys = null; |
||||||
2961 | $this->get_rows($query,$org_contacts,$readonlys,true); // true = only return the id's |
||||||
2962 | |||||||
2963 | return $org_contacts ? $org_contacts : array($contact_id); |
||||||
2964 | } |
||||||
2965 | |||||||
2966 | /** |
||||||
2967 | * convert email-address in compose link |
||||||
2968 | * |
||||||
2969 | * @param string $email email-addresse |
||||||
2970 | * @return array/string array with get-params or mailto:$email, or '' or no mail addresse |
||||||
0 ignored issues
–
show
|
|||||||
2971 | */ |
||||||
2972 | function email2link($email) |
||||||
2973 | { |
||||||
2974 | if (strpos($email,'@') == false) return ''; |
||||||
0 ignored issues
–
show
|
|||||||
2975 | |||||||
2976 | if($GLOBALS['egw_info']['user']['apps']['mail']) |
||||||
2977 | { |
||||||
2978 | return array( |
||||||
2979 | 'menuaction' => 'mail.mail_compose.compose', |
||||||
2980 | 'send_to' => base64_encode($email) |
||||||
2981 | ); |
||||||
2982 | } |
||||||
2983 | if($GLOBALS['egw_info']['user']['apps']['felamimail']) |
||||||
2984 | { |
||||||
2985 | return array( |
||||||
2986 | 'menuaction' => 'felamimail.uicompose.compose', |
||||||
2987 | 'send_to' => base64_encode($email) |
||||||
2988 | ); |
||||||
2989 | } |
||||||
2990 | if($GLOBALS['egw_info']['user']['apps']['email']) |
||||||
2991 | { |
||||||
2992 | return array( |
||||||
2993 | 'menuaction' => 'email.uicompose.compose', |
||||||
2994 | 'to' => $email, |
||||||
2995 | ); |
||||||
2996 | } |
||||||
2997 | return 'mailto:' . $email; |
||||||
2998 | } |
||||||
2999 | |||||||
3000 | /** |
||||||
3001 | * Extended search |
||||||
3002 | * |
||||||
3003 | * @param array $_content |
||||||
3004 | * @return string |
||||||
3005 | */ |
||||||
3006 | function search($_content=array()) |
||||||
3007 | { |
||||||
3008 | if(!empty($_content)) |
||||||
3009 | { |
||||||
3010 | |||||||
3011 | $_content['cat_id'] = $this->config['cat_tab'] === 'Tree' ? $_content['cat_id_tree'] : $_content['cat_id']; |
||||||
3012 | |||||||
3013 | $response = Api\Json\Response::get(); |
||||||
3014 | |||||||
3015 | $query = Api\Cache::getSession('addressbook', 'index'); |
||||||
3016 | |||||||
3017 | if ($_content['button']['cancelsearch']) |
||||||
3018 | { |
||||||
3019 | unset($query['advanced_search']); |
||||||
3020 | } |
||||||
3021 | else |
||||||
3022 | { |
||||||
3023 | $query['advanced_search'] = array_intersect_key($_content,array_flip(array_merge($this->get_contact_columns(),array('operator','meth_select')))); |
||||||
3024 | foreach ($query['advanced_search'] as $key => $value) |
||||||
3025 | { |
||||||
3026 | if(!$value) unset($query['advanced_search'][$key]); |
||||||
3027 | } |
||||||
3028 | // Skip n_fn, it causes problems in sql |
||||||
3029 | unset($query['advanced_search']['n_fn']); |
||||||
3030 | } |
||||||
3031 | $query['search'] = ''; |
||||||
3032 | // store the index state in the session |
||||||
3033 | Api\Cache::setSession('addressbook', 'index', $query); |
||||||
3034 | |||||||
3035 | // store the advanced search in the session to call it again |
||||||
3036 | Api\Cache::setSession('addressbook', 'advanced_search', $query['advanced_search']); |
||||||
3037 | |||||||
3038 | // Update client / nextmatch with filters, or clear |
||||||
3039 | $response->call("app.addressbook.adv_search", array('advanced_search' => $_content['button']['search'] ? $query['advanced_search'] : '')); |
||||||
3040 | if ($_content['button']['cancelsearch']) |
||||||
3041 | { |
||||||
3042 | Framework::window_close (); |
||||||
3043 | |||||||
3044 | // No need to reload popup |
||||||
3045 | return; |
||||||
3046 | } |
||||||
3047 | } |
||||||
3048 | |||||||
3049 | $GLOBALS['egw_info']['etemplate']['advanced_search'] = true; |
||||||
3050 | |||||||
3051 | // initialize etemplate arrays |
||||||
3052 | $sel_options = $readonlys = array(); |
||||||
3053 | $this->tmpl->read('addressbook.edit'); |
||||||
3054 | $content = Api\Cache::getSession('addressbook', 'advanced_search'); |
||||||
3055 | $content['n_fn'] = $this->fullname($content); |
||||||
3056 | // Avoid ID conflict with tree & selectboxes |
||||||
3057 | $content['cat_id_tree'] = $content['cat_id']; |
||||||
3058 | |||||||
3059 | for($i = -23; $i<=23; $i++) |
||||||
3060 | { |
||||||
3061 | $tz[$i] = ($i > 0 ? '+' : '').$i; |
||||||
3062 | } |
||||||
3063 | $sel_options['tz'] = $tz + array('' => lang('doesn\'t matter')); |
||||||
3064 | $sel_options['tid'][] = lang('all'); |
||||||
3065 | //foreach($this->content_types as $type => $data) $sel_options['tid'][$type] = $data['name']; |
||||||
3066 | |||||||
3067 | // configure search options |
||||||
3068 | $sel_options['owner'] = $this->get_addressbooks(Acl::READ,lang('all')); |
||||||
3069 | $sel_options['operator'] = array( |
||||||
3070 | 'AND' => 'AND', |
||||||
3071 | 'OR' => 'OR', |
||||||
3072 | ); |
||||||
3073 | $sel_options['meth_select'] = array( |
||||||
3074 | '%' => lang('contains'), |
||||||
3075 | false => lang('exact'), |
||||||
3076 | ); |
||||||
3077 | if ($this->customfields) |
||||||
0 ignored issues
–
show
The expression
$this->customfields of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||||
3078 | { |
||||||
3079 | foreach($this->customfields as $name => $data) |
||||||
3080 | { |
||||||
3081 | if (substr($data['type'], 0, 6) == 'select' && !($data['rows'] > 1)) |
||||||
3082 | { |
||||||
3083 | if (!isset($content['#'.$name])) $content['#'.$name] = ''; |
||||||
3084 | if(!isset($data['values'][''])) $sel_options['#'.$name][''] = lang('Select one'); |
||||||
3085 | } |
||||||
3086 | // Make them not required, otherwise you can't search |
||||||
3087 | $this->tmpl->setElementAttribute('#'.$name, 'needed', FALSE); |
||||||
3088 | } |
||||||
3089 | } |
||||||
3090 | // configure edit template as search dialog |
||||||
3091 | $readonlys['change_photo'] = true; |
||||||
3092 | $readonlys['fileas_type'] = true; |
||||||
3093 | $readonlys['creator'] = true; |
||||||
3094 | // this setting will enable (and show) the search and cancel buttons, setting this to true will hide the before mentioned buttons completely |
||||||
3095 | $readonlys['button'] = false; |
||||||
3096 | // disable not needed tabs |
||||||
3097 | $readonlys['tabs']['cats'] = !($content['cat_tab'] = $this->config['cat_tab']); |
||||||
3098 | $readonlys['tabs']['custom'] = !$this->customfields; |
||||||
3099 | $readonlys['tabs']['custom_private'] = !$this->customfields || !$this->config['private_cf_tab']; |
||||||
0 ignored issues
–
show
The expression
$this->customfields of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||||
3100 | $readonlys['tabs']['links'] = true; |
||||||
3101 | $readonlys['tabs']['distribution_list'] = true; |
||||||
3102 | $readonlys['tabs']['history'] = true; |
||||||
3103 | // setting hidebuttons for content will hide the 'normal' addressbook edit dialog buttons |
||||||
3104 | $content['hidebuttons'] = true; |
||||||
3105 | $content['no_tid'] = true; |
||||||
3106 | $content['showsearchbuttons'] = true; // enable search operation and search buttons| they're disabled by default |
||||||
3107 | |||||||
3108 | if ($this->config['private_cf_tab']) $content['no_private_cfs'] = 0; |
||||||
3109 | |||||||
3110 | $this->tmpl->set_cell_attribute('change_org','disabled',true); |
||||||
0 ignored issues
–
show
The function
EGroupware\Api\Etemplate::set_cell_attribute() has been deprecated: use setElementAttribute($name, $attr, $val)
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. ![]() |
|||||||
3111 | return $this->tmpl->exec('addressbook.addressbook_ui.search',$content,$sel_options,$readonlys,array(),2); |
||||||
3112 | } |
||||||
3113 | |||||||
3114 | /** |
||||||
3115 | * Check if there's a photo for given contact id. This is used for avatar widget |
||||||
3116 | * to set or unset delete button. If there's no uploaded photo it responses true. |
||||||
3117 | * |
||||||
3118 | * @param type $contact_id |
||||||
3119 | */ |
||||||
3120 | function ajax_noPhotoExists ($contact_id) |
||||||
3121 | { |
||||||
3122 | $response = Api\Json\Response::get(); |
||||||
3123 | $response->data((!($contact = $this->read($contact_id)) || |
||||||
3124 | empty($contact['photo']) && !(($contact['files'] & Api\Contacts::FILES_BIT_PHOTO) && |
||||||
3125 | ($size = filesize($url=Api\Link::vfs_path('addressbook', $contact_id, Api\Contacts::FILES_PHOTO)))))); |
||||||
0 ignored issues
–
show
|
|||||||
3126 | } |
||||||
3127 | |||||||
3128 | /** |
||||||
3129 | * Ajax method to update edited avatar photo via avatar widget |
||||||
3130 | * |
||||||
3131 | * @param string $etemplate_exec_id to update id, files, etag, ... |
||||||
3132 | * @param file string $file null means to delete |
||||||
3133 | */ |
||||||
3134 | function ajax_update_photo ($etemplate_exec_id, $file) |
||||||
3135 | { |
||||||
3136 | $et_request = Api\Etemplate\Request::read($etemplate_exec_id); |
||||||
3137 | $response = Api\Json\Response::get(); |
||||||
3138 | if ($file) |
||||||
3139 | { |
||||||
3140 | $filteredFile = substr($file, strpos($file, ",")+1); |
||||||
3141 | // resize photo if wider then default width of 240pixel (keeping aspect ratio) |
||||||
3142 | $decoded = $this->resize_photo(base64_decode($filteredFile)); |
||||||
3143 | } |
||||||
3144 | $response->data(true); |
||||||
3145 | // add photo into current eT2 request |
||||||
3146 | $et_request->preserv = array_merge($et_request->preserv, array( |
||||||
3147 | 'jpegphoto' => is_null($file) ? $file : $decoded, |
||||||
3148 | 'photo_unchanged' => false, // hint photo is changed |
||||||
3149 | )); |
||||||
3150 | } |
||||||
3151 | |||||||
3152 | /** |
||||||
3153 | * Callback for vfs-upload widgets for PGP and S/Mime pubkey |
||||||
3154 | * |
||||||
3155 | * @param array $file |
||||||
3156 | * @param string $widget_id |
||||||
3157 | * @param Api\Etemplate\Request $request eT2 request eg. to access attribute $content |
||||||
3158 | * @param Api\Json\Response $response |
||||||
3159 | */ |
||||||
3160 | public function pubkey_uploaded(array $file, $widget_id, Api\Etemplate\Request $request, Api\Json\Response $response) |
||||||
3161 | { |
||||||
3162 | //error_log(__METHOD__."(".array2string($file).", ...) widget_id=$widget_id, id=".$request->content['id'].", files=".$request->content['files']); |
||||||
3163 | unset($file, $response); // not used, but required by function signature |
||||||
3164 | list(,,$path) = explode(':', $widget_id); |
||||||
3165 | $bit = $path === Api\Contacts::FILES_PGP_PUBKEY ? Api\Contacts::FILES_BIT_PGP_PUBKEY : Api\Contacts::FILES_BIT_SMIME_PUBKEY; |
||||||
3166 | if (!($request->content['files'] & $bit) && $this->check_perms(Acl::EDIT, $request->content)) |
||||||
3167 | { |
||||||
3168 | $content = $request->content; |
||||||
3169 | $content['files'] |= $bit; |
||||||
3170 | $content['photo_unchanged'] = true; // hint no need to store photo |
||||||
3171 | if ($this->save($content)) |
||||||
3172 | { |
||||||
3173 | $changed = array_diff_assoc($content, $request->content); |
||||||
3174 | //error_log(__METHOD__."() changed=".array2string($changed)); |
||||||
3175 | $request->content = $content; |
||||||
3176 | // need to update preserv, as edit stores content there too and we would get eg. an contact modified error when trying to store |
||||||
3177 | $request->preserv = array_merge($request->preserv, $changed); |
||||||
3178 | } |
||||||
3179 | } |
||||||
3180 | } |
||||||
3181 | |||||||
3182 | /** |
||||||
3183 | * Migrate contacts to or from LDAP (called by Admin >> Addressbook >> Site configuration (Admin only) |
||||||
3184 | * |
||||||
3185 | */ |
||||||
3186 | function migrate2ldap() |
||||||
3187 | { |
||||||
3188 | $GLOBALS['egw_info']['flags']['app_header'] = lang('Addressbook').' - '.lang('Migration to LDAP'); |
||||||
3189 | echo $GLOBALS['egw']->framework->header(); |
||||||
3190 | echo $GLOBALS['egw']->framework->navbar(); |
||||||
3191 | |||||||
3192 | if (!$this->is_admin()) |
||||||
3193 | { |
||||||
3194 | echo '<h1>'.lang('Permission denied !!!')."</h1>\n"; |
||||||
3195 | } |
||||||
3196 | else |
||||||
3197 | { |
||||||
3198 | parent::migrate2ldap($_GET['type']); |
||||||
3199 | echo '<p style="margin-top: 20px;"><b>'.lang('Migration finished')."</b></p>\n"; |
||||||
3200 | } |
||||||
3201 | echo $GLOBALS['egw']->framework->footer(); |
||||||
3202 | } |
||||||
3203 | |||||||
3204 | /** |
||||||
3205 | * Set n_fileas (and n_fn) in contacts of all users (called by Admin >> Addressbook >> Site configuration (Admin only) |
||||||
3206 | * |
||||||
3207 | * If $_GET[all] all fileas fields will be set, if !$_GET[all] only empty ones |
||||||
3208 | * |
||||||
3209 | */ |
||||||
3210 | function admin_set_fileas() |
||||||
3211 | { |
||||||
3212 | Api\Translation::add_app('admin'); |
||||||
3213 | $GLOBALS['egw_info']['flags']['app_header'] = lang('Addressbook').' - '.lang('Contact maintenance'); |
||||||
3214 | echo $GLOBALS['egw']->framework->header(); |
||||||
3215 | echo $GLOBALS['egw']->framework->navbar(); |
||||||
3216 | |||||||
3217 | // check if user has admin rights AND if a valid fileas type is given (Security) |
||||||
3218 | if (!$this->is_admin() || $_GET['type'] != '' && !in_array($_GET['type'],$this->fileas_types)) |
||||||
3219 | { |
||||||
3220 | echo '<h1>'.lang('Permission denied !!!')."</h1>\n"; |
||||||
3221 | } |
||||||
3222 | else |
||||||
3223 | { |
||||||
3224 | $errors = null; |
||||||
3225 | $updated = parent::set_all_fileas($_GET['type'],(boolean)$_GET['all'],$errors,true); // true = ignore Acl |
||||||
3226 | echo '<p style="margin-top: 20px;"><b>'.lang('%1 contacts updated (%2 errors).',$updated,$errors)."</b></p>\n"; |
||||||
0 ignored issues
–
show
The call to
lang() has too many arguments starting with $updated .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||||
3227 | } |
||||||
3228 | echo $GLOBALS['egw']->framework->footer(); |
||||||
3229 | } |
||||||
3230 | |||||||
3231 | /** |
||||||
3232 | * Cleanup all contacts of all users (called by Admin >> Addressbook >> Site configuration (Admin only) |
||||||
3233 | * |
||||||
3234 | */ |
||||||
3235 | function admin_set_all_cleanup() |
||||||
3236 | { |
||||||
3237 | Api\Translation::add_app('admin'); |
||||||
3238 | $GLOBALS['egw_info']['flags']['app_header'] = lang('Addressbook').' - '.lang('Contact maintenance'); |
||||||
3239 | echo $GLOBALS['egw']->framework->header(); |
||||||
3240 | echo $GLOBALS['egw']->framework->navbar(); |
||||||
3241 | |||||||
3242 | // check if user has admin rights (Security) |
||||||
3243 | if (!$this->is_admin()) |
||||||
3244 | { |
||||||
3245 | echo '<h1>'.lang('Permission denied !!!')."</h1>\n"; |
||||||
3246 | } |
||||||
3247 | else |
||||||
3248 | { |
||||||
3249 | $errors = null; |
||||||
3250 | $updated = parent::set_all_cleanup($errors,true); // true = ignore Acl |
||||||
3251 | echo '<p style="margin-top: 20px;"><b>'.lang('%1 contacts updated (%2 errors).',$updated,$errors)."</b></p>\n"; |
||||||
0 ignored issues
–
show
The call to
lang() has too many arguments starting with $updated .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue. If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above. ![]() |
|||||||
3252 | } |
||||||
3253 | echo $GLOBALS['egw']->framework->footer(); |
||||||
3254 | } |
||||||
3255 | |||||||
3256 | /** |
||||||
3257 | * Set up history log widget |
||||||
3258 | */ |
||||||
3259 | protected function setup_history(&$content, &$sel_options) |
||||||
3260 | { |
||||||
3261 | if ($this->contact_repository == 'ldap' || !$content['id'] || |
||||||
3262 | $this->account_repository == 'ldap' && $content['account_id']) |
||||||
3263 | { |
||||||
3264 | return; // no history for ldap as history table only allows integer id's |
||||||
3265 | } |
||||||
3266 | $content['history'] = array( |
||||||
3267 | 'id' => $content['id'], |
||||||
3268 | 'app' => 'addressbook', |
||||||
3269 | 'status-widgets' => array( |
||||||
3270 | 'owner' => 'select-account', |
||||||
3271 | 'creator' => 'select-account', |
||||||
3272 | 'created' => 'date-time', |
||||||
3273 | 'cat_id' => 'select-cat', |
||||||
3274 | 'adr_one_countrycode' => 'select-country', |
||||||
3275 | 'adr_two_countrycode' => 'select-country', |
||||||
3276 | ), |
||||||
3277 | ); |
||||||
3278 | |||||||
3279 | foreach($this->content_types as $id => $settings) |
||||||
3280 | { |
||||||
3281 | $content['history']['status-widgets']['tid'][$id] = $settings['name']; |
||||||
3282 | } |
||||||
3283 | $sel_options['status'] = $this->contact_fields; |
||||||
3284 | |||||||
3285 | // custom fields no longer need to be added, historylog-widget "knows" about them |
||||||
3286 | } |
||||||
3287 | } |
||||||
3288 |