1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* EGroupware: Admin app UI: edit/add account |
4
|
|
|
* |
5
|
|
|
* @link http://www.egroupware.org |
6
|
|
|
* @author Ralf Becker <[email protected]> |
7
|
|
|
* @package admin |
8
|
|
|
* @copyright (c) 2014-19 by Ralf Becker <[email protected]> |
9
|
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
use EGroupware\Api; |
13
|
|
|
use EGroupware\Api\Acl; |
14
|
|
|
use EGroupware\Api\Etemplate; |
15
|
|
|
use EGroupware\Api\Framework; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* UI for admin: edit/add account |
19
|
|
|
*/ |
20
|
|
|
class admin_account |
21
|
|
|
{ |
22
|
|
|
/** |
23
|
|
|
* Functions callable via menuaction |
24
|
|
|
* |
25
|
|
|
* @var array |
26
|
|
|
*/ |
27
|
|
|
public $public_functions = array( |
28
|
|
|
'delete' => true, |
29
|
|
|
); |
30
|
|
|
|
31
|
|
|
// Copying account uses addressbook fields, but we explicitly clear these |
32
|
|
|
protected static $copy_clear_fields = array( |
33
|
|
|
'account_firstname','account_lastname','account_fullname', 'person_id', |
34
|
|
|
'account_id','account_lid', |
35
|
|
|
'account_lastlogin','accountlastloginfrom','account_lastpwd_change' |
36
|
|
|
); |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Hook to edit account data via "Account" tab in addressbook edit dialog |
40
|
|
|
* |
41
|
|
|
* @param array $content |
42
|
|
|
* @return array |
43
|
|
|
* @throws Api\Exception\NotFound |
44
|
|
|
*/ |
45
|
|
|
public function addressbook_edit(array $content) |
46
|
|
|
{ |
47
|
|
|
if ((string)$content['owner'] === '0' && $GLOBALS['egw_info']['user']['apps']['admin']) |
48
|
|
|
{ |
49
|
|
|
$deny_edit = $content['account_id'] ? $GLOBALS['egw']->acl->check('account_access', 16, 'admin') : |
50
|
|
|
$GLOBALS['egw']->acl->check('account_access', 4, 'admin'); |
51
|
|
|
//error_log(__METHOD__."() contact_id=$content[contact_id], account_id=$content[account_id], deny_edit=".array2string($deny_edit)); |
52
|
|
|
|
53
|
|
|
if (!$content['account_id'] && $deny_edit) return; // no right to add new accounts, should not happen by AB ACL |
54
|
|
|
|
55
|
|
|
// load our translations |
56
|
|
|
Api\Translation::add_app('admin'); |
57
|
|
|
|
58
|
|
|
if ($content['id']) // existing account |
59
|
|
|
{ |
60
|
|
|
// invalidate account, before reading it, to code with changed to DB or LDAP outside EGw |
61
|
|
|
Api\Accounts::cache_invalidate((int)$content['account_id']); |
62
|
|
|
if (!($account = $GLOBALS['egw']->accounts->read($content['account_id']))) |
63
|
|
|
{ |
64
|
|
|
throw new Api\Exception\NotFound('Account data NOT found!'); |
65
|
|
|
} |
66
|
|
|
if ($account['account_expires'] == -1) $account['account_expires'] = ''; |
67
|
|
|
unset($account['account_pwd']); // do NOT send to client |
68
|
|
|
$account['account_groups'] = array_keys($account['memberships']); |
69
|
|
|
$acl = new Acl($content['account_id']); |
70
|
|
|
$acl->read_repository(); |
71
|
|
|
$account['anonymous'] = $acl->check('anonymous', 1, 'phpgwapi'); |
72
|
|
|
$account['changepassword'] = !$acl->check('nopasswordchange', 1, 'preferences'); |
73
|
|
|
$auth = new Api\Auth(); |
74
|
|
|
if (($account['account_lastpwd_change'] = $auth->getLastPwdChange($account['account_lid'])) === false) |
75
|
|
|
{ |
76
|
|
|
$account['account_lastpwd_change'] = null; |
77
|
|
|
} |
78
|
|
|
$account['mustchangepassword'] = isset($account['account_lastpwd_change']) && |
79
|
|
|
(string)$account['account_lastpwd_change'] === '0'; |
80
|
|
|
} |
81
|
|
|
else // new account |
82
|
|
|
{ |
83
|
|
|
$account = array( |
84
|
|
|
'account_status' => 'A', |
85
|
|
|
'account_groups' => array(), |
86
|
|
|
'anonymous' => false, |
87
|
|
|
'changepassword' => true, //old default: (bool)$GLOBALS['egw_info']['server']['change_pwd_every_x_days'], |
88
|
|
|
'mustchangepassword' => false, |
89
|
|
|
'account_primary_group' => $GLOBALS['egw']->accounts->name2id('Default'), |
90
|
|
|
'homedirectory' => $GLOBALS['egw_info']['server']['ldap_account_home'], |
91
|
|
|
'loginshell' => $GLOBALS['egw_info']['server']['ldap_account_shell'], |
92
|
|
|
); |
93
|
|
|
} |
94
|
|
|
// should we show extra ldap attributes home-directory and login-shell |
95
|
|
|
$account['ldap_extra_attributes'] = $GLOBALS['egw_info']['server']['ldap_extra_attributes'] && |
96
|
|
|
get_class($GLOBALS['egw']->accounts->backend) === 'EGroupware\\Api\\Accounts\\Ldap'; |
97
|
|
|
|
98
|
|
|
$readonlys = array(); |
99
|
|
|
|
100
|
|
|
// at least ADS does not allow to unset it and SQL backend does not implement it either |
101
|
|
|
if ($account['mustchangepassword']) |
102
|
|
|
{ |
103
|
|
|
$readonlys['mustchangepassword'] = true; |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
if ($deny_edit) |
107
|
|
|
{ |
108
|
|
|
foreach(array_keys($account) as $key) |
109
|
|
|
{ |
110
|
|
|
$readonlys[$key] = true; |
111
|
|
|
} |
112
|
|
|
$readonlys['account_passwd'] = $readonlys['account_passwd2'] = true; |
113
|
|
|
} |
114
|
|
|
// save old values to only trigger save, if one of the following values change (contact data get saved anyway) |
115
|
|
|
$preserve = empty($content['id']) ? array() : |
116
|
|
|
array('old_account' => array_intersect_key($account, array_flip(array( |
117
|
|
|
'account_lid', 'account_status', 'account_groups', 'anonymous', 'changepassword', |
118
|
|
|
'mustchangepassword', 'account_primary_group', 'homedirectory', 'loginshell', |
119
|
|
|
'account_expires', 'account_firstname', 'account_lastname', 'account_email'))), |
120
|
|
|
'deny_edit' => $deny_edit); |
121
|
|
|
|
122
|
|
|
if($content && $_GET['copy']) |
|
|
|
|
123
|
|
|
{ |
124
|
|
|
$this->copy($content, $account, $preserve); |
125
|
|
|
} |
126
|
|
|
return array( |
127
|
|
|
'name' => 'admin.account', |
128
|
|
|
'prepend' => true, |
129
|
|
|
'label' => 'Account', |
130
|
|
|
'data' => $account, |
131
|
|
|
'preserve' => $preserve, |
132
|
|
|
'readonlys' => $readonlys, |
133
|
|
|
'pre_save_callback' => $deny_edit ? null : 'admin_account::addressbook_pre_save', |
134
|
|
|
); |
135
|
|
|
} |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* Hook called by addressbook prior to saving addressbook data |
140
|
|
|
* |
141
|
|
|
* @param array &$content |
142
|
|
|
* @throws Exception for errors |
143
|
|
|
* @return string Success message |
144
|
|
|
*/ |
145
|
|
|
public static function addressbook_pre_save(&$content) |
146
|
|
|
{ |
147
|
|
|
if (!isset($content['mustchangepassword'])) |
148
|
|
|
{ |
149
|
|
|
$content['mustchangepassword'] = true; // was readonly because already set |
150
|
|
|
} |
151
|
|
|
$content['account_firstname'] = $content['n_given']; |
152
|
|
|
$content['account_lastname'] = $content['n_family']; |
153
|
|
|
$content['account_email'] = $content['email']; |
154
|
|
|
if($content['account_passwd'] && $content['account_passwd'] !== $content['account_passwd_2']) |
155
|
|
|
{ |
156
|
|
|
throw new Api\Exception\WrongUserinput('Passwords are not the same'); |
157
|
|
|
} |
158
|
|
|
if (!empty($content['old_account'])) |
159
|
|
|
{ |
160
|
|
|
$old = array_diff_assoc($content['old_account'], $content); |
161
|
|
|
// array_diff_assoc compares everything as string (cast to string) |
162
|
|
|
if ($content['old_account']['account_groups'] != $content['account_groups']) |
163
|
|
|
{ |
164
|
|
|
$old['account_groups'] = $content['old_account']['account_groups']; |
165
|
|
|
} |
166
|
|
|
if($content['account_passwd']) |
167
|
|
|
{ |
168
|
|
|
// Don't put password into history |
169
|
|
|
$old['account_passwd'] = ''; |
170
|
|
|
} |
171
|
|
|
} |
172
|
|
|
if ($content['deny_edit'] || $old === array()) |
173
|
|
|
{ |
174
|
|
|
return ''; // no need to save account data, if nothing changed |
175
|
|
|
} |
176
|
|
|
//error_log(__METHOD__."(".array2string($content).")"); |
177
|
|
|
$account = array(); |
178
|
|
|
foreach(array( |
179
|
|
|
// need to copy/rename some fields named different in account and contact |
180
|
|
|
'n_given' => 'account_firstname', |
181
|
|
|
'n_family' => 'account_lastname', |
182
|
|
|
'email' => 'account_email', |
183
|
|
|
'account_groups', |
184
|
|
|
// copy following fields to account |
185
|
|
|
'account_lid', |
186
|
|
|
'changepassword', 'anonymous', 'mustchangepassword', |
187
|
|
|
'account_passwd', 'account_passwd_2', |
188
|
|
|
'account_primary_group', |
189
|
|
|
'account_expires', 'account_status', |
190
|
|
|
'homedirectory', 'loginshell', |
191
|
|
|
'requested', 'requested_email', 'comment', // admin_cmd documentation (EPL) |
192
|
|
|
) as $c_name => $a_name) |
193
|
|
|
{ |
194
|
|
|
if (is_int($c_name)) $c_name = $a_name; |
195
|
|
|
|
196
|
|
|
// only record real changes |
197
|
|
|
if (isset($content['old_account']) && |
198
|
|
|
// currently LDAP (and probably also AD and UCS) can not skip unchanged fields! |
199
|
|
|
get_class($GLOBALS['egw']->accounts->backend) === 'EGroupware\\Api\\Accounts\\Sql' && |
200
|
|
|
(!isset($content[$c_name]) && $c_name !== 'account_expires' || // account_expires is not set when empty! |
201
|
|
|
$content['old_account'][$a_name] == $content[$c_name])) |
202
|
|
|
{ |
203
|
|
|
continue; // no change --> no need to log setting it to identical value |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
switch($a_name) |
207
|
|
|
{ |
208
|
|
|
case 'account_expires': |
209
|
|
|
case 'account_status': |
210
|
|
|
$account['account_expires'] = $content['account_expires'] ? $content['account_expires'] : |
211
|
|
|
($content['account_status'] ? 'never' : 'already'); |
212
|
|
|
break; |
213
|
|
|
|
214
|
|
|
case 'changepassword': // boolean values: admin_cmd_edit_user understands '' as NOT set |
215
|
|
|
case 'anonymous': |
216
|
|
|
case 'mustchangepassword': |
217
|
|
|
$account[$a_name] = (boolean)$content[$c_name]; |
218
|
|
|
break; |
219
|
|
|
|
220
|
|
|
default: |
221
|
|
|
$account[$a_name] = $content[$c_name]; |
222
|
|
|
break; |
223
|
|
|
} |
224
|
|
|
} |
225
|
|
|
// Make sure primary group is in account groups |
226
|
|
|
if (isset($account['account_groups']) && $account['account_primary_group'] && |
227
|
|
|
!in_array($account['account_primary_group'], (array)$account['account_groups'])) |
228
|
|
|
{ |
229
|
|
|
$account['account_groups'][] = $account['account_primary_group']; |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
$cmd = new admin_cmd_edit_user(array( |
233
|
|
|
'account' => (int)$content['account_id'], |
234
|
|
|
'set' => $account, |
235
|
|
|
'old' => $old, |
236
|
|
|
)+(array)$content['admin_cmd']); |
237
|
|
|
$cmd->run(); |
238
|
|
|
|
239
|
|
|
Api\Json\Response::get()->call('egw.refresh', '', 'admin', $cmd->account, $content['account_id'] ? 'edit' : 'add'); |
240
|
|
|
|
241
|
|
|
$addressbook_bo = new Api\Contacts(); |
242
|
|
|
if (!($content['id'] = Api\Accounts::id2name($cmd->account, 'person_id')) || |
243
|
|
|
!($contact = $addressbook_bo->read($content['id']))) |
244
|
|
|
{ |
245
|
|
|
throw new Api\Exception\AssertionFailed("Can't find contact of just created account!"); |
246
|
|
|
} |
247
|
|
|
// for a new account a new contact was created, need to merge that data with $content |
248
|
|
|
if (!$content['account_id']) |
249
|
|
|
{ |
250
|
|
|
$content['account_id'] = $cmd->account; |
251
|
|
|
$content = array_merge($contact, $content); |
252
|
|
|
} |
253
|
|
|
else // for updated account, we need to refresh etag |
254
|
|
|
{ |
255
|
|
|
$content['etag'] = $contact['etag']; |
256
|
|
|
} |
257
|
|
|
} |
258
|
|
|
|
259
|
|
|
public function copy(array &$content, array &$account, array &$preserve) |
260
|
|
|
{ |
261
|
|
|
// We skipped the addressbook copy, call it now |
262
|
|
|
$ab_ui = new addressbook_ui(); |
263
|
|
|
$ab_ui->copy_contact($content, true); |
264
|
|
|
|
265
|
|
|
// copy_contact() reset the owner, fix it |
266
|
|
|
$content['owner'] = '0'; |
267
|
|
|
|
268
|
|
|
// Explicitly, always clear these |
269
|
|
|
static $clear_content = Array( |
270
|
|
|
'n_family','n_given','n_middle','n_suffix','n_fn','n_fileas', |
271
|
|
|
'account_id','contact_id','id','etag','carddav_name','uid' |
272
|
|
|
); |
273
|
|
|
foreach($clear_content as $field) |
274
|
|
|
{ |
275
|
|
|
$account[$field] =''; |
276
|
|
|
$preserve[$field] = ''; |
277
|
|
|
} |
278
|
|
|
$account['link_to']['to_id'] = 0; |
279
|
|
|
unset($preserve['old_account']); |
280
|
|
|
|
281
|
|
|
// Never copy these on an account |
282
|
|
|
foreach(static::$copy_clear_fields as $field) |
283
|
|
|
{ |
284
|
|
|
unset($account[$field]); |
285
|
|
|
} |
286
|
|
|
} |
287
|
|
|
|
288
|
|
|
/** |
289
|
|
|
* Delete an account |
290
|
|
|
* |
291
|
|
|
* @param array $content =null |
292
|
|
|
*/ |
293
|
|
|
public static function delete(array $content=null) |
294
|
|
|
{ |
295
|
|
|
if (!is_array($content)) |
296
|
|
|
{ |
297
|
|
|
if (isset($_GET['contact_id']) && ($account_id = $GLOBALS['egw']->accounts->name2id((int)$_GET['contact_id'], 'person_id'))) |
298
|
|
|
{ |
299
|
|
|
$content = array( |
300
|
|
|
'account_id' => $account_id, |
301
|
|
|
'contact_id' => (int)$_GET['contact_id'], |
302
|
|
|
); |
303
|
|
|
} |
304
|
|
|
else |
305
|
|
|
{ |
306
|
|
|
$content = array('account_id' => (int)$_GET['account_id']); |
307
|
|
|
} |
308
|
|
|
//error_log(__METHOD__."() \$_GET[account_id]=$_GET[account_id], \$_GET[contact_id]=$_GET[contact_id] content=".array2string($content)); |
309
|
|
|
} |
310
|
|
|
if ($GLOBALS['egw']->acl->check('account_access',32,'admin') || |
311
|
|
|
$GLOBALS['egw_info']['user']['account_id'] == $content['account_id']) |
312
|
|
|
{ |
313
|
|
|
Framework::window_close(lang('Permission denied!!!')); |
314
|
|
|
} |
315
|
|
|
if ($content['delete']) |
316
|
|
|
{ |
317
|
|
|
$cmd = new admin_cmd_delete_account(array( |
318
|
|
|
'account' => $content['account_id'], |
319
|
|
|
'new_user' => $content['new_owner'], |
320
|
|
|
'is_user' => $content['account_id'] > 0, |
321
|
|
|
'change_apps' => $content['delete_apps'] |
322
|
|
|
) + (array)$content['admin_cmd']); |
323
|
|
|
$msg = $cmd->run(); |
324
|
|
|
if ($content['contact_id']) |
325
|
|
|
{ |
326
|
|
|
Framework::refresh_opener($msg, 'addressbook', $content['contact_id'], 'delete'); |
327
|
|
|
} |
328
|
|
|
else |
329
|
|
|
{ |
330
|
|
|
Framework::refresh_opener($msg, 'admin', $content['account_id'], 'delete'); |
331
|
|
|
} |
332
|
|
|
Framework::window_close(); |
333
|
|
|
} |
334
|
|
|
|
335
|
|
|
$sel_options = array(); |
336
|
|
|
$preserve = $content; |
337
|
|
|
|
338
|
|
|
// Get a count of entries owned by the user |
339
|
|
|
$counts = $GLOBALS['egw']->accounts->get_account_entry_counts($content['account_id']); |
340
|
|
|
foreach($counts as $app => $counts) |
341
|
|
|
{ |
342
|
|
|
$entry = Api\Link::get_registry($app, 'entries'); |
343
|
|
|
if(!$entry) |
344
|
|
|
{ |
345
|
|
|
$entry = lang('Entries'); |
346
|
|
|
} |
347
|
|
|
if($counts['total'] && Api\Hooks::exists('deleteaccount', $app)) |
348
|
|
|
{ |
349
|
|
|
$content['delete_apps'][] = $app; |
350
|
|
|
$sel_options['delete_apps'][] = array( |
351
|
|
|
'value' => $app, |
352
|
|
|
'label' => lang($app) . ': ' . $counts['total'] . ' '.$entry |
|
|
|
|
353
|
|
|
); |
354
|
|
|
} |
355
|
|
|
else if ($counts['total']) |
356
|
|
|
{ |
357
|
|
|
// These ones don't support the needed hook |
358
|
|
|
$content['counts'][] = array( |
359
|
|
|
'app' => $app, |
360
|
|
|
'count' => $counts['total'] . ' '.$entry |
361
|
|
|
); |
362
|
|
|
} |
363
|
|
|
} |
364
|
|
|
// Add filemanager home directory in as special case, hook is in the API |
365
|
|
|
if(Api\Vfs::file_exists('/home/'.$GLOBALS['egw']->accounts->id2name($content['account_id']))) |
366
|
|
|
{ |
367
|
|
|
$app = 'filemanager'; |
368
|
|
|
$sel_options['delete_apps'][] = array( |
369
|
|
|
'value' => $app, |
370
|
|
|
'label' => lang($app) . ': /home' |
371
|
|
|
); |
372
|
|
|
$content['delete_apps'][] = $app; |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
$tpl = new Etemplate('admin.account.delete'); |
376
|
|
|
$tpl->exec('admin_account::delete', $content, $sel_options, array(), $preserve, 2); |
377
|
|
|
} |
378
|
|
|
|
379
|
|
|
/** |
380
|
|
|
* Delete a group via ajax |
381
|
|
|
* |
382
|
|
|
* @param int $account_id |
383
|
|
|
* @param String[] $data Optional data |
384
|
|
|
* @param string $etemplate_exec_id to check against CSRF |
385
|
|
|
*/ |
386
|
|
|
public static function ajax_delete_group($account_id, $data, $etemplate_exec_id) |
387
|
|
|
{ |
388
|
|
|
Api\Etemplate\Request::csrfCheck($etemplate_exec_id, __METHOD__, func_get_args()); |
389
|
|
|
|
390
|
|
|
$cmd = new admin_cmd_delete_account(Api\Accounts::id2name(Api\Accounts::id2name($account_id)), null, false, (array)$data['admin_cmd']); |
391
|
|
|
$msg = $cmd->run(); |
392
|
|
|
|
393
|
|
|
Api\Json\Response::get()->call('egw.refresh', $msg, 'admin', $account_id, 'delete'); |
394
|
|
|
} |
395
|
|
|
|
396
|
|
|
/** |
397
|
|
|
* Check entered data and return error-msg via json data or null |
398
|
|
|
* |
399
|
|
|
* @param array $data values for account_id and account_lid |
400
|
|
|
* @param string $changed name of addressbook widget triggering change eg. "email", "n_given" or "n_family" |
401
|
|
|
*/ |
402
|
|
|
public static function ajax_check(array $data, $changed) |
403
|
|
|
{ |
404
|
|
|
// warn if anonymous user is renamed, as it breaks eg. sharing and Collabora |
405
|
|
|
if ($changed == 'account_lid' && Api\Accounts::id2name($data['account_id']) === 'anonymous' && $data['account_lid'] !== 'anonymous') |
406
|
|
|
{ |
407
|
|
|
Api\Json\Response::get()->data(lang("Renaming user 'anonymous' will break file sharing and Collabora Online Office!")); |
408
|
|
|
return; |
409
|
|
|
} |
410
|
|
|
|
411
|
|
|
// for 1. password field just check password complexity |
412
|
|
|
if ($changed == 'account_passwd') |
413
|
|
|
{ |
414
|
|
|
$data['account_fullname'] = $data['account_firstname'].' '.$data['account_lastname']; |
415
|
|
|
if (($error = Api\Auth::crackcheck($data['account_passwd'], null, null, null, $data))) |
416
|
|
|
{ |
417
|
|
|
$error .= "\n\n".lang('If you ignore that error as admin, you should check "%1"!', lang('Must change password upon next login')); |
|
|
|
|
418
|
|
|
} |
419
|
|
|
Api\Json\Response::get()->data($error); |
420
|
|
|
return; |
421
|
|
|
} |
422
|
|
|
// generate default email address, but only for new Api\Accounts |
423
|
|
|
if (!$data['account_id'] && in_array($changed, array('n_given', 'n_family', 'account_lid'))) |
424
|
|
|
{ |
425
|
|
|
$email = Api\Accounts::email($data['account_firstname'], $data['account_lastname'], $data['account_lid']); |
426
|
|
|
if ($email && $email[0] != '@' && strpos($email, '@')) // only add valid email addresses |
427
|
|
|
{ |
428
|
|
|
Api\Json\Response::get()->assign('addressbook-edit_email', 'value', $email); |
429
|
|
|
} |
430
|
|
|
} |
431
|
|
|
|
432
|
|
|
if (!$data['account_lid'] && !$data['account_id']) return; // makes no sense to check before |
433
|
|
|
|
434
|
|
|
// set home-directory when account_lid is entered, but only for new Api\Accounts |
435
|
|
|
if ($changed == 'account_lid' && !$data['account_id'] && |
436
|
|
|
$GLOBALS['egw_info']['server']['ldap_extra_attributes'] && |
437
|
|
|
$GLOBALS['egw_info']['server']['ldap_account_home']) |
438
|
|
|
{ |
439
|
|
|
Api\Json\Response::get()->assign('addressbook-edit_homedirectory', 'value', |
440
|
|
|
$GLOBALS['egw_info']['server']['ldap_account_home'].'/'.preg_replace('/[^a-z0-9_.-]/i', '', |
441
|
|
|
Api\Translation::to_ascii($data['account_lid']))); |
442
|
|
|
} |
443
|
|
|
|
444
|
|
|
// set dummy membership to get no error about no members yet |
445
|
|
|
$data['account_memberships'] = array($data['account_primary_user'] = $GLOBALS['egw_info']['user']['account_primary_group']); |
446
|
|
|
|
447
|
|
|
try { |
448
|
|
|
$cmd = new admin_cmd_edit_user($data['account_id'], $data); |
449
|
|
|
$cmd->run(null, false, false, true); |
450
|
|
|
} |
451
|
|
|
catch(Exception $e) |
452
|
|
|
{ |
453
|
|
|
Api\Json\Response::get()->data($e->getMessage()); |
454
|
|
|
} |
455
|
|
|
} |
456
|
|
|
} |
457
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.