Total Complexity | 603 |
Total Lines | 2623 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like infolog_ui often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use infolog_ui, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
23 | class infolog_ui |
||
24 | { |
||
25 | var $public_functions = array( |
||
26 | 'index' => True, |
||
27 | 'edit' => True, |
||
28 | 'delete' => True, |
||
29 | 'close' => True, |
||
30 | 'admin' => True, |
||
31 | 'hook_view' => True, |
||
32 | 'writeLangFile' => True, |
||
33 | 'mail_import' => True |
||
34 | ); |
||
35 | /** |
||
36 | * reference to the infolog preferences of the user |
||
37 | * |
||
38 | * @var array |
||
39 | */ |
||
40 | var $prefs; |
||
41 | /** |
||
42 | * instance of the bo-class |
||
43 | * |
||
44 | * @var infolog_bo |
||
45 | */ |
||
46 | var $bo; |
||
47 | /** |
||
48 | * instance of the etemplate class |
||
49 | * |
||
50 | * @var Etemplate |
||
51 | */ |
||
52 | var $tmpl; |
||
53 | /** |
||
54 | * allowed units and hours per day, can be overwritten by the projectmanager configuration, default all units, 8h |
||
55 | * |
||
56 | * @var string |
||
57 | */ |
||
58 | var $duration_format = ','; // comma is necessary! |
||
59 | |||
60 | var $icons = array( |
||
61 | 'type' => array( |
||
62 | 'task' => 'task.gif', 'task_alt' => 'Task', |
||
63 | 'phone' => 'phone.gif', 'phone_alt' => 'Phonecall', |
||
64 | 'note' => 'note.gif', 'note_alt' => 'Note', |
||
65 | 'confirm' => 'confirm.gif', 'confirm_alt' => 'Confirmation', |
||
66 | 'reject' => 'reject.gif', 'reject_alt' => 'Reject', |
||
67 | 'email' => 'email.gif', 'email_alt' => 'Email' ), |
||
68 | 'action' => array( |
||
69 | 'new' => 'new.gif', 'new_alt' => 'Add Sub', |
||
70 | 'view' => 'view.gif', 'view_alt' => 'View Subs', |
||
71 | 'parent' => 'parent.gif', 'parent_alt' => 'View other Subs', |
||
72 | 'edit' => 'edit.gif', 'edit_alt' => 'Edit', |
||
73 | 'addfile' => 'addfile.gif', 'addfile_alt' => 'Add a file', |
||
74 | 'delete' => 'delete.gif', 'delete_alt' => 'Delete', |
||
75 | 'close' => 'done.gif', 'close_alt' => 'Close' , |
||
76 | 'close_all' => 'done_all.gif', 'close_all_alt' => 'Close' ), |
||
77 | 'status' => array( |
||
78 | 'billed' => 'billed.gif', 'billed_alt' => 'billed', |
||
79 | 'done' => 'done.gif', 'done_alt' => 'done', |
||
80 | 'will-call' => 'will-call.gif', 'will-call_alt' => 'will-call', |
||
81 | 'call' => 'call.gif', 'call_alt' => 'call', |
||
82 | 'ongoing' => 'ongoing.gif', 'ongoing_alt' => 'ongoing', |
||
83 | 'offer' => 'offer.gif', 'offer_alt' => 'offer' ) |
||
84 | ); |
||
85 | var $filters; |
||
86 | var $messages = array( |
||
87 | 'edit' => 'InfoLog - Edit', |
||
88 | 'add' => 'InfoLog - New', |
||
89 | 'add_sub' => 'InfoLog - New Subproject', |
||
90 | 'sp' => '- Subprojects from', |
||
91 | ); |
||
92 | |||
93 | /** |
||
94 | * Constructor |
||
95 | * |
||
96 | * @return infolog_ui |
||
97 | */ |
||
98 | function __construct(Etemplate $etemplate = null) |
||
149 | } |
||
150 | |||
151 | /** |
||
152 | * Sets additional fields for one infolog entry, which are not persistent in the DB |
||
153 | * |
||
154 | * @param array $info infolog entry read from the db |
||
155 | * @param array &$readonlys ACL specific settings for the buttons |
||
156 | * @param string $action |
||
157 | * @param string/int $action_id |
||
158 | * @param boolean $show_links |
||
159 | * @param int $details |
||
160 | * @return array |
||
161 | */ |
||
162 | function get_info($info,&$readonlys,$action='',$action_id='',$show_links=false,$details = 1) |
||
273 | } |
||
274 | |||
275 | /** |
||
276 | * Check if no filter is active |
||
277 | * |
||
278 | * @param array $query |
||
279 | * @return string name of 1. filter found or null |
||
280 | */ |
||
281 | protected static function filter(array $query) |
||
282 | { |
||
283 | $filter = $query['filter'] ? 'filter' : ($query['cat_id'] ? 'cat_id' : null); |
||
284 | foreach((array)$query['col_filter'] as $name => $value) |
||
285 | { |
||
286 | if ((string)$value !== '') |
||
287 | { |
||
288 | $filter = $name; |
||
289 | break; |
||
290 | } |
||
291 | } |
||
292 | //error_log(__METHOD__."(col_filter=".array2string($query['col_filter']).") returning ".array2string($filter)); |
||
293 | return $filter; |
||
294 | } |
||
295 | |||
296 | /** |
||
297 | * Callback for nextmatch widget |
||
298 | * |
||
299 | * @param array &$query |
||
300 | * @param array &$rows |
||
301 | * @param array &$readonlys |
||
302 | * @return int |
||
303 | */ |
||
304 | function get_rows(&$query,&$rows,&$readonlys) |
||
305 | { |
||
306 | //error_log(__METHOD__."() query[csv_export]=".array2string($query['csv_export']).", query[filter]=".array2string($query['filter']).", query[col_filter]=".array2string(array_diff($query['col_filter'],array('',0))).' '.function_backtrace()); |
||
307 | if (!$query['csv_export']) |
||
308 | { |
||
309 | unset($query['no_actions']); |
||
310 | if (!$query['col_filter']['parent_id'] && !$query['search'] && |
||
311 | ($this->prefs['listNoSubs'] == '1' || $this->prefs['listNoSubs'] === 'filter' && !self::filter($query))) |
||
312 | { |
||
313 | $parent_id = 0; |
||
314 | } |
||
315 | else |
||
316 | { |
||
317 | $parent_id = $query['col_filter']['parent_id']; |
||
318 | } |
||
319 | //error_log(__METHOD__."() prefs[listNoSubs]=".array2string($this->prefs['listNoSubs'])." --> parent_id=$parent_id"); |
||
320 | unset($query['col_filter']['parent_id']); |
||
321 | if(!$query['action']) |
||
322 | { |
||
323 | Api\Cache::setSession('infolog', $query['session_for'].'session_data', |
||
324 | array_diff_key ($query, array_flip(array('rows','actions','action_links','placeholder_actions')))); |
||
325 | } |
||
326 | $query['actions'] = $this->get_actions($query); |
||
327 | $query['row_id'] = 'info_id'; |
||
328 | $query['row_modified'] = 'row_mod'; |
||
329 | $query['parent_id'] = 'info_id_parent'; |
||
330 | $query['is_parent'] = 'info_anz_subs'; |
||
331 | $query['action_var'] = 'multi_action'; // as 'action' is already used in infolog |
||
332 | } |
||
333 | // nextmatch opened an infolog containing children --> do not filter them, always show all children |
||
334 | elseif($query['csv_export'] === 'children') |
||
335 | { |
||
336 | $query['filter'] = $query['search'] = $query['cat_id'] = ''; |
||
337 | $query['col_filter'] = array('info_id_parent' => $query['col_filter']['info_id_parent']); |
||
338 | } |
||
339 | |||
340 | $GLOBALS['egw']->session->commit_session(); |
||
341 | $orginal_colfilter = $query['col_filter']; |
||
342 | if (isset($parent_id)) $query['col_filter']['info_id_parent'] = (string)$parent_id; |
||
343 | |||
344 | //echo "<p>infolog_ui.get_rows(start=$query[start],search='$query[search]',filter='$query[filter]',cat_id=$query[cat_id],action='$query[action]/$query[action_id]',col_filter=".print_r($query['col_filter'],True).",sort=$query[sort],order=$query[order])</p>\n"; |
||
345 | if (!isset($query['start'])) $query['start'] = 0; |
||
346 | |||
347 | // handle action and linked filter (show only entries linked to a certain other entry) |
||
348 | $link_filters = array(); |
||
349 | $links = array(); |
||
350 | if ($query['col_filter']['linked']) |
||
351 | { |
||
352 | $link_filters['linked'] = $query['col_filter']['linked']; |
||
353 | $links['linked'] = array(); |
||
354 | unset($query['col_filter']['linked']); |
||
355 | } |
||
356 | if($query['action'] && in_array($query['action'], array_keys($GLOBALS['egw_info']['apps'])) && $query['action_id']) |
||
357 | { |
||
358 | $link_filters['action'] = array('app'=>$query['action'], 'id' => $query['action_id']); |
||
359 | $links['action'] = array(); |
||
360 | } |
||
361 | foreach($link_filters as $key => $link) |
||
362 | { |
||
363 | if(!is_array($link)) |
||
364 | { |
||
365 | // Legacy string style |
||
366 | list($app,$id) = explode(':',$link); |
||
367 | } |
||
368 | else |
||
369 | { |
||
370 | // Full info |
||
371 | $app = $link['app']; |
||
372 | $id = $link['id']; |
||
373 | } |
||
374 | if(!is_array($id)) $id = explode(',',$id); |
||
375 | if (!($linked = Link::get_links_multiple($app,$id,true,'infolog','',$query['col_filter']['info_status'] == 'deleted'))) |
||
376 | { |
||
377 | $rows = array(); // no infologs linked to selected link --> no rows to return |
||
378 | return 0; |
||
379 | } |
||
380 | |||
381 | |||
382 | foreach($linked as $infos) |
||
383 | { |
||
384 | $links[$key] = array_merge($links[$key],$infos); |
||
385 | } |
||
386 | $links[$key] = array_unique($links[$key]); |
||
387 | if($key == 'linked') |
||
388 | { |
||
389 | $linked = array('app' => $app, 'id' => $id, 'title' => (count($id) == 1 ? Link::title($app, $id) : lang('multiple'))); |
||
390 | } |
||
391 | } |
||
392 | if(count($links)) |
||
393 | { |
||
394 | $query['col_filter']['info_id'] = count($links) > 1 ? call_user_func_array('array_intersect', $links) : $links[$key]; |
||
395 | } |
||
396 | |||
397 | // check if we have a custom, type-specific template |
||
398 | $old_template = $query['template']; |
||
399 | |||
400 | // Reset custom, type-specific template if type was cleared (without changing it for home) |
||
401 | if(!$query['template'] || stripos($query['template'], 'infolog.index.rows') === 0) |
||
402 | { |
||
403 | $query['template'] = 'infolog.index.rows'; |
||
404 | } |
||
405 | unset($query['custom_fields']); |
||
406 | if ($query['col_filter']['info_type']) |
||
407 | { |
||
408 | $tpl = new Etemplate; |
||
409 | if ($tpl->read('infolog.index.rows.'.$query['col_filter']['info_type'])) |
||
410 | { |
||
411 | $query['template'] = $tpl->name; |
||
412 | $query['custom_fields'] = true; // read the custom fields too |
||
413 | } |
||
414 | // If status is not valid for selected type, clear status filter |
||
415 | if($query['col_filter']['info_status'] && $query['col_filter']['info_status'] != 'deleted' && |
||
416 | !in_array($query['col_filter']['info_status'], array_keys($this->bo->status[$query['col_filter']['info_type']]))) |
||
417 | { |
||
418 | $query['col_filter']['info_status'] = ''; |
||
419 | $clear_status_filter = true; |
||
420 | } |
||
421 | } |
||
422 | // Framework\Template change forces the UI to do a full update first, no point in getting rows right now |
||
423 | if($old_template && $old_template != $query['template']) return 0; |
||
424 | |||
425 | // do we need to read the custom fields, depends on the column is enabled and customfields exist, prefs are filter specific |
||
426 | // so we have to check that as well |
||
427 | $details = $query['filter2'] == 'all'; |
||
428 | $columnselection_pref = 'nextmatch-'.($query['action'] ? 'infolog.'.$query['action'] : ($tpl && $tpl->name == $query['template'] ? $query['template'] : 'infolog.index.rows')) |
||
429 | .($details ? '-details' : ''); |
||
430 | //error_log(__METHOD__."(start=$query[start], num_rows=$query[num_rows]) query[col_filter][info_type]={$query['col_filter']['info_type']} --> query[template]=$query[template], columselection_pref=$columnselection_pref"); |
||
431 | |||
432 | $columselection = $this->prefs[$columnselection_pref]; |
||
433 | |||
434 | if (!$query['selectcols'] && $columselection) |
||
435 | { |
||
436 | $columselection = is_array($columselection) ? $columselection : explode(',',$columselection); |
||
437 | } |
||
438 | else |
||
439 | { |
||
440 | $columselection = $query['selectcols'] ? (is_array($query['selectcols']) ? $query['selectcols'] : explode(',',$query['selectcols'])) : array(); |
||
441 | } |
||
442 | // do we need to query the cf's |
||
443 | $query['custom_fields'] = $this->bo->customfields && (!$columselection || in_array('customfields',$columselection)); |
||
444 | |||
445 | $infos = $this->bo->search($query); |
||
446 | $query['col_filter'] = $orginal_colfilter; |
||
447 | if (!is_array($infos)) |
||
448 | { |
||
449 | $infos = array( ); |
||
450 | } |
||
451 | // add a '-details' to the name of the columnselection pref |
||
452 | if ($details) |
||
453 | { |
||
454 | $query['default_cols'] = '!cat_id,info_used_time_info_planned_time,info_used_time_info_planned_time_info_replanned_time,info_id'; |
||
455 | } |
||
456 | else |
||
457 | { |
||
458 | $query['default_cols'] = '!cat_id,info_datemodified,info_used_time_info_planned_time,info_used_time_info_planned_time_info_replanned_time,info_id'; |
||
459 | } |
||
460 | // set old show_times pref, that get_info calculates the cumulated time of the timesheets (we only check used&planned to work for both time cols) |
||
461 | $this->prefs['show_times'] = strpos($this->prefs[$query['columnselection_pref']],'info_used_time_info_planned_time') !== false; |
||
462 | |||
463 | // query all links and sub counts in one go |
||
464 | if ($infos && (!$query['csv_export'] || !is_array($query['csv_export']))) |
||
465 | { |
||
466 | $links = Link::get_links_multiple('infolog',array_keys($infos),true,'','link_lastmod DESC',true); // true=incl. deleted |
||
467 | $anzSubs = $this->bo->anzSubs(array_keys($infos)); |
||
468 | } |
||
469 | $rows = array(); |
||
470 | |||
471 | // Don't add parent in if info_id_parent (expanding to show subs) |
||
472 | if ($query['action_id'] && $query['csv_export'] !== 'children') |
||
473 | { |
||
474 | $parents = $query['action'] == 'sp' && $query['action_id'] ? (array)$query['action_id'] : array(); |
||
475 | if (!empty($parents) && count($parents) == 1 && is_array($query['action_id'])) |
||
476 | { |
||
477 | $query['action_id'] = array_shift($query['action_id']); // display single parent as app_header |
||
478 | } |
||
479 | } |
||
480 | |||
481 | $parent_first = !empty($parents) && count($parents) == 1; |
||
482 | $parent_index = 0; |
||
483 | // et2 nextmatch listens to total, and only displays that many rows, so add parent in or we'll lose the last row |
||
484 | if($parent_first || $query['action'] == 'sp' && is_array($query['action_id'])) $query['total']++; |
||
485 | |||
486 | // Check to see if we need to remove description |
||
487 | foreach($infos as $id => $info) |
||
488 | { |
||
489 | if (!$query['csv_export'] || !is_array($query['csv_export'])) |
||
490 | { |
||
491 | $info['links'] =& $links[$id]; |
||
492 | $info['info_anz_subs'] = (int)$anzSubs[$id]; |
||
493 | $info = $this->get_info($info,$readonlys,null,null,false,$details); |
||
494 | } |
||
495 | // for subs view ('sp') add parent(s) in front of subs once(!) |
||
496 | if ( $parent_first && ($main = $this->bo->read($query['action_id'])) || |
||
497 | $parents && ($parent_index = array_search($info['info_id_parent'], $parents)) !== false && |
||
498 | ($main = $this->bo->read($info['info_id_parent']))) |
||
499 | { |
||
500 | $main = $this->get_info($main, $readonlys); |
||
501 | $main['class'] .= 'th '; |
||
502 | // if only certain custom-fields are to be displayed, we need to unset the not displayed ones manually |
||
503 | // as read() always read them all, while search() only reads the selected ones |
||
504 | if ($query['custom_fields']) |
||
505 | { |
||
506 | foreach($columselection as $col) |
||
507 | { |
||
508 | if ($col[0] == '#') |
||
509 | { |
||
510 | foreach(array_keys($main) as $n) |
||
511 | { |
||
512 | if ($n[0] == '#' && !in_array($n, $columselection)) unset($main[$n]); |
||
513 | } |
||
514 | break; |
||
515 | } |
||
516 | } |
||
517 | } |
||
518 | $parent_first = false; |
||
519 | if($query['start'] == 0) |
||
520 | { |
||
521 | array_splice($rows, $id, 0, array($main)); |
||
522 | unset($parents[$parent_index]); |
||
523 | } |
||
524 | } |
||
525 | $rows[] = $info; |
||
526 | } |
||
527 | unset($links); |
||
528 | |||
529 | if ($query['cat_id']) $rows['no_cat_id'] = true; |
||
530 | if ($query['no_actions']) $rows['no_actions'] = true; |
||
531 | $rows['no_timesheet'] = !isset($GLOBALS['egw_info']['user']['apps']['timesheet']); |
||
532 | if($clear_status_filter) |
||
533 | { |
||
534 | $rows['info_status'] = ''; |
||
535 | } |
||
536 | |||
537 | // switch cf column off, if we have no cf's |
||
538 | $rows['no_customfields'] = !$query['custom_fields']; |
||
539 | |||
540 | $rows['no_info_owner_info_responsible'] = ( |
||
541 | $GLOBALS['egw_info']['user']['preferences']['common']['account_selection'] == 'none' && |
||
542 | !isset($GLOBALS['egw_info']['user']['apps']['admin']) |
||
543 | ); |
||
544 | |||
545 | // if filtered by type, show only the stati of the filtered type |
||
546 | $rows['sel_options']['info_status'] = $this->bo->get_status($query['col_filter']['info_type']); |
||
547 | |||
548 | if ($this->bo->history) |
||
549 | { |
||
550 | $rows['sel_options']['info_status']['deleted'] = 'deleted'; |
||
551 | } |
||
552 | // Update actions for selected type / status / etc. |
||
553 | $query['actions'] = $this->get_actions($query); |
||
554 | |||
555 | if ($GLOBALS['egw_info']['flags']['currentapp'] == 'infolog' && !$this->called_by) |
||
556 | { |
||
557 | $headers = array(); |
||
558 | if ($query['filter'] != '' && !empty($this->filters[$query['filter']])) |
||
559 | { |
||
560 | $headers[] = lang($this->filters[$query['filter']]); |
||
561 | } |
||
562 | if ($query['action'] && ($title = $query['action_title'] || is_array($query['action_id']) ? |
||
563 | $query['action_title'] : Link::title($query['action']=='sp'?'infolog':$query['action'],$query['action_id']))) |
||
564 | { |
||
565 | $headers[] = $title; |
||
566 | } |
||
567 | if ($query['search']) |
||
568 | { |
||
569 | $headers[] = lang("Search for '%1'", $query['search']); |
||
570 | } |
||
571 | $GLOBALS['egw_info']['flags']['app_header'] = implode(': ', $headers); |
||
572 | } |
||
573 | |||
574 | if (isset($linked)) $query['col_filter']['linked'] = $linked; // add linked back to the colfilter |
||
575 | |||
576 | return $query['total']; |
||
577 | } |
||
578 | |||
579 | /** |
||
580 | * Hook for timesheet to set some extra data and links |
||
581 | * |
||
582 | * @param array $data |
||
583 | * @param int $data[id] info_id |
||
584 | * @return array with key => value pairs to set in new timesheet and link_app/link_id arrays |
||
585 | */ |
||
586 | function timesheet_set($data) |
||
587 | { |
||
588 | $set = array(); |
||
589 | if ((int)$data['id'] && ($info = $this->bo->read($data['id']))) |
||
590 | { |
||
591 | if ($info['info_cat']) $set['cat_id'] = $info['info_cat']; |
||
592 | if ($info['info_used_time']) |
||
593 | { |
||
594 | $set['ts_duration'] = $info['info_used_time']; |
||
595 | } |
||
596 | if ($info['pl_id']) |
||
597 | { |
||
598 | $set['pl_id'] = $info['pl_id']; |
||
599 | } |
||
600 | if ($info['info_price']) |
||
601 | { |
||
602 | $set['ts_unitprice'] = $info['info_price']; |
||
603 | } |
||
604 | |||
605 | foreach(Link::get_links('infolog',$info['info_id'],'','link_lastmod DESC',true) as $link) |
||
606 | { |
||
607 | if ($link['app'] != 'timesheet' && $link['app'] != Link::VFS_APPNAME) |
||
608 | { |
||
609 | $set['link_app'][] = $link['app']; |
||
610 | $set['link_id'][] = $link['id']; |
||
611 | } |
||
612 | } |
||
613 | |||
614 | } |
||
615 | return $set; |
||
616 | } |
||
617 | |||
618 | /** |
||
619 | * Hook for calendar to set some extra data and links |
||
620 | * |
||
621 | * @param array $data event-array preset by calendar plus |
||
622 | * @param int $data[entry_id] info_id |
||
623 | * @return array with key => value pairs to set in new event and link_app/link_id arrays |
||
624 | */ |
||
625 | function calendar_set($data) |
||
626 | { |
||
627 | if (!($infolog = $this->bo->read($data['entry_id']))) |
||
628 | { |
||
629 | return $data; |
||
630 | } |
||
631 | $event = array_merge($data,array( |
||
632 | 'category' => $GLOBALS['egw']->categories->check_list(Acl::READ, $infolog['info_cat']), |
||
633 | 'priority' => $infolog['info_priority'] + 1, |
||
634 | 'public' => $infolog['info_access'] != 'private', |
||
635 | 'title' => $infolog['info_subject'], |
||
636 | 'description' => $infolog['info_des'], |
||
637 | 'location' => $infolog['info_location'], |
||
638 | 'start' => $infolog['info_startdate'], |
||
639 | 'end' => $infolog['info_enddate'] ? $infolog['info_enddate'] : $infolog['info_datecompleted'] |
||
640 | )); |
||
641 | unset($event['entry_id']); |
||
642 | if (!$event['end']) $event['end'] = $event['start'] + (int) $GLOBALS['egw_info']['user']['preferences']['calendar']['defaultlength']*60; |
||
643 | |||
644 | // Match Api\Categories by name |
||
645 | $event['category'] = $GLOBALS['egw']->categories->name2id(Api\Categories::id2name($infolog['info_cat'])); |
||
646 | |||
647 | // make current user the owner of the new event, not the selected calendar, if current user has rights for it |
||
648 | $event['owner'] = $user = $GLOBALS['egw_info']['user']['account_id']; |
||
649 | |||
650 | // add/modify participants according to prefs |
||
651 | $prefs = explode(',',$this->prefs['calendar_set'] ? $this->prefs['calendar_set'] : 'responsible,contact,user'); |
||
652 | |||
653 | // if no default participants (selected calendars) --> remove all |
||
654 | if (!in_array('selected',$prefs)) |
||
655 | { |
||
656 | $event['participants'] = $event['participant_types'] = array(); |
||
657 | } |
||
658 | // Add responsible as participant |
||
659 | if (in_array('responsible',$prefs)) |
||
660 | { |
||
661 | foreach($infolog['info_responsible'] as $responsible) |
||
662 | { |
||
663 | $event['participants'][$responsible] = $event['participant_types']['u'][$responsible] = |
||
664 | calendar_so::combine_status($user==$responsible?'A':'U'); |
||
665 | } |
||
666 | } |
||
667 | // Add linked contact as participant |
||
668 | if (in_array('contact',$prefs) && $infolog['info_link']['app'] == 'addressbook') |
||
669 | { |
||
670 | $event['participants'][calendar_so::combine_user('c',$infolog['info_link']['id'])] = |
||
671 | $event['participant_types']['c'][$infolog['info_link']['id']] = calendar_so::combine_status('U'); |
||
672 | } |
||
673 | if (in_array('owner',$prefs)) |
||
674 | { |
||
675 | $event['participants'][$infolog['info_owner']] = $event['participant_types']['u'][$infolog['info_owner']] = |
||
676 | calendar_so::combine_status('A',1,'CHAIR'); |
||
677 | } |
||
678 | // Add current user, if set or no other participants, which is not allowed |
||
679 | if (in_array('user',$prefs)) |
||
680 | { |
||
681 | $event['participants'][$user] = $event['participant_types']['u'][$user] = |
||
682 | calendar_so::combine_status('A',1,'CHAIR'); |
||
683 | } |
||
684 | |||
685 | // Add infolog link to calendar entry |
||
686 | $event['link_app'][] = $infolog['info_link']['app']; |
||
687 | $event['link_id'][] = $infolog['info_link']['id']; |
||
688 | |||
689 | // Copy infolog's links |
||
690 | foreach(Link::get_links('infolog',$infolog['info_id'],'','link_lastmod DESC',true) as $link) |
||
691 | { |
||
692 | if ($link['app'] != Link::VFS_APPNAME) |
||
693 | { |
||
694 | $event['link_app'][] = $link['app']; |
||
695 | $event['link_id'][] = $link['id']; |
||
696 | } |
||
697 | } |
||
698 | // Copy same custom fields |
||
699 | foreach(array_keys(Api\Storage\Customfields::get('calendar')) as $name) |
||
700 | { |
||
701 | if ($this->bo->customfields[$name]) $event['#'.$name] = $infolog['#'.$name]; |
||
702 | } |
||
703 | //error_log(__METHOD__.'('.array2string($data).') infolog='.array2string($infolog).' returning '.array2string($event)); |
||
704 | return $event; |
||
705 | } |
||
706 | |||
707 | /** |
||
708 | * hook called be calendar to include events or todos in the cal-dayview |
||
709 | * Since the hook has no idea about infolog or preferences, we add the user's |
||
710 | * current sorting for infolog here so they're in the expected order |
||
711 | * |
||
712 | * @param int $args[year], $args[month], $args[day] date of the events |
||
713 | * @param int $args[owner] owner of the events |
||
714 | * @param string $args[location] calendar_include_{events|todos} |
||
715 | * @return array of events (array with keys starttime, endtime, title, view, icon, content) |
||
716 | */ |
||
717 | public function cal_to_include($args) |
||
718 | { |
||
719 | $nm = Api\Cache::getSession('infolog', 'session_data'); |
||
720 | if($nm) |
||
721 | { |
||
722 | $args['order'] = $nm['order']; |
||
723 | $args['sort'] = $nm['sort']; |
||
724 | } |
||
725 | |||
726 | return $this->bo->cal_to_include($args); |
||
727 | } |
||
728 | |||
729 | /** |
||
730 | * Shows the infolog list |
||
731 | * |
||
732 | * @param array/string $values etemplate content or 'reset_action_view' if called by index.php to reset an action-view |
||
733 | * @param string $action if set only entries liked to that $action:$action_id are shown |
||
734 | * @param string $action_id if set only entries liked to that $action:$action_id are shown |
||
735 | * @param mixed $called_as is how we got called, for a hook eg. the call-params of that page containing the hook |
||
736 | * @param boolean $e$extra_app_header * @param boolean $return_html=false |
||
737 | * @param string $own_referer='' this is our own referer |
||
738 | * @param string $action_title='' app_header for the action, if '' we try the link-title |
||
739 | */ |
||
740 | function index($values = null,$action='',$action_id='',$called_as=0,$extra_app_header=False,$return_html=False,$own_referer='',$action_title='') |
||
741 | { |
||
742 | unset($extra_app_header); // not used, but dont want to change signature |
||
743 | if (is_array($values)) |
||
744 | { |
||
745 | $called_as = $values['called_as']; |
||
746 | $own_referer = $values['own_referer']; |
||
747 | } |
||
748 | elseif ($own_referer === '') |
||
749 | { |
||
750 | $own_referer = Api\Header\Referer::get(); |
||
751 | if (strpos($own_referer,'menuaction=infolog.infolog_ui.edit') !== false) |
||
752 | { |
||
753 | $own_referer = Api\Cache::getSession('infolog', 'own_session'); |
||
754 | } |
||
755 | else |
||
756 | { |
||
757 | Api\Cache::setSession('infolog', 'own_session', $own_referer); |
||
758 | } |
||
759 | } |
||
760 | |||
761 | // Handle legacy buttons like actions |
||
762 | if(is_array($values)) |
||
763 | { |
||
764 | foreach(array('document', 'view', 'delete') as $button) |
||
765 | { |
||
766 | if(isset($values['nm']['rows'][$button])) |
||
767 | { |
||
768 | $id = @key($values['nm']['rows'][$button]); |
||
769 | $values['nm']['multi_action'] = $button; |
||
770 | $values['nm']['selected'] = array($id); |
||
771 | break; // Only one can come per submit |
||
772 | } |
||
773 | } |
||
774 | } |
||
775 | if (is_array($values) && !empty($values['nm']['multi_action'])) |
||
776 | { |
||
777 | if (empty($values['nm']['selected']) && !$values['nm']['select_all']) |
||
778 | { |
||
779 | $msg = lang('You need to select some entries first'); |
||
780 | } |
||
781 | else |
||
782 | { |
||
783 | // Some processing to add values in for links and cats |
||
784 | $multi_action = $values['nm']['multi_action']; |
||
785 | // Action has an additional action - add / delete, etc. Buttons named <multi-action>_action[action_name] |
||
786 | if(in_array($multi_action, array('link', 'responsible', 'startdate', 'enddate'))) |
||
787 | { |
||
788 | // eTemplate ignores the _popup namespace, but et2 doesn't |
||
789 | if($values[$multi_action.'_popup']) |
||
790 | { |
||
791 | $popup =& $values[$multi_action.'_popup']; |
||
792 | } |
||
793 | else |
||
794 | { |
||
795 | $popup =& $values; |
||
796 | } |
||
797 | $values['nm']['multi_action'] .= '_' . key($popup[$multi_action . '_action']); |
||
798 | if($multi_action == 'link') |
||
799 | { |
||
800 | $popup[$multi_action] = $popup['link']['app'] . ':'.$popup['link']['id']; |
||
801 | } |
||
802 | else if(is_array($popup[$multi_action])) |
||
803 | { |
||
804 | $popup[$multi_action] = implode(',',$popup[$multi_action]); |
||
805 | } |
||
806 | $values['nm']['multi_action'] .= '_' . $popup[$multi_action]; |
||
807 | unset($values[$multi_action.'_popup']); |
||
808 | unset($values[$multi_action]); |
||
809 | } |
||
810 | $success = $failed = $action_msg = null; |
||
811 | if ($this->action($values['nm']['multi_action'], $values['nm']['selected'], $values['nm']['select_all'], |
||
812 | $success, $failed, $action_msg, $values['nm'], $msg, $values['nm']['checkboxes']['no_notifications'])) |
||
813 | { |
||
814 | $msg .= lang('%1 entries %2',$success,$action_msg); |
||
815 | Framework::message($msg); |
||
816 | } |
||
817 | elseif(is_null($msg)) |
||
818 | { |
||
819 | $msg .= lang('%1 entries %2, %3 failed because of insufficent rights !!!',$success,$action_msg,$failed); |
||
820 | Framework::message($msg,'error'); |
||
821 | } |
||
822 | elseif($msg) |
||
823 | { |
||
824 | $msg .= "\n".lang('%1 entries %2, %3 failed.',$success,$action_msg,$failed); |
||
825 | Framework::message($msg,'error'); |
||
826 | } |
||
827 | unset($values['nm']['multi_action']); |
||
828 | unset($values['nm']['select_all']); |
||
829 | } |
||
830 | } |
||
831 | if (!$action) |
||
832 | { |
||
833 | $action = is_array($values) && $values['action'] ? $values['action'] : $_REQUEST['action']; |
||
834 | $action_id = is_array($values) && $values['action_id'] ? $values['action_id'] : $_REQUEST['action_id']; |
||
835 | $action_title = is_array($values) && $values['action_title'] ? $values['action_title'] : $_REQUEST['action_title']; |
||
836 | } |
||
837 | //echo "<p>".__METHOD__."(action='$action/$action_id',called_as='$called_as/$values[referer]',own_referer='$own_referer') values=\n"; _debug_array($values); |
||
838 | if (!is_array($values)) |
||
839 | { |
||
840 | $nm = Api\Cache::getSession('infolog', $this->called_by.'session_data'); |
||
841 | unset($nm['rows']); |
||
842 | if ($values === 'reset_action_view') |
||
843 | { |
||
844 | $action = ''; |
||
845 | $action_id = 0; |
||
846 | $action_title = ''; |
||
847 | } |
||
848 | if($_GET['ajax'] === 'true') |
||
849 | { |
||
850 | $nm['action'] = ''; |
||
851 | $nm['action_id'] = 0; |
||
852 | $nm['action_title'] = ''; |
||
853 | // check if action-view reset filter and restore it |
||
854 | if (($filter = Api\Cache::getSession('infolog', 'filter_reset_from'))) |
||
855 | { |
||
856 | $nm['filter'] = $filter; |
||
857 | Api\Cache::unsetSession('infolog', 'filter_reset_from'); |
||
858 | } |
||
859 | } |
||
860 | $values = array('nm' => $nm); |
||
861 | |||
862 | if (isset($_GET['filter']) && $_GET['filter'] != 'default' || !isset($values['nm']['filter']) && !$this->called_by) |
||
863 | { |
||
864 | $values['nm']['filter'] = $_GET['filter'] && $_GET['filter'] != 'default' ? $_GET['filter'] : |
||
865 | $this->prefs['defaultFilter']; |
||
866 | } |
||
867 | if (!isset($values['nm']['order']) || !$values['nm']['order']) |
||
868 | { |
||
869 | $values['nm']['order'] = 'info_datemodified'; |
||
870 | $values['nm']['sort'] = 'DESC'; |
||
871 | } |
||
872 | |||
873 | if (!$values['nm']['session_for'] && $this->called_by) $values['nm']['session_for'] = $this->called_by; |
||
874 | |||
875 | $action_id = $values['action_id'] = $action ? $action_id : $nm['action_id']; |
||
876 | $action_title = $values['action_title'] = $action ? $action_title : $nm['action_title']; |
||
877 | $action = $values['action'] = $action ? $action : $nm['action']; |
||
878 | } |
||
879 | if($_GET['search']) $values['nm']['search'] = $_GET['search']; |
||
880 | |||
881 | if ($values['nm']['add']) |
||
882 | { |
||
883 | $values['add'] = $values['nm']['add']; |
||
884 | unset($values['nm']['add']); |
||
885 | } |
||
886 | unset($values['nm']['rows']['checked']); // not longer used, but hides button actions |
||
887 | |||
888 | switch ($action) |
||
889 | { |
||
890 | case 'sp': |
||
891 | if (!is_array($action_id) && strpos($action_id, 'infolog:') === 0) $action_id = (int)substr($action_id, 8); |
||
892 | if ((is_array($action_id) && !$this->bo->read(current($action_id))) || !$this->bo->read($action_id)) |
||
893 | { |
||
894 | $action = ''; |
||
895 | $action_id = 0; |
||
896 | break; |
||
897 | } |
||
898 | else |
||
899 | { |
||
900 | $values['nm']['col_filter']['info_id_parent'] = $action_id; |
||
901 | } |
||
902 | break; |
||
903 | default: |
||
904 | // Nothing |
||
905 | } |
||
906 | $readonlys['cancel'] = $action != 'sp'; |
||
907 | |||
908 | $this->tmpl->read('infolog.index'); |
||
909 | $values['nm']['options-filter'] = $this->filters; |
||
910 | $values['nm']['get_rows'] = 'infolog.infolog_ui.get_rows'; |
||
911 | $values['nm']['options-filter2'] = (in_array($this->prefs['show_links'],array('all','no_describtion')) ? array() : array( |
||
912 | '' => 'default', |
||
913 | )) + array( |
||
914 | 'no_describtion' => 'no details', |
||
915 | 'all' => 'details', |
||
916 | ); |
||
917 | |||
918 | //apply infolog_filter_change javascript method (hide/show of date filter form) over onchange filter |
||
919 | $values['nm']['filter_onchange'] = "app.infolog.filter_change();"; |
||
920 | |||
921 | //apply infolog_filter2_change javascript method (show/hide details each rows) over onchange filter2 |
||
922 | $values['nm']['filter2_onchange'] = "return app.infolog.filter2_change(ev, widget)"; |
||
923 | |||
924 | // disable favories dropdown button, if not running as infolog |
||
925 | if ($called_as && $called_as != 'infolog') |
||
926 | { |
||
927 | $values['nm']['favorites'] = false; |
||
928 | } |
||
929 | else |
||
930 | { |
||
931 | // Allow saving parent ID into favorites |
||
932 | $values['nm']['favorites'] = array('action','action_id'); |
||
933 | } |
||
934 | |||
935 | // Allow add actions even when there's no rows |
||
936 | $values['nm']['placeholder_actions'] = array('new'); |
||
937 | |||
938 | if(!isset($values['nm']['filter2'])) $values['nm']['filter2'] = $this->prefs['nextmatch-'.($action ? 'infolog.'.$action : 'infolog.index.rows').'-details-pref']; |
||
939 | |||
940 | // disable columns for main entry as set in the pref for details or no details |
||
941 | $values['nm']['columnselection_pref'] = 'nextmatch-'.($action ? 'infolog.'.$action : 'infolog.index.rows') |
||
942 | .($values['nm']['filter2']=='all' ? '-details' : ''); |
||
943 | if ($action == 'sp') |
||
944 | { |
||
945 | $pref = $values['nm']['columnselection_pref']; |
||
946 | foreach(array('info_used_time_info_planned_time_info_replanned_time','info_datemodified','info_owner_info_responsible','customfields') as $name) |
||
947 | { |
||
948 | $values['main']['no_'.$name] = strpos($this->prefs[$pref],$name) === false; |
||
949 | } |
||
950 | if (!$values['main']['no_customfields']) |
||
951 | { |
||
952 | // set the column-header of the main table for the customfields. |
||
953 | foreach(array_keys($this->bo->customfields) as $lname) |
||
954 | { |
||
955 | $values['main']['customfields'].=$lname."\n"; |
||
956 | } |
||
957 | } |
||
958 | } |
||
959 | if ($values['nm']['filter']=='bydate') |
||
960 | { |
||
961 | foreach (array_keys($values['nm']['col_filter']) as $colfk) |
||
962 | { |
||
963 | if (is_int($colfk)) unset($values['nm']['col_filter']); |
||
964 | } |
||
965 | } |
||
966 | $values['action'] = $persist['action'] = $values['nm']['action'] = $action; |
||
967 | $values['action_id'] = $persist['action_id'] = $values['nm']['action_id'] = $action_id; |
||
968 | $values['action_title'] = $persist['action_title'] = $values['nm']['action_title'] = $action_title; |
||
969 | $values['duration_format'] = ','.$this->duration_format; |
||
970 | $persist['called_as'] = $called_as; |
||
971 | $persist['own_referer'] = $own_referer; |
||
972 | |||
973 | // store whole $values[nm] in etemplate request |
||
974 | unset($values['nm']['rows']); |
||
975 | $persist['nm'] = $values['nm']; |
||
976 | |||
977 | if (!$called_as) |
||
978 | { |
||
979 | $GLOBALS['egw_info']['flags']['params']['manual'] = array('page' => 'ManualInfologIndex'); |
||
980 | } |
||
981 | else |
||
982 | { |
||
983 | $values['css'] = '<style type="text/css">@import url('.$GLOBALS['egw_info']['server']['webserver_url'].'/infolog/templates/default/app.css);'."</style>"; |
||
984 | // Avoid DOM conflicts |
||
985 | $this->tmpl->set_dom_id("{$this->tmpl->name}-$action-$action_id"); |
||
986 | } |
||
987 | // add scrollbar to long description, if user choose so in his prefs |
||
988 | if ($this->prefs['limit_des_lines'] > 0 || (string)$this->prefs['limit_des_lines'] == '') |
||
989 | { |
||
990 | $values['css'] .= '<style type="text/css">@media screen { .infoDes { '. |
||
991 | ' max-height: '. |
||
992 | (($this->prefs['limit_des_lines'] ? $this->prefs['limit_des_lines'] : 5) * 1.35). // dono why em is not real lines |
||
993 | 'em; overflow: auto; }}</style>'; |
||
994 | } |
||
995 | |||
996 | $sel_options = array( |
||
997 | 'info_type' => $this->bo->enums['type'], |
||
998 | 'pm_id' => array(lang('No project')), |
||
999 | 'info_priority' => $this->bo->enums['priority'], |
||
1000 | ); |
||
1001 | |||
1002 | // remove group-types user has not any rights to as filter |
||
1003 | // does not take implicit rights as delegated into account, so they will not be available as filters |
||
1004 | foreach($this->bo->group_owners as $type => $group) |
||
1005 | { |
||
1006 | if (!isset($this->bo->grants[$group])) unset($sel_options['info_type'][$type]); |
||
1007 | } |
||
1008 | |||
1009 | |||
1010 | return $this->tmpl->exec('infolog.infolog_ui.index',$values,$sel_options,$readonlys,$persist,$return_html ? -1 : 0); |
||
1011 | } |
||
1012 | |||
1013 | /** |
||
1014 | * Get valid types |
||
1015 | * |
||
1016 | * @return array - array of valid types |
||
1017 | */ |
||
1018 | private function get_validtypes() |
||
1034 | } |
||
1035 | |||
1036 | /** |
||
1037 | * Get actions / context menu items |
||
1038 | * |
||
1039 | * @param array $query |
||
1040 | * @return array see nextmatch_widget::get_actions() |
||
1041 | */ |
||
1042 | private function get_actions(array $query) |
||
1043 | { |
||
1044 | for($i = 0; $i <= 100; $i += 10) |
||
1045 | { |
||
1046 | $percent[$i] = $i.'%'; |
||
1047 | } |
||
1048 | // Types |
||
1049 | $types = $this->get_validtypes(); |
||
1050 | $types_add = array(); |
||
1051 | // Do not add deleted type to add or change menus |
||
1052 | unset($types['delete']); |
||
1053 | foreach($types as $type => &$data) |
||
1054 | { |
||
1055 | $image_exists = Api\Image::find('infolog',$type); |
||
1056 | $data = array( |
||
1057 | 'caption' => $data, |
||
1058 | 'icon' => $image_exists ? $type : 'infolog/navbar', |
||
1059 | ); |
||
1060 | $types_add[$type] = $data + array( |
||
1061 | 'onExecute' => "javaScript:app.infolog.add_action_handler" |
||
1062 | ); |
||
1063 | } |
||
1064 | |||
1065 | $icons = null; |
||
1066 | $statis = $this->bo->get_status($query['col_filter']['info_type'], $icons); |
||
1067 | foreach($statis as $type => &$data) |
||
1068 | { |
||
1069 | $image_exists = Api\Image::find('infolog',$icons[$type]); |
||
1070 | $data = array( |
||
1071 | 'caption' => $data, |
||
1072 | 'icon' => $image_exists ? $icons[$type] : 'infolog/status', |
||
1073 | ); |
||
1074 | } |
||
1075 | |||
1076 | $actions = array( |
||
1077 | 'open' => array( |
||
1078 | 'caption' => 'Open', |
||
1079 | 'default' => true, |
||
1080 | 'allowOnMultiple' => false, |
||
1081 | 'onExecute' => Api\Header\UserAgent::mobile()?'javaScript:app.infolog.viewEntry':'', |
||
1082 | 'url' => 'menuaction=infolog.infolog_ui.edit&info_id=$id', |
||
1083 | 'popup' => Link::get_registry('infolog', 'add_popup'), |
||
1084 | 'group' => $group=1, |
||
1085 | 'mobileViewTemplate' => 'view?'.filemtime(Api\Etemplate\Widget\Template::rel2path('/infolog/templates/mobile/view.xet')) |
||
1086 | ), |
||
1087 | 'parent' => array( |
||
1088 | 'caption' => 'View parent with children', |
||
1089 | 'icon' => 'up.grey', |
||
1090 | 'allowOnMultiple' => false, |
||
1091 | 'enabled' => 'javaScript:app.infolog.has_parent', |
||
1092 | 'onExecute' => 'javaScript:app.infolog.view_parent', |
||
1093 | 'group' => $group, |
||
1094 | 'hideOnMobile' => true |
||
1095 | ), |
||
1096 | 'add' => array( |
||
1097 | 'caption' => 'Add', |
||
1098 | 'group' => $group, |
||
1099 | 'children' => array( |
||
1100 | 'new' => array( |
||
1101 | 'caption' => 'New', |
||
1102 | 'children' => $types_add, |
||
1103 | 'icon' => 'task', |
||
1104 | ), |
||
1105 | 'sub' => array( |
||
1106 | 'caption' => 'Sub-entry', |
||
1107 | 'url' => 'menuaction=infolog.infolog_ui.edit&action=sp&action_id=$id', |
||
1108 | 'popup' => Link::get_registry('infolog', 'add_popup'), |
||
1109 | 'allowOnMultiple' => false, |
||
1110 | 'hint' => 'Add a new sub-task, -note, -call to this entry', |
||
1111 | 'icon' => 'new', |
||
1112 | ), |
||
1113 | 'copy' => array( |
||
1114 | 'caption' => 'Copy', |
||
1115 | 'url' => 'menuaction=infolog.infolog_ui.edit&action=copy&info_id=$id', |
||
1116 | 'popup' => Link::get_registry('infolog', 'add_popup'), |
||
1117 | 'allowOnMultiple' => false, |
||
1118 | 'icon' => 'copy', |
||
1119 | ), |
||
1120 | ), |
||
1121 | 'hideOnMobile' => true |
||
1122 | ), |
||
1123 | 'no_notifications' => array( |
||
1124 | 'caption' => 'Do not notify', |
||
1125 | 'checkbox' => true, |
||
1126 | 'confirm_mass_selection' => "You are going to change %1 entries: Are you sure you want to send notifications about this change?", |
||
1127 | 'hint' => 'Do not notify of these changes', |
||
1128 | 'group' => $group, |
||
1129 | ), |
||
1130 | // modifying content of one or multiple infolog(s) |
||
1131 | 'change' => array( |
||
1132 | 'caption' => 'Change', |
||
1133 | 'group' => ++$group, |
||
1134 | 'icon' => 'edit', |
||
1135 | 'disableClass' => 'rowNoEdit', |
||
1136 | 'confirm_mass_selection' => true, |
||
1137 | 'children' => array( |
||
1138 | 'type' => array( |
||
1139 | 'caption' => 'Type', |
||
1140 | 'prefix' => 'type_', |
||
1141 | 'children' => $types, |
||
1142 | 'group' => $group, |
||
1143 | 'icon' => 'task', |
||
1144 | ), |
||
1145 | 'status' => array( |
||
1146 | 'caption' => 'Status', |
||
1147 | 'prefix' => 'status_', |
||
1148 | 'children' => $statis, |
||
1149 | 'group' => $group, |
||
1150 | 'icon' => 'ongoing', |
||
1151 | ), |
||
1152 | 'completion' => array( |
||
1153 | 'caption' => 'Completed', |
||
1154 | 'prefix' => 'completion_', |
||
1155 | 'children' => $percent, |
||
1156 | 'group' => $group, |
||
1157 | 'icon' => 'completed', |
||
1158 | ), |
||
1159 | 'cat' => Etemplate\Widget\Nextmatch::category_action( |
||
1160 | 'infolog',$group,'Change category','cat_' |
||
1161 | ), |
||
1162 | 'startdate' => array( |
||
1163 | 'caption' => 'Start date', |
||
1164 | 'group' => $group, |
||
1165 | 'nm_action' => 'open_popup', |
||
1166 | ), |
||
1167 | 'enddate' => array( |
||
1168 | 'caption' => 'Due date', |
||
1169 | 'group' => $group, |
||
1170 | 'nm_action' => 'open_popup', |
||
1171 | ), |
||
1172 | 'responsible' => array( |
||
1173 | 'caption' => 'Delegation', |
||
1174 | 'group' => $group, |
||
1175 | 'icon' => 'users', |
||
1176 | 'nm_action' => 'open_popup', |
||
1177 | 'onExecute' => 'javaScript:app.infolog.change_responsible' |
||
1178 | ), |
||
1179 | 'link' => array( |
||
1180 | 'caption' => 'Links', |
||
1181 | 'group' => $group, |
||
1182 | 'nm_action' => 'open_popup', |
||
1183 | ), |
||
1184 | ), |
||
1185 | 'hideOnMobile' => true |
||
1186 | ), |
||
1187 | 'close' => array( |
||
1188 | 'caption' => 'Close', |
||
1189 | 'icon' => 'done', |
||
1190 | 'group' => $group, |
||
1191 | 'disableClass' => 'rowNoClose', |
||
1192 | 'confirm_mass_selection' => true, |
||
1193 | ), |
||
1194 | 'close_all' => array( |
||
1195 | 'caption' => 'Close all', |
||
1196 | 'icon' => 'done_all', |
||
1197 | 'group' => $group, |
||
1198 | 'hint' => 'Sets the status of this entry and its subs to done', |
||
1199 | 'allowOnMultiple' => false, |
||
1200 | 'disableClass' => 'rowNoCloseAll', |
||
1201 | 'confirm_mass_selection' => true, |
||
1202 | ), |
||
1203 | 'print' => array( |
||
1204 | 'caption' => 'Print', |
||
1205 | 'icon' => 'print', |
||
1206 | 'group' => $group, |
||
1207 | 'onExecute' => 'javaScript:app.infolog.infolog_menu_print' |
||
1208 | ) |
||
1209 | ); |
||
1210 | ++$group; // integration with other apps |
||
1211 | if ($GLOBALS['egw_info']['user']['apps']['filemanager']) |
||
1212 | { |
||
1213 | $actions['filemanager'] = array( |
||
1214 | 'icon' => 'filemanager/navbar', |
||
1215 | 'caption' => 'Filemanager', |
||
1216 | 'url' => 'menuaction=filemanager.filemanager_ui.index&path=/apps/infolog/$id&ajax=true', |
||
1217 | 'allowOnMultiple' => false, |
||
1218 | 'group' => $group, |
||
1219 | ); |
||
1220 | } |
||
1221 | if ($GLOBALS['egw_info']['user']['apps']['calendar']) |
||
1222 | { |
||
1223 | $actions['calendar'] = array( // interactive add for a single event |
||
1224 | 'icon' => 'calendar/navbar', |
||
1225 | 'caption' => 'Schedule appointment', |
||
1226 | 'group' => $group, |
||
1227 | 'url' => 'menuaction=calendar.calendar_uiforms.edit&'. |
||
1228 | Link::get_registry('calendar', 'add_app') . '[]=infolog&'.Link::get_registry('calendar','add_id').'[]=$id', |
||
1229 | 'allowOnMultiple' => false, |
||
1230 | 'popup' => Link::get_registry('calendar', 'edit_popup') |
||
1231 | ); |
||
1232 | } |
||
1233 | if ($GLOBALS['egw_info']['user']['apps']['timesheet']) |
||
1234 | { |
||
1235 | $actions['timesheet'] = array( // interactive add for a single event |
||
1236 | 'icon' => 'timesheet/navbar', |
||
1237 | 'caption' => 'Timesheet', |
||
1238 | 'group' => $group, |
||
1239 | 'allowOnMultiple' => false, |
||
1240 | |||
1241 | 'children' => array( |
||
1242 | 'timesheet_list' => array( |
||
1243 | 'caption' => lang('View linked %1 entries', lang('timesheet')), |
||
1244 | 'icon' => 'infolog/navbar', |
||
1245 | 'onExecute' => 'javaScript:app.infolog.timesheet_list', |
||
1246 | 'allowOnMultiple' => false, |
||
1247 | 'hideOnDisabled' => true, |
||
1248 | ), |
||
1249 | 'timesheet_add' => array( |
||
1250 | 'icon' => 'timesheet/navbar', |
||
1251 | 'caption' => 'Add timesheet entry', |
||
1252 | 'url' => 'menuaction=timesheet.timesheet_ui.edit&link_app[]=infolog&link_id[]=$id', |
||
1253 | 'popup' => Link::get_registry('timesheet', 'add_popup'), |
||
1254 | ) |
||
1255 | ) |
||
1256 | ); |
||
1257 | } |
||
1258 | if ($GLOBALS['egw_info']['user']['apps']['tracker']) |
||
1259 | { |
||
1260 | $actions['to_tracker'] = array( |
||
1261 | 'icon' => 'tracker/navbar', |
||
1262 | 'caption' => 'Tracker', |
||
1263 | 'hint' => 'Convert to a ticket', |
||
1264 | 'group' => $group, |
||
1265 | 'url' => 'menuaction=tracker.tracker_ui.edit&'. |
||
1266 | Link::get_registry('tracker', 'add_app') . '[]=infolog&'.Link::get_registry('tracker','add_id').'[]=$id', |
||
1267 | 'allowOnMultiple' => false, |
||
1268 | 'popup' => Link::get_registry('tracker', 'add_popup'), |
||
1269 | ); |
||
1270 | } |
||
1271 | |||
1272 | $actions['documents'] = infolog_merge::document_action( |
||
1273 | $this->prefs['document_dir'], ++$group, 'Insert in document', 'document_', |
||
1274 | $this->prefs['default_document'] |
||
1275 | ); |
||
1276 | $actions['ical'] = array( |
||
1277 | 'icon' => 'ical', |
||
1278 | 'caption' => 'Export iCal', |
||
1279 | 'postSubmit' => true, // download needs post submit to work |
||
1280 | 'group' => $group, |
||
1281 | 'allowOnMultiple' => true, |
||
1282 | 'hideOnMobile' => true |
||
1283 | ); |
||
1284 | |||
1285 | $actions['delete'] = array( |
||
1286 | 'caption' => 'Delete', |
||
1287 | 'group' => ++$group, |
||
1288 | 'disableClass' => 'rowNoDelete', |
||
1289 | 'onExecute' => 'javaScript:app.infolog.confirm_delete', |
||
1290 | 'confirm_mass_selection' => true, |
||
1291 | ); |
||
1292 | if ($query['col_filter']['info_status'] == 'deleted') |
||
1293 | { |
||
1294 | $actions['undelete'] = array( |
||
1295 | 'caption' => 'Un-Delete', |
||
1296 | 'group' => $group, |
||
1297 | 'icon' => 'revert', |
||
1298 | 'disableClass' => 'rowNoUndelete', |
||
1299 | 'confirm_mass_selection' => true, |
||
1300 | ); |
||
1301 | } |
||
1302 | $actions['info_drop_mail'] = array( |
||
1303 | 'type' => 'drop', |
||
1304 | 'caption' => 'Link mail', |
||
1305 | 'acceptedTypes' => 'mail', |
||
1306 | 'onExecute' => 'javaScript:app.infolog.handle_dropped_mail', |
||
1307 | 'hideOnDisabled' => true |
||
1308 | ); |
||
1309 | //echo "<p>".__METHOD__."($do_email, $tid_filter, $org_view)</p>\n"; _debug_array($actions); |
||
1310 | return $actions; |
||
1311 | } |
||
1312 | |||
1313 | /** |
||
1314 | * Handles actions on multiple infologs |
||
1315 | * |
||
1316 | * @param string $_action |
||
1317 | * @param array $checked contact id's to use if !$use_all |
||
1318 | * @param boolean $use_all if true use all entries of the current selection (in the session) |
||
1319 | * @param int &$success number of succeded actions |
||
1320 | * @param int &$failed number of failed actions (not enought permissions) |
||
1321 | * @param string &$action_msg translated verb for the actions, to be used in a message like '%1 entries deleted' |
||
1322 | * @param array $query get_rows parameter |
||
1323 | * @param string &$msg on return user feedback |
||
1324 | * @param boolean $skip_notifications true to NOT notify users about changes |
||
1325 | * @return boolean true if all actions succeded, false otherwise |
||
1326 | */ |
||
1327 | function action($_action, $checked, $use_all, &$success, &$failed, &$action_msg, |
||
1580 | } |
||
1581 | |||
1582 | /** |
||
1583 | * Closes an infolog |
||
1584 | * |
||
1585 | * @param int|array $values=0 info_id (default _GET[info_id]) |
||
1586 | * @param string $_referer='' |
||
1587 | * @param boolean $closesingle=false |
||
1588 | */ |
||
1589 | function close($values=0,$_referer='',$closesingle=false,$skip_notification = false) |
||
1630 | } |
||
1631 | |||
1632 | /** |
||
1633 | * Deletes an InfoLog entry |
||
1634 | * |
||
1635 | * @param array|int $values info_id (default _GET[info_id]) |
||
1636 | * @param string $_referer |
||
1637 | * @param string $called_by |
||
1638 | * @param boolean $skip_notification Do not send notification of deletion |
||
1639 | */ |
||
1640 | function delete($values=0,$_referer='',$called_by='',$skip_notification=False) |
||
1641 | { |
||
1642 | $info_id = (int) (is_array($values) ? $values['info_id'] : ($values ? $values : $_GET['info_id'])); |
||
1643 | $referer = is_array($values) ? $values['referer'] : $_referer; |
||
1644 | |||
1645 | if (!is_array($values) && $info_id > 0 && !$this->bo->anzSubs($info_id)) // entries without subs get confirmed by javascript |
||
1646 | { |
||
1647 | $values = array('delete' => true); |
||
1648 | } |
||
1649 | //echo "<p>infolog_ui::delete(".print_r($values,true).",'$referer','$called_by') info_id=$info_id</p>\n"; |
||
1650 | |||
1651 | if (is_array($values) || $info_id <= 0) |
||
1652 | { |
||
1653 | if (($values['delete'] || $values['delete_subs']) && $info_id > 0 && $this->bo->check_access($info_id,Acl::DELETE)) |
||
1654 | { |
||
1655 | $deleted = $this->bo->delete($info_id,$values['delete_subs'],$values['info_id_parent'], $skip_notification); |
||
1656 | } |
||
1657 | if ($called_by) // direct call from the same request |
||
1658 | { |
||
1659 | return $deleted ? lang('InfoLog entry deleted') : ''; |
||
1660 | } |
||
1661 | if ($values['called_by'] == 'edit') // we run in the edit popup => give control back to edit |
||
1662 | { |
||
1663 | $this->edit(array( |
||
1664 | 'info_id' => $info_id, |
||
1665 | 'button' => array('deleted' => true), // not delete! |
||
1666 | 'referer' => $referer, |
||
1667 | 'msg' => $deleted ? lang('Infolog entry deleted') : '', |
||
1668 | )); |
||
1669 | } |
||
1670 | return $referer ? $this->tmpl->location($referer) : $this->index(); |
||
1671 | } |
||
1672 | $readonlys = $values = array(); |
||
1673 | $values['main'][1] = $this->get_info($info_id,$readonlys['main']); |
||
1674 | |||
1675 | $this->tmpl->read('infolog.delete'); |
||
1676 | |||
1677 | $values['nm'] = array( |
||
1678 | 'action' => 'sp', |
||
1679 | 'action_id' => $info_id, |
||
1680 | 'options-filter' => $this->filters, |
||
1681 | 'get_rows' => 'infolog.infolog_ui.get_rows', |
||
1682 | 'no_filter2' => True |
||
1683 | ); |
||
1684 | $values['main']['no_actions'] = $values['nm']['no_actions'] = True; |
||
1685 | |||
1686 | $persist['info_id'] = $info_id; |
||
1687 | $persist['referer'] = $referer; |
||
1688 | $persist['info_id_parent'] = $values['main'][1]['info_id_parent']; |
||
1689 | $persist['called_by'] = $called_by; |
||
1690 | |||
1691 | $GLOBALS['egw_info']['flags']['app_header'] = lang('InfoLog').' - '.lang('Delete'); |
||
1692 | $GLOBALS['egw_info']['flags']['params']['manual'] = array('page' => 'ManualInfologDelete'); |
||
1693 | |||
1694 | $this->tmpl->exec('infolog.infolog_ui.delete',$values,array(),$readonlys,$persist,$called_by == 'edit' ? 2 : 0); |
||
1695 | } |
||
1696 | |||
1697 | /** |
||
1698 | * Edit/Create an InfoLog Entry |
||
1699 | * |
||
1700 | * @param array $content Content from the eTemplate Exec call or info_id on inital call |
||
1701 | * @param string $action Name of an app of 'sp' for a infolog-sub |
||
1702 | * @param int $action_id of app-entry to which a link is created |
||
1703 | * @param string $type Type of log-entry: note,todo,task |
||
1704 | * @param string $referer array with param/get-vars of the refering page |
||
1705 | */ |
||
1706 | function edit($content = null,$action = '',$action_id=0,$type='',$referer='') |
||
1707 | { |
||
1708 | if (($submit = is_array($content))) |
||
1709 | { |
||
1710 | //echo "infolog_ui::edit: content="; _debug_array($content); |
||
1711 | $info_id = $content['info_id']; |
||
1712 | $action = $content['action']; unset($content['action']); |
||
1713 | $action_id = $content['action_id']; unset($content['action_id']); |
||
1714 | $referer = $content['referer']; unset($content['referer']); |
||
1715 | $no_popup = $content['no_popup']; unset($content['no_popup']); |
||
1716 | |||
1717 | $button = @key($content['button']); |
||
1718 | if (!$button && $action) $button = $action; // action selectbox |
||
1719 | //info_cc expects an comma separated string |
||
1720 | //error_log(__METHOD__.__LINE__.array2string($content)); |
||
1721 | if (empty($content['info_cc'])) $content['info_cc'] = ""; |
||
1722 | if (is_array($content['info_cc'])) |
||
1723 | { |
||
1724 | foreach($content['info_cc'] as $i => $value) |
||
1725 | { |
||
1726 | //imap_rfc822 should not be used, but it works reliable here, until we have some regex solution or use horde stuff |
||
1727 | $addresses = imap_rfc822_parse_adrlist($value, ''); |
||
1728 | //error_log(__METHOD__.__LINE__.$value.'->'.array2string($addresses[0])); |
||
1729 | $content['info_cc'][$i]=$addresses[0]->host ? $addresses[0]->mailbox.'@'.$addresses[0]->host : $addresses[0]->mailbox; |
||
1730 | } |
||
1731 | if (!empty($content['info_cc'])) $content['info_cc'] = implode(',',$content['info_cc']); |
||
1732 | } |
||
1733 | unset($content['button']); |
||
1734 | if ($button) |
||
1735 | { |
||
1736 | // Copy or schedule Infolog |
||
1737 | if (in_array($button,array('copy','schedule','ical','tracker'))) |
||
1738 | { |
||
1739 | $action = $button; |
||
1740 | if (!$info_id || $this->bo->check_access($info_id,Acl::EDIT)) |
||
1741 | { |
||
1742 | $button = 'apply'; // need to store infolog first |
||
1743 | } |
||
1744 | } |
||
1745 | //Validate the enddate must be grather than startdate |
||
1746 | if (!empty($content['info_enddate']) && !empty($content['info_startdate'])) |
||
1747 | { |
||
1748 | $duration_date = $content['info_enddate']-$content['info_startdate']; |
||
1749 | if ($duration_date < 0) |
||
1750 | { |
||
1751 | $this->tmpl->set_validation_error('info_startdate', lang('Startdate must be before Enddate!!!')); |
||
1752 | $button = $action = ''; // stop save or apply |
||
1753 | } |
||
1754 | } |
||
1755 | //echo "<p>infolog_ui::edit(info_id=$info_id) '$button' button pressed, content="; _debug_array($content); |
||
1756 | if (($button == 'save' || $button == 'apply') && isset($content['info_subject']) && empty($content['info_subject'])) |
||
1757 | { |
||
1758 | $this->tmpl->set_validation_error('info_subject',lang('Field must not be empty !!!')); |
||
1759 | $button = $action = ''; // stop save or apply |
||
1760 | } |
||
1761 | if (($button == 'save' || $button == 'apply') && $info_id) |
||
1762 | { |
||
1763 | $old = $this->bo->read($info_id); |
||
1764 | if (!($edit_acl = $this->bo->check_access($info_id,Acl::EDIT))) |
||
1765 | { |
||
1766 | $status_only = $this->bo->is_responsible($old); |
||
1767 | $undelete = $this->bo->check_access($old,infolog_bo::ACL_UNDELETE); |
||
1768 | } |
||
1769 | // enddate in the past gives warning |
||
1770 | if (isset($content['info_enddate']) |
||
1771 | && $content['info_enddate'] < $this->bo->user_time_now |
||
1772 | && !$this->bo->allow_past_due_date && !($content['info_status'] == 'done' |
||
1773 | || $content['info_status'] == 'archive')) |
||
1774 | { |
||
1775 | $this->tmpl->set_validation_error('info_enddate', lang('Due date must be in the future!!!')); |
||
1776 | } |
||
1777 | } |
||
1778 | if (($button == 'save' || $button == 'apply') && (!$info_id || $edit_acl || $status_only || $undelete)) |
||
1779 | { |
||
1780 | $operation = $info_id ? 'edit' : 'add'; |
||
1781 | |||
1782 | if (is_array($content['link_to']['to_id']) && count($content['link_to']['to_id'])) |
||
1783 | { |
||
1784 | $content['info_link_id'] = 0; // as field has to be int |
||
1785 | } |
||
1786 | $active_tab = $content['tabs']; |
||
1787 | if (!($info_id = $this->bo->write($content, true, true, true, $content['no_notifications']))) |
||
1788 | { |
||
1789 | $content['msg'] = $info_id !== 0 || !$content['info_id'] ? lang('Error: saving the entry') : |
||
1790 | lang('Error: the entry has been updated since you opened it for editing!').'<br />'. |
||
1791 | lang('Copy your changes to the clipboard, %1reload the entry%2 and merge them.','<a href="'. |
||
1792 | htmlspecialchars(Egw::link('/index.php',array( |
||
1793 | 'menuaction' => 'infolog.infolog_ui.edit', |
||
1794 | 'info_id' => $content['info_id'], |
||
1795 | 'no_popup' => $no_popup, |
||
1796 | 'referer' => $referer, |
||
1797 | ))).'">','</a>'); |
||
1798 | $button = $action = ''; // not exiting edit |
||
1799 | $info_id = $content['info_id']; |
||
1800 | } |
||
1801 | else |
||
1802 | { |
||
1803 | $GLOBALS['egw']->preferences->add('infolog','preferred_type',$content['info_type']); |
||
1804 | $GLOBALS['egw']->preferences->save_repository(false,'user',false); |
||
1805 | $content['msg'] = lang('InfoLog entry saved'); |
||
1806 | Framework::refresh_opener($content['msg'],'infolog',$info_id,$operation); |
||
1807 | } |
||
1808 | $content['tabs'] = $active_tab; |
||
1809 | |||
1810 | $pm_links = Link::get_links('infolog',$content['info_id'],'projectmanager'); |
||
1811 | |||
1812 | $content['link_to']['to_app'] = 'infolog'; |
||
1813 | $content['link_to']['to_id'] = $info_id; |
||
1814 | |||
1815 | if ($info_link_id && strpos($info_link_id,':') !== false) // updating info_link_id if necessary |
||
1816 | { |
||
1817 | list($app,$id) = explode(':',$info_link_id); |
||
1818 | $link = Link::get_link('infolog',$info_id,$app,$id); |
||
1819 | if ((int) $content['info_link_id'] != (int) $link['link_id']) |
||
1820 | { |
||
1821 | $content['info_link_id'] = $link['link_id']; |
||
1822 | |||
1823 | $to_write = array( |
||
1824 | 'info_id' => $content['info_id'], |
||
1825 | 'info_link_id' => $content['info_link_id'], |
||
1826 | 'info_from' => $content['info_from'], |
||
1827 | 'info_type' => $content['info_type'], |
||
1828 | 'info_owner' => $content['info_owner'], |
||
1829 | ); |
||
1830 | //echo "<p>updating info_link_id: ".print_r($to_write,true)."</p>\n"; |
||
1831 | $this->bo->write($to_write,False,true,true,true); // last true = no notifications, as no real change |
||
1832 | |||
1833 | // Do not override info_contact if is already filled with contact |
||
1834 | if ($content['info_contact']) |
||
1835 | { |
||
1836 | unset($to_write['info_contact']); |
||
1837 | unset($to_write['blur_title']); |
||
1838 | } |
||
1839 | |||
1840 | // we need eg. the new modification date, for further updates |
||
1841 | $content = array_merge($content,$to_write); |
||
1842 | } |
||
1843 | } |
||
1844 | |||
1845 | // Need to purge description history after encryption? |
||
1846 | if($content['clean_history']) |
||
1847 | { |
||
1848 | $history = new Api\Storage\History('infolog'); |
||
1849 | $record_count = $history->delete_field($info_id, 'De'); |
||
1850 | } |
||
1851 | } |
||
1852 | elseif ($button == 'delete' && $info_id > 0) |
||
1853 | { |
||
1854 | if (!$referer && $action) $referer = array( |
||
1855 | 'menuaction' => 'infolog.infolog_ui.index', |
||
1856 | 'action' => $action, |
||
1857 | 'action_id' => $action_id |
||
1858 | ); |
||
1859 | if (!($content['msg'] = $this->delete($info_id,$referer,'edit'))) return; // checks ACL first |
||
1860 | |||
1861 | Framework::refresh_opener($content['msg'],'infolog',$info_id,'delete'); |
||
1862 | } |
||
1863 | // called again after delete confirmation dialog |
||
1864 | elseif ($button == 'deleted' && $content['msg']) |
||
1865 | { |
||
1866 | Framework::refresh_opener($content['msg'],'infolog',$info_id,'delete'); |
||
1867 | } |
||
1868 | if ($button == 'save' || $button == 'cancel' || $button == 'delete' || $button == 'deleted') |
||
1869 | { |
||
1870 | if ($no_popup) |
||
1871 | { |
||
1872 | Egw::redirect_link($referer,array('msg' => $content['msg'])); |
||
1873 | } |
||
1874 | Framework::window_close(); |
||
1875 | } |
||
1876 | } |
||
1877 | // on a type-change, set the status to the default status of that type, if the actual status is not supported by the new type |
||
1878 | if (!array_key_exists($content['info_status'],$this->bo->status[$content['info_type']])) |
||
1879 | { |
||
1880 | $content['info_status'] = $this->bo->status['defaults'][$content['info_type']]; |
||
1881 | // Make sure we don't end up with invalid status / percent combinations |
||
1882 | if ($content['info_status'] != 'done') |
||
1883 | { |
||
1884 | $content['info_datecompleted'] = ''; |
||
1885 | if((int)$content['info_percent'] === 100) |
||
1886 | { |
||
1887 | $content['info_percent'] = 10; |
||
1888 | } |
||
1889 | } |
||
1890 | else |
||
1891 | { |
||
1892 | $content['info_percent'] = 100; |
||
1893 | } |
||
1894 | if($content['info_status'] != 'not-started' && (int)$content['info_percent'] == 0) |
||
1895 | { |
||
1896 | $content['info_percent'] = 10; |
||
1897 | } |
||
1898 | } |
||
1899 | } |
||
1900 | else // new call via GET |
||
1901 | { |
||
1902 | //echo "<p>infolog_ui::edit: info_id=$info_id, action='$action', action_id='$action_id', type='$type', referer='$referer'</p>\n"; |
||
1903 | $action = $action ? $action : $_REQUEST['action']; |
||
1904 | $action_id = $action_id ? $action_id : $_REQUEST['action_id']; |
||
1905 | $info_id = $content ? $content : $_REQUEST['info_id']; |
||
1906 | $type = $type ? $type : $_REQUEST['type']; |
||
1907 | $referer = $referer !== '' ? $referer : ($_GET['referer'] ? $_GET['referer'] : |
||
1908 | Api\Header\Referer::get('/index.php?menuaction=infolog.infolog_ui.index')); |
||
1909 | if (strpos($referer, 'msg=') !== false) $referer = preg_replace('/([&?]{1})msg=[^&]+&?/','\\1',$referer); // remove previou/old msg from referer |
||
1910 | $no_popup = $_GET['no_popup']; |
||
1911 | $print = (int) $_REQUEST['print']; |
||
1912 | //echo "<p>infolog_ui::edit: info_id=$info_id, action='$action', action_id='$action_id', type='$type', referer='$referer'</p>\n"; |
||
1913 | |||
1914 | if (($content = $this->bo->read( $info_id || $action != 'sp' ? $info_id : $action_id )) === false) |
||
1915 | { |
||
1916 | Framework::window_close(lang('Permission denied!')); |
||
1917 | } |
||
1918 | if (is_numeric($_REQUEST['cat_id'])) |
||
1919 | { |
||
1920 | $content['info_cat'] = (int)$_REQUEST['cat_id']; |
||
1921 | } |
||
1922 | if (!$content) |
||
1923 | { |
||
1924 | $content['info_cat'] = $this->prefs['cat_add_default']; |
||
1925 | } |
||
1926 | if ($_GET['msg']) $content['msg'] = strip_tags($_GET['msg']); // dont allow HTML! |
||
1927 | |||
1928 | switch($this->prefs['set_start']) |
||
1929 | { |
||
1930 | case 'date': default: $set_startdate = mktime(0,0,0,date('m',$this->bo->user_time_now),date('d',$this->bo->user_time_now),date('Y',$this->bo->user_time_now)); break; |
||
1931 | case 'datetime': $set_startdate = $this->bo->user_time_now; break; |
||
1932 | case 'empty': $set_startdate = 0; break; |
||
1933 | } |
||
1934 | if ((int)$content['info_link_id'] > 0 && !Link::get_link($content['info_link_id'])) |
||
1935 | { |
||
1936 | $content['info_link_id'] = 0; // link has been deleted |
||
1937 | if (!$content['info_custom_link']) $content['info_from'] = ''; |
||
1938 | } |
||
1939 | if (!$info_id && $action_id && $action == 'sp') // new SubProject |
||
1940 | { |
||
1941 | if (!$this->bo->check_access($action_id,Acl::ADD)) |
||
1942 | { |
||
1943 | return $referer ? $this->tmpl->location($referer) : $this->index(0,$action,$action_id); |
||
1944 | } |
||
1945 | } |
||
1946 | else |
||
1947 | { |
||
1948 | $undelete = $this->bo->check_access($content,infolog_bo::ACL_UNDELETE); |
||
1949 | } |
||
1950 | $content['links'] = $content['link_to'] = array( |
||
1951 | 'to_id' => $info_id, |
||
1952 | 'to_app' => 'infolog', |
||
1953 | ); |
||
1954 | } |
||
1955 | // new call via GET or some actions handled here, as they can happen both ways ($_GET[action] or button/action in GUI) |
||
1956 | if (!$submit || in_array($action,array('sp','copy','schedule','ical','to_tracker'))) |
||
1957 | { |
||
1958 | switch ($action) |
||
1959 | { |
||
1960 | case 'schedule': |
||
1961 | Egw::redirect_link('/index.php',array( |
||
1962 | 'menuaction' => 'calendar.calendar_uiforms.edit', |
||
1963 | 'link_app' => 'infolog', |
||
1964 | 'link_id' => $info_id, |
||
1965 | )); |
||
1966 | break; |
||
1967 | case 'ical': |
||
1968 | $boical = new infolog_ical(); |
||
1969 | $result = $boical->exportVTODO($content,'2.0','PUBLISH',false); |
||
1970 | Api\Header\Content::type('todo.ics', 'text/calendar'); |
||
1971 | echo $result; |
||
1972 | exit(); |
||
1973 | case 'sp': |
||
1974 | case 'copy': |
||
1975 | $info_id = 0; |
||
1976 | $this->create_copy($content, $action == 'sp'); |
||
1977 | if ($action == 'sp') // for sub-entries use type or category, like for new entries |
||
1978 | { |
||
1979 | if ($type) $content['info_type'] = $type; |
||
1980 | if (is_numeric($_REQUEST['cat_id'])) $content['info_cat'] = (int) $_REQUEST['cat_id']; |
||
1981 | } |
||
1982 | unset($action); // it get stored in $content and will cause an other copy after [apply] |
||
1983 | break; |
||
1984 | case 'to_tracker': |
||
1985 | Egw::redirect_link('/index.php',array( |
||
1986 | 'menuaction' => 'tracker.tracker_ui.edit', |
||
1987 | Link::get_registry('tracker', 'add_app').'[]' => 'infolog', |
||
1988 | Link::get_registry('tracker','add_id').'[]' => $info_id, |
||
1989 | )); |
||
1990 | break; |
||
1991 | case 'projectmanager': |
||
1992 | $content['pm_id'] = $action_id; |
||
1993 | default: // to allow other apps to participate |
||
1994 | $content['info_subject'] = Link::title($action, $id); |
||
1995 | $action_ids = explode(',',$action_id); |
||
1996 | if(count($action_ids) == 1) |
||
1997 | { |
||
1998 | $content['info_contact'] = array('app' => $action, 'id' => $action_id); |
||
1999 | } |
||
2000 | foreach ($action_ids as $n => $id) |
||
2001 | { |
||
2002 | Link::link('infolog', $content['link_to']['to_id'], $action, $id); |
||
2003 | |||
2004 | // calling "infolog_set" hook for first, in case app wants to set some more values |
||
2005 | if (!$n && ($set = Api\Hooks::single(array('location'=>'infolog_set','id'=>$action_id),$action))) |
||
2006 | { |
||
2007 | foreach((array)$set['link_app'] as $i => $l_app) |
||
2008 | { |
||
2009 | if (($l_id=$set['link_id'][$i])) Link::link('infolog',$content['link_to']['to_id'],$l_app,$l_id); |
||
2010 | } |
||
2011 | unset($set['link_app']); |
||
2012 | unset($set['link_id']); |
||
2013 | |||
2014 | $content = array_merge($content, $set); |
||
2015 | } |
||
2016 | } |
||
2017 | // fall through |
||
2018 | case '': |
||
2019 | if ($info_id) |
||
2020 | { |
||
2021 | if (!isset($pm_links)) |
||
2022 | { |
||
2023 | $pm_links = Link::get_links('infolog',$info_id,'projectmanager'); |
||
2024 | } |
||
2025 | break; // normal edit |
||
2026 | } |
||
2027 | case 'new': // new entry, set some defaults, if not set by infolog_set hook |
||
2028 | if (empty($content['info_startdate'])) $content['info_startdate'] = (int) $_GET['startdate'] ? (int) $_GET['startdate'] : $set_startdate; |
||
2029 | if (empty($content['info_priority'])) $content['info_priority'] = 1; // normal |
||
2030 | $content['info_owner'] = $this->user; |
||
2031 | if ($type != '' && empty($content['info_type'])) |
||
2032 | { |
||
2033 | $content['info_type'] = $type; |
||
2034 | } |
||
2035 | else if ($type == '' && empty($content['info_type']) && isset($GLOBALS['egw_info']['user']['preferences']['infolog']['preferred_type'])) |
||
2036 | { |
||
2037 | $content['info_type'] = $GLOBALS['egw_info']['user']['preferences']['infolog']['preferred_type']; |
||
2038 | } |
||
2039 | if (empty($content['info_status'])) $content['info_status'] = $this->bo->status['defaults'][$content['info_type']]; |
||
2040 | if (empty($content['info_percent'])) $content['info_percent'] = $content['info_status'] == 'done' ? '100%' : '0%'; |
||
2041 | break; |
||
2042 | } |
||
2043 | if (!isset($this->bo->enums['type'][$content['info_type']])) |
||
2044 | { |
||
2045 | $content['info_type'] = 'note'; |
||
2046 | } |
||
2047 | } |
||
2048 | // group owners |
||
2049 | $types = $this->bo->enums['type']; |
||
2050 | if ($this->bo->group_owners) |
||
2051 | { |
||
2052 | // remove types owned by groups the user has no edit grant (current type is made readonly) |
||
2053 | foreach($this->bo->group_owners as $type => $group) |
||
2054 | { |
||
2055 | if (!($this->bo->grants[$group] & Acl::EDIT)) |
||
2056 | { |
||
2057 | if ($type == $content['info_type']) |
||
2058 | { |
||
2059 | //echo "<p>setting type to r/o as user has no edit rights from group #$group</p>\n"; |
||
2060 | $readonlys['info_type'] = true; |
||
2061 | } |
||
2062 | else |
||
2063 | { |
||
2064 | unset($types[$type]); |
||
2065 | } |
||
2066 | } |
||
2067 | } |
||
2068 | // set group as owner if type has a group-owner set |
||
2069 | if (isset($this->bo->group_owners[$content['info_type']])) |
||
2070 | { |
||
2071 | $content['info_owner'] = $this->bo->group_owners[$content['info_type']]; |
||
2072 | // Dont allow to change the type, if user has no delete rights from the group-owner |
||
2073 | if ($info_id && !($this->bo->grants[$content['info_owner']] & Acl::DELETE)) |
||
2074 | { |
||
2075 | //echo "<p>setting type to r/o as user has no delete rights from group #$group</p>\n"; |
||
2076 | $readonlys['info_type'] = true; |
||
2077 | } |
||
2078 | // disable info_access for group-owners |
||
2079 | $readonlys['info_access'] = true; |
||
2080 | } |
||
2081 | elseif($GLOBALS['egw']->accounts->get_type($content['info_owner']) == 'g') |
||
2082 | { |
||
2083 | $content['info_owner'] = $this->user; |
||
2084 | } |
||
2085 | } |
||
2086 | $preserv = $content; |
||
2087 | |||
2088 | // Don't preserve message or links |
||
2089 | unset($preserv['msg']); |
||
2090 | unset($preserv['links']); unset($preserv['link_to']); |
||
2091 | |||
2092 | // for no edit rights or implizit edit of responsible user make all fields readonly, but status and percent |
||
2093 | if ($info_id && !$this->bo->check_access($content, Acl::EDIT) && !$undelete) |
||
2094 | { |
||
2095 | $readonlys['__ALL__'] = true; // make all fields not explicitly set readonly |
||
2096 | if ($this->bo->is_responsible($content)) |
||
2097 | { |
||
2098 | foreach($this->bo->responsible_edit as $name) |
||
2099 | { |
||
2100 | $readonlys[$name] = false; |
||
2101 | } |
||
2102 | $readonlys['timestamp'] = $readonlys['info_des']; |
||
2103 | $readonlys['button[edit]'] = $readonlys['button[save]'] = $readonlys['button[apply]'] = $readonlys['no_notifications'] = false; |
||
2104 | } |
||
2105 | $readonlys['action'] = $readonlys['button[cancel]'] = false; // always allowed |
||
2106 | } |
||
2107 | elseif (!$info_id) |
||
2108 | { |
||
2109 | $readonlys['action'] = true; |
||
2110 | } |
||
2111 | // ToDo: use the old status before the delete |
||
2112 | if ($info_id && $undelete) |
||
2113 | { |
||
2114 | $content['info_status'] = $this->bo->status['defaults'][$content['info_type']]; |
||
2115 | $this->tmpl->setElementAttribute('button[save]', 'label', 'Un-Delete'); |
||
2116 | } |
||
2117 | |||
2118 | if (!($readonlys['button[delete]'] = !$info_id || !$this->bo->check_access($content, Acl::DELETE))) |
||
2119 | { |
||
2120 | $content['info_anz_subs'] = $this->bo->anzSubs($info_id); // to determine js confirmation of delete or not |
||
2121 | } |
||
2122 | $GLOBALS['egw_info']['flags']['app_header'] = lang($this->messages[$info_id ? 'edit' : ($action == 'sp' ? 'add_sub' : 'add')]); |
||
2123 | |||
2124 | // use a typ-specific template (infolog.edit.xyz), if one exists, otherwise fall back to the generic one |
||
2125 | if (!$this->tmpl->read('infolog.edit.'.$content['info_type'])) |
||
2126 | { |
||
2127 | $this->tmpl->read($print ? 'infolog.edit.print':'infolog.edit'); |
||
2128 | } |
||
2129 | if ($this->bo->has_customfields($content['info_type'])) |
||
2130 | { |
||
2131 | $content['customfields'] = $content['info_type']; |
||
2132 | } |
||
2133 | else |
||
2134 | { |
||
2135 | $readonlys['tabs']['customfields'] = true; |
||
2136 | } |
||
2137 | if (!isset($GLOBALS['egw_info']['user']['apps']['projectmanager'])) |
||
2138 | { |
||
2139 | $readonlys['tabs']['project'] = true; // disable the project tab |
||
2140 | } |
||
2141 | |||
2142 | $content['duration_format'] = $this->duration_format; |
||
2143 | $content['hours_per_workday'] = $this->hours_per_workday; |
||
2144 | if ($this->prefs['show_id']) $content['info_number'] = $info_id; |
||
2145 | |||
2146 | // Check no notification preference, update if type changed |
||
2147 | if($content['info_type'] != $content['old_type']) |
||
2148 | { |
||
2149 | $content['no_notifications'] = in_array($content['info_type'], !is_array($this->prefs['no_notification_types']) ? |
||
2150 | explode(',',$this->prefs['no_notification_types']): |
||
2151 | $this->prefs['no_notification_types'] |
||
2152 | ); |
||
2153 | } |
||
2154 | |||
2155 | $content['info_anz_subs'] = (int)$content['info_anz_subs']; // gives javascript error if empty! |
||
2156 | |||
2157 | $old_pm_id = is_array($pm_links) ? array_shift($pm_links) : $content['old_pm_id']; |
||
2158 | unset($content['old_pm_id']); |
||
2159 | |||
2160 | if ($info_id && $this->bo->history) |
||
2161 | { |
||
2162 | $content['history'] = array( |
||
2163 | 'id' => $info_id, |
||
2164 | 'app' => 'infolog', |
||
2165 | 'status-widgets' => array( |
||
2166 | 'Ty' => $types, |
||
2167 | //'Li', // info_link_id |
||
2168 | 'parent' => 'link-entry:infolog', |
||
2169 | 'Ca' => 'select-cat', |
||
2170 | 'Pr' => $this->bo->enums['priority'], |
||
2171 | 'Ow' => 'select-account', |
||
2172 | //'Ac', // info_access: private||public |
||
2173 | 'St' => (array)$this->bo->status[$content['info_type']]+array('deleted' => 'deleted'), |
||
2174 | 'Pe' => 'select-percent', |
||
2175 | 'Co' => 'date-time', |
||
2176 | 'st' => 'date-time', |
||
2177 | 'Mo' => 'date-time', |
||
2178 | 'En' => 'date', |
||
2179 | 'Re' => 'select-account', |
||
2180 | // PM fields, ToDo: access control!!! |
||
2181 | 'pT' => 'date-duration', |
||
2182 | 'uT' => 'date-duration', |
||
2183 | 'replanned' => 'date-duration', |
||
2184 | // 'pL' => 'projectmanager-pricelist', |
||
2185 | 'pr' => 'float', |
||
2186 | ), |
||
2187 | ); |
||
2188 | $history_stati = array(); |
||
2189 | $tracking = new infolog_tracking($this); |
||
2190 | foreach($tracking->field2history as $field => $history) |
||
2191 | { |
||
2192 | $history_stati[$history] = $tracking->field2label[$field]; |
||
2193 | } |
||
2194 | // Modified date removed from field2history, we don't need that in the history |
||
2195 | $history_stati['Mo'] = $tracking->field2label['info_datemodified']; |
||
2196 | unset($tracking); |
||
2197 | } |
||
2198 | else |
||
2199 | { |
||
2200 | $readonlys['tabs']['history'] = true; |
||
2201 | } |
||
2202 | $sel_options = array( |
||
2203 | 'info_type' => $types, |
||
2204 | 'info_priority' => $this->bo->enums['priority'], |
||
2205 | 'info_confirm' => $this->bo->enums['confirm'], |
||
2206 | 'info_status' => $this->bo->status[$content['info_type']], |
||
2207 | 'status' => $history_stati, |
||
2208 | 'action' => array( |
||
2209 | 'copy' => array('label' => 'Copy', 'title' => 'Copy this Infolog'), |
||
2210 | 'sp' => 'Sub-entry', |
||
2211 | 'print' => array('label' => 'Print', 'title' => 'Print this Infolog'), |
||
2212 | 'ical' => array('label' => 'Export iCal', 'title' => 'Export iCal'), |
||
2213 | 'to_tracker' => array('label' => 'Tracker', 'title' => 'Convert to a ticket'), |
||
2214 | ), |
||
2215 | ); |
||
2216 | if ($GLOBALS['egw_info']['user']['apps']['calendar']) |
||
2217 | { |
||
2218 | $sel_options['action']['schedule'] = array('label' => 'Schedule', 'title' => 'Schedule appointment'); |
||
2219 | } |
||
2220 | if ($GLOBALS['egw_info']['user']['apps']['stylite'] && !$GLOBALS['egw_info']['server']['disable_pgp_encryption']) |
||
2221 | { |
||
2222 | $content['encryption_ts'] = filemtime(EGW_SERVER_ROOT.'/stylite/js/infolog-encryption.js'); |
||
2223 | } |
||
2224 | elseif ($GLOBALS['egw_info']['server']['disable_pgp_encryption']) |
||
2225 | { |
||
2226 | $readonlys['encrypt'] = true; |
||
2227 | } |
||
2228 | $GLOBALS['egw_info']['flags']['app_header'] = lang('InfoLog').' - '. |
||
2229 | ($content['status_only'] ? lang('Edit Status') : lang('Edit')); |
||
2230 | $GLOBALS['egw_info']['flags']['params']['manual'] = array('page' => ($info_id ? 'ManualInfologEdit' : 'ManualInfologAdd')); |
||
2231 | //error_log(substr($content['info_des'],1793,10)); |
||
2232 | //$content['info_des'] = substr($content['info_des'],0,1793); |
||
2233 | //echo "<p>infolog_ui.edit(info_id='$info_id',action='$action',action_id='$action_id') readonlys="; print_r($readonlys); echo ", content = "; _debug_array($content); |
||
2234 | //$content['info_cc'] is expected (by the widget) to be an array of emailaddresses, but is stored as comma separated string |
||
2235 | if (!empty($content['info_cc'])&&!is_array($content['info_cc']))$content['info_cc'] = explode(',',$content['info_cc']); |
||
2236 | $preserve = array_merge( $preserv, array( // preserved values |
||
2237 | 'info_id' => $info_id, |
||
2238 | 'action' => $action, |
||
2239 | 'action_id' => $action_id, |
||
2240 | 'referer' => $referer, |
||
2241 | 'no_popup' => $no_popup, |
||
2242 | 'old_pm_id' => $old_pm_id, |
||
2243 | 'old_type' => $content['info_type'], |
||
2244 | )); |
||
2245 | $this->tmpl->exec('infolog.infolog_ui.edit',$content,$sel_options,$readonlys,$preserve,$no_popup ? 0 : 2); |
||
2246 | } |
||
2247 | |||
2248 | /** |
||
2249 | * Create copy or sub-entry from an entry currently read into $content |
||
2250 | * |
||
2251 | * Taking into account prefs and config about what to copy |
||
2252 | * |
||
2253 | * @param array &$content |
||
2254 | * @param boolean $create_sub true: create a sub-entry instead of a copy, default false to create a copy |
||
2255 | */ |
||
2256 | private function create_copy(array &$content, $create_sub=false) |
||
2357 | } |
||
2358 | } |
||
2359 | |||
2360 | function icon($cat,$id,$status='') |
||
2378 | } |
||
2379 | |||
2380 | /** |
||
2381 | * Infolog's site configuration |
||
2382 | * |
||
2383 | */ |
||
2384 | public function admin($content = array()) |
||
2510 | } |
||
2511 | |||
2512 | /** |
||
2513 | * imports a mail as infolog |
||
2514 | * |
||
2515 | * @param array $mailContent = null content of mail |
||
2516 | * @return array |
||
2517 | */ |
||
2518 | function mail_import(array $mailContent=null) |
||
2519 | { |
||
2520 | // It would get called from compose as a popup with egw_data |
||
2521 | if (!is_array($mailContent) && ($_GET['egw_data'])) |
||
2522 | { |
||
2523 | // get the mail raw data |
||
2524 | Link::get_data ($_GET['egw_data']); |
||
2525 | return false; |
||
2526 | } |
||
2527 | |||
2528 | return $this->edit($this->bo->import_mail($mailContent['addresses'], |
||
2529 | $mailContent['subject'], |
||
2530 | $mailContent['message'], |
||
2531 | $mailContent['attachments'], |
||
2532 | $mailContent['date'])); |
||
2533 | } |
||
2534 | |||
2535 | /** |
||
2536 | * shows infolog in other applications |
||
2537 | * |
||
2538 | * @param $args['location'] location des hooks: {addressbook|projects|calendar}_view|infolog |
||
2539 | * @param $args['view'] menuaction to view, if location == 'infolog' |
||
2540 | * @param $args['app'] app-name, if location == 'infolog' |
||
2541 | * @param $args['view_id'] name of the id-var for location == 'infolog' |
||
2542 | * @param $args[$args['view_id']] id of the entry |
||
2543 | * this function can be called for any app, which should include infolog: \ |
||
2544 | * Api\Hooks::process(array( \ |
||
2545 | * * 'location' => 'infolog', \ |
||
2546 | * * 'app' => <your app>, \ |
||
2547 | * * 'view_id' => <id name>, \ |
||
2548 | * * <id name> => <id value>, \ |
||
2549 | * * 'view' => <menuaction to view an entry in your app> \ |
||
2550 | * )); |
||
2551 | */ |
||
2552 | function hook_view($args) |
||
2596 | } |
||
2597 | |||
2598 | /** |
||
2599 | * Defines the fields for the csv export |
||
2600 | * |
||
2601 | * @param string $type infolog type to include only the matching custom fields if set |
||
2602 | * @return array |
||
2603 | */ |
||
2604 | function csv_export_fields($type=null) |
||
2648 |