PageRenderTime 24ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Backend/Modules/Users/Engine/Model.php

http://github.com/forkcms/forkcms
PHP | 477 lines | 281 code | 57 blank | 139 comment | 5 complexity | 096e5c3d639b444d87c3efb53cb3af3b MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, MIT, AGPL-3.0, LGPL-2.1, BSD-3-Clause
  1. <?php
  2. namespace Backend\Modules\Users\Engine;
  3. use Backend\Core\Engine\Authentication as BackendAuthentication;
  4. use Backend\Core\Engine\Model as BackendModel;
  5. use Backend\Core\Engine\User as BackendUser;
  6. /**
  7. * In this file we store all generic functions that we will be using in the users module.
  8. */
  9. class Model
  10. {
  11. const QUERY_BROWSE =
  12. 'SELECT i.id
  13. FROM users AS i
  14. WHERE i.deleted = ?';
  15. /**
  16. * Mark the user as deleted and deactivate his account.
  17. *
  18. * @param int $id The userId to delete.
  19. */
  20. public static function delete(int $id): void
  21. {
  22. BackendModel::getContainer()->get('database')->update(
  23. 'users',
  24. ['active' => false, 'deleted' => true],
  25. 'id = ?',
  26. [$id]
  27. );
  28. }
  29. /**
  30. * Deletes the reset_password_key and reset_password_timestamp for a given user ID
  31. *
  32. * @param int $id The userId wherefore the reset-stuff should be deleted.
  33. */
  34. public static function deleteResetPasswordSettings(int $id): void
  35. {
  36. BackendModel::getContainer()->get('database')->delete(
  37. 'users_settings',
  38. '(name = \'reset_password_key\' OR name = \'reset_password_timestamp\') AND user_id = ?',
  39. [$id]
  40. );
  41. }
  42. /**
  43. * Was a user deleted before?
  44. *
  45. * @param string $email The e-mail address to check.
  46. *
  47. * @return bool
  48. */
  49. public static function emailDeletedBefore(string $email): bool
  50. {
  51. // no user to ignore
  52. return (bool) BackendModel::getContainer()->get('database')->getVar(
  53. 'SELECT 1
  54. FROM users AS i
  55. WHERE i.email = ? AND i.deleted = ?
  56. LIMIT 1',
  57. [$email, true]
  58. );
  59. }
  60. /**
  61. * Does the user exist.
  62. *
  63. * @param int $id The userId to check for existence.
  64. * @param bool $active Should the user be active also?
  65. *
  66. * @return bool
  67. */
  68. public static function exists(int $id, bool $active = true): bool
  69. {
  70. // get database
  71. $database = BackendModel::getContainer()->get('database');
  72. // if the user should also be active, there should be at least one row to return true
  73. if ($active) {
  74. return (bool) $database->getVar(
  75. 'SELECT 1
  76. FROM users AS i
  77. WHERE i.id = ? AND i.deleted = ?
  78. LIMIT 1',
  79. [$id, false]
  80. );
  81. }
  82. // fallback, this doesn't take the active nor deleted status in account
  83. return (bool) $database->getVar(
  84. 'SELECT 1
  85. FROM users AS i
  86. WHERE i.id = ?
  87. LIMIT 1',
  88. [$id]
  89. );
  90. }
  91. /**
  92. * Does a email already exist?
  93. * If you specify a userId, the email with the given id will be ignored.
  94. *
  95. * @param string $email The email to check for.
  96. * @param int $id The userId to be ignored.
  97. *
  98. * @return bool
  99. */
  100. public static function existsEmail(string $email, int $id = null): bool
  101. {
  102. // get database
  103. $database = BackendModel::getContainer()->get('database');
  104. // userid specified?
  105. if ($id !== null) {
  106. return (bool) $database->getVar(
  107. 'SELECT 1
  108. FROM users AS i
  109. WHERE i.id != ? AND i.email = ?
  110. LIMIT 1',
  111. [$id, $email]
  112. );
  113. }
  114. // no user to ignore
  115. return (bool) $database->getVar(
  116. 'SELECT 1
  117. FROM users AS i
  118. WHERE i.email = ?
  119. LIMIT 1',
  120. [$email]
  121. );
  122. }
  123. public static function get(int $id): array
  124. {
  125. // get database
  126. $database = BackendModel::getContainer()->get('database');
  127. // get general user data
  128. $user = (array) $database->getRecord(
  129. 'SELECT i.id, i.email, i.password, i.active
  130. FROM users AS i
  131. WHERE i.id = ?',
  132. [$id]
  133. );
  134. // Don't add a settings element, just return an empty array here if no user is found.
  135. if (empty($user)) {
  136. return [];
  137. }
  138. // get user-settings
  139. $user['settings'] = (array) $database->getPairs(
  140. 'SELECT s.name, s.value
  141. FROM users_settings AS s
  142. WHERE s.user_id = ?',
  143. [$id]
  144. );
  145. // loop settings and unserialize them
  146. foreach ($user['settings'] as &$value) {
  147. $value = unserialize($value);
  148. }
  149. // return
  150. return $user;
  151. }
  152. public static function getCSVLineEndings(): array
  153. {
  154. return [
  155. '\n' => '\n',
  156. '\r\n' => '\r\n',
  157. ];
  158. }
  159. public static function getCSVSplitCharacters(): array
  160. {
  161. return [
  162. ';' => ';',
  163. ',' => ',',
  164. ];
  165. }
  166. /**
  167. * Fetch the list of date formats including examples of these formats.
  168. *
  169. * @return array
  170. */
  171. public static function getDateFormats(): array
  172. {
  173. // init var
  174. $possibleFormats = [];
  175. // loop available formats
  176. foreach ((array) BackendModel::get('fork.settings')->get('Users', 'date_formats') as $format) {
  177. $possibleFormats[$format] = \SpoonDate::getDate(
  178. $format,
  179. null,
  180. BackendAuthentication::getUser()->getSetting('interface_language')
  181. );
  182. }
  183. // return
  184. return $possibleFormats;
  185. }
  186. public static function getGroups(): array
  187. {
  188. return (array) BackendModel::getContainer()->get('database')->getPairs(
  189. 'SELECT i.id, i.name
  190. FROM groups AS i'
  191. );
  192. }
  193. /**
  194. * Get all module action combinations a user has access to
  195. *
  196. * @param string $module
  197. *
  198. * @return array
  199. */
  200. public static function getModuleGroupsRightsActions(string $module): array
  201. {
  202. return (array) BackendModel::get('database')->getRecords(
  203. 'SELECT a.module, a.action
  204. FROM groups AS g
  205. INNER JOIN users_groups AS u ON u.group_id = g.id
  206. INNER JOIN groups_rights_modules AS m ON m.group_id = g.id
  207. INNER JOIN groups_rights_actions AS a ON a.group_id = g.id
  208. AND m.module = a.module
  209. WHERE m.module = ?
  210. GROUP BY a.module, a.action',
  211. $module
  212. );
  213. }
  214. /**
  215. * Get the user ID linked to a given email
  216. *
  217. * @param string $email The email for the user.
  218. *
  219. * @return int|false
  220. */
  221. public static function getIdByEmail(string $email)
  222. {
  223. // get user-settings
  224. $userId = (int) BackendModel::getContainer()->get('database')->getVar(
  225. 'SELECT i.id
  226. FROM users AS i
  227. WHERE i.email = ?',
  228. [$email]
  229. );
  230. if ($userId === 0) {
  231. return false;
  232. }
  233. return $userId;
  234. }
  235. /**
  236. * Fetch the list of number formats including examples of these formats.
  237. *
  238. * @return array
  239. */
  240. public static function getNumberFormats(): array
  241. {
  242. // init var
  243. $possibleFormats = [];
  244. // loop available formats
  245. foreach ((array) BackendModel::get('fork.settings')->get('Core', 'number_formats') as $format => $example) {
  246. $possibleFormats[$format] = $example;
  247. }
  248. // return
  249. return $possibleFormats;
  250. }
  251. public static function getSetting(int $userId, string $setting)
  252. {
  253. return @unserialize(
  254. BackendModel::getContainer()->get('database')->getVar(
  255. 'SELECT value
  256. FROM users_settings
  257. WHERE user_id = ? AND name = ?',
  258. [$userId, $setting]
  259. )
  260. );
  261. }
  262. /**
  263. * Fetch the list of time formats including examples of these formats.
  264. *
  265. * @return array
  266. */
  267. public static function getTimeFormats(): array
  268. {
  269. // init var
  270. $possibleFormats = [];
  271. // loop available formats
  272. foreach (BackendModel::get('fork.settings')->get('Users', 'time_formats') as $format) {
  273. $possibleFormats[$format] = \SpoonDate::getDate(
  274. $format,
  275. null,
  276. BackendAuthentication::getUser()->getSetting('interface_language')
  277. );
  278. }
  279. // return
  280. return $possibleFormats;
  281. }
  282. public static function getUsers(): array
  283. {
  284. // fetch users
  285. $users = (array) BackendModel::getContainer()->get('database')->getPairs(
  286. 'SELECT i.id, s.value
  287. FROM users AS i
  288. INNER JOIN users_settings AS s ON i.id = s.user_id AND s.name = ?
  289. WHERE i.active = ? AND i.deleted = ?',
  290. ['nickname', true, false]
  291. );
  292. // loop users & unserialize
  293. foreach ($users as &$value) {
  294. $value = unserialize($value);
  295. }
  296. // return
  297. return $users;
  298. }
  299. public static function insert(array $user, array $settings): int
  300. {
  301. // get database
  302. $database = BackendModel::getContainer()->get('database');
  303. // update user
  304. $userId = (int) $database->insert('users', $user);
  305. $userSettings = [];
  306. // loop settings
  307. foreach ($settings as $key => $value) {
  308. $userSettings[] = [
  309. 'user_id' => $userId,
  310. 'name' => $key,
  311. 'value' => serialize($value),
  312. ];
  313. }
  314. // insert all settings at once
  315. $database->insert('users_settings', $userSettings);
  316. // return the new users' id
  317. return $userId;
  318. }
  319. public static function setSetting(int $userId, string $setting, string $value): void
  320. {
  321. // insert or update
  322. BackendModel::getContainer()->get('database')->execute(
  323. 'INSERT INTO users_settings(user_id, name, value)
  324. VALUES(?, ?, ?)
  325. ON DUPLICATE KEY UPDATE value = ?',
  326. [$userId, $setting, serialize($value), serialize($value)]
  327. );
  328. }
  329. /**
  330. * Restores a user
  331. *
  332. * @later this method should check if all needed data is present
  333. *
  334. * @param string $email The e-mail address of the user to restore.
  335. *
  336. * @return bool
  337. */
  338. public static function undoDelete(string $email): bool
  339. {
  340. // get database
  341. $database = BackendModel::getContainer()->get('database');
  342. // get id
  343. $id = $database->getVar(
  344. 'SELECT id
  345. FROM users AS i
  346. INNER JOIN users_settings AS s ON i.id = s.user_id
  347. WHERE i.email = ? AND i.deleted = ?',
  348. [$email, true]
  349. );
  350. // no valid users
  351. if ($id === null) {
  352. return false;
  353. }
  354. // restore
  355. $database->update('users', ['active' => true, 'deleted' => false], 'id = ?', (int) $id);
  356. // return
  357. return true;
  358. }
  359. /**
  360. * Save the changes for a given user
  361. * Remark: $user['id'] should be available
  362. *
  363. * @param array $user The userdata.
  364. * @param array $settings The settings for the user.
  365. */
  366. public static function update(array $user, array $settings): int
  367. {
  368. // get database
  369. $database = BackendModel::getContainer()->get('database');
  370. // update user
  371. $updated = $database->update('users', $user, 'id = ?', [$user['id']]);
  372. // loop settings
  373. foreach ($settings as $key => $value) {
  374. // insert or update
  375. $database->execute(
  376. 'INSERT INTO users_settings(user_id, name, value)
  377. VALUES(?, ?, ?)
  378. ON DUPLICATE KEY UPDATE value = ?',
  379. [$user['id'], $key, serialize($value), serialize($value)]
  380. );
  381. }
  382. return $updated;
  383. }
  384. /**
  385. * Update the user password
  386. *
  387. * @param BackendUser $user An instance of BackendUser.
  388. * @param string $password The new password for the user.
  389. */
  390. public static function updatePassword(BackendUser $user, string $password): void
  391. {
  392. // fetch user info
  393. $userId = $user->getUserId();
  394. // update user
  395. BackendModel::getContainer()->get('database')->update(
  396. 'users',
  397. ['password' => BackendAuthentication::encryptPassword($password)],
  398. 'id = ?',
  399. $userId
  400. );
  401. // remove the user settings linked to the resetting of passwords
  402. self::deleteResetPasswordSettings($userId);
  403. }
  404. /**
  405. * Get encrypted password for an email.
  406. *
  407. * @param string $email
  408. *
  409. * @return null|string
  410. */
  411. public static function getEncryptedPassword(string $email): ?string
  412. {
  413. return BackendModel::get('database')->getVar(
  414. 'SELECT password
  415. FROM users
  416. WHERE email = :email',
  417. ['email' => $email]
  418. );
  419. }
  420. }