Completed
Push — master ( 8fa8af...312807 )
by Nazar
04:29
created

profile   C

Complexity

Total Complexity 57

Size/Duplication

Total Lines 297
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 10

Test Coverage

Coverage 16.37%

Importance

Changes 0
Metric Value
dl 0
loc 297
ccs 28
cts 171
cp 0.1637
rs 5.1724
c 0
b 0
f 0
wmc 57
lcom 0
cbo 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
A profile_get() 0 18 2
D profile_patch() 0 31 9
B profile_change_password() 0 23 6
C profile_registration() 0 45 8
A try_to_register() 0 13 4
B fill_optional_profile_data() 0 18 6
B profile_restore_password() 0 32 6
C profile_sign_in() 0 45 12
A profile_sign_out() 0 16 3
A profile_configuration() 0 8 1

How to fix   Complexity   

Complex Class

Complex classes like profile 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 profile, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @package    CleverStyle Framework
4
 * @subpackage System module
5
 * @category   modules
6
 * @author     Nazar Mokrynskyi <[email protected]>
7
 * @copyright  Copyright (c) 2015-2016, Nazar Mokrynskyi
8
 * @license    MIT License, see license.txt
9
 */
10
namespace cs\modules\System\api\Controller;
11
use
12
	cs\Config,
13
	cs\Core,
14
	cs\ExitException,
15
	cs\Language,
16
	cs\Mail,
17
	cs\Session,
18
	cs\User;
19
20
trait profile {
21 2
	public static function profile_get () {
22 2
		$User         = User::instance();
23
		$fields       = [
24 2
			'id',
25
			'login',
26
			'username',
27
			'language',
28
			'timezone',
29
			'avatar'
30
		];
31 2
		$result       = $User->get($fields, $User->id);
32 2
		$result['id'] = (int)$result['id'];
33 2
		if ($User->guest()) {
34 2
			$result['username'] = Language::instance()->system_profile_guest;
35 2
			$result['avatar']   = $User->avatar();
36
		}
37 2
		return $result;
38
	}
39
	/**
40
	 * @param \cs\Request $Request
41
	 *
42
	 * @throws ExitException
43
	 */
44
	public static function profile_patch ($Request) {
45
		$user_data = $Request->data('login', 'username', 'language', 'timezone', 'avatar');
46
		if (
47
			!$user_data ||
48
			!$user_data['login']
49
		) {
50
			throw new ExitException(400);
51
		}
52
		$User = User::instance();
53
		if ($User->guest()) {
54
			throw new ExitException(403);
55
		}
56
		$user_data          = xap($user_data, false);
57
		$user_data['login'] = mb_strtolower($user_data['login']);
58
		/**
59
		 * Check for changing login to new one and whether it is available
60
		 */
61
		if (
62
			$user_data['login'] != $User->login &&
63
			$user_data['login'] != $User->email &&
64
			(
65
				filter_var($user_data['login'], FILTER_VALIDATE_EMAIL) ||
66
				$User->get_id(hash('sha224', $user_data['login'])) !== false
67
			)
68
		) {
69
			throw new ExitException(Language::instance()->system_admin_users_login_occupied, 400);
70
		}
71
		if (!$User->set($user_data)) {
72
			throw new ExitException(500);
73
		}
74
	}
75
	/**
76
	 * @param \cs\Request $Request
77
	 *
78
	 * @throws ExitException
79
	 */
80
	public static function profile_change_password ($Request) {
81
		$L    = Language::prefix('system_profile_');
82
		$User = User::instance();
83
		$data = $Request->data('current_password', 'new_password');
84
		if (!$data) {
85
			throw new ExitException(400);
86
		}
87
		if (!$User->user()) {
88
			throw new ExitException(403);
89
		}
90
		if (!$data['new_password']) {
91
			throw new ExitException($L->please_type_new_password, 400);
92
		}
93
		if (!$User->validate_password($data['current_password'], $User->id, true)) {
94
			throw new ExitException($L->wrong_current_password, 400);
95
		}
96
		$id = $User->id;
97
		if ($User->set_password($data['new_password'], $id, true)) {
98
			Session::instance()->add($id);
99
		} else {
100
			throw new ExitException($L->change_password_server_error, 400);
101
		}
102
	}
103
	/**
104
	 * @param \cs\Request  $Request
105
	 * @param \cs\Response $Response
106
	 *
107
	 * @throws ExitException
108
	 */
109
	public static function profile_registration ($Request, $Response) {
110
		$Config = Config::instance();
111
		$L      = Language::prefix('system_profile_registration_');
112
		$User   = User::instance();
113
		if (!$User->guest()) {
114
			throw new ExitException(403);
115
		}
116
		if (!$Config->core['allow_user_registration']) {
117
			throw new ExitException($L->prohibited, 403);
118
		}
119
		$email   = $Request->data('email');
120
		$email   = mb_strtolower($email);
121
		$result  = static::try_to_register($User, $L, $email);
122
		$confirm = $result['reg_key'] !== true;
123
		static::fill_optional_profile_data($Request, $User, $result['id']);
124
		$title = $L->success_mail($Config->core['site_name']);
125
		$body  = $L->success_mail(
126
			$User->username($result['id']),
127
			$Config->core['site_name'],
128
			$Config->core_url().'/profile/settings',
129
			$User->get('login', $result['id'])
130
		);
131
		if ($confirm) {
132
			$title = $L->need_confirmation_mail($Config->core['site_name']);
133
			$body  = $L->need_confirmation_mail_body(
134
				$User->username($result['id']),
135
				$Config->core['site_name'],
136
				$Config->core_url()."/profile/registration_confirmation/$result[reg_key]",
137
				$L->time($Config->core['registration_confirmation_time'], 'd')
138
			);
139
		} elseif (!$Request->data('password') && $result['password']) {
140
			$body = $L->success_mail_with_password_body(
141
				$User->username($result['id']),
142
				$Config->core['site_name'],
143
				$Config->core_url().'/profile/settings',
144
				$User->get('login', $result['id']),
145
				$result['password']
146
			);
147
		}
148
		if (!Mail::instance()->send_to($email, $title, $body)) {
149
			$User->registration_cancel();
150
			throw new ExitException($L->mail_sending_error, 500);
151
		}
152
		$Response->code = $confirm ? 202 : 201;
153
	}
154
	/**
155
	 * @param User            $User
156
	 * @param Language\Prefix $L
157
	 * @param string          $email
158
	 *
159
	 * @return array
160
	 *
161
	 * @throws ExitException
162
	 */
163
	protected static function try_to_register ($User, $L, $email) {
164
		$result = $User->registration($email);
165
		if ($result === false) {
166
			throw new ExitException($L->please_type_correct_email, 400);
167
		}
168
		if ($result == 'error') {
169
			throw new ExitException($L->server_error, 500);
170
		}
171
		if ($result == 'exists') {
172
			throw new ExitException($L->error_exists, 400);
173
		}
174
		return $result;
175
	}
176
	/**
177
	 * @param \cs\Request $Request
178
	 * @param User        $User
179
	 * @param int         $user_id
180
	 */
181
	protected static function fill_optional_profile_data ($Request, $User, $user_id) {
182
		if ($Request->data('username')) {
183
			$User->set('username', $Request->data['username'], $user_id);
184
		}
185
		// Actually `sha512(sha512(password) + public_key)` instead of plain password
186
		if ($Request->data('password')) {
187
			$User->set_password($Request->data['password'], $user_id, true);
188
		}
189
		if ($Request->data('language')) {
190
			$User->set('language', $Request->data['language'], $user_id);
191
		}
192
		if ($Request->data('timezone')) {
193
			$User->set('timezone', $Request->data['timezone'], $user_id);
194
		}
195
		if ($Request->data('avatar')) {
196
			$User->set('avatar', $Request->data['avatar'], $user_id);
197
		}
198
	}
199
	/**
200
	 * @param \cs\Request $Request
201
	 *
202
	 * @throws ExitException
203
	 */
204
	public static function profile_restore_password ($Request) {
205
		$Config = Config::instance();
206
		$L      = Language::prefix('system_profile_restore_password_');
207
		$User   = User::instance();
208
		$email  = $Request->data('email');
209
		if (!$User->guest()) {
210
			throw new ExitException(403);
211
		}
212
		if (!$email) {
213
			throw new ExitException($L->please_type_your_email, 400);
214
		}
215
		$id = $User->get_id(mb_strtolower($email));
216
		if (!$id) {
217
			throw new ExitException($L->user_with_such_login_email_not_found, 400);
218
		}
219
		$key = $User->restore_password($id);
220
		if (
221
			!$key ||
222
			!Mail::instance()->send_to(
223
				$User->get('email', $id),
224
				$L->confirmation_mail($Config->core['site_name']),
225
				$L->confirmation_mail_body(
226
					$User->username($id),
227
					$Config->core['site_name'],
228
					$Config->core_url()."/profile/restore_password_confirmation/$key",
229
					$L->time($Config->core['registration_confirmation_time'], 'd')
230
				)
231
			)
232
		) {
233
			throw new ExitException($L->server_error, 500);
234
		}
235
	}
236
	/**
237
	 * @param \cs\Request $Request
238
	 *
239
	 * @throws ExitException
240
	 */
241 2
	public static function profile_sign_in ($Request) {
242 2
		$Config = Config::instance();
243 2
		$L      = Language::prefix('system_profile_sign_in_');
244 2
		$User   = User::instance();
245 2
		$data   = $Request->data('login', 'password');
246 2
		if (!$data) {
247
			throw new ExitException(400);
248
		}
249 2
		if (!$User->guest()) {
250
			return;
251
		}
252
		if (
253 2
			$Config->core['sign_in_attempts_block_count'] &&
254 2
			$User->get_sign_in_attempts_count($data['login']) >= $Config->core['sign_in_attempts_block_count']
255
		) {
256
			$User->sign_in_result(false, $data['login']);
257
			throw new ExitException($L->attempts_are_over_try_again_in(format_time($Config->core['sign_in_attempts_block_time'])), 403);
258
		}
259 2
		$id = $User->get_id($data['login']);
260 2
		if ($id && $User->validate_password($data['password'], $id, true)) {
261 2
			$status      = $User->get('status', $id);
262 2
			$block_until = $User->get('block_until', $id);
263 2
			if ($status == User::STATUS_NOT_ACTIVATED) {
264
				throw new ExitException($L->your_account_is_not_active, 403);
265
			}
266 2
			if ($status == User::STATUS_INACTIVE) {
267
				throw new ExitException($L->your_account_disabled, 403);
268
			}
269 2
			if ($block_until > time()) {
270
				throw new ExitException($L->your_account_blocked_until(date($L->_datetime, $block_until)), 403);
271
			}
272 2
			Session::instance()->add($id);
273 2
			$User->sign_in_result(true, $data['login']);
274
		} else {
275
			$User->sign_in_result(false, $data['login']);
276
			$content = $L->authentication_error;
277
			if (
278
				$Config->core['sign_in_attempts_block_count'] &&
279
				$User->get_sign_in_attempts_count($data['login']) >= $Config->core['sign_in_attempts_block_count'] * 2 / 3
280
			) {
281
				$content .= ' '.$L->attempts_left($Config->core['sign_in_attempts_block_count'] - $User->get_sign_in_attempts_count($data['login']));
282
			}
283
			throw new ExitException($content, 400);
284
		}
285 2
	}
286
	/**
287
	 * @param \cs\Request  $Request
288
	 * @param \cs\Response $Response
289
	 *
290
	 * @throws ExitException
291
	 */
292
	public static function profile_sign_out (
293
		/** @noinspection PhpUnusedParameterInspection */
294
		$Request,
295
		$Response
296
	) {
297
		if (User::instance()->guest()) {
298
			return;
299
		}
300
		if (!Session::instance()->del()) {
301
			throw new ExitException(500);
302
		}
303
		/**
304
		 * Hack for 403 after sign out in administration
305
		 */
306
		$Response->cookie('sign_out', 1, time() + 5, true);
307
	}
308
	public static function profile_configuration () {
309
		$Config = Config::instance();
310
		return [
311
			'public_key'            => Core::instance()->public_key,
312
			'password_min_length'   => (int)$Config->core['password_min_length'],
313
			'password_min_strength' => (int)$Config->core['password_min_strength']
314
		];
315
	}
316
}
317