View.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. <?php
  2. /**
  3. * This file is part of the ForkBB <https://github.com/forkbb>.
  4. *
  5. * @copyright (c) Visman <mio.visman@yandex.ru, https://github.com/MioVisman>
  6. * @license The MIT License (MIT)
  7. */
  8. declare(strict_types=1);
  9. namespace ForkBB\Models\Pages\Admin\Users;
  10. use ForkBB\Core\Validator;
  11. use ForkBB\Models\Page;
  12. use ForkBB\Models\Pages\Admin\Users;
  13. use function \ForkBB\__;
  14. class View extends Users
  15. {
  16. /**
  17. * Генерирует список доступных групп пользователей
  18. */
  19. protected function groups(bool $onlyKeys = false): array
  20. {
  21. $groups = [
  22. -1 => __('All groups'),
  23. 0 => __('Unverified users'),
  24. ];
  25. foreach ($this->c->groups->getList() as $group) {
  26. if (! $group->groupGuest) {
  27. $groups[$group->g_id] = $group->g_title;
  28. }
  29. }
  30. return $onlyKeys ? \array_keys($groups) : $groups;
  31. }
  32. /**
  33. * Подготавливает данные для шаблона поиска пользователей
  34. */
  35. public function view(array $args, string $method, array $data = []): Page
  36. {
  37. if ('POST' === $method) {
  38. $v = $this->c->Validator->reset()
  39. ->addRules([
  40. 'token' => 'token:AdminUsers',
  41. 'ip' => 'required',
  42. ]);
  43. if ($v->validation($_POST)) {
  44. $ip = \filter_var($v->ip, \FILTER_VALIDATE_IP);
  45. if (false === $ip) {
  46. $this->fIswev = ['v', 'Bad IP message'];
  47. $data = $v->getData();
  48. } else {
  49. return $this->c->Redirect->page('AdminUsersResult', ['data' => $this->encodeData($ip)]);
  50. }
  51. } else {
  52. $v = $this->c->Validator->reset()
  53. ->addValidators([
  54. ])->addRules([
  55. 'token' => 'token:AdminUsers',
  56. 'username' => 'string:null|max:25',
  57. 'email' => 'string:null|max:80',
  58. 'title' => 'string:null|max:50',
  59. 'realname' => 'string:null|max:40',
  60. 'gender' => 'integer|in:0,1,2',
  61. 'url' => 'string:null|max:100',
  62. 'location' => 'string:null|max:30',
  63. 'signature' => 'string:null|max:512',
  64. 'admin_note' => 'string:null|max:30',
  65. 'num_posts_1' => 'integer|min:0|max:9999999999',
  66. 'num_posts_2' => 'integer|min:0|max:9999999999',
  67. 'last_post_1' => 'date',
  68. 'last_post_2' => 'date',
  69. 'last_visit_1' => 'date',
  70. 'last_visit_2' => 'date',
  71. 'registered_1' => 'date',
  72. 'registered_2' => 'date',
  73. 'order_by' => 'required|string|in:username,email,num_posts,last_post,last_visit,registered',
  74. 'direction' => 'required|string|in:ASC,DESC',
  75. 'user_group' => 'required|integer|in:' . \implode(',', $this->groups(true)),
  76. ])->addAliases([
  77. 'username' => 'Username label',
  78. 'email' => 'E-mail address label',
  79. 'title' => 'Title label',
  80. 'realname' => 'Real name label',
  81. 'gender' => 'Gender label',
  82. 'url' => 'Website label',
  83. 'location' => 'Location label',
  84. 'signature' => 'Signature label',
  85. 'admin_note' => 'Admin note label',
  86. 'num_posts_1' => 'Posts label',
  87. 'num_posts_2' => 'Posts label',
  88. 'last_post_1' => 'Last post label',
  89. 'last_post_2' => 'Last post label',
  90. 'last_visit_1' => 'Last visit label',
  91. 'last_visit_2' => 'Last visit label',
  92. 'registered_1' => 'Registered label',
  93. 'registered_2' => 'Registered label',
  94. 'order_by' => 'Order by label',
  95. # 'direction' => ,
  96. 'user_group' => 'User group label',
  97. ])->addArguments([
  98. ])->addMessages([
  99. ]);
  100. if ($v->validation($_POST)) {
  101. return $this->c->Redirect->page('AdminUsersResult', ['data' => $this->encodeData($v->getData())]);
  102. }
  103. $this->fIswev = $v->getErrors();
  104. $data = $v->getData();
  105. }
  106. }
  107. $this->nameTpl = 'admin/users';
  108. $this->formSearch = $this->form($data);
  109. if ($this->c->userRules->viewIP) {
  110. $this->formIP = $this->formIP($data);
  111. }
  112. if ($this->user->isAdmin) {
  113. $this->formNew = $this->formNew();
  114. $this->formRecalculate = $this->formRecalculate();
  115. }
  116. return $this;
  117. }
  118. /**
  119. * Создает массив данных для кнопки добавления пользователя
  120. */
  121. protected function formNew(): array
  122. {
  123. $form = [
  124. 'action' => $this->c->Router->link('AdminUsers'),
  125. 'hidden' => [],
  126. 'sets' => [
  127. 'new' => [
  128. 'legend' => 'New user',
  129. 'fields' => [],
  130. ]
  131. ],
  132. 'btns' => [
  133. 'new' => [
  134. 'type' => 'btn',
  135. 'value' => __('Add'),
  136. 'link' => $this->c->Router->link('AdminUsersNew'),
  137. ],
  138. ],
  139. ];
  140. return $form;
  141. }
  142. /**
  143. * Создает массив данных для формы поиска
  144. */
  145. protected function form(array $data): array
  146. {
  147. $form = [
  148. 'action' => $this->c->Router->link('AdminUsers'),
  149. 'hidden' => [
  150. 'token' => $this->c->Csrf->create('AdminUsers'),
  151. ],
  152. 'sets' => [],
  153. 'btns' => [
  154. 'search' => [
  155. 'type' => 'submit',
  156. 'value' => __('Submit search'),
  157. ],
  158. ],
  159. ];
  160. $form['sets']['search-info'] = [
  161. 'info' => [
  162. [
  163. 'value' => __('User search info'),
  164. ],
  165. ],
  166. ];
  167. $fields = [];
  168. $fields['username'] = [
  169. 'type' => 'text',
  170. 'maxlength' => '25',
  171. 'caption' => 'Username label',
  172. 'value' => $data['username'] ?? null,
  173. ];
  174. $fields['email'] = [
  175. 'type' => 'text',
  176. 'maxlength' => '80',
  177. 'caption' => 'E-mail address label',
  178. 'value' => $data['email'] ?? null,
  179. ];
  180. $fields['title'] = [
  181. 'type' => 'text',
  182. 'maxlength' => '50',
  183. 'caption' => 'Title label',
  184. 'value' => $data['title'] ?? null,
  185. ];
  186. $fields['realname'] = [
  187. 'type' => 'text',
  188. 'maxlength' => '40',
  189. 'caption' => 'Real name label',
  190. 'value' => $data['realname'] ?? null,
  191. ];
  192. $genders = [
  193. 0 => __('Do not display'),
  194. 1 => __('Male'),
  195. 2 => __('Female'),
  196. ];
  197. $fields['gender'] = [
  198. # 'class' => ['block'],
  199. 'type' => 'radio',
  200. 'value' => $data['gender'] ?? -1,
  201. 'values' => $genders,
  202. 'caption' => 'Gender label',
  203. ];
  204. $fields['url'] = [
  205. 'id' => 'website',
  206. 'type' => 'text',
  207. 'maxlength' => '100',
  208. 'caption' => 'Website label',
  209. 'value' => $data['url'] ?? null,
  210. ];
  211. $fields['location'] = [
  212. 'type' => 'text',
  213. 'maxlength' => '30',
  214. 'caption' => 'Location label',
  215. 'value' => $data['location'] ?? null,
  216. ];
  217. $fields['signature'] = [
  218. 'type' => 'text',
  219. 'maxlength' => '512',
  220. 'caption' => 'Signature label',
  221. 'value' => $data['signature'] ?? null,
  222. ];
  223. $fields['admin_note'] = [
  224. 'type' => 'text',
  225. 'maxlength' => '30',
  226. 'caption' => 'Admin note label',
  227. 'value' => $data['admin_note'] ?? null,
  228. ];
  229. $fields['between1'] = [
  230. 'class' => ['between'],
  231. 'type' => 'wrap',
  232. ];
  233. $fields['num_posts_1'] = [
  234. 'type' => 'number',
  235. 'class' => ['bstart'],
  236. 'min' => '0',
  237. 'max' => '9999999999',
  238. 'value' => $data['num_posts_1'] ?? null,
  239. 'caption' => 'Posts label',
  240. ];
  241. $fields['num_posts_2'] = [
  242. 'type' => 'number',
  243. 'class' => ['bend'],
  244. 'min' => '0',
  245. 'max' => '9999999999',
  246. 'value' => $data['num_posts_2'] ?? null,
  247. ];
  248. $fields[] = [
  249. 'type' => 'endwrap',
  250. ];
  251. $fields['between2'] = [
  252. 'class' => ['between'],
  253. 'type' => 'wrap',
  254. ];
  255. $fields['last_post_1'] = [
  256. 'class' => ['bstart'],
  257. 'type' => 'text',
  258. 'maxlength' => '100',
  259. 'value' => $data['last_post_1'] ?? null,
  260. 'caption' => 'Last post label',
  261. ];
  262. $fields['last_post_2'] = [
  263. 'class' => ['bend'],
  264. 'type' => 'text',
  265. 'maxlength' => '100',
  266. 'value' => $data['last_post_2'] ?? null,
  267. ];
  268. $fields[] = [
  269. 'type' => 'endwrap',
  270. ];
  271. $fields['between3'] = [
  272. 'class' => ['between'],
  273. 'type' => 'wrap',
  274. ];
  275. $fields['last_visit_1'] = [
  276. 'class' => ['bstart'],
  277. 'type' => 'text',
  278. 'maxlength' => '100',
  279. 'value' => $data['last_visit_1'] ?? null,
  280. 'caption' => 'Last visit label',
  281. ];
  282. $fields['last_visit_2'] = [
  283. 'class' => ['bend'],
  284. 'type' => 'text',
  285. 'maxlength' => '100',
  286. 'value' => $data['last_visit_2'] ?? null,
  287. ];
  288. $fields[] = [
  289. 'type' => 'endwrap',
  290. ];
  291. $fields['between4'] = [
  292. 'class' => ['between'],
  293. 'type' => 'wrap',
  294. ];
  295. $fields['registered_1'] = [
  296. 'class' => ['bstart'],
  297. 'type' => 'text',
  298. 'maxlength' => '100',
  299. 'value' => $data['registered_1'] ?? null,
  300. 'caption' => 'Registered label',
  301. ];
  302. $fields['registered_2'] = [
  303. 'class' => ['bend'],
  304. 'type' => 'text',
  305. 'maxlength' => '100',
  306. 'value' => $data['registered_2'] ?? null,
  307. ];
  308. $fields[] = [
  309. 'type' => 'endwrap',
  310. ];
  311. $form['sets']['filters'] = [
  312. 'legend' => 'User search subhead',
  313. 'fields' => $fields,
  314. ];
  315. $fields = [];
  316. $fields['between5'] = [
  317. 'class' => ['between'],
  318. 'type' => 'wrap',
  319. ];
  320. $fields['order_by'] = [
  321. 'class' => ['bstart'],
  322. 'type' => 'select',
  323. 'options' => [
  324. 'username' => __('Order by username'),
  325. 'email' => __('Order by e-mail'),
  326. 'num_posts' => __('Order by posts'),
  327. 'last_post' => __('Order by last post'),
  328. 'last_visit' => __('Order by last visit'),
  329. 'registered' => __('Order by registered'),
  330. ],
  331. 'value' => $data['order_by'] ?? 'registered',
  332. 'caption' => 'Order by label',
  333. ];
  334. $fields['direction'] = [
  335. 'class' => ['bend'],
  336. 'type' => 'select',
  337. 'options' => [
  338. 'ASC' => __('Ascending'),
  339. 'DESC' => __('Descending'),
  340. ],
  341. 'value' => $data['direction'] ?? 'DESC',
  342. ];
  343. $fields[] = [
  344. 'type' => 'endwrap',
  345. ];
  346. $fields['user_group'] = [
  347. 'type' => 'select',
  348. 'options' => $this->groups(),
  349. 'value' => $data['user_group'] ?? -1,
  350. 'caption' => 'User group label',
  351. ];
  352. $form['sets']['sorting'] = [
  353. 'legend' => 'Search results legend',
  354. 'fields' => $fields,
  355. ];
  356. return $form;
  357. }
  358. /**
  359. * Создает массив данных для формы поиска по IP
  360. */
  361. protected function formIP(array $data): array
  362. {
  363. $form = [
  364. 'action' => $this->c->Router->link('AdminUsers'),
  365. 'hidden' => [
  366. 'token' => $this->c->Csrf->create('AdminUsers'),
  367. ],
  368. 'sets' => [],
  369. 'btns' => [
  370. 'find' => [
  371. 'type' => 'submit',
  372. 'value' => __('Find IP address'),
  373. ],
  374. ],
  375. ];
  376. $fields = [];
  377. $fields['ip'] = [
  378. 'type' => 'text',
  379. 'maxlength' => '49',
  380. 'caption' => 'IP address label',
  381. 'value' => $data['ip'] ?? null,
  382. 'required' => true,
  383. ];
  384. $form['sets']['ip'] = [
  385. 'legend' => 'IP search subhead',
  386. 'fields' => $fields,
  387. ];
  388. return $form;
  389. }
  390. /**
  391. * Пересчитывает количество сообщений пользователей
  392. */
  393. public function recalculate(array $args, string $method): Page
  394. {
  395. $v = $this->c->Validator->reset()
  396. ->addValidators([
  397. ])->addRules([
  398. 'confirm' => 'checkbox',
  399. 'token' => 'token:AdminUsersRecalculate',
  400. ])->addAliases([
  401. ])->addArguments([
  402. ])->addMessages([
  403. ]);
  404. if (
  405. ! $v->validation($_POST)
  406. || '1' !== $v->confirm
  407. ) {
  408. return $this->c->Message->message(
  409. '1' !== $v->confirm ? 'No confirm redirect' : ($this->c->Csrf->getError() ?? 'Bad token')
  410. );
  411. }
  412. $this->c->users->updateCountPosts();
  413. return $this->c->Redirect->page('AdminUsers')->message('Updated the number of users posts redirect');
  414. }
  415. /**
  416. * Создает массив данных для формы пересчета количества сообщений
  417. */
  418. protected function formRecalculate(): array
  419. {
  420. $form = [
  421. 'action' => $this->c->Router->link('AdminUsersRecalculate'),
  422. 'hidden' => [
  423. 'token' => $this->c->Csrf->create('AdminUsersRecalculate'),
  424. ],
  425. 'sets' => [
  426. 'recalculate' => [
  427. 'legend' => 'Number of users posts',
  428. 'fields' => [
  429. 'confirm' => [
  430. 'type' => 'checkbox',
  431. 'label' => 'Confirm action',
  432. 'checked' => false,
  433. ],
  434. ],
  435. ],
  436. ],
  437. 'btns' => [
  438. 'recalculate' => [
  439. 'type' => 'submit',
  440. 'value' => __('Recalculate'),
  441. ],
  442. ],
  443. ];
  444. return $form;
  445. }
  446. }