Completed
Push — master ( 042356...63fe0f )
by Nazar
04:34
created

users::admin_users___search_get()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 12

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 16
rs 9.4285
cc 2
eloc 12
nc 2
nop 2
1
<?php
2
/**
3
 * @package    CleverStyle CMS
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\admin;
11
use
12
	cs\ExitException,
13
	cs\Language\Prefix,
14
	cs\Page,
15
	cs\User;
16
17
trait users {
18
	/**
19
	 * Get user's data or data of several specified groups if specified in ids query parameter or allows to search for users by login or email (users id will
20
	 * be returned)
21
	 *
22
	 * Data will be pre-processed with `reg_date_formatted` and `reg_ip_formatted` keys added
23
	 *
24
	 * @param int[] $route_ids
25
	 *
26
	 * @throws ExitException
27
	 */
28
	static function admin_users___get ($route_ids) {
29
		$User    = User::instance();
30
		$Page    = Page::instance();
31
		$columns = static::admin_users___search_options_get()['columns'];
32
		if (isset($route_ids[0])) {
33
			$result = static::admin_users___get_post_process(
34
				$User->get($columns, $route_ids[0])
35
			);
36
		} elseif (isset($_GET['ids'])) {
37
			$ids    = _int(explode(',', $_GET['ids']));
38
			$result = [];
39
			foreach ($ids as $id) {
40
				$result[] = static::admin_users___get_post_process(
41
					$User->get($columns, $id)
42
				);
43
			}
44
		} elseif (isset($_GET['search'])) {
45
			$result = _int($User->search_users($_GET['search']));
46
		} else {
47
			throw new ExitException(400);
48
		}
49
		if (!$result) {
50
			throw new ExitException(404);
51
		}
52
		$Page->json($result);
53
	}
54
	protected static function admin_users___get_post_process ($data) {
55
		$L                          = new Prefix('system_admin_users_');
56
		$data['reg_date_formatted'] = $data['reg_date'] ? date($L->_date, $data['reg_date']) : $L->undefined;
57
		$data['reg_ip_formatted']   = hex2ip($data['reg_ip'], 10);
58
		return $data;
59
	}
60
	/**
61
	 * Update user's data
62
	 *
63
	 * @param int[] $route_ids
64
	 *
65
	 * @throws ExitException
66
	 */
67
	static function admin_users___patch ($route_ids) {
68
		if (!isset($route_ids[0], $_POST['user'])) {
69
			throw new ExitException(400);
70
		}
71
		$User    = User::instance();
72
		$user_id = (int)$route_ids[0];
73
		$is_bot  = in_array(User::BOT_GROUP_ID, $User->get_groups($user_id));
74
		if ($is_bot && !@$_POST['user']['login'] && !@$_POST['user']['email']) {
75
			throw new ExitException(400);
76
		}
77
		$columns_allowed_to_edit = $is_bot
78
			? ['login', 'username', 'email', 'status']
79
			: ['login', 'username', 'email', 'language', 'timezone', 'status', 'block_until', 'avatar'];
80
		$user_data               = array_filter(
81
			$_POST['user'],
82
			function ($item) use ($columns_allowed_to_edit) {
83
				return in_array($item, $columns_allowed_to_edit, true);
84
			},
85
			ARRAY_FILTER_USE_KEY
86
		);
87
		foreach ($user_data as &$d) {
88
			$d = xap($d, false);
89
		}
90
		unset($d);
91
		if (!$user_data && ($is_bot || !isset($_POST['user']['password']))) {
92
			throw new ExitException(400);
93
		}
94
		$L = new Prefix('system_admin_users_');
95
		if (
96
			isset($user_data['login']) &&
97
			$user_data['login'] !== $User->get('login', $user_id) &&
98
			$User->get_id(hash('sha224', $user_data['login']))
99
		) {
100
			throw new ExitException($L->login_occupied, 400);
101
		}
102
		if (
103
			isset($user_data['email']) &&
104
			$user_data['email'] !== $User->get('email', $user_id) &&
105
			$User->get_id(hash('sha224', $user_data['email']))
106
		) {
107
			throw new ExitException($L->email_occupied, 400);
108
		}
109
		if (!$User->set($user_data, null, $user_id)) {
110
			throw new ExitException(500);
111
		}
112
		if (!$is_bot && isset($_POST['user']['password']) && !$User->set_password($_POST['user']['password'], $user_id)) {
113
			throw new ExitException(500);
114
		}
115
	}
116
	/**
117
	 * Add new user or bot (different parameters required depending on `type` parameter)
118
	 *
119
	 * @throws ExitException
120
	 */
121
	static function admin_users___post () {
122
		if (!isset($_POST['type'])) {
123
			throw new ExitException(400);
124
		}
125
		$User = User::instance();
126
		$Page = Page::instance();
127
		if ($_POST['type'] === 'user' && isset($_POST['email'])) {
128
			$result = $User->registration($_POST['email'], false, false);
129
			if (!$result) {
130
				throw new ExitException(500);
131
			}
132
			if ($result === 'exists') {
133
				$L = new Prefix('system_admin_users_');
134
				throw new ExitException($L->user_already_exists, 400);
135
			}
136
			status_code(201);
137
			$Page->json(
138
				[
139
					'login'    => $User->get('login', $result['id']),
140
					'password' => $result['password']
141
				]
142
			);
143
		} elseif ($_POST['type'] === 'bot' && isset($_POST['name'], $_POST['user_agent'], $_POST['ip'])) {
144
			if ($User->add_bot($_POST['name'], $_POST['user_agent'], $_POST['ip'])) {
145
				status_code(201);
146
			} else {
147
				throw new ExitException(500);
148
			}
149
		} else {
150
			throw new ExitException(400);
151
		}
152
	}
153
	/**
154
	 * Advanced search for users (users data will be returned similar to GET method)
155
	 *
156
	 * @throws ExitException
157
	 */
158
	static function admin_users___search () {
159
		if (!isset($_POST['mode'], $_POST['column'], $_POST['text'], $_POST['page'], $_POST['limit'])) {
160
			throw new ExitException(400);
161
		}
162
		$mode           = $_POST['mode'];
163
		$column         = $_POST['column'];
164
		$text           = $_POST['text'];
165
		$page           = (int)$_POST['page'];
166
		$limit          = (int)$_POST['limit'];
167
		$search_options = static::admin_users___search_options_get();
168
		if (
169
			!in_array($mode, $search_options['modes']) ||
170
			(
171
				$column !== '' &&
172
				!in_array($column, $search_options['columns'])
173
			)
174
		) {
175
			throw new ExitException(400);
176
		}
177
		$cdb   = User::instance()->db();
178
		$where = static::admin_users___search_prepare_where($mode, $text, $column ?: $search_options['columns'], $cdb);
179
		/**
180
		 * Deleted users do not have any email, login or password, all of them are empty strings
181
		 */
182
		$where =
183
			"$where AND
184
			(
185
				`login`	!= `password_hash` OR
186
				`email`	!= `password_hash`
187
			)";
188
		$count = $cdb->qfs(
189
			[
190
				"SELECT COUNT(`id`)
191
				FROM `[prefix]users`
192
				WHERE $where"
193
			]
194
		);
195
		if (!$count) {
196
			throw new ExitException(404);
197
		}
198
		$where = str_replace('%', '%%', $where);
199
		$ids   = $cdb->qfas(
200
			[
201
				"SELECT `id`
202
				FROM `[prefix]users`
203
				WHERE $where
204
				ORDER BY `id`
205
				LIMIT %d, %d",
206
				($page - 1) * $limit,
207
				$limit
208
			]
209
		);
210
		Page::instance()->json(
211
			[
212
				'count' => $count,
213
				'users' => static::admin_users___search_get($ids, $search_options['columns'])
214
			]
215
		);
216
	}
217
	/**
218
	 * @param string           $mode
219
	 * @param string           $text
220
	 * @param string|string[]  $column
221
	 * @param \cs\DB\_Abstract $cdb
222
	 *
223
	 * @return string
224
	 */
225
	protected static function admin_users___search_prepare_where ($mode, $text, $column, $cdb) {
226
		$where = '1';
227
		if ($text && $mode) {
228
			switch ($mode) {
229
				case '=':
230
				case '!=':
231
				case '>':
232
				case '<':
233
				case '>=':
234
				case '<=':
235
				case 'LIKE':
236
				case 'NOT LIKE':
237
				case 'REGEXP':
238
				case 'NOT REGEXP':
239
					$where = static::admin_users___search_prepare_where_compose(
240
						"`%s` $mode %s",
241
						$column,
242
						$cdb->s($text)
243
					);
244
					break;
245
				case 'IN':
246
				case 'NOT IN':
247
					$where = static::admin_users___search_prepare_where_compose(
248
						"`%s` $mode (%s)",
249
						$column,
250
						implode(
251
							", ",
252
							$cdb->s(
253
								_trim(
254
									_trim(explode(',', $text), "'")
255
								)
256
							)
257
						)
258
					);
259
					break;
260
			}
261
		}
262
		return $where;
263
	}
264
	/**
265
	 * @param string          $where
266
	 * @param string|string[] $column
267
	 * @param string          $text
268
	 *
269
	 * @return string
270
	 */
271
	protected static function admin_users___search_prepare_where_compose ($where, $column, $text) {
272
		if (is_array($column)) {
273
			$return = [];
274
			foreach ($column as $c) {
275
				$return[] = sprintf($where, $c, $text);
276
			}
277
			return '('.implode(' OR ', $return).')';
278
		}
279
		return sprintf($where, $column, $text);
280
	}
281
	/**
282
	 * @param int[]    $users
283
	 * @param string[] $columns
284
	 *
285
	 * @return array[]
0 ignored issues
show
Documentation introduced by
Should the return type not be integer[]?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
286
	 */
287
	protected static function admin_users___search_get ($users, $columns) {
288
		$User = User::instance();
289
		foreach ($users as &$user) {
290
			$groups         = (array)$User->get_groups($user);
291
			$user           =
292
				$User->get($columns, $user) +
293
				[
294
					'is_user'  => in_array(User::USER_GROUP_ID, $groups),
295
					'is_bot'   => in_array(User::BOT_GROUP_ID, $groups),
296
					'is_admin' => in_array(User::ADMIN_GROUP_ID, $groups),
297
					'username' => $User->username($user)
298
				];
299
			$user['reg_ip'] = hex2ip($user['reg_ip'], 10);
300
		}
301
		return $users;
302
	}
303
	/**
304
	 * Get available search options
305
	 */
306
	static function admin_users___search_options () {
307
		Page::instance()->json(
308
			static::admin_users___search_options_get()
309
		);
310
	}
311
	/*
312
	 * @return string[][]
0 ignored issues
show
Documentation introduced by
Should the return type not be array<string,array>?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
313
	 */
314
	protected static function admin_users___search_options_get () {
315
		return [
316
			'modes'   => [
317
				'=',
318
				'!=',
319
				'>',
320
				'<',
321
				'>=',
322
				'<=',
323
				'LIKE',
324
				'NOT LIKE',
325
				'IN',
326
				'NOT IN',
327
				'IS NULL',
328
				'IS NOT NULL',
329
				'REGEXP',
330
				'NOT REGEXP'
331
			],
332
			'columns' => array_values(
333
				array_filter(
334
					User::instance()->get_users_columns(),
335
					function ($column) {
336
						return $column !== 'password_hash';
337
					}
338
				)
339
			)
340
		];
341
	}
342
}
343