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.