Completed
Push — master ( 078041...8fa8af )
by Nazar
04:09
created

profile::fill_optional_profile_data()   B

Complexity

Conditions 6
Paths 32

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

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