Completed
Push — master ( 790997...0c1ba7 )
by Nazar
08:20
created

profile::profile_sign_out()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3.0261

Importance

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