1 | <?php |
||
2 | /** |
||
3 | * EGroupware admin - Edit global categories |
||
4 | * |
||
5 | * @link http://www.egroupware.org |
||
6 | * @author Ralf Becker <RalfBecker-AT-outdoor-training.de> |
||
7 | * @package admin |
||
8 | * @copyright (c) 2010-16 by Ralf Becker <RalfBecker-AT-outdoor-training.de> |
||
9 | * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License |
||
10 | * @version $Id$ |
||
11 | */ |
||
12 | |||
13 | use EGroupware\Api; |
||
14 | use EGroupware\Api\Framework; |
||
15 | use EGroupware\Api\Acl; |
||
16 | use EGroupware\Api\Etemplate; |
||
17 | use EGroupware\Api\Categories; |
||
18 | |||
19 | /** |
||
20 | * Edit global categories |
||
21 | */ |
||
22 | class admin_categories |
||
23 | { |
||
24 | /** |
||
25 | * Which methods of this class can be called as menuaction |
||
26 | * |
||
27 | * @var array |
||
28 | */ |
||
29 | public $public_functions = array( |
||
30 | 'index' => true, |
||
31 | 'edit' => true, |
||
32 | 'delete' => true, |
||
33 | ); |
||
34 | |||
35 | /** |
||
36 | * Path where the icons are stored (relative to webserver_url) |
||
37 | */ |
||
38 | const ICON_PATH = '/api/images'; |
||
39 | |||
40 | protected $appname = 'admin'; |
||
41 | protected $get_rows = 'admin.admin_categories.get_rows'; |
||
42 | protected $list_link = 'admin.admin_categories.index'; |
||
43 | protected $add_link = 'admin.admin_categories.edit'; |
||
44 | protected $edit_link = 'admin.admin_categories.edit'; |
||
45 | |||
46 | /** |
||
47 | * Stupid old admin ACL - dont think anybody uses or understands it ;-) |
||
48 | * |
||
49 | * @var boolean |
||
50 | */ |
||
51 | private static $acl_search; |
||
52 | private static $acl_add; |
||
53 | private static $acl_view; |
||
54 | private static $acl_edit; |
||
55 | private static $acl_delete; |
||
56 | private static $acl_add_sub; |
||
57 | |||
58 | /** |
||
59 | * Constructor |
||
60 | */ |
||
61 | function __construct() |
||
62 | { |
||
63 | if (!isset($GLOBALS['egw_info']['user']['apps']['admin'])) |
||
64 | { |
||
65 | throw new Api\Exception\NoPermission\Admin(); |
||
66 | } |
||
67 | if ($GLOBALS['egw']->acl->check('global_categorie',1,'admin')) |
||
68 | { |
||
69 | $GLOBALS['egw']->redirect_link('/index.php'); |
||
70 | } |
||
71 | self::init_static(); |
||
72 | } |
||
73 | |||
74 | /** |
||
75 | * Init static vars (static constructor) |
||
76 | */ |
||
77 | public static function init_static() |
||
78 | { |
||
79 | if (is_null(self::$acl_search)) |
||
80 | { |
||
81 | self::$acl_search = !$GLOBALS['egw']->acl->check('global_categorie',2,'admin'); |
||
82 | self::$acl_add = !$GLOBALS['egw']->acl->check('global_categorie',4,'admin'); |
||
83 | self::$acl_view = !$GLOBALS['egw']->acl->check('global_categorie',8,'admin'); |
||
84 | self::$acl_edit = !$GLOBALS['egw']->acl->check('global_categorie',16,'admin'); |
||
85 | self::$acl_delete = !$GLOBALS['egw']->acl->check('global_categorie',32,'admin'); |
||
86 | self::$acl_add_sub= !$GLOBALS['egw']->acl->check('global_categorie',64,'admin'); |
||
87 | } |
||
88 | } |
||
89 | |||
90 | /** |
||
91 | * Edit / add a category |
||
92 | * |
||
93 | * @param array $content = null |
||
94 | * @param string $msg = '' |
||
95 | */ |
||
96 | public function edit(array $content=null,$msg='') |
||
97 | { |
||
98 | // read the session, as the global_cats param is stored with it. |
||
99 | $appname = $content['appname'] ? $content['appname'] : ($_GET['appname']?$_GET['appname']:Api\Categories::GLOBAL_APPNAME); |
||
100 | $session = Api\Cache::getSession(__CLASS__.$appname,'nm'); |
||
101 | unset($session); |
||
102 | if (!isset($content)) |
||
103 | { |
||
104 | if (!(isset($_GET['cat_id']) && $_GET['cat_id'] > 0 && |
||
105 | ($content = Categories::read($_GET['cat_id'])))) |
||
106 | { |
||
107 | $content = array('data' => array()); |
||
108 | if(isset($_GET['parent']) && $_GET['parent'] > 0) |
||
109 | { |
||
110 | // Sub-category - set some defaults from parent |
||
111 | $content['parent'] = (int)$_GET['parent']; |
||
112 | $parent_cat = Categories::read($content['parent']); |
||
113 | $content['owner'] = $parent_cat['owner']; |
||
114 | } |
||
115 | if (isset($_GET['appname']) && isset($GLOBALS['egw_info']['apps'][$_GET['appname']])) |
||
116 | { |
||
117 | $appname = $_GET['appname']; |
||
118 | } |
||
119 | else |
||
120 | { |
||
121 | $appname = Categories::GLOBAL_APPNAME; |
||
122 | } |
||
123 | } |
||
124 | elseif ($content['appname'] != $appname || !self::$acl_edit || ( $content['owner'] != $GLOBALS['egw_info']['user']['account_id'] && $this->appname != 'admin')) |
||
125 | { |
||
126 | // only allow to view category |
||
127 | $readonlys['__ALL__'] = true; |
||
128 | $readonlys['button[cancel]'] = false; |
||
129 | } |
||
130 | $content['base_url'] = self::icon_url(); |
||
131 | } |
||
132 | elseif ($content['button'] || $content['delete']) |
||
133 | { |
||
134 | $cats = new Categories($content['owner'] ? $content['owner'] : Categories::GLOBAL_ACCOUNT,$content['appname']); |
||
135 | |||
136 | if ($content['delete']['delete'] || $content['delete']['subs']) |
||
137 | { |
||
138 | $button = 'delete'; |
||
139 | $delete_subs = $content['delete']['subs']?true:false; |
||
140 | } |
||
141 | else |
||
142 | { |
||
143 | $button = key($content['button']); |
||
144 | unset($content['button']); |
||
145 | } |
||
146 | unset($content['delete']); |
||
147 | |||
148 | $refresh_app = $this->appname == 'preferences' ? $content['appname'] : $this->appname; |
||
149 | |||
150 | switch($button) |
||
151 | { |
||
152 | case 'save': |
||
153 | case 'apply': |
||
154 | if(is_array($content['owner'])) $content['owner'] = implode(',',$content['owner']); |
||
155 | if($content['owner'] == '') $content['owner'] = 0; |
||
156 | unset($content['msg']); |
||
157 | if ($content['id'] && self::$acl_edit) |
||
158 | { |
||
159 | |||
160 | $data = $cats->id2name($content['id'],'data'); |
||
161 | if(!$content['parent']) |
||
162 | { |
||
163 | $content['parent'] = '0'; |
||
164 | } |
||
165 | try |
||
166 | { |
||
167 | $cmd = new admin_cmd_category($appname, $content, $cats->read($content['id']), $content['admin_cmd']); |
||
168 | $msg = $cmd->run(); |
||
169 | } |
||
170 | catch (Api\Exception\WrongUserinput $e) |
||
171 | { |
||
172 | $msg = lang('Unwilling to save category with current settings. Check for inconsistency:').$e->getMessage(); // display conflicts etc. |
||
173 | } |
||
174 | } |
||
175 | elseif (!$content['id'] && ( |
||
176 | $content['parent'] && self::$acl_add_sub || |
||
177 | !$content['parent'] && self::$acl_add)) |
||
178 | { |
||
179 | $cmd = new admin_cmd_category($appname, $content); |
||
180 | $cmd->run(); |
||
181 | $content['id'] = $cmd->cat_id; |
||
182 | $msg = lang('Category saved.'); |
||
183 | } |
||
184 | else |
||
185 | { |
||
186 | $msg = lang('Permission denied!'); |
||
187 | unset($button); |
||
188 | } |
||
189 | // If color changed, we need to do an edit 'refresh' instead of 'update' |
||
190 | // to reload the whole nextmatch instead of just the row |
||
191 | $change_color = ($data['color'] != $content['data']['color']); |
||
192 | // Nicely reload just the category window / iframe |
||
193 | if($change_color) |
||
194 | { |
||
195 | if(Api\Json\Response::isJSONResponse()) |
||
196 | { |
||
197 | if($this->appname != 'admin') |
||
198 | { |
||
199 | // Need to forcably re-load everything to force the CSS to be loaded |
||
200 | Api\Json\Response::get()->redirect(Framework::link('/index.php', array( |
||
201 | 'menuaction' => 'preferences.preferences_categories_ui.index', |
||
202 | 'ajax' => 'true', |
||
203 | 'cats_app' => $appname |
||
204 | )), TRUE, $this->appname); |
||
205 | } |
||
206 | else |
||
207 | { |
||
208 | // Need to forcably re-load everything to force the CSS to be loaded |
||
209 | Api\Json\Response::get()->redirect(Framework::link('/index.php', array( |
||
210 | 'menuaction' => 'admin.admin_ui.index', |
||
211 | 'load' => $this->list_link, |
||
212 | 'ajax' => 'true', |
||
213 | 'appname' => $appname |
||
214 | )), TRUE, $this->appname); |
||
215 | } |
||
216 | Framework::window_close(); |
||
217 | return; |
||
218 | } |
||
219 | else |
||
220 | { |
||
221 | Categories::css($refresh_app == 'admin' ? Categories::GLOBAL_APPNAME : $refresh_app); |
||
222 | Framework::refresh_opener('', null, null); |
||
223 | if ($button == 'save') |
||
224 | { |
||
225 | Framework::window_close(); |
||
226 | } |
||
227 | return; |
||
228 | } |
||
229 | } |
||
230 | |||
231 | if ($button == 'save') |
||
232 | { |
||
233 | Framework::refresh_opener($msg, $this->appname, $content['id'], $change_color ? null : 'update', $refresh_app); |
||
234 | Framework::window_close(); |
||
235 | } |
||
236 | break; |
||
237 | |||
238 | case 'delete': |
||
239 | if (self::$acl_delete) |
||
240 | { |
||
241 | $cmd = new admin_cmd_delete_category($content['id'], $delete_subs); |
||
242 | $msg = $cmd->run(); |
||
243 | |||
244 | Framework::refresh_opener($msg, $refresh_app, $content['id'],'delete', $this->appname); |
||
245 | Framework::window_close(); |
||
246 | return; |
||
247 | } |
||
248 | else |
||
249 | { |
||
250 | $msg = lang('Permission denied!'); |
||
251 | unset($button); |
||
252 | } |
||
253 | break; |
||
254 | } |
||
255 | // This should probably refresh the application $this->appname in the target tab $refresh_app, but that breaks pretty much everything |
||
256 | Framework::refresh_opener($msg, $this->appname, $content['id'], $change_color ? null : 'update', $refresh_app); |
||
257 | } |
||
258 | $content['msg'] = $msg; |
||
259 | if(!$content['appname']) $content['appname'] = $appname; |
||
260 | if($content['data']['icon']) |
||
261 | { |
||
262 | $content['icon_url'] = $content['base_url'] . $content['data']['icon']; |
||
263 | } |
||
264 | |||
265 | $sel_options['icon'] = self::get_icons(); |
||
266 | $sel_options['owner'] = array(); |
||
267 | |||
268 | // User's category - add current value to be able to preserve owner |
||
269 | if(!$content['id']) |
||
270 | { |
||
271 | if($this->appname != 'admin') |
||
272 | { |
||
273 | $content['owner'] = $GLOBALS['egw_info']['user']['account_id']; |
||
274 | } |
||
275 | elseif (!$content['owner']) |
||
276 | { |
||
277 | $content['owner'] = 0; |
||
278 | } |
||
279 | } |
||
280 | |||
281 | if($this->appname != 'admin' && $content['owner'] > 0 ) |
||
282 | { |
||
283 | $sel_options['owner'][$content['owner']] = Api\Accounts::username($content['owner']); |
||
284 | } |
||
285 | // Add 'All users', in case owner is readonlys |
||
286 | if($content['id'] && $content['owner'] == 0) |
||
287 | { |
||
288 | $sel_options['owner'][0] = lang('All users'); |
||
289 | } |
||
290 | if($this->appname == 'admin' || ($content['id'] && !((int)$content['owner'] > 0))) |
||
291 | { |
||
292 | if($content['owner'] > 0) |
||
293 | { |
||
294 | $content['msg'] .= "\n".lang('owner "%1" removed, please select group-owner', Api\Accounts::username($content['owner'])); |
||
295 | $content['owner'] = 0; |
||
296 | } |
||
297 | $sel_options['owner'][0] = lang('All users'); |
||
298 | foreach($GLOBALS['egw']->accounts->search(array('type' => 'groups')) as $acc) |
||
299 | { |
||
300 | if ($acc['account_type'] == 'g') |
||
301 | { |
||
302 | $sel_options['owner'][$acc['account_id']] = Etemplate\Widget\Select::accountInfo($acc['account_id'], $acc); |
||
303 | } |
||
304 | } |
||
305 | $content['no_private'] = true; |
||
306 | } |
||
307 | |||
308 | if($this->appname == 'admin') |
||
309 | { |
||
310 | $content['access'] = 'public'; |
||
311 | // Allow admins access to all categories as parent |
||
312 | $content['all_cats'] = 'all_no_acl'; |
||
313 | $readonlys['owner'] = false; |
||
314 | } else { |
||
315 | $readonlys['owner'] = true; |
||
316 | $readonlys['access'] = $content['owner'] != $GLOBALS['egw_info']['user']['account_id']; |
||
317 | } |
||
318 | |||
319 | Framework::includeJS('.','global_categories','admin'); |
||
320 | Api\Translation::add_app('admin'); |
||
321 | |||
322 | $readonlys['button[delete]'] = !$content['id'] || !self::$acl_delete || // cant delete not yet saved category |
||
323 | $appname != $content['appname'] || // Can't edit a category from a different app |
||
324 | ($this->appname != 'admin' && $content['owner'] != $GLOBALS['egw_info']['user']['account_id']); |
||
325 | // Make sure $content['owner'] is an array otherwise it wont show up values in the multiselectbox |
||
326 | if (!is_array($content['owner'])) $content['owner'] = explode(',',$content['owner']); |
||
327 | $tmpl = new Etemplate('admin.categories.edit'); |
||
328 | $tmpl->exec($this->edit_link,$content,$sel_options,$readonlys,$content+array( |
||
329 | 'old_parent' => $content['old_parent'] ? $content['old_parent'] : $content['parent'], 'appname' => $appname |
||
330 | ),2); |
||
331 | } |
||
332 | |||
333 | /** |
||
334 | * Return URL of an icon, or base url with trailing slash |
||
335 | * |
||
336 | * @param string $icon = '' filename |
||
337 | * @return string url |
||
338 | */ |
||
339 | static function icon_url($icon='') |
||
340 | { |
||
341 | return $GLOBALS['egw_info']['server']['webserver_url'].self::ICON_PATH.'/'.$icon; |
||
342 | } |
||
343 | |||
344 | /** |
||
345 | * Return icons from /api/images |
||
346 | * |
||
347 | * @return array filename => label |
||
348 | */ |
||
349 | static function get_icons() |
||
350 | { |
||
351 | $icons = array(); |
||
352 | if (file_exists($image_dir=EGW_SERVER_ROOT.self::ICON_PATH) && ($dir = dir($image_dir))) |
||
353 | { |
||
354 | $matches = null; |
||
355 | while(($file = $dir->read())) |
||
356 | { |
||
357 | if (preg_match('/^(.*)\\.(png|gif|jpe?g)$/i',$file,$matches)) |
||
358 | { |
||
359 | $icons[$file] = ucfirst($matches[1]); |
||
360 | } |
||
361 | } |
||
362 | $dir->close(); |
||
363 | asort($icons); |
||
364 | } |
||
365 | return $icons; |
||
366 | } |
||
367 | |||
368 | /** |
||
369 | * query rows for the nextmatch widget |
||
370 | * |
||
371 | * @param array $query with keys 'start', 'search', 'order', 'sort', 'col_filter' |
||
372 | * @param array &$rows returned rows/competitions |
||
373 | * @param array &$readonlys eg. to disable buttons based on Acl, not use here, maybe in a derived class |
||
374 | * @return int total number of rows |
||
375 | */ |
||
376 | public function get_rows(&$query,&$rows,&$readonlys) |
||
377 | { |
||
378 | self::init_static(); |
||
379 | |||
380 | $filter = array(); |
||
381 | $globalcat = ($query['filter'] === Categories::GLOBAL_ACCOUNT || !$query['filter']); |
||
382 | if (isset($query['global_cats']) && $query['global_cats']===false) |
||
383 | { |
||
384 | $globalcat = false; |
||
385 | } |
||
386 | if ($globalcat && $query['filter']) $filter['access'] = 'public'; |
||
387 | // new column-filter access has highest priority |
||
388 | if (!empty($query['col_filter']['access']))$filter['access'] = $query['col_filter']['access']; |
||
389 | |||
390 | Api\Cache::setSession(__CLASS__.$query['appname'],'nm',$query); |
||
391 | |||
392 | if($query['filter'] > 0 || $query['col_filter']['owner']) |
||
393 | { |
||
394 | $owner = $query['col_filter']['owner'] ? $query['col_filter']['owner'] : $query['filter']; |
||
395 | } |
||
396 | if($query['col_filter']['app']) |
||
397 | { |
||
398 | $filter['appname'] = $query['col_filter']['app']; |
||
399 | } |
||
400 | $GLOBALS['egw']->categories = $cats = new Categories($filter['owner'],$query['appname']); |
||
401 | $globals = isset($GLOBALS['egw_info']['user']['apps']['admin']) ? 'all_no_acl' : $globalcat; // ignore Acl only for admins |
||
402 | $parent = $query['search'] ? false : 0; |
||
403 | $rows = $cats->return_sorted_array($query['start'],false,$query['search'],$query['sort'],$query['order'],$globals,$parent,true,$filter); |
||
404 | $count = $cats->total_records; |
||
405 | foreach($rows as $key => &$row) |
||
406 | { |
||
407 | $row['owner'] = explode(',',$row['owner']); |
||
408 | if(($owner && !in_array($owner, $row['owner'])) || ((string)$query['filter'] === (string)Api\Categories::GLOBAL_ACCOUNT && $row['owner'][0] > 0)) |
||
409 | { |
||
410 | unset($rows[$key]); |
||
411 | $count--; |
||
412 | continue; |
||
413 | } |
||
414 | |||
415 | if($row['level'] >= 0) |
||
416 | { |
||
417 | $row['level_spacer'] = str_repeat(' ',$row['level']); |
||
418 | } |
||
419 | |||
420 | if ($row['data']['icon']) $row['icon_url'] = self::icon_url($row['data']['icon']); |
||
421 | |||
422 | $row['subs'] = $row['children'] ? count($row['children']) : 0; |
||
423 | |||
424 | $row['class'] = 'level'.$row['level']; |
||
425 | if($row['owner'][0] > 0 && !$GLOBALS['egw_info']['user']['apps']['admin'] && $row['owner'][0] != $GLOBALS['egw_info']['user']['account_id']) |
||
426 | { |
||
427 | $row['class'] .= ' rowNoEdit rowNoDelete '; |
||
428 | } |
||
429 | else if (!$GLOBALS['egw_info']['user']['apps']['admin']) |
||
430 | { |
||
431 | if(!$cats->check_perms(Acl::EDIT, $row['id']) || !self::$acl_edit) |
||
432 | { |
||
433 | $row['class'] .= ' rowNoEdit'; |
||
434 | } |
||
435 | if(!$cats->check_perms(Acl::DELETE, $row['id']) || !self::$acl_delete || |
||
436 | // Only admins can delete globals |
||
437 | $cats->is_global($row['id']) && !$GLOBALS['egw_info']['user']['apps']['admin']) |
||
438 | { |
||
439 | $row['class'] .= ' rowNoDelete'; |
||
440 | } |
||
441 | } |
||
442 | // Can only edit or delete (via context menu) Categories for the selected app (backend restriction) |
||
443 | if($row['appname'] != $query['appname']) |
||
444 | { |
||
445 | $row['class'] .= ' rowNoEdit rowNoDelete '; |
||
446 | } |
||
447 | $readonlys['nm']["edit[$row[id]]"] = !self::$acl_edit; |
||
448 | $readonlys['nm']["add[$row[id]]"] = !self::$acl_add_sub; |
||
449 | $readonlys['nm']["delete[$row[id]]"] = !self::$acl_delete; |
||
450 | } |
||
451 | if (true) $rows = $count <= $query['num_rows'] ? array_values($rows) : array_slice($rows, $query['start'], $query['num_rows']); |
||
452 | // make appname available for actions |
||
453 | $rows['appname'] = $query['appname']; |
||
454 | $rows['edit_link'] = $this->edit_link; |
||
455 | |||
456 | // disable access column for global Categories |
||
457 | if ($GLOBALS['egw_info']['flags']['currentapp'] == 'admin') $rows['no_access'] = true; |
||
458 | |||
459 | $GLOBALS['egw_info']['flags']['app_header'] = lang($this->appname).' - '.lang('categories'). |
||
460 | ($query['appname'] != Categories::GLOBAL_APPNAME ? ': '.lang($query['appname']) : ''); |
||
461 | |||
462 | return $count; |
||
463 | } |
||
464 | |||
465 | /** |
||
466 | * Display the accesslog |
||
467 | * |
||
468 | * @param array $content = null |
||
469 | * @param string $msg = '' |
||
470 | */ |
||
471 | public function index(array $content=null,$msg='') |
||
472 | { |
||
473 | //_debug_array($_GET); |
||
474 | if ($this->appname != 'admin') Api\Translation::add_app('admin'); // need admin translations |
||
475 | |||
476 | if(!isset($content)) |
||
477 | { |
||
478 | if (isset($_GET['msg'])) $msg = $_GET['msg']; |
||
479 | |||
480 | $appname = Categories::GLOBAL_APPNAME; |
||
481 | foreach(array($content['nm']['appname'], $_GET['cats_app'], $_GET['appname']) as $field) |
||
482 | { |
||
483 | if($field) |
||
484 | { |
||
485 | $appname = $field; |
||
486 | break; |
||
487 | } |
||
488 | } |
||
489 | $content['nm'] = Api\Cache::getSession(__CLASS__.$appname,'nm'); |
||
490 | if (!is_array($content['nm'])) |
||
491 | { |
||
492 | $content['nm'] = array( |
||
493 | 'get_rows' => $this->get_rows, // I method/callback to request the data for the rows eg. 'notes.bo.get_rows' |
||
494 | 'options-filter' => array( |
||
495 | '' => lang('All categories'), |
||
496 | Categories::GLOBAL_ACCOUNT => lang('Global categories'), |
||
497 | $GLOBALS['egw_info']['user']['account_id'] => lang('Own categories'), |
||
498 | ), |
||
499 | 'no_filter2' => True, // I disable the 2. filter (params are the same as for filter) |
||
500 | 'no_cat' => True, // I disable the cat-selectbox |
||
501 | 'header_left' => false, // I template to show left of the range-value, left-aligned (optional) |
||
502 | 'header_right' => false, // I template to show right of the range-value, right-aligned (optional) |
||
503 | 'never_hide' => True, // I never hide the nextmatch-line if less then maxmatch entries |
||
504 | 'lettersearch' => false, // I show a lettersearch |
||
505 | 'start' => 0, // IO position in list |
||
506 | 'order' => 'name', // IO name of the column to sort after (optional for the sortheaders) |
||
507 | 'sort' => 'ASC', // IO direction of the sort: 'ASC' or 'DESC' |
||
508 | 'default_cols' => '!color,last_mod,subs,legacy_actions', // I columns to use if there's no user or default pref (! as first char uses all but the named columns), default all columns |
||
509 | 'csv_fields' => false, // I false=disable csv export, true or unset=enable it with auto-detected fieldnames, |
||
510 | //or array with name=>label or name=>array('label'=>label,'type'=>type) pairs (type is a eT widget-type) |
||
511 | 'no_search' => !self::$acl_search, |
||
512 | 'row_id' => 'id', |
||
513 | 'dataStorePrefix' => 'categories' // Avoid conflict with user list when in admin |
||
514 | ); |
||
515 | $content['nm']['filter'] = $this->appname == 'admin'?Api\Categories::GLOBAL_ACCOUNT:$GLOBALS['egw_info']['user']['account_id']; |
||
516 | } |
||
517 | else |
||
518 | { |
||
519 | $content['nm']['start']=0; |
||
520 | } |
||
521 | $content['nm']['appname'] = $appname = $_GET['appname'] ? $_GET['appname'] : $appname; |
||
522 | $content['nm']['actions'] = $this->get_actions($appname); |
||
523 | // switch filter off for super-global categories |
||
524 | if($appname == 'phpgw') |
||
525 | { |
||
526 | $content['nm']['no_filter'] = true; |
||
527 | // Make sure filter is set properly, could be different if user was looking at something else |
||
528 | $content['nm']['filter'] = Categories::GLOBAL_ACCOUNT; |
||
529 | } |
||
530 | |||
531 | $content['nm']['global_cats'] = true; |
||
532 | if (isset($_GET['global_cats']) && empty($_GET['global_cats'] )) |
||
533 | { |
||
534 | $content['nm']['global_cats'] = false; |
||
535 | } |
||
536 | } |
||
537 | elseif($content['nm']['action']) |
||
538 | { |
||
539 | $appname = $content['nm']['appname']; |
||
540 | if (!count($content['nm']['selected']) && !$content['nm']['select_all']) |
||
541 | { |
||
542 | $msg = lang('You need to select some entries first!'); |
||
543 | } |
||
544 | else |
||
545 | { |
||
546 | // Action has an additional action - add / delete, etc. Buttons named <multi-action>_action[action_name] |
||
547 | if(in_array($content['nm']['action'], array('owner'))) |
||
548 | { |
||
549 | $action = $content['nm']['action']; |
||
550 | if ($content[$action.'_popup']) |
||
551 | { |
||
552 | $content = array_merge($content,$content[$action.'_popup']); |
||
553 | } |
||
554 | $content['nm']['action'] .= '_' . key($content[$action . '_action']); |
||
555 | |||
556 | if(is_array($content[$action])) |
||
557 | { |
||
558 | $content[$action] = implode(',',$content[$action]); |
||
559 | } |
||
560 | $content['nm']['action'] .= '_' . $content[$action]; |
||
561 | } |
||
562 | $success = $failed = 0; |
||
563 | $action_msg = null; |
||
564 | if ($this->action($content['nm']['action'],$content['nm']['selected'],$content['nm']['select_all'], |
||
565 | $success,$failed,$action_msg,$content['nm'])) |
||
566 | { |
||
567 | $msg .= lang('%1 category(s) %2',$success,$action_msg); |
||
568 | } |
||
569 | elseif(empty($msg)) |
||
570 | { |
||
571 | $msg .= lang('%1 category(s) %2, %3 failed because of insufficent rights !!!',$success,$action_msg,$failed); |
||
572 | } |
||
573 | Framework::refresh_opener($msg, $this->appname); |
||
574 | $msg = ''; |
||
575 | } |
||
576 | } |
||
577 | $content['msg'] = $msg; |
||
578 | $content['nm']['add_link']= Framework::link('/index.php','menuaction='.$this->add_link . '&cat_id=&appname='.$appname); |
||
579 | $content['edit_link']= $this->edit_link.'&appname='.$appname; |
||
580 | $content['owner'] = ''; |
||
581 | |||
582 | $sel_options['appname'] = $this->get_app_list(); |
||
583 | $sel_options['app'] = array( |
||
584 | '' => lang('All'), |
||
585 | $appname => lang($appname) |
||
586 | ); |
||
587 | $sel_options['access'] = array( |
||
588 | 'public' => 'No', |
||
589 | 'private' => 'Yes', |
||
590 | ); |
||
591 | |||
592 | $sel_options['owner'][0] = lang('All users'); |
||
593 | foreach($GLOBALS['egw']->accounts->search(array('type' => 'groups')) as $acc) |
||
594 | { |
||
595 | if ($acc['account_type'] == 'g') |
||
596 | { |
||
597 | $sel_options['owner'][$acc['account_id']] = Etemplate\Widget\Select::accountInfo($acc['account_id'], $acc); |
||
598 | } |
||
599 | } |
||
600 | |||
601 | $readonlys['add'] = !self::$acl_add; |
||
602 | if(!$GLOBALS['egw_info']['user']['apps']['admin']) |
||
603 | { |
||
604 | $readonlys['nm']['rows']['owner'] = true; |
||
605 | $readonlys['nm']['col_filter']['owner'] = true; |
||
606 | } |
||
607 | if($appname == Categories::GLOBAL_APPNAME) { |
||
608 | $sel_options['app'] = array(''=>''); |
||
609 | $readonlys['nm']['rows']['app'] = true; |
||
610 | } |
||
611 | |||
612 | $tmpl = new Etemplate('admin.categories.index'); |
||
613 | // we need to set a different dom-id for each application and also global categories of that app |
||
614 | // otherwise eT2 objects are overwritter when a second categories template is shown |
||
615 | $tmpl->set_dom_id($appname.'.'.$this->appname.'.categories.index'); |
||
616 | |||
617 | // Category styles |
||
618 | Categories::css($appname); |
||
619 | |||
620 | $tmpl->exec($this->list_link,$content,$sel_options,$readonlys,array( |
||
621 | 'nm' => $content['nm'], |
||
622 | )); |
||
623 | } |
||
624 | |||
625 | /** |
||
626 | * Dialog to delete a category |
||
627 | * |
||
628 | * @param array $content =null |
||
629 | */ |
||
630 | public function delete(array $content=null) |
||
631 | { |
||
632 | if (!is_array($content)) |
||
633 | { |
||
634 | if (isset($_GET['cat_id'])) |
||
635 | { |
||
636 | $content = array( |
||
637 | 'cat_id'=>(int)$_GET['cat_id'], |
||
638 | ); |
||
639 | } |
||
640 | //error_log(__METHOD__."() \$_GET[account_id]=$_GET[account_id], \$_GET[contact_id]=$_GET[contact_id] content=".array2string($content)); |
||
641 | } |
||
642 | $cats = new Categories('', Categories::id2name($content['cat_id'],'appname')); |
||
643 | if((!$cats->check_perms(Acl::DELETE, $content['cat_id']) || !self::$acl_delete) && |
||
644 | // Only admins can delete globals |
||
645 | $cats->is_global($content['cat_id']) && !$GLOBALS['egw_info']['user']['apps']['admin']) |
||
646 | |||
647 | { |
||
648 | Framework::window_close(lang('Permission denied!!!')); |
||
649 | } |
||
650 | if ($content['button']) |
||
651 | { |
||
652 | if($cats->check_perms(Acl::DELETE, $content['cat_id'], (boolean)$GLOBALS['egw_info']['user']['apps']['admin'])) |
||
653 | { |
||
654 | $cmd = new admin_cmd_delete_category( |
||
655 | $content['cat_id'], |
||
656 | key($content['button']) == 'delete_sub', |
||
657 | $content['admin_cmd'] |
||
658 | ); |
||
659 | $cmd->run(); |
||
660 | Framework::refresh_opener(lang('Deleted'), 'admin', $content['cat_id'], 'delete'); |
||
661 | Framework::window_close(); |
||
662 | } |
||
663 | } |
||
664 | $tpl = new Etemplate('admin.categories.delete'); |
||
665 | $tpl->exec('admin.admin_categories.delete', $content, array(), array(), $content, 2); |
||
666 | } |
||
667 | |||
668 | protected function get_actions($appname=Api\Categories::GLOBAL_APPNAME) { |
||
669 | |||
670 | $actions = array( |
||
671 | 'open' => array( // does edit if allowed, otherwise view |
||
672 | 'caption' => 'Open', |
||
673 | 'default' => true, |
||
674 | 'allowOnMultiple' => false, |
||
675 | 'url' => 'menuaction='.$this->edit_link.'&cat_id=$id&appname='.$appname, |
||
676 | 'popup' => '600x380', |
||
677 | 'group' => $group=1, |
||
678 | ), |
||
679 | 'add' => array( |
||
680 | 'caption' => 'Add', |
||
681 | 'allowOnMultiple' => false, |
||
682 | 'icon' => 'new', |
||
683 | 'url' => 'menuaction='.$this->add_link.'&appname='.$appname, |
||
684 | 'popup' => '600x380', |
||
685 | 'group' => $group, |
||
686 | ), |
||
687 | 'sub' => array( |
||
688 | 'caption' => 'Add sub', |
||
689 | 'allowOnMultiple' => false, |
||
690 | 'icon' => 'new', |
||
691 | 'url' => 'menuaction='.$this->add_link.'&parent=$id&appname='.$appname, |
||
692 | 'popup' => '600x380', |
||
693 | 'group' => $group, |
||
694 | 'disableClass' => 'rowNoSub', |
||
695 | ), |
||
696 | 'owner' => array( |
||
697 | 'caption' => 'Change owner', |
||
698 | 'icon' => 'users', |
||
699 | 'nm_action' => 'open_popup', |
||
700 | 'group' => $group, |
||
701 | 'disableClass' => 'rowNoEdit', |
||
702 | ), |
||
703 | 'delete' => array( |
||
704 | 'caption' => 'Delete', |
||
705 | 'allowOnMultiple' => true, |
||
706 | 'group' => ++$group, |
||
707 | 'disableClass' => 'rowNoDelete', |
||
708 | 'popup' => '450x400', |
||
709 | 'url' => 'menuaction=admin.admin_categories.delete&cat_id=$id', |
||
710 | ), |
||
711 | ); |
||
712 | |||
713 | if(!$GLOBALS['egw_info']['user']['apps']['admin']) |
||
714 | { |
||
715 | unset($actions['owner']); |
||
716 | } |
||
717 | |||
718 | return $actions; |
||
719 | } |
||
720 | |||
721 | /** |
||
722 | * Handles actions on multiple entries |
||
723 | * |
||
724 | * @param string $_action |
||
725 | * @param array $checked contact id's to use if !$use_all |
||
726 | * @param boolean $use_all if true use all entries of the current selection (in the session) |
||
727 | * @param int &$success number of succeded actions |
||
728 | * @param int &$failed number of failed actions (not enought permissions) |
||
729 | * @param string &$action_msg translated verb for the actions, to be used in a message like '%1 entries deleted' |
||
730 | * @param array $query get_rows parameter |
||
731 | * @return boolean true if all actions succeded, false otherwise |
||
732 | */ |
||
733 | function action($_action, $checked, $use_all, &$success, &$failed, &$action_msg, array $query) |
||
734 | { |
||
735 | //echo '<p>'.__METHOD__."('$action',".array2string($checked).','.(int)$use_all.",...)</p>\n"; |
||
736 | $success = $failed = 0; |
||
737 | if ($use_all) |
||
738 | { |
||
739 | @set_time_limit(0); // switch off the execution time limit, as it's for big selections to small |
||
0 ignored issues
–
show
|
|||
740 | $query['num_rows'] = -1; // all |
||
741 | $result = $readonlys = array(); |
||
742 | $this->get_rows($query,$result,$readonlys); |
||
743 | $checked = array(); |
||
744 | foreach($result as $key => $info) |
||
745 | { |
||
746 | if(is_numeric($key)) |
||
747 | { |
||
748 | $checked[] = $info['id']; |
||
749 | } |
||
750 | } |
||
751 | } |
||
752 | $owner = $query['col_filter']['owner'] ? $query['col_filter']['owner'] : $query['filter']; |
||
753 | $app = $query['col_filter']['app'] ? $query['col_filter']['app'] : $query['appname']; |
||
754 | $cats = new Categories($owner,$app); |
||
755 | |||
756 | list($action, $settings) = explode('_', $_action, 2); |
||
757 | |||
758 | switch($action) |
||
759 | { |
||
760 | case 'delete': |
||
761 | $action_msg = lang('deleted'); |
||
762 | foreach($checked as $id) |
||
763 | { |
||
764 | if($cats->check_perms(Acl::DELETE, $id, (boolean)$GLOBALS['egw_info']['user']['apps']['admin'])) |
||
765 | { |
||
766 | $cmd = new admin_cmd_delete_category($id, $settings == 'sub'); |
||
767 | $cmd->run(); |
||
768 | $success++; |
||
769 | } |
||
770 | else |
||
771 | { |
||
772 | $failed++; |
||
773 | } |
||
774 | } |
||
775 | break; |
||
776 | case 'owner': |
||
777 | $action_msg = lang('updated'); |
||
778 | list($add_remove, $ids_csv) = explode('_', $settings, 2); |
||
779 | $ids = explode(',', $ids_csv); |
||
780 | // Adding 'All users' removes all the others |
||
781 | if($add_remove == 'add' && array_search(Categories::GLOBAL_ACCOUNT,$ids) !== false) $ids = array(Categories::GLOBAL_ACCOUNT); |
||
782 | |||
783 | foreach($checked as $id) |
||
784 | { |
||
785 | if (!$data = $cats->read($id)) continue; |
||
786 | $data['owner'] = explode(',',$data['owner']); |
||
787 | if(array_search(Categories::GLOBAL_ACCOUNT,$data['owner']) !== false || $data['owner'][0] > 0) |
||
788 | { |
||
789 | $data['owner'] = array(); |
||
790 | } |
||
791 | $data['owner'] = $add_remove == 'add' ? |
||
792 | $ids == array(Categories::GLOBAL_ACCOUNT) ? $ids : array_merge($data['owner'],$ids) : |
||
793 | array_diff($data['owner'],$ids); |
||
794 | $data['owner'] = implode(',',array_unique($data['owner'])); |
||
795 | |||
796 | $cmd = new admin_cmd_category($app, $data, array()); |
||
797 | if ($cmd->run()) |
||
798 | { |
||
799 | $success++; |
||
800 | } |
||
801 | else |
||
802 | { |
||
803 | $failed++; |
||
804 | } |
||
805 | } |
||
806 | break; |
||
807 | } |
||
808 | |||
809 | return $failed == 0; |
||
810 | } |
||
811 | |||
812 | /** |
||
813 | * Get a list of apps for selectbox / filter |
||
814 | */ |
||
815 | protected function get_app_list() |
||
816 | { |
||
817 | $apps = array(); |
||
818 | foreach ($GLOBALS['egw_info']['apps'] as $app => $data) |
||
819 | { |
||
820 | if ($app == 'phpgwapi') |
||
821 | { |
||
822 | $apps['phpgw'] = lang('Global'); |
||
823 | continue; |
||
824 | } |
||
825 | // Skip apps that don't show in the app bar, they [usually] don't have Categories |
||
826 | if($data['status'] > 1 || in_array($app, array('home','admin','felamimail','sitemgr','sitemgr-link'))) continue; |
||
827 | if ($GLOBALS['egw_info']['user']['apps'][$app]) |
||
828 | { |
||
829 | $apps[$app] = $data['title'] ? $data['title'] : lang($app); |
||
830 | } |
||
831 | } |
||
832 | return $apps; |
||
833 | } |
||
834 | } |
||
835 | |||
836 | admin_categories::init_static(); |
||
837 |
If you suppress an error, we recommend checking for the error condition explicitly: