| Total Complexity | 85 |
| Total Lines | 434 |
| Duplicated Lines | 0 % |
| Changes | 1 | ||
| Bugs | 1 | Features | 0 |
Complex classes like admin_account 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 admin_account, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 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) |
||
| 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) |
||
| 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.