1: <?php
2: /**
3: * This code is licensed under AGPLv3 license or Afterlogic Software License
4: * if commercial version of the product was purchased.
5: * For full statements of the licenses see LICENSE-AFTERLOGIC and LICENSE-AGPL3 files.
6: */
7:
8: namespace Aurora\Modules\Core;
9:
10: use Aurora\Api;
11: use Aurora\Modules\Contacts\Enums\StorageType;
12: use Aurora\Modules\Contacts\Models\Contact;
13: use Aurora\Modules\Core\Enums\ErrorCodes;
14: use Aurora\Modules\Core\Models\Group;
15: use Aurora\Modules\Core\Models\User;
16: use Aurora\Modules\Core\Models\UserBlock;
17: use Aurora\System\Enums\UserRole;
18: use Aurora\System\Exceptions\ApiException;
19: use Aurora\System\Notifications;
20: use Illuminate\Database\Eloquent\Builder;
21: use stdClass;
22: use Symfony\Component\Console\Input\ArrayInput;
23: use Symfony\Component\Console\Output\NullOutput;
24: use Symfony\Component\Console\Output\BufferedOutput;
25:
26: /**
27: * System module that provides core functionality such as User management, Tenants management.
28: *
29: * @license https://www.gnu.org/licenses/agpl-3.0.html AGPL-3.0
30: * @license https://afterlogic.com/products/common-licensing Afterlogic Software License
31: * @copyright Copyright (c) 2023, Afterlogic Corp.
32: *
33: * @package Modules
34: */
35: class Module extends \Aurora\System\Module\AbstractModule
36: {
37: protected $oTenantsManager = null;
38:
39: protected $oChannelsManager = null;
40:
41: protected $oUsersManager = null;
42:
43: protected $oIntegratorManager = null;
44:
45: /**
46: *
47: * @return Module
48: */
49: public static function getInstance()
50: {
51: return \Aurora\System\Api::GetModule(self::GetName());
52: }
53:
54: public function getTenantsManager()
55: {
56: if ($this->oTenantsManager === null) {
57: $this->oTenantsManager = new Managers\Tenants($this);
58: }
59:
60: return $this->oTenantsManager;
61: }
62:
63: public function getChannelsManager()
64: {
65: if ($this->oChannelsManager === null) {
66: $this->oChannelsManager = new Managers\Channels($this);
67: }
68:
69: return $this->oChannelsManager;
70: }
71:
72: public function getUsersManager()
73: {
74: if ($this->oUsersManager === null) {
75: $this->oUsersManager = new Managers\Users($this);
76: }
77:
78: return $this->oUsersManager;
79: }
80:
81: public function getIntegratorManager()
82: {
83: if ($this->oIntegratorManager === null) {
84: $this->oIntegratorManager = new \Aurora\System\Managers\Integrator();
85: }
86:
87: return $this->oIntegratorManager;
88: }
89:
90:
91: /***** private functions *****/
92: /**
93: * Initializes Core Module.
94: *
95: * @ignore
96: */
97: public function init()
98: {
99: $this->aErrors = [
100: Enums\ErrorCodes::ChannelDoesNotExist => $this->i18N('ERROR_CHANNEL_NOT_EXISTS'),
101: Enums\ErrorCodes::TenantAlreadyExists => $this->i18N('ERROR_TENANT_ALREADY_EXISTS'),
102: Enums\ErrorCodes::GroupAlreadyExists => $this->i18N('ERROR_GROUP_ALREADY_EXISTS'),
103: Enums\ErrorCodes::MySqlConfigError => 'Please make sure your PHP/MySQL environment meets the minimal system requirements.',
104: ];
105:
106: \Aurora\System\Router::getInstance()->registerArray(
107: self::GetName(),
108: [
109: 'api' => [$this, 'EntryApi'],
110: 'ping' => [$this, 'EntryPing'],
111: 'pull' => [$this, 'EntryPull'],
112: 'mobile' => [$this, 'EntryMobile'],
113: 'sso' => [$this, 'EntrySso'],
114: 'postlogin' => [$this, 'EntryPostlogin'],
115: 'file-cache' => [$this, 'EntryFileCache']
116: ]
117: );
118:
119: \Aurora\System\EventEmitter::getInstance()->onAny(
120: [
121: ['CreateAccount', [$this, 'onCreateAccount'], 100],
122: ['Core::GetCompatibilities::after', [$this, 'onAfterGetCompatibilities']],
123: ['System::RunEntry::before', [$this, 'onBeforeRunEntry'], 100]
124: ]
125: );
126:
127: $this->denyMethodsCallByWebApi([
128: 'UpdateUserObject',
129: 'GetUserByUUID',
130: 'GetUserByPublicId',
131: 'GetAdminUser',
132: 'GetTenantUnchecked',
133: 'GetTenantName',
134: 'GetTenantIdByName',
135: 'GetDefaultGlobalTenant',
136: 'UpdateTenantObject',
137: 'GetUserUnchecked',
138: 'UpdateTokensValidFromTimestamp',
139: 'GetAccountUsedToAuthorize',
140: 'GetDigestHash',
141: 'VerifyPassword',
142: 'SetAuthDataAndGetAuthToken',
143: 'IsModuleDisabledForObject',
144: 'GetBlockedUser',
145: 'BlockUser',
146: 'CheckIsBlockedUser',
147: 'GetAllGroup'
148: ]);
149: }
150:
151: /**
152: *
153: * @return mixed
154: */
155: private function getUploadData()
156: {
157: $mResult = false;
158: $oFile = null;
159: if (isset($_FILES) && count($_FILES) > 0) {
160: $oFile = current($_FILES);
161: }
162: if (isset($oFile, $oFile['name'], $oFile['tmp_name'], $oFile['size'], $oFile['type'])) {
163: $iError = (isset($oFile['error'])) ? (int) $oFile['error'] : UPLOAD_ERR_OK;
164: $mResult = (UPLOAD_ERR_OK === $iError) ? $oFile : false;
165: }
166:
167: return $mResult;
168: }
169:
170: /**
171: * Is called by CreateAccount event. Finds or creates and returns User for new account.
172: *
173: * @ignore
174: * @param array $Args {
175: * *int* **UserId** Identifier of existing user.
176: * *int* **TenantId** Identifier of tenant for creating new user in it.
177: * *int* **$PublicId** New user name.
178: * }
179: * @param \Aurora\Modules\Core\Models\User $oResult
180: */
181: public function onCreateAccount(&$Args, &$Result)
182: {
183: $oUser = null;
184:
185: if (isset($Args['UserId']) && (int)$Args['UserId'] > 0) {
186: $oUser = $this->getUsersManager()->getUser($Args['UserId']);
187: } else {
188: $Email = (isset($Args['Email'])) ? $Args['Email'] : '';
189: $PublicId = (isset($Args['PublicId'])) ? $Args['PublicId'] : '';
190: $sPublicId = null;
191: if (!empty($PublicId)) {
192: $sPublicId = $PublicId;
193: } elseif (!empty($Email)) {
194: $sPublicId = $Email;
195: }
196: if (!empty($sPublicId)) {
197: $oUser = $this->getUsersManager()->getUserByPublicId($sPublicId);
198: }
199: if (!isset($oUser)) {
200: $bPrevState = \Aurora\System\Api::skipCheckUserRole(true);
201: $iUserId = self::Decorator()->CreateUser(isset($Args['TenantId']) ? (int) $Args['TenantId'] : 0, $sPublicId);
202: \Aurora\System\Api::skipCheckUserRole($bPrevState);
203: $oUser = $this->getUsersManager()->getUser($iUserId);
204: }
205:
206: if (isset($oUser) && isset($oUser->Id)) {
207: $Args['UserId'] = $oUser->Id;
208: }
209: }
210:
211: $Result = $oUser;
212: }
213:
214: /**
215: * @ignore
216: * @param type $aArgs
217: * @param array $mResult
218: */
219: public function onAfterGetCompatibilities($aArgs, &$mResult)
220: {
221: $aCompatibility['php.version'] = phpversion();
222: $aCompatibility['php.version.valid'] = (int) (version_compare($aCompatibility['php.version'], '7.2.5') > -1);
223:
224: $aCompatibility['safe-mode'] = @ini_get('safe_mode');
225: $aCompatibility['safe-mode.valid'] = is_numeric($aCompatibility['safe-mode'])
226: ? !((bool) $aCompatibility['safe-mode'])
227: : ('off' === strtolower($aCompatibility['safe-mode']) || empty($aCompatibility['safe-mode']));
228:
229: $aCompatibility['mysql.valid'] = (int) extension_loaded('mysql');
230: $aCompatibility['pdo.valid'] = (int)
231: ((bool) extension_loaded('pdo') && (bool) extension_loaded('pdo_mysql'));
232:
233: $aCompatibility['mysqlnd.valid'] = (int) (
234: function_exists('mysqli_fetch_all') &&
235: strpos(mysqli_get_client_info(), "mysqlnd") !== false
236: );
237:
238: $aCompatibility['socket.valid'] = (int) function_exists('fsockopen');
239: $aCompatibility['iconv.valid'] = (int) function_exists('iconv');
240: $aCompatibility['curl.valid'] = (int) function_exists('curl_init');
241: $aCompatibility['mbstring.valid'] = (int) function_exists('mb_detect_encoding');
242: $aCompatibility['openssl.valid'] = (int) extension_loaded('openssl');
243: $aCompatibility['xml.valid'] = (int) (class_exists('DOMDocument') && function_exists('xml_parser_create'));
244: $aCompatibility['json.valid'] = (int) function_exists('json_decode');
245: $aCompatibility['gd.valid'] = (int) extension_loaded('gd');
246:
247: $aCompatibility['ini-get.valid'] = (int) function_exists('ini_get');
248: $aCompatibility['ini-set.valid'] = (int) function_exists('ini_set');
249: $aCompatibility['set-time-limit.valid'] = (int) function_exists('set_time_limit');
250:
251: $aCompatibility['session.valid'] = (int) (function_exists('session_start') && isset($_SESSION['checksessionindex']));
252:
253: $dataPath = \Aurora\System\Api::DataPath();
254:
255: $aCompatibility['data.dir'] = $dataPath;
256: $aCompatibility['data.dir.valid'] = (int) (@is_dir($aCompatibility['data.dir']) && @is_writable($aCompatibility['data.dir']));
257:
258: $sTempPathName = '_must_be_deleted_'.md5(time());
259:
260: $aCompatibility['data.dir.create'] =
261: (int) @mkdir($aCompatibility['data.dir'].'/'.$sTempPathName);
262: $aCompatibility['data.file.create'] =
263: (int) (bool) @fopen($aCompatibility['data.dir'].'/'.$sTempPathName.'/'.$sTempPathName.'.test', 'w+');
264: $aCompatibility['data.file.delete'] =
265: (int) (bool) @unlink($aCompatibility['data.dir'].'/'.$sTempPathName.'/'.$sTempPathName.'.test');
266: $aCompatibility['data.dir.delete'] =
267: (int) @rmdir($aCompatibility['data.dir'].'/'.$sTempPathName);
268:
269:
270: $oSettings =& \Aurora\System\Api::GetSettings();
271:
272: $aCompatibility['settings.file'] = $oSettings ? $oSettings->GetPath() : '';
273:
274: $aCompatibility['settings.file.exist'] = (int) @file_exists($aCompatibility['settings.file']);
275: $aCompatibility['settings.file.read'] = (int) @is_readable($aCompatibility['settings.file']);
276: $aCompatibility['settings.file.write'] = (int) @is_writable($aCompatibility['settings.file']);
277:
278: $aCompatibilities = [
279: [
280: 'Name' => 'PHP version',
281: 'Result' => $aCompatibility['php.version.valid'],
282: 'Value' => $aCompatibility['php.version.valid']
283: ? 'OK'
284: : [$aCompatibility['php.version'].' detected, 7.2.5 or above required.',
285: 'You need to upgrade PHP engine installed on your server.
286: If it\'s a dedicated or your local server, you can download the latest version of PHP from its
287: <a href="http://php.net/downloads.php" target="_blank">official site</a> and install it yourself.
288: In case of a shared hosting, you need to ask your hosting provider to perform the upgrade.']
289: ],
290: [
291: 'Name' => 'Safe Mode is off',
292: 'Result' => $aCompatibility['safe-mode.valid'],
293: 'Value' => ($aCompatibility['safe-mode.valid'])
294: ? 'OK'
295: : ['Error, safe_mode is enabled.',
296: 'You need to <a href="http://php.net/manual/en/ini.sect.safe-mode.php" target="_blank">disable it in your php.ini</a>
297: or contact your hosting provider and ask to do this.']
298: ],
299: [
300: 'Name' => 'PDO MySQL Extension',
301: 'Result' => $aCompatibility['pdo.valid'],
302: 'Value' => ($aCompatibility['pdo.valid'])
303: ? 'OK'
304: : ['Error, PHP PDO MySQL extension not detected.',
305: 'You need to install this PHP extension or enable it in php.ini file.']
306: ],
307: [
308: 'Name' => 'MySQL Native Driver (mysqlnd)',
309: 'Result' => $aCompatibility['mysqlnd.valid'],
310: 'Value' => ($aCompatibility['mysqlnd.valid'])
311: ? 'OK'
312: : ['Error, MySQL Native Driver not found.',
313: 'You need to install this PHP extension or enable it in php.ini file.']
314: ],
315: [
316: 'Name' => 'Iconv Extension',
317: 'Result' => $aCompatibility['iconv.valid'],
318: 'Value' => ($aCompatibility['iconv.valid'])
319: ? 'OK'
320: : ['Error, iconv extension not detected.',
321: 'You need to install this PHP extension or enable it in php.ini file.']
322: ],
323: [
324: 'Name' => 'Multibyte String Extension',
325: 'Result' => $aCompatibility['mbstring.valid'],
326: 'Value' => ($aCompatibility['mbstring.valid'])
327: ? 'OK'
328: : ['Error, mb_string extension not detected.',
329: 'You need to install this PHP extension or enable it in php.ini file.']
330: ],
331: [
332: 'Name' => 'CURL Extension',
333: 'Result' => $aCompatibility['curl.valid'],
334: 'Value' => ($aCompatibility['curl.valid'])
335: ? 'OK'
336: : ['Error, curl extension not detected.',
337: 'You need to install this PHP extension or enable it in php.ini file.']
338: ],
339: [
340: 'Name' => 'JSON Extension',
341: 'Result' => $aCompatibility['json.valid'],
342: 'Value' => ($aCompatibility['json.valid'])
343: ? 'OK'
344: : ['Error, JSON extension not detected.',
345: 'You need to install this PHP extension or enable it in php.ini file.']
346: ],
347: [
348: 'Name' => 'XML/DOM Extension',
349: 'Result' => $aCompatibility['xml.valid'],
350: 'Value' => ($aCompatibility['xml.valid'])
351: ? 'OK'
352: : ['Error, xml (DOM) extension not detected.',
353: 'You need to install this PHP extension or enable it in php.ini file.']
354: ],
355: [
356: 'Name' => 'GD Extension',
357: 'Result' => $aCompatibility['gd.valid'],
358: 'Value' => ($aCompatibility['gd.valid'])
359: ? 'OK'
360: : ['Error, GD extension not detected.',
361: 'You need to install this PHP extension or enable it in php.ini file.']
362: ],
363: [
364: 'Name' => 'Sockets',
365: 'Result' => $aCompatibility['socket.valid'],
366: 'Value' => ($aCompatibility['socket.valid'])
367: ? 'OK'
368: : ['Error, creating network sockets must be enabled.', '
369: To enable sockets, you should remove fsockopen function from the list of prohibited functions in disable_functions directive of your php.ini file.
370: In case of a shared hosting, you need to ask your hosting provider to do this.']
371: ],
372: [
373: 'Name' => 'SSL (OpenSSL extension)',
374: 'Result' => $aCompatibility['openssl.valid'],
375: 'Value' => ($aCompatibility['openssl.valid'])
376: ? 'OK'
377: : ['SSL connections (like Gmail) will not be available. ', '
378: You need to enable OpenSSL support in your PHP configuration and make sure OpenSSL library is installed on your server.
379: For instructions, please refer to the official PHP documentation. In case of a shared hosting,
380: you need to ask your hosting provider to enable OpenSSL support.
381: You may ignore this if you\'re not going to connect to SSL-only mail servers (like Gmail).']
382: ],
383: [
384: 'Name' => 'Setting memory limits',
385: 'Result' => $aCompatibility['ini-get.valid'],
386: 'Value' => ($aCompatibility['ini-get.valid'] && $aCompatibility['ini-set.valid'])
387: ? 'OK'
388: : ['Opening large e-mails may fail.', '
389: You need to enable setting memory limits in your PHP configuration, i.e. remove ini_get and ini_set functions
390: from the list of prohibited functions in disable_functions directive of your php.ini file.
391: In case of a shared hosting, you need to ask your hosting provider to do this.']
392: ],
393: [
394: 'Name' => 'Setting script timeout',
395: 'Result' => $aCompatibility['set-time-limit.valid'],
396: 'Value' => ($aCompatibility['set-time-limit.valid'])
397: ? 'OK'
398: : ['Downloading large mailboxes may fail.', '
399: To enable setting script timeout, you should remove set_time_limit function from the list
400: of prohibited functions in disable_functions directive of your php.ini file.
401: In case of a shared hosting, you need to ask your hosting provider to do this.']
402: ],
403: [
404: 'Name' => 'WebMail data directory',
405: 'Result' => $aCompatibility['data.dir.valid'],
406: 'Value' => ($aCompatibility['data.dir.valid'])
407: ? 'Found'
408: : ['Error, data directory path discovery failure.']
409: ],
410: [
411: 'Name' => 'Creating/deleting directories',
412: 'Result' => $aCompatibility['data.dir.create'] && $aCompatibility['data.dir.delete'],
413: 'Value' => ($aCompatibility['data.dir.create'] && $aCompatibility['data.dir.delete'])
414: ? 'OK'
415: : ['Error, can\'t create/delete sub-directories in the data directory.', '
416: You need to grant read/write permission over data directory and all its contents to your web server user.
417: For instructions, please refer to this section of documentation and our
418: <a href="https://afterlogic.com/docs/webmail-pro-8/troubleshooting/troubleshooting-issues-with-data-directory" target="_blank">FAQ</a>.']
419: ],
420: [
421: 'Name' => 'Creating/deleting files',
422: 'Result' => $aCompatibility['data.file.create'] && $aCompatibility['data.file.delete'],
423: 'Value' => ($aCompatibility['data.file.create'] && $aCompatibility['data.file.delete'])
424: ? 'OK'
425: : ['Error, can\'t create/delete files in the data directory.', '
426: You need to grant read/write permission over data directory and all its contents to your web server user.
427: For instructions, please refer to this section of documentation and our
428: <a href="https://afterlogic.com/docs/webmail-pro-8/troubleshooting/troubleshooting-issues-with-data-directory" target="_blank">FAQ</a>.']
429: ],
430: [
431: 'Name' => 'WebMail Settings File',
432: 'Result' => $aCompatibility['settings.file.exist'],
433: 'Value' => ($aCompatibility['settings.file.exist'])
434: ? 'Found'
435: : ['Not Found, can\'t find "'.$aCompatibility['settings.file'].'" file.', '
436: Make sure you completely copied the data directory with all its contents from installation package.
437: By default, the data directory is webmail subdirectory, and if it\'s not the case make sure its location matches one specified in inc_settings_path.php file.']
438: ],
439: [
440: 'Name' => 'Read/write settings file',
441: 'Result' => $aCompatibility['settings.file.read'] && $aCompatibility['settings.file.write'],
442: 'Value' => ($aCompatibility['settings.file.read'] && $aCompatibility['settings.file.write'])
443: ? 'OK / OK'
444: : ['Not Found, can\'t find "'.$aCompatibility['settings.file'].'" file.', '
445: You should grant read/write permission over settings file to your web server user.
446: For instructions, please refer to this section of documentation and our
447: <a href="https://afterlogic.com/docs/webmail-pro-8/troubleshooting/troubleshooting-issues-with-data-directory" target="_blank">FAQ</a>.']
448: ],
449: ];
450:
451: $mResult[self::GetName()] = $aCompatibilities;
452: }
453:
454: public function onBeforeRunEntry($aArgs, &$mResult)
455: {
456: \Aurora\Api::removeOldLogs();
457:
458: return $this->redirectToHttps($aArgs['EntryName'], $mResult);
459: }
460:
461: /**
462: * Recursively deletes temporary files and folders on time.
463: *
464: * @param string $sTempPath Path to the temporary folder.
465: * @param int $iTime2Kill Interval in seconds at which files needs removing.
466: * @param int $iNow Current Unix timestamp.
467: */
468: protected function removeDirByTime($sTempPath, $iTime2Kill, $iNow)
469: {
470: $iFileCount = 0;
471: if (@is_dir($sTempPath)) {
472: $rDirH = @opendir($sTempPath);
473: if ($rDirH) {
474: while (($sFile = @readdir($rDirH)) !== false) {
475: if ('.' !== $sFile && '..' !== $sFile) {
476: if (@is_dir($sTempPath.'/'.$sFile)) {
477: $this->removeDirByTime($sTempPath.'/'.$sFile, $iTime2Kill, $iNow);
478: } else {
479: $iFileCount++;
480: }
481: }
482: }
483: @closedir($rDirH);
484: }
485:
486: if ($iFileCount > 0) {
487: if ($this->removeFilesByTime($sTempPath, $iTime2Kill, $iNow)) {
488: @rmdir($sTempPath);
489: }
490: } else {
491: @rmdir($sTempPath);
492: }
493: }
494: }
495:
496: /**
497: * Recursively deletes temporary files on time.
498: *
499: * @param string $sTempPath Path to the temporary folder.
500: * @param int $iTime2Kill Interval in seconds at which files needs removing.
501: * @param int $iNow Current Unix timestamp.
502: *
503: * @return bool
504: */
505: protected function removeFilesByTime($sTempPath, $iTime2Kill, $iNow)
506: {
507: $bResult = true;
508: if (@is_dir($sTempPath)) {
509: $rDirH = @opendir($sTempPath);
510: if ($rDirH) {
511: while (($sFile = @readdir($rDirH)) !== false) {
512: if ($sFile !== '.' && $sFile !== '..') {
513: if ($iNow - filemtime($sTempPath.'/'.$sFile) > $iTime2Kill) {
514: @unlink($sTempPath.'/'.$sFile);
515: } else {
516: $bResult = false;
517: }
518: }
519: }
520: @closedir($rDirH);
521: }
522: }
523: return $bResult;
524: }
525:
526: protected function redirectToHttps($sEntryName, $mResult)
527: {
528: $oSettings =& \Aurora\Api::GetSettings();
529: if ($oSettings) {
530: $bRedirectToHttps = $oSettings->RedirectToHttps;
531:
532: $bHttps = \Aurora\Api::isHttps();
533: if ($bRedirectToHttps && !$bHttps) {
534: if (\strtolower($sEntryName) !== 'api') {
535: \header("Location: https://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
536: } else {
537: $mResult = [
538: 'ErrorCode' => 110
539: ];
540: return true;
541: }
542: }
543: }
544: }
545:
546: /***** private functions *****/
547:
548: /***** static functions *****/
549: /**
550: * @ignore
551: * @return bool
552: */
553: private function deleteTree($dir)
554: {
555: $files = array_diff(scandir($dir), array('.','..'));
556:
557: foreach ($files as $file) {
558: (is_dir("$dir/$file")) ? $this->deleteTree("$dir/$file") : unlink("$dir/$file");
559: }
560:
561: return rmdir($dir);
562: }
563: /***** static functions *****/
564:
565: /***** public functions *****/
566: /**
567: *
568: * @return string
569: * @throws \Aurora\System\Exceptions\ApiException
570: */
571: public function EntryApi()
572: {
573: @ob_start();
574:
575: if (!is_writable(\Aurora\System\Api::DataPath())) {
576: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::SystemNotConfigured);
577: }
578:
579: $aResponseItem = null;
580: $sModule = $this->oHttp->GetPost('Module', null);
581: $sMethod = $this->oHttp->GetPost('Method', null);
582: $sParameters = $this->oHttp->GetPost('Parameters', null);
583: $sFormat = $this->oHttp->GetPost('Format', null);
584: $sTenantName = $this->oHttp->GetPost('TenantName', null);
585:
586: if (isset($sModule, $sMethod)) {
587: $oModule = \Aurora\System\Api::GetModule($sModule);
588: if ($oModule instanceof \Aurora\System\Module\AbstractModule) {
589: try {
590: \Aurora\System\Api::Log(" ");
591: \Aurora\System\Api::Log(" ===== API: " . $sModule . '::' . $sMethod);
592:
593: $bIsEmptyAuthToken = !\Aurora\System\Api::getAuthTokenFromHeaders();
594:
595: if ($this->getConfig('CsrfTokenProtection', true) && !\Aurora\System\Api::validateCsrfToken()/* && !$bIsEmptyAuthToken*/) {
596: throw new \Aurora\System\Exceptions\ApiException(
597: \Aurora\System\Notifications::InvalidToken
598: );
599: }
600:
601: if (!empty($sModule) && !empty($sMethod)) {
602: if (!\Aurora\System\Api::validateAuthToken() && !$bIsEmptyAuthToken) {
603: throw new \Aurora\System\Exceptions\ApiException(
604: \Aurora\System\Notifications::AuthError
605: );
606: }
607:
608: \Aurora\System\Api::setTenantName($sTenantName);
609:
610: $aParameters = [];
611: if (isset($sParameters) && \is_string($sParameters)) {
612: $aParameters = @\json_decode($sParameters, true);
613: if (!\is_array($aParameters)) {
614: $aParameters = array($aParameters);
615: }
616: }
617:
618: $mUploadData = $this->getUploadData();
619: if (\is_array($mUploadData)) {
620: $aParameters['UploadData'] = $mUploadData;
621: }
622:
623: $oModule->CallMethod(
624: $sMethod,
625: $aParameters,
626: true
627: );
628:
629: $oLastException = \Aurora\System\Api::GetModuleManager()->GetLastException();
630: if (isset($oLastException)) {
631: throw $oLastException;
632: }
633:
634: $aResponseItem = $oModule->DefaultResponse(
635: $sMethod,
636: \Aurora\System\Api::GetModuleManager()->GetResults()
637: );
638: }
639:
640: if (!\is_array($aResponseItem)) {
641: throw new \Aurora\System\Exceptions\ApiException(
642: \Aurora\System\Notifications::UnknownError
643: );
644: }
645: } catch (\Exception $oException) {
646: \Aurora\System\Api::LogException($oException);
647:
648: $aAdditionalParams = null;
649: if ($oException instanceof \Aurora\System\Exceptions\ApiException) {
650: $aAdditionalParams = $oException->GetObjectParams();
651: }
652:
653: $aResponseItem = $oModule->ExceptionResponse(
654: $sMethod,
655: $oException,
656: $aAdditionalParams
657: );
658: }
659: } else {
660: $oException = new \Aurora\System\Exceptions\ApiException(
661: \Aurora\System\Notifications::ModuleNotFound
662: );
663: $aResponseItem = $this->ExceptionResponse(
664: $sMethod,
665: $oException
666: );
667: }
668: } else {
669: $oException = new \Aurora\System\Exceptions\ApiException(
670: \Aurora\System\Notifications::InvalidInputParameter
671: );
672: $aResponseItem = $this->ExceptionResponse(
673: $sMethod,
674: $oException
675: );
676: }
677:
678: if (isset($aResponseItem['Parameters'])) {
679: unset($aResponseItem['Parameters']);
680: }
681:
682: return \Aurora\System\Managers\Response::GetJsonFromObject($sFormat, $aResponseItem);
683: }
684:
685: /**
686: * @ignore
687: */
688: public function EntryMobile()
689: {
690: $oApiIntegrator = $this->getIntegratorManager();
691: $oApiIntegrator->setMobile(true);
692:
693: \Aurora\System\Api::Location('./');
694: }
695:
696: /**
697: * @ignore
698: */
699: public function EntrySso()
700: {
701: try {
702: $sHash = $this->oHttp->GetRequest('hash');
703: if (!empty($sHash)) {
704: $sData = \Aurora\System\Api::Cacher()->get('SSO:'.$sHash, true);
705: $aData = \Aurora\System\Api::DecodeKeyValues($sData);
706:
707: if (isset($aData['Password'], $aData['Email'])) {
708: $sLanguage = $this->oHttp->GetRequest('lang');
709: $aResult = self::Decorator()->Login($aData['Email'], $aData['Password'], $sLanguage);
710:
711: if (is_array($aResult) && isset($aResult['AuthToken'])) {
712: $iAuthTokenCookieExpireTime = (int) self::getInstance()->getConfig('AuthTokenCookieExpireTime', 30);
713: @\setcookie(
714: \Aurora\System\Application::AUTH_TOKEN_KEY,
715: $aResult['AuthToken'],
716: ($iAuthTokenCookieExpireTime === 0) ? 0 : \strtotime('+' . $iAuthTokenCookieExpireTime . ' days'),
717: \Aurora\System\Api::getCookiePath(),
718: null,
719: \Aurora\System\Api::getCookieSecure()
720: );
721: } else {
722: @\setcookie(
723: \Aurora\System\Application::AUTH_TOKEN_KEY,
724: null,
725: -1
726: );
727: }
728: }
729: } else {
730: self::Decorator()->Logout();
731: }
732: } catch (\Exception $oExc) {
733: \Aurora\System\Api::LogException($oExc);
734: }
735:
736: \Aurora\System\Api::Location('./');
737: }
738:
739: /**
740: * @ignore
741: */
742: public function EntryPostlogin()
743: {
744: if ($this->getConfig('AllowPostLogin', false)) {
745: $sEmail = trim((string) $this->oHttp->GetRequest('Email', ''));
746: $sLogin = (string) $this->oHttp->GetRequest('Login', '');
747:
748: if ($sLogin==='') {
749: $sLogin = $sEmail;
750: }
751: $sPassword = (string) $this->oHttp->GetRequest('Password', '');
752:
753: $sAtDomain = trim(\Aurora\System\Api::GetSettings()->GetValue('LoginAtDomainValue'));
754: if (0 < strlen($sAtDomain)) {
755: $sEmail = \Aurora\System\Utils::GetAccountNameFromEmail($sLogin).'@'.$sAtDomain;
756: $sLogin = $sEmail;
757: }
758:
759: $aResult = self::Decorator()->Login($sLogin, $sPassword);
760: if (is_array($aResult) && isset($aResult['AuthToken'])) {
761: $iAuthTokenCookieExpireTime = (int) self::getInstance()->getConfig('AuthTokenCookieExpireTime', 30);
762: @\setcookie(
763: \Aurora\System\Application::AUTH_TOKEN_KEY,
764: $aResult['AuthToken'],
765: ($iAuthTokenCookieExpireTime === 0) ? 0 : \strtotime('+' . $iAuthTokenCookieExpireTime . ' days'),
766: \Aurora\System\Api::getCookiePath(),
767: null,
768: \Aurora\System\Api::getCookieSecure()
769: );
770: }
771:
772: \Aurora\System\Api::Location('./');
773: }
774: }
775:
776: public function EntryFileCache()
777: {
778: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
779:
780: $sRawKey = \Aurora\System\Router::getItemByIndex(1, '');
781: $sAction = \Aurora\System\Router::getItemByIndex(2, '');
782: $aValues = \Aurora\System\Api::DecodeKeyValues($sRawKey);
783:
784: $bDownload = true;
785: $bThumbnail = false;
786:
787: switch ($sAction) {
788: case 'view':
789: $bDownload = false;
790: $bThumbnail = false;
791: break;
792: case 'thumb':
793: $bDownload = false;
794: $bThumbnail = true;
795: break;
796: default:
797: $bDownload = true;
798: $bThumbnail = false;
799: break;
800: }
801:
802: $iUserId = (isset($aValues['UserId'])) ? $aValues['UserId'] : 0;
803:
804: if (isset($aValues['TempFile'], $aValues['TempName'], $aValues['Name'])) {
805: $sModule = isset($aValues['Module']) && !empty($aValues['Module']) ? $aValues['Module'] : 'System';
806: $bResult = false;
807: $sUUID = \Aurora\System\Api::getUserUUIDById($iUserId);
808: $oApiFileCache = new \Aurora\System\Managers\Filecache();
809: $mResult = $oApiFileCache->getFile($sUUID, $aValues['TempName'], '', $sModule);
810:
811: if (is_resource($mResult)) {
812: $bResult = true;
813: $sFileName = $aValues['Name'];
814: $sContentType = (empty($sFileName)) ? 'text/plain' : \MailSo\Base\Utils::MimeContentType($sFileName);
815: $sFileName = \Aurora\System\Utils::clearFileName($sFileName, $sContentType);
816:
817: \Aurora\System\Utils::OutputFileResource($sUUID, $sContentType, $sFileName, $mResult, $bThumbnail, $bDownload);
818: }
819: }
820: }
821:
822: public function IsModuleExists($Module)
823: {
824: return \Aurora\System\Api::GetModuleManager()->ModuleExists($Module);
825: }
826:
827: /**
828: *
829: * @return string
830: */
831: public function GetVersion()
832: {
833: return \Aurora\System\Api::Version();
834: }
835:
836: /**
837: * Clears temporary files by cron.
838: *
839: * @ignore
840: * @todo check if it works.
841: *
842: * @return bool
843: */
844: protected function ClearTempFiles()
845: {
846: $sTempPath =\Aurora\System\Api::DataPath().'/temp';
847: if (@is_dir($sTempPath)) {
848: $iNow = time();
849:
850: $iTime2Run = $this->getConfig('CronTimeToRunSeconds', 10800);
851: $iTime2Kill = $this->getConfig('CronTimeToKillSeconds', 10800);
852: $sDataFile = $this->getConfig('CronTimeFile', '.clear.dat');
853:
854: $iFiletTime = -1;
855: if (@file_exists(\Aurora\System\Api::DataPath().'/'.$sDataFile)) {
856: $iFiletTime = (int) @file_get_contents(\Aurora\System\Api::DataPath().'/'.$sDataFile);
857: }
858:
859: if ($iFiletTime === -1 || $iNow - $iFiletTime > $iTime2Run) {
860: $this->removeDirByTime($sTempPath, $iTime2Kill, $iNow);
861: @file_put_contents(\Aurora\System\Api::DataPath().'/'.$sDataFile, $iNow);
862: }
863: }
864:
865: return true;
866: }
867:
868: /**
869: * !Not public
870: * This method is restricted to be called by web API (see denyMethodsCallByWebApi method).
871: *
872: * Updates user by object.
873: *
874: * @param \Aurora\Modules\Core\Models\User $oUser
875: * returns bool
876: */
877: public function UpdateUserObject($oUser)
878: {
879: /** This method is restricted to be called by web API (see denyMethodsCallByWebApi method). **/
880:
881: return $this->getUsersManager()->updateUser($oUser);
882: }
883:
884: /**
885: * !Not public
886: * This method is restricted to be called by web API (see denyMethodsCallByWebApi method).
887: *
888: * Returns user object.
889: *
890: * @param int|string $UserId User identifier or UUID.
891: * @return \Aurora\Modules\Core\Models\User
892: */
893: public function GetUserUnchecked($UserId = '')
894: {
895: // doesn't call checkUserRoleIsAtLeast because checkUserRoleIsAtLeast function calls GetUserUnchecked function
896:
897: /** This method is restricted to be called by web API (see denyMethodsCallByWebApi method). **/
898:
899: $oUser = $this->getUsersManager()->getUser($UserId);
900:
901: return $oUser ? $oUser : null;
902: }
903:
904: /**
905: * !Not public
906: * This method is restricted to be called by web API (see denyMethodsCallByWebApi method).
907: *
908: * Returns user object.
909: *
910: * @param int $UUID User uuid identifier.
911: * @return \Aurora\Modules\Core\Models\User
912: */
913: public function GetUserByUUID($UUID)
914: {
915: // doesn't call checkUserRoleIsAtLeast because checkUserRoleIsAtLeast function calls GetUserUnchecked function
916:
917: /** This method is restricted to be called by web API (see denyMethodsCallByWebApi method). **/
918:
919: $oUser = $this->getUsersManager()->getUser($UUID);
920:
921: return $oUser ? $oUser : null;
922: }
923:
924: /**
925: * !Not public
926: * This method is restricted to be called by web API (see denyMethodsCallByWebApi method).
927: *
928: * Returns user object.
929: *
930: * @param string $PublicId User public identifier.
931: * @return \Aurora\Modules\Core\Models\User
932: */
933: public function GetUserByPublicId($PublicId)
934: {
935: /** This method is restricted to be called by web API (see denyMethodsCallByWebApi method). **/
936:
937: $oUser = $this->getUsersManager()->getUserByPublicId($PublicId);
938:
939: return $oUser ? $oUser : null;
940: }
941:
942: /**
943: * !Not public
944: * This method is restricted to be called by web API (see denyMethodsCallByWebApi method).
945: *
946: * Creates and returns user with super administrator role.
947: *
948: * @return \Aurora\Modules\Core\Models\User
949: */
950: public function GetAdminUser()
951: {
952: // doesn't call checkUserRoleIsAtLeast because checkUserRoleIsAtLeast function calls GetAdminUser function
953:
954: /** This method is restricted to be called by web API (see denyMethodsCallByWebApi method). **/
955:
956: return $this->getIntegratorManager()->GetAdminUser();
957: }
958:
959: /**
960: * !Not public
961: * This method is restricted to be called by web API (see denyMethodsCallByWebApi method).
962: *
963: * Returns tenant object by identifier.
964: *
965: * @param int $Id Tenant identifier.
966: * @return \Aurora\Modules\Core\Models\Tenant|null
967: */
968: public function GetTenantUnchecked($Id)
969: {
970: /** This method is restricted to be called by web API (see denyMethodsCallByWebApi method). **/
971:
972: $oTenant = $this->getTenantsManager()->getTenantById($Id);
973:
974: return $oTenant ? $oTenant : null;
975: }
976:
977: /**
978: * !Not public
979: * This method is restricted to be called by web API (see denyMethodsCallByWebApi method).
980: *
981: * Returns tenant identifier by tenant name.
982: *
983: * @param string $TenantName Tenant name.
984: * @return int|null
985: */
986: public function GetTenantIdByName($TenantName = '')
987: {
988: /** This method is restricted to be called by web API (see denyMethodsCallByWebApi method). **/
989:
990: $iTenantId = $this->getTenantsManager()->getTenantIdByName((string) $TenantName);
991:
992: return $iTenantId ? $iTenantId : null;
993: }
994:
995: /**
996: * !Not public
997: * This method is restricted to be called by web API (see denyMethodsCallByWebApi method).
998: *
999: * Returns current tenant name.
1000: *
1001: * @return string
1002: */
1003: public function GetTenantName()
1004: {
1005: /** This method is restricted to be called by web API (see denyMethodsCallByWebApi method). **/
1006:
1007: $sTenant = '';
1008: $sAuthToken = \Aurora\System\Api::getAuthToken();
1009: if (!empty($sAuthToken)) {
1010: $iUserId = \Aurora\System\Api::getAuthenticatedUserId();
1011: if ($iUserId !== false && $iUserId > 0) {
1012: $oUser = self::Decorator()->GetUserUnchecked($iUserId);
1013: if ($oUser) {
1014: $oTenant = self::Decorator()->GetTenantUnchecked($oUser->IdTenant);
1015: if ($oTenant) {
1016: $sTenant = $oTenant->Name;
1017: }
1018: }
1019: }
1020: $sPostTenant = $this->oHttp->GetPost('TenantName', '');
1021: if (!empty($sPostTenant) && !empty($sTenant) && $sPostTenant !== $sTenant) {
1022: $sTenant = '';
1023: }
1024: } else {
1025: $sTenant = $this->oHttp->GetRequest('tenant', '');
1026: }
1027: \Aurora\System\Api::setTenantName($sTenant);
1028: return $sTenant;
1029: }
1030:
1031: /**
1032: * @deprecated since version 8.3.7
1033: */
1034: public function GetTenantById($Id)
1035: {
1036: return self::Decorator()->GetTenant($Id);
1037: }
1038:
1039: /**
1040: * !Not public
1041: * This method is restricted to be called by web API (see denyMethodsCallByWebApi method).
1042: *
1043: * Returns default global tenant.
1044: *
1045: * @return \Aurora\Modules\Core\Models\Tenant
1046: */
1047: public function GetDefaultGlobalTenant()
1048: {
1049: /** This method is restricted to be called by web API (see denyMethodsCallByWebApi method). **/
1050:
1051: $oTenant = $this->getTenantsManager()->getDefaultGlobalTenant();
1052:
1053: return $oTenant ? $oTenant : null;
1054: }
1055:
1056: /**
1057: * !Not public
1058: * This method is restricted to be called by web API (see denyMethodsCallByWebApi method).
1059: *
1060: * Updates tenant.
1061: *
1062: * @param Models\Tenant $oTenant
1063: * @return void
1064: */
1065: public function UpdateTenantObject($oTenant)
1066: {
1067: /** This method is restricted to be called by web API (see denyMethodsCallByWebApi method). **/
1068:
1069: return $this->getTenantsManager()->updateTenant($oTenant);
1070: }
1071:
1072: /**
1073: * !Not public
1074: * This method is restricted to be called by web API (see denyMethodsCallByWebApi method).
1075: *
1076: * @param \Aurora\Modules\Core\Models\User $oUser
1077: * @return int
1078: */
1079: public function UpdateTokensValidFromTimestamp($oUser)
1080: {
1081: /** This method is restricted to be called by web API (see denyMethodsCallByWebApi method). **/
1082:
1083: $oUser->TokensValidFromTimestamp = time();
1084: $this->getUsersManager()->updateUser($oUser);
1085: return $oUser->TokensValidFromTimestamp;
1086: }
1087: /***** public functions *****/
1088:
1089: /***** public functions might be called with web API *****/
1090: /**
1091: * @apiDefine Core Core Module
1092: * System module that provides core functionality such as User management, Tenants management
1093: */
1094:
1095: /**
1096: * @api {post} ?/Api/ DoServerInitializations
1097: * @apiName DoServerInitializations
1098: * @apiGroup Core
1099: * @apiDescription Does some pending actions to be executed when you log in.
1100: *
1101: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1102: * @apiHeaderExample {json} Header-Example:
1103: * {
1104: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1105: * }
1106: *
1107: * @apiParam {string=Core} Module Module name.
1108: * @apiParam {string=DoServerInitializations} Method Method name.
1109: *
1110: * @apiParamExample {json} Request-Example:
1111: * {
1112: * Module: 'Core',
1113: * Method: 'DoServerInitializations'
1114: * }
1115: *
1116: * @apiSuccess {object[]} Result Array of response objects.
1117: * @apiSuccess {string} Result.Module Module name.
1118: * @apiSuccess {string} Result.Method Method name.
1119: * @apiSuccess {bool} Result.Result Indicates if server initializations were made successfully.
1120: * @apiSuccess {int} [Result.ErrorCode] Error code.
1121: *
1122: * @apiSuccessExample {json} Success response example:
1123: * {
1124: * Module: 'Core',
1125: * Method: 'DoServerInitializations',
1126: * Result: true
1127: * }
1128: *
1129: * @apiSuccessExample {json} Error response example:
1130: * {
1131: * Module: 'Core',
1132: * Method: 'DoServerInitializations',
1133: * Result: false,
1134: * ErrorCode: 102
1135: * }
1136: */
1137: /**
1138: * Does some pending actions to be executed when you log in.
1139: *
1140: * @return bool
1141: */
1142: public function DoServerInitializations($Timezone = '')
1143: {
1144: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Customer);
1145: $result = true;
1146:
1147: $iUserId = \Aurora\System\Api::getAuthenticatedUserId();
1148:
1149: $oApiIntegrator = $this->getIntegratorManager();
1150:
1151: if ($iUserId && $oApiIntegrator) {
1152: $oApiIntegrator->resetCookies();
1153: }
1154:
1155: $oCacher = \Aurora\System\Api::Cacher();
1156:
1157: $bDoGC = false;
1158: $bDoHepdeskClear = false;
1159: if ($oCacher && $oCacher->IsInited()) {
1160: $iTime = $oCacher->GetTimer('Cache/ClearFileCache');
1161: if (0 === $iTime || $iTime + 60 * 60 * 24 < time()) {
1162: if ($oCacher->SetTimer('Cache/ClearFileCache')) {
1163: $bDoGC = true;
1164: }
1165: }
1166:
1167: // if (\Aurora\System\Api::GetModuleManager()->ModuleExists('Helpdesk'))
1168: // {
1169: // $iTime = $oCacher->GetTimer('Cache/ClearHelpdeskUsers');
1170: // if (0 === $iTime || $iTime + 60 * 60 * 24 < time())
1171: // {
1172: // if ($oCacher->SetTimer('Cache/ClearHelpdeskUsers'))
1173: // {
1174: // $bDoHepdeskClear = true;
1175: // }
1176: // }
1177: // }
1178: }
1179:
1180: if ($bDoGC) {
1181: \Aurora\System\Api::Log('GC: FileCache / Start');
1182: $oApiFileCache = new \Aurora\System\Managers\Filecache();
1183: $oApiFileCache->gc();
1184: $oCacher->gc();
1185: \Aurora\System\Api::Log('GC: FileCache / End');
1186: }
1187:
1188: // if ($bDoHepdeskClear && \Aurora\System\Api::GetModuleManager()->ModuleExists('Helpdesk'))
1189: // {
1190: // \Aurora\System\Api::ExecuteMethod('Helpdesk::ClearUnregistredUsers');
1191: // \Aurora\System\Api::ExecuteMethod('Helpdesk::ClearAllOnline');
1192: // }
1193:
1194: return $result;
1195: }
1196:
1197: /**
1198: * @api {post} ?/Api/ Ping
1199: * @apiName Ping
1200: * @apiGroup Core
1201: * @apiDescription Method is used for checking Internet connection.
1202: *
1203: * @apiParam {string=Core} Module Module name.
1204: * @apiParam {string=Ping} Method Method name.
1205: *
1206: * @apiParamExample {json} Request-Example:
1207: * {
1208: * Module: 'Core',
1209: * Method: 'Ping'
1210: * }
1211: *
1212: * @apiSuccess {object[]} Result Array of response objects.
1213: * @apiSuccess {string} Result.Module Module name.
1214: * @apiSuccess {string} Result.Method Method name.
1215: * @apiSuccess {string} Result.Result Just a string to indicate that connection to backend is working.
1216: * @apiSuccess {int} [Result.ErrorCode] Error code.
1217: *
1218: * @apiSuccessExample {json} Success response example:
1219: * {
1220: * Module: 'Core',
1221: * Method: 'Ping',
1222: * Result: 'Pong'
1223: * }
1224: */
1225: /**
1226: * Method is used for checking Internet connection.
1227: *
1228: * @return 'Pong'
1229: */
1230: public function Ping()
1231: {
1232: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
1233:
1234: return 'Pong';
1235: }
1236:
1237: /**
1238: * @api {post} ?/Api/ GetAppData
1239: * @apiName GetAppData
1240: * @apiGroup Core
1241: * @apiDescription Obtains a list of settings for each module for the current user.
1242: *
1243: * @apiParam {string=Core} Module Module name.
1244: * @apiParam {string=GetAppData} Method Method name.
1245: *
1246: * @apiParamExample {json} Request-Example:
1247: * {
1248: * Module: 'Core',
1249: * Method: 'GetAppData'
1250: * }
1251: *
1252: * @apiSuccess {object[]} Result Array of response objects.
1253: * @apiSuccess {string} Result.Module Module name.
1254: * @apiSuccess {string} Result.Method Method name.
1255: * @apiSuccess {string} Result.Result List of settings for each module for the current user.
1256: * @apiSuccess {int} [Result.ErrorCode] Error code.
1257: *
1258: * @apiSuccessExample {json} Success response example:
1259: * {
1260: * Module: 'Core',
1261: * Method: 'GetAppData',
1262: * Result: {
1263: * User: {Id: 0, Role: 4, Name: "", PublicId: ""},
1264: * Core: { ... },
1265: * Contacts: { ... },
1266: * ...
1267: * CoreWebclient: { ... },
1268: * ...
1269: * }
1270: * }
1271: */
1272: /**
1273: * Obtains a list of settings for each module for the current user.
1274: *
1275: * @return array
1276: */
1277: public function GetAppData()
1278: {
1279: $oApiIntegrator = $this->getIntegratorManager();
1280: return $oApiIntegrator->appData();
1281: }
1282:
1283: /**
1284: * @api {post} ?/Api/ GetSettings
1285: * @apiName GetSettings
1286: * @apiGroup Core
1287: * @apiDescription Obtains list of module settings for authenticated user.
1288: *
1289: * @apiHeader {string} [Authorization] "Bearer " + Authentication token which was received as the result of Core.Login method.
1290: * @apiHeaderExample {json} Header-Example:
1291: * {
1292: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1293: * }
1294: *
1295: * @apiParam {string=Core} Module Module name.
1296: * @apiParam {string=GetSettings} Method Method name.
1297: *
1298: * @apiParamExample {json} Request-Example:
1299: * {
1300: * Module: 'Core',
1301: * Method: 'GetSettings'
1302: * }
1303: *
1304: * @apiSuccess {object[]} Result Array of response objects.
1305: * @apiSuccess {string} Result.Module Module name.
1306: * @apiSuccess {string} Result.Method Method name.
1307: * @apiSuccess {mixed} Result.Result List of module settings in case of success, otherwise **false**.
1308: * @apiSuccess {string} Result.Result.SiteName Site name.
1309: * @apiSuccess {string} Result.Result.Language Language of interface.
1310: * @apiSuccess {int} Result.Result.TimeFormat Time format.
1311: * @apiSuccess {string} Result.Result.DateFormat Date format.
1312: * @apiSuccess {bool} Result.Result.AutodetectLanguage Indicates if language should be taken from browser.
1313: * @apiSuccess {object} Result.Result.EUserRole Enumeration with user roles.
1314: * @apiSuccess {string} [Result.Result.DBHost] Database host is returned only if super administrator is authenticated.
1315: * @apiSuccess {string} [Result.Result.DBName] Database name is returned only if super administrator is authenticated.
1316: * @apiSuccess {string} [Result.Result.DBLogin] Database login is returned only if super administrator is authenticated.
1317: * @apiSuccess {string} [Result.Result.AdminLogin] Super administrator login is returned only if super administrator is authenticated.
1318: * @apiSuccess {bool} [Result.Result.AdminHasPassword] Indicates if super administrator has set up password. It is returned only if super administrator is authenticated.
1319: * @apiSuccess {string} [Result.Result.AdminLanguage] Super administrator language is returned only if super administrator is authenticated.
1320: * @apiSuccess {bool} [Result.Result.IsSystemConfigured] Indicates if 'data' folder exist and writable and salt was generated.
1321: * @apiSuccess {bool} [Result.Result.SaltNotEmpty] Indicates if salt was generated. It is returned only if super administrator is authenticated.
1322: * @apiSuccess {bool} [Result.Result.EnableLogging] Indicates if logging is enabled. It is returned only if super administrator is authenticated.
1323: * @apiSuccess {bool} [Result.Result.EnableEventLogging] Indicates if event logging is enabled. It is returned only if super administrator is authenticated.
1324: * @apiSuccess {string} [Result.Result.LoggingLevel] Value of logging level. It is returned only if super administrator is authenticated.
1325: * @apiSuccess {int} [Result.ErrorCode] Error code.
1326: *
1327: * @apiSuccessExample {json} Success response example:
1328: * {
1329: * Module: 'Core',
1330: * Method: 'GetSettings',
1331: * Result: { SiteName: "Aurora Cloud", Language: "English", TimeFormat: 1, DateFormat: "MM/DD/YYYY",
1332: * EUserRole: { SuperAdmin: 0, TenantAdmin: 1, NormalUser: 2, Customer: 3, Anonymous: 4 } }
1333: * }
1334: *
1335: * @apiSuccessExample {json} Error response example:
1336: * {
1337: * Module: 'Core',
1338: * Method: 'GetSettings',
1339: * Result: false,
1340: * ErrorCode: 102
1341: * }
1342: */
1343: /**
1344: * Obtains list of module settings for authenticated user.
1345: *
1346: * @return array
1347: */
1348: public function GetSettings()
1349: {
1350: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
1351:
1352: $oUser = \Aurora\System\Api::getAuthenticatedUser();
1353:
1354: $oApiIntegrator = $this->getIntegratorManager();
1355: $iLastErrorCode = $oApiIntegrator->getLastErrorCode();
1356: if (0 < $iLastErrorCode) {
1357: $oApiIntegrator->clearLastErrorCode();
1358: }
1359:
1360: $oSettings =& \Aurora\System\Api::GetSettings();
1361:
1362: $aSettings = array(
1363: 'AutodetectLanguage' => $this->getConfig('AutodetectLanguage'),
1364: 'UserSelectsDateFormat' => $this->getConfig('UserSelectsDateFormat', false),
1365: 'DateFormat' => $this->getConfig('DateFormat', 'DD/MM/YYYY'),
1366: 'DateFormatList' => $this->getConfig('DateFormatList', ['DD/MM/YYYY', 'MM/DD/YYYY', 'DD Month YYYY']),
1367: 'EUserRole' => (new \Aurora\System\Enums\UserRole())->getMap(),
1368: 'Language' => \Aurora\System\Api::GetLanguage(),
1369: 'ShortLanguage' => \Aurora\System\Utils::ConvertLanguageNameToShort(\Aurora\System\Api::GetLanguage()),
1370: 'LanguageList' => $oApiIntegrator->getLanguageList(),
1371: 'LastErrorCode' => $iLastErrorCode,
1372: 'SiteName' => $this->getConfig('SiteName'),
1373: 'SocialName' => '',
1374: 'TenantName' => \Aurora\System\Api::getTenantName(),
1375: 'EnableMultiTenant' => $oSettings && $oSettings->GetValue('EnableMultiTenant', false),
1376: 'TimeFormat' => $this->getConfig('TimeFormat'),
1377: 'UserId' => \Aurora\System\Api::getAuthenticatedUserId(),
1378: 'IsSystemConfigured' => is_writable(\Aurora\System\Api::DataPath()) &&
1379: (file_exists(\Aurora\System\Api::GetSaltPath()) && strlen(@file_get_contents(\Aurora\System\Api::GetSaltPath()))),
1380: 'Version' => \Aurora\System\Api::VersionFull(),
1381: 'ProductName' => $this->getConfig('ProductName'),
1382: 'PasswordMinLength' => $oSettings ? $oSettings->GetValue('PasswordMinLength', 0) : 0,
1383: 'PasswordMustBeComplex' => $oSettings && $oSettings->GetValue('PasswordMustBeComplex', false),
1384: 'CookiePath' => \Aurora\System\Api::getCookiePath(),
1385: 'CookieSecure' => \Aurora\System\Api::getCookieSecure(),
1386: 'AuthTokenCookieExpireTime' => $this->getConfig('AuthTokenCookieExpireTime', 30),
1387: 'StoreAuthTokenInDB' => $oSettings->GetValue('StoreAuthTokenInDB'),
1388: 'AvailableClientModules' => $oApiIntegrator->GetClientModuleNames(),
1389: 'AvailableBackendModules' => $oApiIntegrator->GetBackendModules(),
1390: 'AllowGroups' => $this->getConfig('AllowGroups', false),
1391: );
1392:
1393: if ($oSettings && !empty($oUser) && $oUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin) {
1394: $sAdminPassword = $oSettings->GetValue('AdminPassword');
1395:
1396: $aSettings = array_merge($aSettings, array(
1397: 'DBHost' => $oSettings->GetValue('DBHost'),
1398: 'DBName' => $oSettings->GetValue('DBName'),
1399: 'DBLogin' => $oSettings->GetValue('DBLogin'),
1400: 'AdminLogin' => $oSettings->GetValue('AdminLogin'),
1401: 'AdminHasPassword' => !empty($sAdminPassword),
1402: 'AdminLanguage' => $oSettings->GetValue('AdminLanguage'),
1403: 'CommonLanguage' => $this->getConfig('Language'),
1404: 'SaltNotEmpty' => file_exists(\Aurora\System\Api::GetSaltPath()) && strlen(@file_get_contents(\Aurora\System\Api::GetSaltPath())),
1405: 'EnableLogging' => $oSettings->GetValue('EnableLogging'),
1406: 'EnableEventLogging' => $oSettings->GetValue('EnableEventLogging'),
1407: 'LoggingLevel' => $oSettings->GetValue('LoggingLevel'),
1408: 'LogFilesData' => $this->GetLogFilesData(),
1409: 'ELogLevel' => (new \Aurora\System\Enums\LogLevel())->getMap()
1410: ));
1411: }
1412:
1413: if (!empty($oUser) && $oUser->isNormalOrTenant()) {
1414: if ($oUser->DateFormat !== '') {
1415: $aSettings['DateFormat'] = $oUser->DateFormat;
1416: }
1417: $aSettings['TimeFormat'] = $oUser->TimeFormat;
1418: $aSettings['Timezone'] = $oUser->DefaultTimeZone;
1419: }
1420:
1421: return $aSettings;
1422: }
1423:
1424: /**
1425: * @api {post} ?/Api/ UpdateSettings
1426: * @apiName UpdateSettings
1427: * @apiGroup Core
1428: * @apiDescription Updates specified settings if super administrator is authenticated.
1429: *
1430: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1431: * @apiHeaderExample {json} Header-Example:
1432: * {
1433: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1434: * }
1435: *
1436: * @apiParam {string=Core} Module Module name.
1437: * @apiParam {string=UpdateSettings} Method Method name.
1438: * @apiParam {string} Parameters JSON.stringified object <br>
1439: * {<br>
1440: * &emsp; **DbLogin** *string* Database login.<br>
1441: * &emsp; **DbPassword** *string* Database password.<br>
1442: * &emsp; **DbName** *string* Database name.<br>
1443: * &emsp; **DbHost** *string* Database host.<br>
1444: * &emsp; **AdminLogin** *string* Login for super administrator.<br>
1445: * &emsp; **Password** *string* Current password for super administrator.<br>
1446: * &emsp; **NewPassword** *string* New password for super administrator.<br>
1447: * &emsp; **AdminLanguage** *string* Language for super administrator.<br>
1448: * &emsp; **Language** *string* Language that is used on login and for new users.<br>
1449: * &emsp; **AutodetectLanguage** *bool* Indicates if browser language should be used on login and for new users.<br>
1450: * &emsp; **TimeFormat** *int* Time format that is used for new users.<br>
1451: * &emsp; **EnableLogging** *bool* Indicates if logs are enabled.<br>
1452: * &emsp; **EnableEventLogging** *bool* Indicates if events logs are enabled.<br>
1453: * &emsp; **LoggingLevel** *int* Specify logging level.<br>
1454: * }
1455: *
1456: * @apiParamExample {json} Request-Example:
1457: * {
1458: * Module: 'Core',
1459: * Method: 'UpdateSettings',
1460: * Parameters: '{ DbLogin: "login_value", DbPassword: "password_value",
1461: * DbName: "db_name_value", DbHost: "host_value", AdminLogin: "admin_login_value",
1462: * Password: "admin_pass_value", NewPassword: "admin_pass_value" }'
1463: * }
1464: *
1465: * @apiSuccess {object[]} Result Array of response objects.
1466: * @apiSuccess {string} Result.Module Module name.
1467: * @apiSuccess {string} Result.Method Method name.
1468: * @apiSuccess {bool} Result.Result Indicates if settings were updated successfully.
1469: * @apiSuccess {int} [Result.ErrorCode] Error code.
1470: *
1471: * @apiSuccessExample {json} Success response example:
1472: * {
1473: * Module: 'Core',
1474: * Method: 'UpdateSettings',
1475: * Result: true
1476: * }
1477: *
1478: * @apiSuccessExample {json} Error response example:
1479: * {
1480: * Module: 'Core',
1481: * Method: 'UpdateSettings',
1482: * Result: false,
1483: * ErrorCode: 102
1484: * }
1485: */
1486: /**
1487: * Updates specified settings if super administrator is authenticated.
1488: *
1489: * @param string $DbLogin Database login.
1490: * @param string $DbPassword Database password.
1491: * @param string $DbName Database name.
1492: * @param string $DbHost Database host.
1493: * @param string $AdminLogin Login for super administrator.
1494: * @param string $Password Current password for super administrator.
1495: * @param string $NewPassword New password for super administrator.
1496: * @param string $AdminLanguage Language for super administrator.
1497: * @param string $SiteName Site name.
1498: * @param string $Language Language that is used on login and for new users.
1499: * @param bool $AutodetectLanguage Indicates if browser language should be used on login and for new users.
1500: * @param int $TimeFormat Time format that is used for new users.
1501: * @param bool $EnableLogging Indicates if logs are enabled.
1502: * @param bool $EnableEventLogging Indicates if events logs are enabled.
1503: * @param int $LoggingLevel Specify logging level.
1504: * @return bool
1505: * @throws \Aurora\System\Exceptions\ApiException
1506: */
1507: public function UpdateSettings(
1508: $DbLogin = null,
1509: $DbPassword = null,
1510: $DbName = null,
1511: $DbHost = null,
1512: $AdminLogin = null,
1513: $Password = null,
1514: $NewPassword = null,
1515: $AdminLanguage = null,
1516: $SiteName = null,
1517: $Language = null,
1518: $AutodetectLanguage = null,
1519: $TimeFormat = null,
1520: $DateFormat = null,
1521: $EnableLogging = null,
1522: $EnableEventLogging = null,
1523: $LoggingLevel = null
1524: )
1525: {
1526: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1527:
1528: $oUser = \Aurora\System\Api::getAuthenticatedUser();
1529:
1530: if ($oUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin) {
1531: if ($SiteName !== null || $Language !== null || $TimeFormat !== null || $AutodetectLanguage !== null) {
1532: if ($SiteName !== null) {
1533: $this->setConfig('SiteName', $SiteName);
1534: }
1535: if ($AutodetectLanguage !== null) {
1536: $this->setConfig('AutodetectLanguage', $AutodetectLanguage);
1537: }
1538: if ($Language !== null) {
1539: $this->setConfig('Language', $Language);
1540: }
1541: if ($TimeFormat !== null) {
1542: $this->setConfig('TimeFormat', (int) $TimeFormat);
1543: }
1544: $this->saveModuleConfig();
1545: }
1546: $oSettings =&\Aurora\System\Api::GetSettings();
1547: if ($DbLogin !== null) {
1548: $oSettings->DBLogin = $DbLogin;
1549: }
1550: if ($DbPassword !== null) {
1551: $oSettings->DBPassword = $DbPassword;
1552: }
1553: if ($DbName !== null) {
1554: $oSettings->DBName = $DbName;
1555: }
1556: if ($DbHost !== null) {
1557: $oSettings->DBHost = $DbHost;
1558: }
1559: if ($AdminLogin !== null && $AdminLogin !== $oSettings->GetValue('AdminLogin')) {
1560: $aArgs = array(
1561: 'Login' => $AdminLogin
1562: );
1563: $this->broadcastEvent(
1564: 'CheckAccountExists',
1565: $aArgs
1566: );
1567:
1568: $oSettings->AdminLogin = $AdminLogin;
1569: }
1570:
1571: $sAdminPassword = $oSettings->GetValue('AdminPassword');
1572: if ((empty($sAdminPassword) && empty($Password) || !empty($Password)) && !empty($NewPassword)) {
1573: if (empty($sAdminPassword) || crypt(trim($Password), \Aurora\System\Api::$sSalt) === $sAdminPassword) {
1574: $oSettings->AdminPassword = crypt(trim($NewPassword), \Aurora\System\Api::$sSalt);
1575: } else {
1576: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Exceptions\Errs::UserManager_AccountOldPasswordNotCorrect);
1577: }
1578: }
1579: if ($AdminLanguage !== null) {
1580: $oSettings->AdminLanguage = $AdminLanguage;
1581: }
1582: if ($EnableLogging !== null) {
1583: $oSettings->EnableLogging = $EnableLogging;
1584: }
1585: if ($EnableEventLogging !== null) {
1586: $oSettings->EnableEventLogging = $EnableEventLogging;
1587: }
1588: if ($LoggingLevel !== null) {
1589: $oSettings->LoggingLevel = $LoggingLevel;
1590: }
1591: return $oSettings->Save();
1592: }
1593:
1594: if ($oUser->isNormalOrTenant()) {
1595: if ($Language !== null) {
1596: $oUser->Language = $Language;
1597: }
1598: if ($TimeFormat !== null) {
1599: $oUser->TimeFormat = $TimeFormat;
1600: }
1601: if ($DateFormat !== null) {
1602: $oUser->DateFormat = $DateFormat;
1603: }
1604: return $this->UpdateUserObject($oUser);
1605: }
1606:
1607: return false;
1608: }
1609:
1610: public function UpdateLoggingSettings($EnableLogging = null, $EnableEventLogging = null, $LoggingLevel = null)
1611: {
1612: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
1613:
1614: $oSettings =&\Aurora\System\Api::GetSettings();
1615:
1616: if ($EnableLogging !== null) {
1617: $oSettings->EnableLogging = $EnableLogging;
1618: }
1619: if ($EnableEventLogging !== null) {
1620: $oSettings->EnableEventLogging = $EnableEventLogging;
1621: }
1622: if ($LoggingLevel !== null) {
1623: $oSettings->LoggingLevel = $LoggingLevel;
1624: }
1625:
1626: return $oSettings->Save();
1627: }
1628:
1629: /**
1630: * @ignore
1631: * Turns on or turns off mobile version.
1632: * @param bool $Mobile Indicates if mobile version should be turned on or turned off.
1633: * @return bool
1634: */
1635: public function SetMobile($Mobile)
1636: {
1637: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
1638: $oApiIntegrator = $this->getIntegratorManager();
1639: return $oApiIntegrator ? $oApiIntegrator->setMobile($Mobile) : false;
1640: }
1641:
1642: /**
1643: * @api {post} ?/Api/ CreateTables
1644: * @apiName CreateTables
1645: * @apiGroup Core
1646: * @apiDescription Creates tables reqired for module work. Creates first channel and tenant if it is necessary.
1647: *
1648: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1649: * @apiHeaderExample {json} Header-Example:
1650: * {
1651: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1652: * }
1653: *
1654: * @apiParam {string=Core} Module Module name.
1655: * @apiParam {string=CreateTables} Method Method name.
1656: *
1657: * @apiParamExample {json} Request-Example:
1658: * {
1659: * Module: 'Core',
1660: * Method: 'CreateTables'
1661: * }
1662: *
1663: * @apiSuccess {object[]} Result Array of response objects.
1664: * @apiSuccess {string} Result.Module Module name.
1665: * @apiSuccess {string} Result.Method Method name.
1666: * @apiSuccess {bool} Result.Result Indicates if tables was created successfully.
1667: * @apiSuccess {int} [Result.ErrorCode] Error code.
1668: *
1669: * @apiSuccessExample {json} Success response example:
1670: * {
1671: * Module: 'Core',
1672: * Method: 'CreateTables',
1673: * Result: true
1674: * }
1675: *
1676: * @apiSuccessExample {json} Error response example:
1677: * {
1678: * Module: 'Core',
1679: * Method: 'CreateTables',
1680: * Result: false,
1681: * ErrorCode: 102
1682: * }
1683: */
1684: /**
1685: * Creates tables required for module work. Creates first channel and tenant if it is necessary.
1686: *
1687: * @return bool
1688: */
1689: public function CreateTables()
1690: {
1691: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
1692:
1693: if (!function_exists('mysqli_fetch_all')) {
1694: throw new ApiException(0, null, 'Please make sure your PHP/MySQL environment meets the minimal system requirements.');
1695: }
1696:
1697: $bResult = false;
1698:
1699: try {
1700: $container = \Aurora\Api::GetContainer();
1701:
1702: $oPdo = $container['connection']->getPdo();
1703: if ($oPdo && strpos($oPdo->getAttribute(\PDO::ATTR_CLIENT_VERSION), 'mysqlnd') === false) {
1704: throw new ApiException(Enums\ErrorCodes::MySqlConfigError);
1705: }
1706:
1707: $container['console']->setAutoExit(false);
1708:
1709: $container['console']->find('migrate')
1710: ->run(new ArrayInput([
1711: '--force' => true,
1712: '--seed' => true
1713: ]), new NullOutput());
1714:
1715: $bResult = true;
1716: } catch (\Exception $oEx) {
1717: \Aurora\System\Api::LogException($oEx);
1718: if ($oEx instanceof ApiException) {
1719: throw $oEx;
1720: }
1721: }
1722:
1723: return $bResult;
1724: }
1725:
1726: public function GetOrphans()
1727: {
1728: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
1729:
1730: $bResult = false;
1731:
1732: try {
1733: $container = \Aurora\Api::GetContainer();
1734: $container['console']->setAutoExit(false);
1735:
1736: $output = new BufferedOutput();
1737: $container['console']->find('get-orphans')
1738: ->run(new ArrayInput([]), $output);
1739:
1740: $content = array_filter(explode(PHP_EOL, $output->fetch()));
1741: $bResult = $content;
1742: } catch (\Exception $oEx) {
1743: \Aurora\System\Api::LogException($oEx);
1744: }
1745:
1746: return $bResult;
1747: }
1748:
1749: /**
1750: * Updates config files.
1751: * @return boolean
1752: */
1753: public function UpdateConfig()
1754: {
1755: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
1756:
1757: $bResult = true;
1758: try {
1759: \Aurora\System\Api::Init();
1760: \Aurora\System\Api::GetModuleManager()->SyncModulesConfigs();
1761:
1762: \Aurora\System\Api::GetSettings()->SyncConfigs();
1763: } catch (\Exception $e) {
1764: $bResult = false;
1765: }
1766:
1767: return $bResult;
1768: }
1769:
1770: /**
1771: * @api {post} ?/Api/ TestDbConnection
1772: * @apiName TestDbConnection
1773: * @apiGroup Core
1774: * @apiDescription Tests connection to database with specified credentials.
1775: *
1776: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1777: * @apiHeaderExample {json} Header-Example:
1778: * {
1779: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1780: * }
1781: *
1782: * @apiParam {string=Core} Module Module name.
1783: * @apiParam {string=TestDbConnection} Method Method name.
1784: * @apiParam {string} Parameters JSON.stringified object <br>
1785: * {<br>
1786: * &emsp; **DbLogin** *string* Database login.<br>
1787: * &emsp; **DbName** *string* Database name.<br>
1788: * &emsp; **DbHost** *string* Database host.<br>
1789: * &emsp; **DbPassword** *string* Database password.<br>
1790: * }
1791: *
1792: * @apiParamExample {json} Request-Example:
1793: * {
1794: * Module: 'Core',
1795: * Method: 'TestDbConnection',
1796: * Parameters: '{ DbLogin: "db_login_value", DbName: "db_name_value", DbHost: "db_host_value",
1797: * DbPassword: "db_pass_value" }'
1798: * }
1799: *
1800: * @apiSuccess {object[]} Result Array of response objects.
1801: * @apiSuccess {string} Result.Module Module name.
1802: * @apiSuccess {string} Result.Method Method name.
1803: * @apiSuccess {bool} Result.Result Indicates if test of database connection was successful.
1804: * @apiSuccess {int} [Result.ErrorCode] Error code.
1805: *
1806: * @apiSuccessExample {json} Success response example:
1807: * {
1808: * Module: 'Core',
1809: * Method: 'TestDbConnection',
1810: * Result: true
1811: * }
1812: *
1813: * @apiSuccessExample {json} Error response example:
1814: * {
1815: * Module: 'Core',
1816: * Method: 'TestDbConnection',
1817: * Result: false,
1818: * ErrorCode: 102
1819: * }
1820: */
1821: /**
1822: * Tests connection to database with specified credentials.
1823: *
1824: * @param string $DbLogin Database login.
1825: * @param string $DbName Database name.
1826: * @param string $DbHost Database host.
1827: * @param string $DbPassword Database password.
1828: * @return bool
1829: */
1830: public function TestDbConnection($DbLogin, $DbName, $DbHost, $DbPassword = null)
1831: {
1832: Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
1833: if (!function_exists('mysqli_fetch_all')) {
1834: throw new ApiException(0, null, 'Please make sure your PHP/MySQL environment meets the minimal system requirements.');
1835: }
1836: $oPdo = null;
1837: $oSettings = &Api::GetSettings();
1838: if ($oSettings) {
1839: if ($DbPassword === null) {
1840: $DbPassword = $oSettings->DBPassword;
1841: }
1842: $capsule = new \Illuminate\Database\Capsule\Manager();
1843: $capsule->addConnection(Api::GetDbConfig(
1844: $oSettings->DBType,
1845: $DbHost,
1846: $DbName,
1847: $oSettings->DBPrefix,
1848: $DbLogin,
1849: $DbPassword
1850: ));
1851: $oPdo = $capsule->getConnection()->getPdo();
1852:
1853: if ($oPdo && strpos($oPdo->getAttribute(\PDO::ATTR_CLIENT_VERSION), 'mysqlnd') === false) {
1854: throw new ApiException(Enums\ErrorCodes::MySqlConfigError);
1855: }
1856: }
1857:
1858: return isset($oPdo);
1859: }
1860:
1861: /**
1862: * Obtains authenticated account.
1863: *
1864: * @param string $AuthToken
1865: */
1866: public function GetAuthenticatedAccount($AuthToken)
1867: {
1868: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
1869:
1870: $aUserInfo = \Aurora\System\Api::getAuthenticatedUserInfo($AuthToken);
1871: $oAccount = call_user_func_array([$aUserInfo['accountType'], 'find'], [(int)$aUserInfo['account']]);
1872:
1873: return $oAccount;
1874: }
1875:
1876: /**
1877: * Obtains all accounts from all modules for authenticated user.
1878: *
1879: * @param string $AuthToken
1880: * @param string $Type
1881: * @return array
1882: */
1883: public function GetAccounts($AuthToken, $Type = '')
1884: {
1885: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
1886:
1887: $aArgs = array(
1888: 'AuthToken' => $AuthToken
1889: );
1890: $aResult = [];
1891:
1892: $this->broadcastEvent(
1893: 'GetAccounts',
1894: $aArgs,
1895: $aResult
1896: );
1897: if (!empty($Type)) {
1898: $aTempResult = [];
1899: foreach ($aResult as $aItem) {
1900: if ($aItem['Type'] === $Type) {
1901: $aTempResult[] = $aItem;
1902: }
1903: }
1904: $aResult = $aTempResult;
1905: }
1906: return $aResult;
1907: }
1908:
1909: public function IsBlockedUser($sEmail, $sIp)
1910: {
1911: $bEnableFailedLoginBlock = $this->getConfig('EnableFailedLoginBlock', false);
1912: $iLoginBlockAvailableTriesCount = $this->getConfig('LoginBlockAvailableTriesCount', 3);
1913: $iLoginBlockDurationMinutes = $this->getConfig('LoginBlockDurationMinutes', 30);
1914:
1915: if ($bEnableFailedLoginBlock) {
1916: try {
1917: $oBlockedUser = $this->GetBlockedUser($sEmail, $sIp);
1918: if ($oBlockedUser) {
1919: if ($oBlockedUser->ErrorLoginsCount >= $iLoginBlockAvailableTriesCount) {
1920: $iBlockTime = (time() - $oBlockedUser->Time) / 60;
1921: if ($iBlockTime > $iLoginBlockDurationMinutes) {
1922: $oBlockedUser->delete();
1923: } else {
1924: throw new \Aurora\System\Exceptions\ApiException(
1925: 1000,
1926: null,
1927: $this->i18N("BLOCKED_USER_MESSAGE_ERROR", [
1928: "N" => $iLoginBlockAvailableTriesCount,
1929: "M" => ceil($iLoginBlockDurationMinutes - $iBlockTime)
1930: ])
1931: );
1932: }
1933: }
1934: }
1935: } catch (\Aurora\System\Exceptions\DbException $oEx) {
1936: \Aurora\System\Api::LogException($oEx);
1937: }
1938: }
1939: }
1940:
1941: public function GetBlockedUser($sEmail, $sIp)
1942: {
1943: $mResult = false;
1944:
1945: if ($this->getConfig('EnableFailedLoginBlock', false)) {
1946: try {
1947: $mResult = Models\UserBlock::where('Email', $sEmail)->where('IpAddress', $sIp)->first();
1948: } catch (\Exception $oEx) {
1949: $mResult = false;
1950: }
1951: }
1952:
1953: return $mResult;
1954: }
1955:
1956: public function BlockUser($sEmail, $sIp)
1957: {
1958: if ($this->getConfig('EnableFailedLoginBlock', false)) {
1959: $iLoginBlockAvailableTriesCount = $this->getConfig('LoginBlockAvailableTriesCount', 3);
1960:
1961: try {
1962: $oBlockedUser = $this->GetBlockedUser($sEmail, $sIp);
1963: if (!$oBlockedUser) {
1964: $oBlockedUser = new Models\UserBlock();
1965: $oBlockedUser->Email = $sEmail;
1966: $oBlockedUser->IpAddress = $sIp;
1967: }
1968: $iUserId = Api::getUserIdByPublicId($sEmail);
1969: if ($iUserId && $oBlockedUser->ErrorLoginsCount < $iLoginBlockAvailableTriesCount) {
1970: $oBlockedUser->UserId = $iUserId;
1971: $oBlockedUser->ErrorLoginsCount = $oBlockedUser->ErrorLoginsCount + 1;
1972: $oBlockedUser->Time = time();
1973:
1974: $oBlockedUser->save();
1975: }
1976: } catch (\Exception $oEx) {
1977: \Aurora\System\Api::LogException($oEx);
1978: }
1979: }
1980: }
1981:
1982: /**
1983: *
1984: */
1985: public function Authenticate($Login, $Password, $SignMe = false)
1986: {
1987: $mResult = false;
1988:
1989: $aArgs = array(
1990: 'Login' => $Login,
1991: 'Password' => $Password,
1992: 'SignMe' => $SignMe
1993: );
1994:
1995: try {
1996: $this->broadcastEvent(
1997: 'Login',
1998: $aArgs,
1999: $mResult
2000: );
2001: } catch (\Exception $oException) {
2002: \Aurora\System\Api::GetModuleManager()->SetLastException($oException);
2003: }
2004:
2005: return $mResult;
2006: }
2007:
2008: public function SetAuthDataAndGetAuthToken($aAuthData, $Language = '', $SignMe = false)
2009: {
2010: $mResult = false;
2011: if ($aAuthData && is_array($aAuthData)) {
2012: $mResult = $aAuthData;
2013: if (isset($aAuthData['token'])) {
2014: $iTime = $SignMe ? 0 : time();
2015: $iAuthTokenExpirationLifetimeDays = \Aurora\Api::GetSettings()->GetValue('AuthTokenExpirationLifetimeDays', 0);
2016: $iExpire = 0;
2017: if ($iAuthTokenExpirationLifetimeDays > 0) {
2018: $iExpire = time() + ($iAuthTokenExpirationLifetimeDays * 24 * 60 * 60);
2019: }
2020:
2021: $sAuthToken = \Aurora\System\Api::UserSession()->Set($aAuthData, $iTime, $iExpire);
2022:
2023: //this will store user data in static variable of Api class for later usage
2024: $oUser = \Aurora\System\Api::getAuthenticatedUser($sAuthToken);
2025:
2026: if ($oUser && $oUser->Role !== \Aurora\System\Enums\UserRole::SuperAdmin) {
2027: // If User is super admin don't try to detect tenant. It will try to connect to DB.
2028: // Super admin should be able to log in without connecting to DB.
2029: $oTenant = \Aurora\System\Api::getTenantByWebDomain();
2030: if ($oTenant && $oUser->IdTenant !== $oTenant->Id) {
2031: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::AuthError);
2032: }
2033: }
2034:
2035: if ($Language !== '' && $oUser && $oUser->Language !== $Language) {
2036: $oUser->Language = $Language;
2037: }
2038:
2039: $oUser->LastLogin = date('Y-m-d H:i:s');
2040: $oUser->LoginsCount = $oUser->LoginsCount + 1;
2041:
2042: $this->getUsersManager()->updateUser($oUser);
2043: \Aurora\System\Api::LogEvent('login-success: ' . $oUser->PublicId, self::GetName());
2044: $mResult = [
2045: 'AuthToken' => $sAuthToken
2046: ];
2047: }
2048: } else {
2049: \Aurora\System\Api::LogEvent('login-failed', self::GetName());
2050: \Aurora\System\Api::GetModuleManager()->SetLastException(
2051: new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::AuthError)
2052: );
2053: }
2054:
2055: return $mResult;
2056: }
2057:
2058: /**
2059: * @api {post} ?/Api/ Login
2060: * @apiName Login
2061: * @apiGroup Core
2062: * @apiDescription Broadcasts event Login to other modules, gets responses from them and returns AuthToken.
2063: *
2064: * @apiParam {string=Core} Module Module name.
2065: * @apiParam {string=Login} Method Method name.
2066: * @apiParam {string} Parameters JSON.stringified object <br>
2067: * {<br>
2068: * &emsp; **Login** *string* Account login.<br>
2069: * &emsp; **Password** *string* Account password.<br>
2070: * &emsp; **Language** *string* New value of language for user.<br>
2071: * &emsp; **SignMe** *bool* Indicates if it is necessary to remember user between sessions. *optional*<br>
2072: * }
2073: *
2074: * @apiParamExample {json} Request-Example:
2075: * {
2076: * Module: 'Core',
2077: * Method: 'Login',
2078: * Parameters: '{ Login: "login_value", Password: "password_value", SignMe: true }'
2079: * }
2080: *
2081: * @apiSuccess {object[]} Result Array of response objects.
2082: * @apiSuccess {string} Result.Module Module name.
2083: * @apiSuccess {string} Result.Method Method name.
2084: * @apiSuccess {mixed} Result.Result Object in case of success, otherwise **false**.
2085: * @apiSuccess {string} Result.Result.AuthToken Authentication token.
2086: * @apiSuccess {int} [Result.ErrorCode] Error code.
2087: *
2088: * @apiSuccessExample {json} Success response example:
2089: * {
2090: * Module: 'Core',
2091: * Method: 'Login',
2092: * Result: { AuthToken: 'token_value' }
2093: * }
2094: *
2095: * @apiSuccessExample {json} Error response example:
2096: * {
2097: * Module: 'Core',
2098: * Method: 'Login',
2099: * Result: false,
2100: * ErrorCode: 102
2101: * }
2102: */
2103: /**
2104: * Broadcasts event Login to other modules, gets responses from them and returns AuthToken.
2105: *
2106: * @param string $Login Account login.
2107: * @param string $Password Account password.
2108: * @param string $Language New value of language for user.
2109: * @param bool $SignMe Indicates if it is necessary to remember user between sessions.
2110: * @return array
2111: * @throws \Aurora\System\Exceptions\ApiException
2112: */
2113: public function Login($Login, $Password, $Language = '', $SignMe = false)
2114: {
2115: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
2116:
2117: $sIp = \Aurora\System\Utils::getClientIp();
2118: $this->IsBlockedUser($Login, $sIp);
2119:
2120: $aAuthData = $this->Decorator()->Authenticate($Login, $Password, $SignMe);
2121:
2122: if (!$aAuthData) {
2123: $this->BlockUser($Login, $sIp);
2124: $this->IsBlockedUser($Login, $sIp);
2125: } else {
2126: $oBlockedUser = $this->GetBlockedUser($Login, $sIp);
2127: if ($oBlockedUser) {
2128: $oBlockedUser->delete();
2129: }
2130: }
2131: return $this->Decorator()->SetAuthDataAndGetAuthToken($aAuthData, $Language, $SignMe);
2132: }
2133:
2134: /**
2135: *
2136: * @param [type] $Login
2137: * @param [type] $Realm
2138: * @param [type] $Type
2139: * @return void
2140: */
2141: public function GetDigestHash($Login, $Realm, $Type)
2142: {
2143: /** This method is restricted to be called by web API (see denyMethodsCallByWebApi method). **/
2144:
2145: $mResult = null;
2146:
2147: $aArgs = array(
2148: 'Login' => $Login,
2149: 'Realm' => $Realm,
2150: 'Type' => $Type
2151: );
2152:
2153: $this->broadcastEvent(
2154: 'GetDigestHash',
2155: $aArgs,
2156: $mResult
2157: );
2158:
2159: return $mResult;
2160: }
2161:
2162: public function GetAccountUsedToAuthorize($Login)
2163: {
2164: /** This method is restricted to be called by web API (see denyMethodsCallByWebApi method). **/
2165:
2166: $mResult = null;
2167:
2168: $aArgs = array(
2169: 'Login' => $Login
2170: );
2171:
2172: $this->broadcastEvent(
2173: 'GetAccountUsedToAuthorize',
2174: $aArgs,
2175: $mResult
2176: );
2177:
2178: return $mResult;
2179: }
2180:
2181: /**
2182: * @param string $Password Account password.
2183: * @return bool
2184: * @throws \Aurora\System\Exceptions\ApiException
2185: */
2186: public function VerifyPassword($Password)
2187: {
2188: /** This method is restricted to be called by web API (see denyMethodsCallByWebApi method). **/
2189:
2190: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
2191: $mResult = false;
2192: $bResult = false;
2193: $sAuthToken = \Aurora\System\Api::getAuthToken();
2194: $oApiIntegrator = $this->getIntegratorManager();
2195:
2196: $aUserInfo = $oApiIntegrator->getAuthenticatedUserInfo($sAuthToken);
2197: if (isset($aUserInfo['account']) && isset($aUserInfo['accountType'])) {
2198: $r = new \ReflectionClass($aUserInfo['accountType']);
2199: $oQuery = $r->getMethod('query')->invoke(null);
2200:
2201: $oAccount = $oQuery->find($aUserInfo['account']);
2202: if ($oAccount) {
2203: $aArgs = array(
2204: 'Login' => $oAccount->getLogin(),
2205: 'Password' => $Password,
2206: 'SignMe' => false
2207: );
2208: $this->broadcastEvent(
2209: 'Login',
2210: $aArgs,
2211: $mResult
2212: );
2213:
2214: if (is_array($mResult)
2215: && isset($mResult['token'])
2216: && $mResult['token'] === 'auth'
2217: && isset($mResult['id'])
2218: ) {
2219: $UserId = \Aurora\System\Api::getAuthenticatedUserId();
2220: if ($mResult['id'] === $UserId) {
2221: $bResult = true;
2222: }
2223: }
2224: }
2225: }
2226:
2227: return $bResult;
2228: }
2229:
2230: /**
2231: * @param $email
2232: * @param $resetOption
2233: * @return bool
2234: */
2235: public function ResetPassword($email, $resetOption)
2236: {
2237: $mResult = false;
2238:
2239: $aArgs = array(
2240: 'email' => $email,
2241: 'resetOption' => $resetOption
2242: );
2243: $this->broadcastEvent(
2244: 'ResetPassword',
2245: $aArgs,
2246: $mResult
2247: );
2248:
2249:
2250: if (!empty($mResult)) {
2251: \Aurora\System\Api::LogEvent('resetPassword-success: ' . $email, self::GetName());
2252: } else {
2253: \Aurora\System\Api::LogEvent('resetPassword-failed: ' . $email, self::GetName());
2254: }
2255:
2256: return $mResult;
2257: }
2258:
2259:
2260: public function ResetPasswordBySecurityQuestion($securityAnswer, $securityToken)
2261: {
2262: $mResult = false;
2263:
2264: $aArgs = array(
2265: 'securityAnswer' => $securityAnswer,
2266: 'securityToken' => $securityToken
2267: );
2268: $this->broadcastEvent(
2269: 'ResetPasswordBySecurityQuestion',
2270: $aArgs,
2271: $mResult
2272: );
2273:
2274:
2275: if (!empty($mResult)) {
2276: \Aurora\System\Api::LogEvent('ResetPasswordBySecurityQuestion-success: ' . $securityAnswer, self::GetName());
2277: return $mResult;
2278: }
2279:
2280: \Aurora\System\Api::LogEvent('ResetPasswordBySecurityQuestion-failed: ' . $securityAnswer, self::GetName());
2281: }
2282:
2283: public function UpdatePassword($Password, $ConfirmPassword, $Hash)
2284: {
2285: $mResult = false;
2286:
2287: $aArgs = array(
2288: 'Password' => $Password,
2289: 'ConfirmPassword' => $ConfirmPassword,
2290: 'Hash' => $Hash
2291: );
2292: $this->broadcastEvent(
2293: 'UpdatePassword',
2294: $aArgs,
2295: $mResult
2296: );
2297:
2298: if (!empty($mResult)) {
2299: \Aurora\System\Api::LogEvent('updatePassword-success: ' . $Hash, self::GetName());
2300: return $mResult;
2301: }
2302:
2303: \Aurora\System\Api::LogEvent('updatePassword-failed: ' . $Hash, self::GetName());
2304: }
2305:
2306: /**
2307: * @api {post} ?/Api/ Logout
2308: * @apiName Logout
2309: * @apiGroup Core
2310: * @apiDescription Logs out authenticated user. Clears session.
2311: *
2312: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
2313: * @apiHeaderExample {json} Header-Example:
2314: * {
2315: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
2316: * }
2317: *
2318: * @apiParam {string=Core} Module Module name.
2319: * @apiParam {string=Logout} Method Method name.
2320: *
2321: * @apiParamExample {json} Request-Example:
2322: * {
2323: * Module: 'Core',
2324: * Method: 'Logout'
2325: * }
2326: *
2327: * @apiSuccess {object[]} Result Array of response objects.
2328: * @apiSuccess {string} Result.Module Module name.
2329: * @apiSuccess {string} Result.Method Method name.
2330: * @apiSuccess {bool} Result.Result Indicates if logout was successful.
2331: * @apiSuccess {int} [Result.ErrorCode] Error code.
2332: *
2333: * @apiSuccessExample {json} Success response example:
2334: * {
2335: * Module: 'Core',
2336: * Method: 'Logout',
2337: * Result: true
2338: * }
2339: *
2340: * @apiSuccessExample {json} Error response example:
2341: * {
2342: * Module: 'Core',
2343: * Method: 'Logout',
2344: * Result: false,
2345: * ErrorCode: 102
2346: * }
2347: */
2348: /**
2349: * Logs out authenticated user. Clears session.
2350: *
2351: * @return bool
2352: * @throws \Aurora\System\Exceptions\ApiException
2353: */
2354: public function Logout()
2355: {
2356: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
2357:
2358: \Aurora\System\Api::LogEvent('logout', self::GetName());
2359:
2360: \Aurora\System\Api::UserSession()->Delete(
2361: \Aurora\System\Api::getAuthToken()
2362: );
2363:
2364:
2365: return true;
2366: }
2367:
2368: /**
2369: * @deprecated since version 8.3.7
2370: */
2371: public function GetEntityList($Type, $Offset = 0, $Limit = 0, $Search = '', $TenantId = 0, $Filters = [])
2372: {
2373: switch ($Type) {
2374: case 'Tenant':
2375: return self::Decorator()->GetTenants($Offset, $Limit, $Search);
2376: case 'User':
2377: return self::Decorator()->GetUsers($TenantId, $Offset, $Limit, 'PublicId', \Aurora\System\Enums\SortOrder::ASC, $Search, $Filters);
2378: }
2379: return null;
2380: }
2381:
2382: /**
2383: * @deprecated since version 8.3.7
2384: */
2385: public function GetEntity($Type, $Id)
2386: {
2387: switch ($Type) {
2388: case 'Tenant':
2389: return self::Decorator()->GetTenant($Id);
2390: case 'User':
2391: return self::Decorator()->GetUser($Id);
2392: }
2393: return null;
2394: }
2395:
2396: /**
2397: * Creates channel with specified login and description.
2398: *
2399: * @param string $Login New channel login.
2400: * @param string $Description New channel description.
2401: * @return int New channel identifier.
2402: * @throws \Aurora\System\Exceptions\ApiException
2403: */
2404: public function CreateChannel($Login, $Description = '')
2405: {
2406: $mResult = -1;
2407: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
2408:
2409: $mResult = false;
2410:
2411: $Login = \trim($Login);
2412: if ($Login !== '') {
2413: $oChannel = new Models\Channel();
2414:
2415: $oChannel->Login = $Login;
2416:
2417: if ($Description !== '') {
2418: $oChannel->Description = $Description;
2419: }
2420:
2421: if ($this->getChannelsManager()->createChannel($oChannel)) {
2422: $mResult = $oChannel->Id;
2423: }
2424: } else {
2425: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
2426: }
2427:
2428: return $mResult;
2429: }
2430:
2431: /**
2432: * Updates channel.
2433: *
2434: * @param int $ChannelId Channel identifier.
2435: * @param string $Login New login for channel.
2436: * @param string $Description New description for channel.
2437: * @return bool
2438: * @throws \Aurora\System\Exceptions\ApiException
2439: */
2440: public function UpdateChannel($ChannelId, $Login = '', $Description = '')
2441: {
2442: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
2443:
2444: if ($ChannelId > 0) {
2445: $oChannel = $this->getChannelsManager()->getChannelById($ChannelId);
2446:
2447: if ($oChannel) {
2448: $Login = \trim($Login);
2449: if (!empty($Login)) {
2450: $oChannel->Login = $Login;
2451: }
2452: if (!empty($Description)) {
2453: $oChannel->Description = $Description;
2454: }
2455:
2456: return $this->getChannelsManager()->updateChannel($oChannel);
2457: }
2458: } else {
2459: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
2460: }
2461:
2462: return false;
2463: }
2464:
2465: /**
2466: * Deletes channel.
2467: *
2468: * @param int $ChannelId Identifier of channel to delete.
2469: * @return bool
2470: * @throws \Aurora\System\Exceptions\ApiException
2471: */
2472: public function DeleteChannel($ChannelId)
2473: {
2474: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
2475:
2476: if ($ChannelId > 0) {
2477: $oChannel = $this->getChannelsManager()->getChannelById($ChannelId);
2478:
2479: if ($oChannel) {
2480: return $this->getChannelsManager()->deleteChannel($oChannel);
2481: }
2482: } else {
2483: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
2484: }
2485:
2486: return false;
2487: }
2488:
2489: /**
2490: * @api {post} ?/Api/ GetTenants
2491: * @apiName GetTenants
2492: * @apiGroup Core
2493: * @apiDescription Obtains tenant list if super administrator is authenticated.
2494: *
2495: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
2496: * @apiHeaderExample {json} Header-Example:
2497: * {
2498: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
2499: * }
2500: *
2501: * @apiParam {string=Core} Module Module name.
2502: * @apiParam {string=GetTenants} Method Method name.
2503: * @apiParam {string} Parameters JSON.stringified object <br>
2504: * {<br>
2505: * &emsp; **Offset** *int* Offset of tenant list.<br>
2506: * &emsp; **Limit** *int* Limit of result tenant list.<br>
2507: * &emsp; **Search** *string* Search string.<br>
2508: * }
2509: *
2510: * @apiParamExample {json} Request-Example:
2511: * {
2512: * Module: 'Core',
2513: * Method: 'GetTenants'
2514: * }
2515: *
2516: * @apiSuccess {object[]} Result Array of response objects.
2517: * @apiSuccess {string} Result.Module Module name.
2518: * @apiSuccess {string} Result.Method Method name.
2519: * @apiSuccess {mixed} Result.Result Object with array of tenants and their count in case of success, otherwise **false**.
2520: * @apiSuccess {int} [Result.ErrorCode] Error code.
2521: *
2522: * @apiSuccessExample {json} Success response example:
2523: * {
2524: * Module: 'Core',
2525: * Method: 'GetTenants',
2526: * Result: {
2527: * Items: [
2528: * { Id: 123, Name: 'Default', SiteName: '' }
2529: * ],
2530: * Count: 1
2531: * }
2532: * }
2533: *
2534: * @apiSuccessExample {json} Error response example:
2535: * {
2536: * Module: 'Core',
2537: * Method: 'GetTenants',
2538: * Result: false,
2539: * ErrorCode: 102
2540: * }
2541: */
2542: /**
2543: * Obtains tenant list if super administrator is authenticated.
2544: * @param int $Offset Offset of the list.
2545: * @param int $Limit Limit of the list.
2546: * @param string $Search Search string.
2547: * @return array {
2548: * *array* **Items** Tenant list
2549: * *int* **Count** Tenant count
2550: * }
2551: * @throws \Aurora\System\Exceptions\ApiException
2552: */
2553: public function GetTenants($Offset = 0, $Limit = 0, $Search = '')
2554: {
2555: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
2556:
2557: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
2558: $bTenant = $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::TenantAdmin;
2559:
2560: $aTenantsFromDb = $this->getTenantsManager()->getTenantList($Offset, $Limit, $Search);
2561: $oSettings = $this->GetModuleSettings();
2562: $aTenants = [];
2563:
2564: foreach ($aTenantsFromDb as $oTenant) {
2565: if (!$bTenant || $oTenant->Id === $oAuthenticatedUser->IdTenant) {
2566: $aTenants[] = [
2567: 'Id' => $oTenant->Id,
2568: 'Name' => $oTenant->Name,
2569: 'SiteName' => $oSettings->GetTenantValue($oTenant->Name, 'SiteName', '')
2570: ];
2571: }
2572: }
2573:
2574: $iTenantsCount = $Limit > 0 ? $this->getTenantsManager()->getTenantsCount($Search) : count($aTenantsFromDb);
2575: return array(
2576: 'Items' => $aTenants,
2577: 'Count' => $iTenantsCount,
2578: );
2579: }
2580:
2581: /**
2582: * @deprecated since version 8.3.7
2583: */
2584: public function GetTenantList($Offset = 0, $Limit = 0, $Search = '')
2585: {
2586: return self::Decorator()->GetTenants($Offset, $Limit, $Search);
2587: }
2588:
2589: /**
2590: * @api {post} ?/Api/ GetTenant
2591: * @apiName GetTenant
2592: * @apiGroup Core
2593: * @apiDescription Returns tenant.
2594: *
2595: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
2596: * @apiHeaderExample {json} Header-Example:
2597: * {
2598: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
2599: * }
2600: *
2601: * @apiParam {string=Core} Module Module name.
2602: * @apiParam {string=GetTenant} Method Method name.
2603: * @apiParam {string} Parameters JSON.stringified object <br>
2604: * {<br>
2605: * &emsp; **Id** *int* Tenant identifier.<br>
2606: * }
2607: *
2608: * @apiParamExample {json} Request-Example:
2609: * {
2610: * Module: 'Core',
2611: * Method: 'GetTenant',
2612: * Parameters: '{ Id: 123 }'
2613: * }
2614: *
2615: * @apiSuccess {object[]} Result Array of response objects.
2616: * @apiSuccess {string} Result.Module Module name.
2617: * @apiSuccess {string} Result.Method Method name.
2618: * @apiSuccess {mixed} Result.Result Object in case of success, otherwise **false**.
2619: * @apiSuccess {int} [Result.ErrorCode] Error code.
2620: *
2621: * @apiSuccessExample {json} Success response example:
2622: * {
2623: * Module: 'Core',
2624: * Method: 'GetTenant',
2625: * Result: { Description: '', Name: 'Default', SiteName: '', WebDomain: '' }
2626: * }
2627: *
2628: * @apiSuccessExample {json} Error response example:
2629: * {
2630: * Module: 'Core',
2631: * Method: 'GetTenant',
2632: * Result: false,
2633: * ErrorCode: 102
2634: * }
2635: */
2636: /**
2637: * Returns tenant object by identifier.
2638: *
2639: * @param int $Id Tenant identifier.
2640: * @return \Aurora\Modules\Core\Models\Tenant|null
2641: */
2642: public function GetTenant($Id)
2643: {
2644: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
2645: if (!empty($oAuthenticatedUser) && $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::TenantAdmin && $oAuthenticatedUser->IdTenant === $Id) {
2646: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
2647: } else {
2648: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
2649: }
2650:
2651: return $this->GetTenantUnchecked($Id);
2652: }
2653:
2654: /**
2655: * @api {post} ?/Api/ CreateTenant
2656: * @apiName CreateTenant
2657: * @apiGroup Core
2658: * @apiDescription Creates tenant.
2659: *
2660: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
2661: * @apiHeaderExample {json} Header-Example:
2662: * {
2663: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
2664: * }
2665: *
2666: * @apiParam {string=Core} Module Module name.
2667: * @apiParam {string=CreateTenant} Method Method name.
2668: * @apiParam {string} Parameters JSON.stringified object <br>
2669: * {<br>
2670: * &emsp; **ChannelId** *int* Identifier of channel new tenant belongs to.<br>
2671: * &emsp; **Name** *string* New tenant name.<br>
2672: * &emsp; **Description** *string* New tenant description.<br>
2673: * &emsp; **WebDomain** *string* New tenant web domain.<br>
2674: * &emsp; **SiteName** *string* New tenant site name.<br>
2675: * }
2676: *
2677: * @apiParamExample {json} Request-Example:
2678: * {
2679: * Module: 'Core',
2680: * Method: 'CreateTenant',
2681: * Parameters: '{ ChannelId: 123, Name: "name_value", Description: "description_value" }'
2682: * }
2683: *
2684: * @apiSuccess {object[]} Result Array of response objects.
2685: * @apiSuccess {string} Result.Module Module name.
2686: * @apiSuccess {string} Result.Method Method name.
2687: * @apiSuccess {bool} Result.Result Indicates if tenant was created successfully.
2688: * @apiSuccess {int} [Result.ErrorCode] Error code.
2689: *
2690: * @apiSuccessExample {json} Success response example:
2691: * {
2692: * Module: 'Core',
2693: * Method: 'CreateTenant',
2694: * Result: true
2695: * }
2696: *
2697: * @apiSuccessExample {json} Error response example:
2698: * {
2699: * Module: 'Core',
2700: * Method: 'CreateTenant',
2701: * Result: false,
2702: * ErrorCode: 102
2703: * }
2704: */
2705: /**
2706: * Creates tenant.
2707: *
2708: * @param int $ChannelId Identifier of channel new tenant belongs to.
2709: * @param string $Name New tenant name.
2710: * @param string $Description New tenant description.
2711: * @param string $WebDomain New tenant web domain.
2712: * @param string $SiteName Tenant site name.
2713: * @return bool
2714: * @throws \Aurora\System\Exceptions\ApiException
2715: */
2716: public function CreateTenant($ChannelId = 0, $Name = '', $Description = '', $WebDomain = '', $SiteName = null)
2717: {
2718: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
2719:
2720: $oSettings =&\Aurora\System\Api::GetSettings();
2721: if (/*!$oSettings->GetValue('EnableMultiChannel') && */$ChannelId === 0) { // TODO: temporary ignore 'EnableMultiChannel' config
2722: $aChannels = $this->getChannelsManager()->getChannelList(0, 1);
2723: $ChannelId = count($aChannels) === 1 ? $aChannels[0]->Id : 0;
2724: }
2725: $Name = \trim(\Aurora\System\Utils::getSanitizedFilename($Name));
2726:
2727: if ($Name !== '' && $ChannelId > 0) {
2728: $iTenantsCount = $this->getTenantsManager()->getTenantsByChannelIdCount($ChannelId);
2729: if ($oSettings->GetValue('EnableMultiTenant') || $iTenantsCount === 0) {
2730: $oTenant = new Models\Tenant();
2731:
2732: $oTenant->Name = $Name;
2733: $oTenant->Description = $Description;
2734: $oTenant->WebDomain = $WebDomain;
2735: $oTenant->IdChannel = $ChannelId;
2736:
2737: if ($this->getTenantsManager()->createTenant($oTenant)) {
2738: if ($SiteName !== null) {
2739: $oSettings = $this->GetModuleSettings();
2740: $oSettings->SetTenantValue($oTenant->Name, 'SiteName', $SiteName);
2741: $oSettings->SaveTenantSettings($oTenant->Name);
2742: }
2743: return $oTenant->Id;
2744: }
2745: }
2746: } else {
2747: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
2748: }
2749:
2750: return false;
2751: }
2752:
2753: /**
2754: * @api {post} ?/Api/ UpdateTenant
2755: * @apiName UpdateTenant
2756: * @apiGroup Core
2757: * @apiDescription Updates tenant.
2758: *
2759: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
2760: * @apiHeaderExample {json} Header-Example:
2761: * {
2762: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
2763: * }
2764: *
2765: * @apiParam {string=Core} Module Module name.
2766: * @apiParam {string=UpdateTenant} Method Method name.
2767: * @apiParam {string} Parameters JSON.stringified object <br>
2768: * {<br>
2769: * &emsp; **TenantId** *int* Identifier of tenant to update.<br>
2770: * &emsp; **Description** *string* Tenant description.<br>
2771: * &emsp; **WebDomain** *string* Tenant web domain.<br>
2772: * &emsp; **SiteName** *string* Tenant site name.<br>
2773: * &emsp; **ChannelId** *int* Identifier of the new tenant channel.<br>
2774: * }
2775: *
2776: * @apiParamExample {json} Request-Example:
2777: * {
2778: * Module: 'Core',
2779: * Method: 'UpdateTenant',
2780: * Parameters: '{ TenantId: 123, Description: "description_value", ChannelId: 123 }'
2781: * }
2782: *
2783: * @apiSuccess {object[]} Result Array of response objects.
2784: * @apiSuccess {string} Result.Module Module name.
2785: * @apiSuccess {string} Result.Method Method name.
2786: * @apiSuccess {bool} Result.Result Indicates if tenant was updated successfully.
2787: * @apiSuccess {int} [Result.ErrorCode] Error code.
2788: *
2789: * @apiSuccessExample {json} Success response example:
2790: * {
2791: * Module: 'Core',
2792: * Method: 'UpdateTenant',
2793: * Result: true
2794: * }
2795: *
2796: * @apiSuccessExample {json} Error response example:
2797: * {
2798: * Module: 'Core',
2799: * Method: 'UpdateTenant',
2800: * Result: false,
2801: * ErrorCode: 102
2802: * }
2803: */
2804: /**
2805: * Updates tenant.
2806: *
2807: * @param int $TenantId Identifier of tenant to update.
2808: * @param string $Description Tenant description.
2809: * @param string $WebDomain Tenant web domain.
2810: * @param string $SiteName Tenant site name.
2811: * @param int $ChannelId Identifier of the tenant channel.
2812: * @return bool
2813: * @throws \Aurora\System\Exceptions\ApiException
2814: */
2815: public function UpdateTenant($TenantId, $Description = null, $WebDomain = null, $SiteName = null, $ChannelId = 0)
2816: {
2817: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
2818: if ($oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::TenantAdmin && $oAuthenticatedUser->IdTenant === $TenantId) {
2819: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
2820: } else {
2821: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
2822: }
2823:
2824: if (!empty($TenantId)) {
2825: $oTenant = $this->getTenantsManager()->getTenantById($TenantId);
2826: if ($oTenant) {
2827: if ($SiteName !== null) {
2828: $oSettings = $this->GetModuleSettings();
2829: $oSettings->SetTenantValue($oTenant->Name, 'SiteName', $SiteName);
2830: $oSettings->SaveTenantSettings($oTenant->Name);
2831: }
2832: if ($Description !== null) {
2833: $oTenant->Description = $Description;
2834: }
2835: if ($WebDomain !== null && $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin) {
2836: $oTenant->WebDomain = $WebDomain;
2837: }
2838: if (!empty($ChannelId) && $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin) {
2839: $oTenant->IdChannel = $ChannelId;
2840: }
2841:
2842: return $this->getTenantsManager()->updateTenant($oTenant);
2843: }
2844: } else {
2845: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
2846: }
2847:
2848: return false;
2849: }
2850:
2851: /**
2852: * @api {post} ?/Api/ DeleteTenants
2853: * @apiName DeleteTenants
2854: * @apiGroup Core
2855: * @apiDescription Deletes tenants specified by a list of identifiers.
2856: *
2857: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
2858: * @apiHeaderExample {json} Header-Example:
2859: * {
2860: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
2861: * }
2862: *
2863: * @apiParam {string=Core} Module Module name.
2864: * @apiParam {string=DeleteTenants} Method Method name.
2865: * @apiParam {string} Parameters JSON.stringified object <br>
2866: * {<br>
2867: * &emsp; **IdList** *array* List of tenants identifiers.<br>
2868: * }
2869: *
2870: * @apiParamExample {json} Request-Example:
2871: * {
2872: * Module: 'Core',
2873: * Method: 'DeleteTenants',
2874: * Parameters: '{ IdList: [123, 456] }'
2875: * }
2876: *
2877: * @apiSuccess {object[]} Result Array of response objects.
2878: * @apiSuccess {string} Result.Module Module name.
2879: * @apiSuccess {string} Result.Method Method name.
2880: * @apiSuccess {bool} Result.Result Indicates if tenants were deleted successfully.
2881: * @apiSuccess {int} [Result.ErrorCode] Error code.
2882: *
2883: * @apiSuccessExample {json} Success response example:
2884: * {
2885: * Module: 'Core',
2886: * Method: 'DeleteTenants',
2887: * Result: true
2888: * }
2889: *
2890: * @apiSuccessExample {json} Error response example:
2891: * {
2892: * Module: 'Core',
2893: * Method: 'DeleteTenants',
2894: * Result: false,
2895: * ErrorCode: 102
2896: * }
2897: */
2898: /**
2899: * Deletes tenants specified by a list of identifiers.
2900: * @param array $IdList List of tenants identifiers.
2901: * @return bool
2902: */
2903: public function DeleteTenants($IdList)
2904: {
2905: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
2906:
2907: $bResult = true;
2908:
2909: foreach ($IdList as $sId) {
2910: $bResult = $bResult && self::Decorator()->DeleteTenant($sId);
2911: }
2912:
2913: return $bResult;
2914: }
2915:
2916: /**
2917: * @api {post} ?/Api/ DeleteTenant
2918: * @apiName DeleteTenant
2919: * @apiGroup Core
2920: * @apiDescription Deletes tenant.
2921: *
2922: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
2923: * @apiHeaderExample {json} Header-Example:
2924: * {
2925: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
2926: * }
2927: *
2928: * @apiParam {string=Core} Module Module name.
2929: * @apiParam {string=DeleteTenant} Method Method name.
2930: * @apiParam {string} Parameters JSON.stringified object <br>
2931: * {<br>
2932: * &emsp; **TenantId** *int* Identifier of tenant to delete.<br>
2933: * }
2934: *
2935: * @apiParamExample {json} Request-Example:
2936: * {
2937: * Module: 'Core',
2938: * Method: 'DeleteTenant',
2939: * Parameters: '{ TenantId: 123 }'
2940: * }
2941: *
2942: * @apiSuccess {object[]} Result Array of response objects.
2943: * @apiSuccess {string} Result.Module Module name.
2944: * @apiSuccess {string} Result.Method Method name.
2945: * @apiSuccess {bool} Result.Result Indicates if tenant was deleted successfully.
2946: * @apiSuccess {int} [Result.ErrorCode] Error code.
2947: *
2948: * @apiSuccessExample {json} Success response example:
2949: * {
2950: * Module: 'Core',
2951: * Method: 'DeleteTenant',
2952: * Result: true
2953: * }
2954: *
2955: * @apiSuccessExample {json} Error response example:
2956: * {
2957: * Module: 'Core',
2958: * Method: 'DeleteTenant',
2959: * Result: false,
2960: * ErrorCode: 102
2961: * }
2962: */
2963: /**
2964: * Deletes tenant.
2965: *
2966: * @param int $TenantId Identifier of tenant to delete.
2967: * @return bool
2968: * @throws \Aurora\System\Exceptions\ApiException
2969: */
2970: public function DeleteTenant($TenantId)
2971: {
2972: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
2973:
2974: if (!empty($TenantId)) {
2975: $oTenant = $this->getTenantsManager()->getTenantById($TenantId);
2976:
2977: if ($oTenant) {
2978: // Delete tenant config files.
2979: $sTenantSpacePath = \Aurora\System\Api::GetModuleManager()->GetModulesSettingsPath().'tenants/'.$oTenant->Name;
2980: if (@is_dir($sTenantSpacePath)) {
2981: $this->deleteTree($sTenantSpacePath);
2982: }
2983:
2984: // Delete tenant itself.
2985: return $this->getTenantsManager()->deleteTenant($oTenant);
2986: }
2987: } else {
2988: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
2989: }
2990:
2991: return false;
2992: }
2993:
2994: /**
2995: * @api {post} ?/Api/ GetUsers
2996: * @apiName GetUsers
2997: * @apiGroup Core
2998: * @apiDescription Returns user list.
2999: *
3000: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
3001: * @apiHeaderExample {json} Header-Example:
3002: * {
3003: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
3004: * }
3005: *
3006: * @apiParam {string=Core} Module Module name.
3007: * @apiParam {string=GetUsers} Method Method name.
3008: * @apiParam {string} Parameters JSON.stringified object <br>
3009: * {<br>
3010: * &emsp; **Offset** *int* Offset of user list.<br>
3011: * &emsp; **Limit** *int* Limit of result user list.<br>
3012: * &emsp; **OrderBy** *string* Name of field order by.<br>
3013: * &emsp; **OrderType** *int* Order type.<br>
3014: * &emsp; **Search** *string* Search string.<br>
3015: * }
3016: *
3017: * @apiParamExample {json} Request-Example:
3018: * {
3019: * Module: 'Core',
3020: * Method: 'GetUsers',
3021: * Parameters: '{ Offset: 0, Limit: 0, OrderBy: "", OrderType: 0, Search: 0 }'
3022: * }
3023: *
3024: * @apiSuccess {object[]} Result Array of response objects.
3025: * @apiSuccess {string} Result.Module Module name.
3026: * @apiSuccess {string} Result.Method Method name.
3027: * @apiSuccess {mixed} Result.Result List of users in case of success, otherwise **false**.
3028: * @apiSuccess {int} [Result.ErrorCode] Error code.
3029: *
3030: * @apiSuccessExample {json} Success response example:
3031: * {
3032: * Module: 'Core',
3033: * Method: 'GetUsers',
3034: * Result: {
3035: * Items: [
3036: * { Id: 123, PublicId: 'user123_PublicId' },
3037: * { Id: 124, PublicId: 'user124_PublicId' }
3038: * ],
3039: * Count: 2
3040: * }
3041: * }
3042: *
3043: * @apiSuccessExample {json} Error response example:
3044: * {
3045: * Module: 'Core',
3046: * Method: 'GetUsers',
3047: * Result: false,
3048: * ErrorCode: 102
3049: * }
3050: */
3051: /**
3052: * Returns user list.
3053: *
3054: * @param int $TenantId Tenant identifier.
3055: * @param int $Offset Offset of user list.
3056: * @param int $Limit Limit of result user list.
3057: * @param string $OrderBy Name of field order by.
3058: * @param int $OrderType Order type.
3059: * @param string $Search Search string.
3060: * @param array $Filters Filters.
3061: * @return array {
3062: * *array* **Items** User list.
3063: * *int* **Count** Users count.
3064: * }
3065: */
3066: public function GetUsers($TenantId = 0, $Offset = 0, $Limit = 0, $OrderBy = 'PublicId', $OrderType = \Aurora\System\Enums\SortOrder::ASC, $Search = '', $Filters = null, $GroupId = -1)
3067: {
3068: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
3069:
3070: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
3071: if ($oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::TenantAdmin && $oAuthenticatedUser->IdTenant === $TenantId) {
3072: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
3073: } else {
3074: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
3075: }
3076:
3077: $aResult = [
3078: 'Items' => [],
3079: 'Count' => 0,
3080: ];
3081:
3082: $Filters = ($Filters instanceof Builder) ? $Filters : Models\User::query();
3083: if ($TenantId !== 0) {
3084: $Filters = $Filters->where('IdTenant', $TenantId);
3085: }
3086:
3087: $aResult['Count'] = $this->getUsersManager()->getUsersCount($Search, $Filters, $GroupId);
3088: $aUsers = $this->getUsersManager()->getUserList($Offset, $Limit, $OrderBy, $OrderType, $Search, $Filters, $GroupId);
3089: foreach ($aUsers as $oUser) {
3090: $aGroups = [];
3091: if ($this->getConfig('AllowGroups', false)) {
3092: foreach ($oUser->Groups as $oGroup) {
3093: if (!$oGroup->IsAll) {
3094: $aGroups[] = [
3095: 'Id' => $oGroup->Id,
3096: 'TenantId' => $oGroup->TenantId,
3097: 'Name' => $oGroup->Name
3098: ];
3099: }
3100: }
3101: }
3102: $aResult['Items'][] = [
3103: 'Id' => $oUser->Id,
3104: 'UUID' => $oUser->UUID,
3105: 'Name' => $oUser->Name,
3106: 'PublicId' => $oUser->PublicId,
3107: 'Role' => $oUser->Role,
3108: 'Groups' => $aGroups
3109: ];
3110: }
3111:
3112: return $aResult;
3113: }
3114:
3115: /**
3116: * @deprecated since version 8.3.7
3117: */
3118: public function GetUserList($TenantId = 0, $Offset = 0, $Limit = 0, $OrderBy = 'PublicId', $OrderType = \Aurora\System\Enums\SortOrder::ASC, $Search = '', $Filters = [])
3119: {
3120: return self::Decorator()->GetUsers($TenantId, $Offset, $Limit, $OrderBy, $OrderType, $Search, $Filters);
3121: }
3122:
3123: public function GetTotalUsersCount()
3124: {
3125: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
3126:
3127: return $this->getUsersManager()->getTotalUsersCount();
3128: }
3129:
3130: /**
3131: * @api {post} ?/Api/ GetUser
3132: * @apiName GetUser
3133: * @apiGroup Core
3134: * @apiDescription Returns user data.
3135: *
3136: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
3137: * @apiHeaderExample {json} Header-Example:
3138: * {
3139: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
3140: * }
3141: *
3142: * @apiParam {string=Core} Module Module name.
3143: * @apiParam {string=GetUser} Method Method name.
3144: * @apiParam {string} Parameters JSON.stringified object <br>
3145: * {<br>
3146: * &emsp; **UserId** *string* User identifier.<br>
3147: * }
3148: *
3149: * @apiParamExample {json} Request-Example:
3150: * {
3151: * Module: 'Core',
3152: * Method: 'GetUser',
3153: * Parameters: '{ "Id": 17 }'
3154: * }
3155: *
3156: * @apiSuccess {object[]} Result Array of response objects.
3157: * @apiSuccess {string} Result.Module Module name.
3158: * @apiSuccess {string} Result.Method Method name.
3159: * @apiSuccess {bool} Result.Result Indicates if test of database connection was successful.
3160: * @apiSuccess {int} [Result.ErrorCode] Error code.
3161: *
3162: * @apiSuccessExample {json} Success response example:
3163: * {
3164: * Module: 'Core',
3165: * Method: 'GetUser',
3166: * Result: {
3167: * 'Name': '',
3168: * 'PublicId': 'mail@domain.com',
3169: * 'Role': 2,
3170: * 'WriteSeparateLog': false
3171: * }
3172: * }
3173: *
3174: * @apiSuccessExample {json} Error response example:
3175: * {
3176: * Module: 'Core',
3177: * Method: 'GetUser',
3178: * Result: false,
3179: * ErrorCode: 102
3180: * }
3181: */
3182: /**
3183: * Returns user object.
3184: *
3185: * @param int|string $Id User identifier or UUID.
3186: * @return \Aurora\Modules\Core\Models\User
3187: */
3188: public function GetUser($Id = '')
3189: {
3190: $oUser = $this->getUsersManager()->getUser($Id);
3191: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
3192:
3193: if (!empty($oUser)) { // User may be needed for anonymous on reset password or register screens. It can be obtained after using skipCheckUserRole method.
3194: if (!empty($oAuthenticatedUser) && $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::NormalUser && $oAuthenticatedUser->Id === $oUser->Id) {
3195: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
3196: } elseif (!empty($oAuthenticatedUser) && $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::TenantAdmin && $oAuthenticatedUser->IdTenant === $oUser->IdTenant) {
3197: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
3198: } else {
3199: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
3200: }
3201:
3202: return $oUser;
3203: }
3204:
3205: return null;
3206: }
3207:
3208: public function TurnOffSeparateLogs()
3209: {
3210: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
3211:
3212: $aResults = $this->getUsersManager()->getUserList(0, 0, 'PublicId', \Aurora\System\Enums\SortOrder::ASC, '', User::where('WriteSeparateLog', true));
3213: foreach ($aResults as $aUser) {
3214: $oUser = self::Decorator()->GetUser($aUser['EntityId']);
3215: if ($oUser) {
3216: $oUser->WriteSeparateLog = false;
3217: $this->UpdateUserObject($oUser);
3218: }
3219: }
3220:
3221: return true;
3222: }
3223:
3224: public function ClearSeparateLogs()
3225: {
3226: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
3227:
3228: \Aurora\System\Api::RemoveSeparateLogs();
3229:
3230: return true;
3231: }
3232:
3233: public function GetUsersWithSeparateLog()
3234: {
3235: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
3236:
3237: $aResults = $this->getUsersManager()->getUserList(0, 0, 'PublicId', \Aurora\System\Enums\SortOrder::ASC, '', Models\User::where('WriteSeparateLog', true));
3238: $aUsers = [];
3239: foreach ($aResults as $aUser) {
3240: $aUsers[] = $aUser['PublicId'];
3241: }
3242: return $aUsers;
3243: }
3244:
3245: /**
3246: * @api {post} ?/Api/ CreateUser
3247: * @apiName CreateUser
3248: * @apiGroup Core
3249: * @apiDescription Creates user.
3250: *
3251: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
3252: * @apiHeaderExample {json} Header-Example:
3253: * {
3254: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
3255: * }
3256: *
3257: * @apiParam {string=Core} Module Module name.
3258: * @apiParam {string=CreateUser} Method Method name.
3259: * @apiParam {string} Parameters JSON.stringified object <br>
3260: * {<br>
3261: * &emsp; **TenantId** *int* Identifier of tenant that will contain new user.<br>
3262: * &emsp; **PublicId** *string* New user name.<br>
3263: * &emsp; **Role** *int* New user role.<br>
3264: * }
3265: *
3266: * @apiParamExample {json} Request-Example:
3267: * {
3268: * Module: 'Core',
3269: * Method: 'CreateUser',
3270: * Parameters: '{ TenantId: 123, PublicId: "PublicId_value", Role: 2 }'
3271: * }
3272: *
3273: * @apiSuccess {object[]} Result Array of response objects.
3274: * @apiSuccess {string} Result.Module Module name.
3275: * @apiSuccess {string} Result.Method Method name.
3276: * @apiSuccess {mixed} Result.Result User identifier in case of success, otherwise **false**.
3277: * @apiSuccess {int} [Result.ErrorCode] Error code.
3278: *
3279: * @apiSuccessExample {json} Success response example:
3280: * {
3281: * Module: 'Core',
3282: * Method: 'CreateUser',
3283: * Result: 123
3284: * }
3285: *
3286: * @apiSuccessExample {json} Error response example:
3287: * {
3288: * Module: 'Core',
3289: * Method: 'CreateUser',
3290: * Result: false,
3291: * ErrorCode: 102
3292: * }
3293: */
3294: /**
3295: * Creates user.
3296: *
3297: * @param int $TenantId Identifier of tenant that will contain new user.
3298: * @param string $PublicId New user name.
3299: * @param int $Role New user role.
3300: * @param bool $WriteSeparateLog Indicates if log file should be written separate for this user.
3301: * @return int|false
3302: * @throws \Aurora\System\Exceptions\ApiException
3303: */
3304: public function CreateUser($TenantId = 0, $PublicId = '', $Role = \Aurora\System\Enums\UserRole::NormalUser, $WriteSeparateLog = false)
3305: {
3306: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
3307:
3308: if (!\Aurora\System\Enums\UserRole::validateValue($Role)) {
3309: throw new ApiException(Notifications::InvalidInputParameter);
3310: }
3311:
3312: if ($TenantId === 0) {
3313: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
3314: $aTenants = $this->getTenantsManager()->getTenantList(0, 1, '');
3315: $TenantId = count($aTenants) === 1 ? $aTenants[0]->Id : 0;
3316: }
3317:
3318: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
3319: if (!empty($oAuthenticatedUser) && $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::TenantAdmin && $oAuthenticatedUser->IdTenant === $TenantId) {
3320: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
3321: } else {
3322: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
3323: }
3324:
3325: $oTenant = $this->getTenantsManager()->getTenantById($TenantId);
3326: if (!$oTenant) {
3327: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
3328: }
3329:
3330: $PublicId = \trim($PublicId);
3331: if (substr_count($PublicId, '@') > 1) {
3332: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
3333: }
3334:
3335: if (!empty($TenantId) && !empty($PublicId)) {
3336: $oUser = $this->getUsersManager()->getUserByPublicId($PublicId);
3337: if ($oUser instanceof \Aurora\Modules\Core\Models\User) {
3338: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::UserAlreadyExists);
3339: } else {
3340: $oLicense = \Aurora\System\Api::GetModuleDecorator('Licensing');
3341: if ($oLicense instanceof \Aurora\System\Module\Decorator) {
3342: if (!$oLicense->ValidateUsersCount($this->GetTotalUsersCount()) || !$oLicense->ValidatePeriod()) {
3343: \Aurora\System\Api::Log("Error: License limit");
3344: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::LicenseLimit);
3345: }
3346: }
3347: }
3348:
3349: $oUser = new Models\User();
3350:
3351: $oUser->PublicId = $PublicId;
3352: $oUser->IdTenant = $TenantId;
3353: $oUser->Role = $Role;
3354: $oUser->WriteSeparateLog = $WriteSeparateLog;
3355:
3356: $oUser->Language = \Aurora\System\Api::GetLanguage(true);
3357: $oUser->TimeFormat = self::getInstance()->getConfig('TimeFormat');
3358: $oUser->DateFormat = self::getInstance()->getConfig('DateFormat');
3359: $oUser->DefaultTimeZone = '';
3360:
3361: if ($this->getUsersManager()->createUser($oUser)) {
3362: return $oUser->Id;
3363: }
3364: } else {
3365: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
3366: }
3367:
3368: return false;
3369: }
3370:
3371: /**
3372: * @api {post} ?/Api/ UpdateUser
3373: * @apiName UpdateUser
3374: * @apiGroup Core
3375: * @apiDescription Updates user.
3376: *
3377: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
3378: * @apiHeaderExample {json} Header-Example:
3379: * {
3380: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
3381: * }
3382: *
3383: * @apiParam {string=Core} Module Module name.
3384: * @apiParam {string=UpdateUser} Method Method name.
3385: * @apiParam {string} Parameters JSON.stringified object <br>
3386: * {<br>
3387: * &emsp; **UserId** *int* Identifier of user to update.<br>
3388: * &emsp; **UserName** *string* New user name.<br>
3389: * &emsp; **TenantId** *int* Identifier of tenant that will contain the user.<br>
3390: * &emsp; **Role** *int* New user role.<br>
3391: * }
3392: *
3393: * @apiParamExample {json} Request-Example:
3394: * {
3395: * Module: 'Core',
3396: * Method: 'UpdateUser',
3397: * Parameters: '{ UserId: 123, UserName: "name_value", TenantId: 123, Role: 2 }'
3398: * }
3399: *
3400: * @apiSuccess {object[]} Result Array of response objects.
3401: * @apiSuccess {string} Result.Module Module name.
3402: * @apiSuccess {string} Result.Method Method name.
3403: * @apiSuccess {bool} Result.Result Indicates if user was updated successfully.
3404: * @apiSuccess {int} [Result.ErrorCode] Error code.
3405: *
3406: * @apiSuccessExample {json} Success response example:
3407: * {
3408: * Module: 'Core',
3409: * Method: 'UpdateUser',
3410: * Result: true
3411: * }
3412: *
3413: * @apiSuccessExample {json} Error response example:
3414: * {
3415: * Module: 'Core',
3416: * Method: 'UpdateUser',
3417: * Result: false,
3418: * ErrorCode: 102
3419: * }
3420: */
3421: /**
3422: * Updates user.
3423: *
3424: * @param int $UserId Identifier of user to update.
3425: * @param string $PublicId New user name.
3426: * @param int $TenantId Identifier of tenant that will contain the user.
3427: * @param int $Role New user role.
3428: * @param bool $WriteSeparateLog New value of indicator if user's logs should be in a separate file.
3429: * @return bool
3430: * @throws \Aurora\System\Exceptions\ApiException
3431: */
3432: public function UpdateUser($UserId, $PublicId = '', $TenantId = 0, $Role = -1, $WriteSeparateLog = null, $GroupIds = null)
3433: {
3434: $PublicId = \trim($PublicId);
3435: if (!empty($PublicId) && empty($TenantId) && $UserId === \Aurora\System\Api::getAuthenticatedUserId()) {
3436: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
3437: } else {
3438: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
3439: }
3440:
3441: if ($UserId > 0) {
3442: $oUser = $this->getUsersManager()->getUser($UserId);
3443:
3444: if ($oUser) {
3445: \Aurora\System\Api::checkUserAccess($oUser);
3446:
3447: if (!empty($PublicId)) {
3448: $oUser->PublicId = $PublicId;
3449: }
3450: if (!empty($TenantId)) {
3451: $oUser->IdTenant = $TenantId;
3452: }
3453: if (\Aurora\System\Enums\UserRole::validateValue($Role)) {
3454: $oUser->Role = $Role;
3455: }
3456: if ($WriteSeparateLog !== null) {
3457: $oUser->WriteSeparateLog = $WriteSeparateLog;
3458: }
3459:
3460: $mResult = $this->getUsersManager()->updateUser($oUser);
3461: if ($mResult && $this->getConfig('AllowGroups', false) && $GroupIds !== null) {
3462: self::Decorator()->UpdateUserGroups($UserId, $GroupIds);
3463: }
3464:
3465: return $mResult;
3466: }
3467: } else {
3468: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
3469: }
3470:
3471: return false;
3472: }
3473:
3474: /**
3475: * @api {post} ?/Api/ DeleteUsers
3476: * @apiName DeleteUsers
3477: * @apiGroup Core
3478: * @apiDescription Deletes users specified by a list of identifiers.
3479: *
3480: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
3481: * @apiHeaderExample {json} Header-Example:
3482: * {
3483: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
3484: * }
3485: *
3486: * @apiParam {string=Core} Module Module name.
3487: * @apiParam {string=DeleteUsers} Method Method name.
3488: * @apiParam {string} Parameters JSON.stringified object <br>
3489: * {<br>
3490: * &emsp; **IdList** *int* List of users identifiers.<br>
3491: * }
3492: *
3493: * @apiParamExample {json} Request-Example:
3494: * {
3495: * Module: 'Core',
3496: * Method: 'DeleteUsers',
3497: * Parameters: '{ IdList: [125, 457] }'
3498: * }
3499: *
3500: * @apiSuccess {object[]} Result Array of response objects.
3501: * @apiSuccess {string} Result.Module Module name.
3502: * @apiSuccess {string} Result.Method Method name.
3503: * @apiSuccess {bool} Result.Result Indicates if users were deleted successfully.
3504: * @apiSuccess {int} [Result.ErrorCode] Error code.
3505: *
3506: * @apiSuccessExample {json} Success response example:
3507: * {
3508: * Module: 'Core',
3509: * Method: 'DeleteUsers',
3510: * Result: true
3511: * }
3512: *
3513: * @apiSuccessExample {json} Error response example:
3514: * {
3515: * Module: 'Core',
3516: * Method: 'DeleteUsers',
3517: * Result: false,
3518: * ErrorCode: 102
3519: * }
3520: */
3521: /**
3522: * Deletes users specified by a list of identifiers.
3523: * @param array $IdList List of users identifiers.
3524: * @return bool
3525: */
3526: public function DeleteUsers($IdList)
3527: {
3528: $bResult = true;
3529:
3530: foreach ($IdList as $sId) {
3531: $bResult = $bResult && self::Decorator()->DeleteUser($sId);
3532: }
3533:
3534: return $bResult;
3535: }
3536:
3537: /**
3538: * @api {post} ?/Api/ DeleteUser
3539: * @apiName DeleteUser
3540: * @apiGroup Core
3541: * @apiDescription Deletes user.
3542: *
3543: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
3544: * @apiHeaderExample {json} Header-Example:
3545: * {
3546: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
3547: * }
3548: *
3549: * @apiParam {string=Core} Module Module name.
3550: * @apiParam {string=DeleteUser} Method Method name.
3551: * @apiParam {string} Parameters JSON.stringified object <br>
3552: * {<br>
3553: * &emsp; **UserId** *int* User identifier.<br>
3554: * }
3555: *
3556: * @apiParamExample {json} Request-Example:
3557: * {
3558: * Module: 'Core',
3559: * Method: 'DeleteUser',
3560: * Parameters: '{ UserId: 123 }'
3561: * }
3562: *
3563: * @apiSuccess {object[]} Result Array of response objects.
3564: * @apiSuccess {string} Result.Module Module name.
3565: * @apiSuccess {string} Result.Method Method name.
3566: * @apiSuccess {bool} Result.Result Indicates if user was deleted successfully.
3567: * @apiSuccess {int} [Result.ErrorCode] Error code.
3568: *
3569: * @apiSuccessExample {json} Success response example:
3570: * {
3571: * Module: 'Core',
3572: * Method: 'DeleteUser',
3573: * Result: true
3574: * }
3575: *
3576: * @apiSuccessExample {json} Error response example:
3577: * {
3578: * Module: 'Core',
3579: * Method: 'DeleteUser',
3580: * Result: false,
3581: * ErrorCode: 102
3582: * }
3583: */
3584: /**
3585: * Deletes user.
3586: *
3587: * @param int $UserId User identifier.
3588: * @return bool
3589: * @throws \Aurora\System\Exceptions\ApiException
3590: */
3591: public function DeleteUser($UserId = 0)
3592: {
3593: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
3594:
3595: $oUser = self::Decorator()->GetUserUnchecked($UserId);
3596:
3597: if ($oUser instanceof \Aurora\Modules\Core\Models\User && $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::TenantAdmin && $oUser->IdTenant === $oAuthenticatedUser->IdTenant) {
3598: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
3599: } else {
3600: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
3601: }
3602:
3603: $bResult = false;
3604:
3605: if (!empty($UserId) && is_int($UserId)) {
3606: $bResult = $this->getUsersManager()->deleteUserById($UserId);
3607: if ($bResult) {
3608: UserBlock::where('UserId', $UserId)->delete();
3609: }
3610: } else {
3611: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
3612: }
3613:
3614: return $bResult;
3615: }
3616:
3617: public function GetLogFilesData()
3618: {
3619: $aData = [];
3620:
3621: $sFileName = \Aurora\System\Api::GetLogFileName();
3622: $sFilePath = \Aurora\System\Api::GetLogFileDir() . $sFileName;
3623: $aData['LogFileName'] = $sFileName;
3624: $aData['LogSizeBytes'] = file_exists($sFilePath) ? filesize($sFilePath) : 0;
3625:
3626: $sEventFileName = \Aurora\System\Api::GetLogFileName(\Aurora\System\Logger::$sEventLogPrefix);
3627: $sEventFilePath = \Aurora\System\Api::GetLogFileDir() . $sEventFileName;
3628: $aData['EventLogFileName'] = $sEventFileName;
3629: $aData['EventLogSizeBytes'] = file_exists($sEventFilePath) ? filesize($sEventFilePath) : 0;
3630:
3631: return $aData;
3632: }
3633:
3634: public function GetLogFile($EventsLog = false, $PublicId = '')
3635: {
3636: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
3637:
3638: $sLogFilePrefix = $EventsLog ? \Aurora\System\Logger::$sEventLogPrefix : '';
3639: if ($PublicId !== '') {
3640: $sLogFilePrefix = $PublicId . '-';
3641: }
3642: $sFileName = \Aurora\System\Api::GetLogFileDir().\Aurora\System\Api::GetLogFileName($sLogFilePrefix);
3643:
3644: if (file_exists($sFileName)) {
3645: $mResult = fopen($sFileName, "r");
3646:
3647: if (false !== $mResult && is_resource($mResult)) {
3648: $sContentType = \MailSo\Base\Utils::MimeContentType($sFileName);
3649: \Aurora\System\Managers\Response::OutputHeaders(true, $sContentType, $sFileName);
3650:
3651: if ($sContentType === 'text/plain') {
3652: $sLogData = stream_get_contents($mResult);
3653: echo(\MailSo\Base\HtmlUtils::ClearTags($sLogData));
3654: } else {
3655: \MailSo\Base\Utils::FpassthruWithTimeLimitReset($mResult, 8192, function ($sData) {
3656: return \MailSo\Base\HtmlUtils::ClearTags($sData);
3657: });
3658: }
3659:
3660: @fclose($mResult);
3661: }
3662: }
3663: }
3664:
3665: public function GetLog($EventsLog, $PartSize = 10240)
3666: {
3667: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
3668:
3669: $sLogFilePrefix = $EventsLog ? \Aurora\System\Logger::$sEventLogPrefix : '';
3670: $sFileName = \Aurora\System\Api::GetLogFileDir().\Aurora\System\Api::GetLogFileName($sLogFilePrefix);
3671:
3672: $logData = '';
3673:
3674: if (file_exists($sFileName)) {
3675: $iOffset = filesize($sFileName) - $PartSize;
3676: $iOffset = $iOffset < 0 ? 0 : $iOffset;
3677: $logData = \MailSo\Base\HtmlUtils::ClearTags(file_get_contents($sFileName, false, null, $iOffset, $PartSize));
3678: }
3679:
3680: return $logData;
3681: }
3682:
3683: /**
3684: *
3685: * @param bool $EventsLog
3686: * @return bool
3687: */
3688: public function ClearLog($EventsLog)
3689: {
3690: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
3691:
3692: $sLogFilePrefix = $EventsLog ? \Aurora\System\Logger::$sEventLogPrefix : '';
3693: $sFileName = \Aurora\System\Api::GetLogFileDir().\Aurora\System\Api::GetLogFileName($sLogFilePrefix);
3694:
3695: return \Aurora\System\Api::ClearLog($sFileName);
3696: }
3697:
3698: /**
3699: *
3700: * @param int $UserId
3701: * @param string $Content
3702: * @param string $FileName
3703: * @return array|bool
3704: * @throws \Aurora\System\Exceptions\ApiException
3705: */
3706: public function SaveContentAsTempFile($UserId, $Content, $FileName)
3707: {
3708: $mResult = false;
3709: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
3710:
3711: $sUUID = \Aurora\System\Api::getUserUUIDById($UserId);
3712: try {
3713: $sTempName = md5($sUUID.$Content.$FileName);
3714: $oApiFileCache = new \Aurora\System\Managers\Filecache();
3715:
3716: if (!$oApiFileCache->isFileExists($sUUID, $sTempName)) {
3717: $oApiFileCache->put($sUUID, $sTempName, $Content);
3718: }
3719:
3720: if ($oApiFileCache->isFileExists($sUUID, $sTempName)) {
3721: $mResult = \Aurora\System\Utils::GetClientFileResponse(
3722: null,
3723: $UserId,
3724: $FileName,
3725: $sTempName,
3726: $oApiFileCache->fileSize($sUUID, $sTempName)
3727: );
3728: }
3729: } catch (\Exception $oException) {
3730: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::FilesNotAllowed, $oException);
3731: }
3732:
3733: return $mResult;
3734: }
3735:
3736: /**
3737: * Updates user Timezone.
3738: *
3739: * @param string $Timezone New Timezone.
3740: *
3741: */
3742: public function UpdateUserTimezone($Timezone)
3743: {
3744: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
3745:
3746: $oUser = \Aurora\System\Api::getAuthenticatedUser();
3747:
3748: if ($oUser && $Timezone) {
3749: if ($oUser && $oUser->DefaultTimeZone !== $Timezone) {
3750: $oUser->DefaultTimeZone = $Timezone;
3751: $this->UpdateUserObject($oUser);
3752: }
3753: } else {
3754: return false;
3755: }
3756: return true;
3757: }
3758:
3759: public function GetCompatibilities()
3760: {
3761: return [];
3762: }
3763:
3764: public function IsModuleDisabledForObject($oObject, $sModuleName)
3765: {
3766: return ($oObject instanceof \Aurora\System\Classes\Model) ? $oObject->isModuleDisabled($sModuleName) : false;
3767: }
3768:
3769: public function GetUserSessions()
3770: {
3771: $aResult = [];
3772: if (\Aurora\Api::GetSettings()->GetValue('StoreAuthTokenInDB', false)) {
3773: $oUser = \Aurora\System\Api::getAuthenticatedUser();
3774: $aUserSessions = \Aurora\System\Api::UserSession()->GetUserSessionsFromDB($oUser->Id);
3775: foreach ($aUserSessions as $oUserSession) {
3776: $aTokenInfo = \Aurora\System\Api::DecodeKeyValues($oUserSession->Token);
3777:
3778: if ($aTokenInfo !== false && isset($aTokenInfo['id'])) {
3779: $aResult[] = [
3780: 'LastUsageDateTime' => $oUserSession->LastUsageDateTime,
3781: 'ExpireDateTime' => (int) isset($aTokenInfo['@expire']) ? $aTokenInfo['@expire'] : 0,
3782: ];
3783: }
3784: }
3785: }
3786: return $aResult;
3787: }
3788:
3789: public function CreateGroup($TenantId, $Name)
3790: {
3791: if (!$this->getConfig('AllowGroups', false)) {
3792: throw new ApiException(Notifications::MethodAccessDenied);
3793: }
3794:
3795: Api::checkUserRoleIsAtLeast(UserRole::TenantAdmin);
3796:
3797: $oUser = Api::getAuthenticatedUser();
3798: if ($oUser->Role === UserRole::TenantAdmin && $oUser->IdTenant !== $TenantId) {
3799: throw new ApiException(Notifications::AccessDenied);
3800: }
3801:
3802: $oGroup = Group::firstWhere([
3803: 'TenantId' => $TenantId,
3804: 'Name' => $Name
3805: ]);
3806:
3807: if ($oGroup) {
3808: throw new \Aurora\Modules\Core\Exceptions\Exception(Enums\ErrorCodes::GroupAlreadyExists);
3809: } else {
3810: $oGroup = new Models\Group();
3811: $oGroup->Name = $Name;
3812: $oGroup->TenantId = $TenantId;
3813: if ($oGroup->save()) {
3814: return $oGroup->Id;
3815: } else {
3816: return false;
3817: }
3818: }
3819: }
3820:
3821: public function GetGroup($TenantId, $GroupId)
3822: {
3823: if (!$this->getConfig('AllowGroups', false)) {
3824: return false;
3825: }
3826:
3827: $mResult = false;
3828:
3829: Api::checkUserRoleIsAtLeast(UserRole::NormalUser);
3830:
3831: $oUser = Api::getAuthenticatedUser();
3832: if ($oUser && ($oUser->Role === UserRole::TenantAdmin || $oUser->Role === UserRole::NormalUser) && $oUser->IdTenant !== $TenantId) {
3833: throw new ApiException(Notifications::AccessDenied);
3834: }
3835:
3836: $mResult = Group::firstWhere([
3837: 'TenantId' => $TenantId,
3838: 'Id' => $GroupId
3839: ]);
3840:
3841: return $mResult;
3842: }
3843:
3844: public function GetAllGroup($TenantId)
3845: {
3846: if (!$this->getConfig('AllowGroups', false)) {
3847: return false;
3848: }
3849:
3850: $mResult = false;
3851:
3852: Api::checkUserRoleIsAtLeast(UserRole::NormalUser);
3853:
3854: $oUser = Api::getAuthenticatedUser();
3855: if ($oUser && ($oUser->Role === UserRole::TenantAdmin || $oUser->Role === UserRole::NormalUser) && $oUser->IdTenant !== $TenantId) {
3856: throw new ApiException(Notifications::AccessDenied);
3857: }
3858:
3859: $oGroup = Group::firstWhere([
3860: 'TenantId' => $TenantId,
3861: 'IsAll' => true
3862: ]);
3863:
3864: if (!$oGroup) {
3865: $oGroup = new Models\Group();
3866: $oGroup->Name = 'All';
3867: $oGroup->TenantId = $TenantId;
3868: $oGroup->IsAll = true;
3869:
3870: if ($oGroup->save()) {
3871: $mResult = $oGroup;
3872: } else {
3873: $mResult = false;
3874: }
3875: } else {
3876: $mResult = $oGroup;
3877: }
3878:
3879: return $mResult;
3880: }
3881:
3882: public function GetGroups($TenantId, $Search = '')
3883: {
3884: if (!$this->getConfig('AllowGroups', false)) {
3885: return [
3886: 'Items' => [],
3887: 'Count' => 0
3888: ];
3889: }
3890:
3891: Api::checkUserRoleIsAtLeast(UserRole::NormalUser);
3892:
3893: $oUser = Api::getAuthenticatedUser();
3894: if ($oUser && ($oUser->Role === UserRole::TenantAdmin || $oUser->Role === UserRole::NormalUser) && $oUser->IdTenant !== $TenantId) {
3895: throw new ApiException(Notifications::AccessDenied);
3896: }
3897:
3898: $query = Group::where('TenantId', $TenantId);
3899: if (!empty($Search)) {
3900: $query = $query->where(function ($q) use ($Search) {
3901: $q->where('Name', 'LIKE', '%' . $Search . '%');
3902: $q->orWhere('IsAll', true);
3903: });
3904: }
3905:
3906: $this->GetAllGroup($TenantId);
3907:
3908: $aGroups = $query->get()->map(function ($oGroup) {
3909: if ($oGroup->IsAll) {
3910: $aEmails = Contact::where('IdTenant', $oGroup->TenantId)
3911: ->where('Storage', StorageType::Team)->get()->map(
3912: function ($oContact) {
3913: if (!empty($oContact->FullName)) {
3914: return '"' . $oContact->FullName . '"' . '<' . $oContact->ViewEmail . '>';
3915: } else {
3916: return $oContact->ViewEmail;
3917: }
3918: }
3919: )->toArray();
3920: } else {
3921: $aEmails = $oGroup->Users->map(function ($oUser) {
3922: $oContact = Contact::where('IdUser', $oUser->Id)->where('Storage', 'team')->first();
3923: if (!empty($oContact->FullName)) {
3924: return '"' . $oContact->FullName . '"' . '<' . $oUser->PublicId . '>';
3925: } else {
3926: return $oUser->PublicId;
3927: }
3928: })->toArray();
3929: }
3930: return [
3931: 'Id' => $oGroup->Id,
3932: 'Name' => $oGroup->getName(),
3933: 'Emails' => implode(', ', $aEmails),
3934: 'IsAll' => !!$oGroup->IsAll
3935: ];
3936: })->toArray();
3937:
3938: if (!empty($Search)) {
3939: $aGroups = array_filter($aGroups, function ($aGroup) use ($Search) {
3940: return (stripos($aGroup['Name'], $Search) !== false);
3941: });
3942: }
3943:
3944: return [
3945: 'Items' => $aGroups,
3946: 'Count' => count($aGroups)
3947: ];
3948: }
3949:
3950: public function UpdateGroup($GroupId, $Name)
3951: {
3952: if (!$this->getConfig('AllowGroups', false)) {
3953: throw new ApiException(Notifications::MethodAccessDenied);
3954: }
3955:
3956: $mResult = false;
3957:
3958: Api::checkUserRoleIsAtLeast(UserRole::TenantAdmin);
3959:
3960: $oGroup = Group::find($GroupId);
3961: if ($oGroup && !$oGroup->IsAll) {
3962: $oUser = Api::getAuthenticatedUser();
3963: if ($oUser && $oUser->Role === UserRole::TenantAdmin && $oGroup->TenantId !== $oUser->IdTenant) {
3964: throw new ApiException(Notifications::AccessDenied);
3965: }
3966:
3967: if ($oGroup->Name !== $Name && Group::where(['TenantId' => $oGroup->TenantId, 'Name' => $Name])->count() > 0) {
3968: throw new ApiException(ErrorCodes::GroupAlreadyExists);
3969: } else {
3970: $oGroup->Name = $Name;
3971: $mResult = !!$oGroup->save();
3972: }
3973: }
3974:
3975: return $mResult;
3976: }
3977:
3978: /**
3979: * Deletes groups specified by a list of identifiers.
3980: * @param array $IdList List of groups identifiers.
3981: * @return bool
3982: */
3983: public function DeleteGroups($IdList)
3984: {
3985: if (!$this->getConfig('AllowGroups', false)) {
3986: throw new ApiException(Notifications::MethodAccessDenied);
3987: }
3988:
3989: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
3990:
3991: $bResult = true;
3992:
3993: foreach ($IdList as $iId) {
3994: $bResult = $bResult && self::Decorator()->DeleteGroup($iId);
3995: }
3996:
3997: return $bResult;
3998: }
3999:
4000: public function DeleteGroup($GroupId)
4001: {
4002: if (!$this->getConfig('AllowGroups', false)) {
4003: throw new ApiException(Notifications::MethodAccessDenied);
4004: }
4005:
4006: $mResult = false;
4007:
4008: Api::checkUserRoleIsAtLeast(UserRole::TenantAdmin);
4009:
4010: $oGroup = Group::find($GroupId);
4011: if ($oGroup && !$oGroup->IsAll) {
4012: $oUser = Api::getAuthenticatedUser();
4013: if ($oUser && $oUser->Role === UserRole::TenantAdmin && $oGroup->TenantId !== $oUser->IdTenant) {
4014: throw new ApiException(Notifications::AccessDenied);
4015: }
4016:
4017: $mResult = $oGroup->delete();
4018: }
4019:
4020: return $mResult;
4021: }
4022:
4023: public function GetGroupUsers($TenantId, $GroupId)
4024: {
4025: if (!$this->getConfig('AllowGroups', false)) {
4026: throw new ApiException(Notifications::MethodAccessDenied);
4027: }
4028:
4029: $mResult = [];
4030:
4031: Api::checkUserRoleIsAtLeast(UserRole::NormalUser);
4032:
4033: $oGroup = Group::where('TenantId', $TenantId)->where('Id', $GroupId)->first();
4034: if ($oGroup) {
4035: $oUser = Api::getAuthenticatedUser();
4036: if ($oUser && ($oUser->Role === UserRole::NormalUser || $oUser->Role === UserRole::TenantAdmin) && $oGroup->TenantId !== $oUser->IdTenant) {
4037: throw new ApiException(Notifications::AccessDenied);
4038: }
4039:
4040: if ($oGroup->IsAll) {
4041: $mResult = Contact::where('IdTenant', $TenantId)
4042: ->where('Storage', StorageType::Team)->get()->map(function ($oContact) {
4043: return [
4044: 'UserId' => $oContact->IdUser,
4045: 'Name' => $oContact->FullName,
4046: 'PublicId' => $oContact->ViewEmail
4047: ];
4048: })->toArray();
4049: } else {
4050: $mResult = $oGroup->Users()->get()->map(function ($oUser) {
4051: return [
4052: 'UserId' => $oUser->Id,
4053: 'Name' => $oUser->Name,
4054: 'PublicId' => $oUser->PublicId
4055: ];
4056: })->toArray();
4057: }
4058: }
4059:
4060: return $mResult;
4061: }
4062:
4063: public function AddUsersToGroup($GroupId, $UserIds)
4064: {
4065: if (!$this->getConfig('AllowGroups', false)) {
4066: throw new ApiException(Notifications::MethodAccessDenied);
4067: }
4068:
4069: $mResult = false;
4070:
4071: Api::checkUserRoleIsAtLeast(UserRole::TenantAdmin);
4072:
4073: $oGroup = Group::find($GroupId);
4074: if ($oGroup && !$oGroup->IsAll) {
4075: $oUser = Api::getAuthenticatedUser();
4076: if ($oUser && $oUser->Role === UserRole::TenantAdmin && $oGroup->TenantId !== $oUser->IdTenant) {
4077: throw new ApiException(Notifications::AccessDenied);
4078: }
4079:
4080: $oGroup->Users()->syncWithoutDetaching($UserIds);
4081: $mResult = true;
4082: }
4083:
4084: return $mResult;
4085: }
4086:
4087: public function RemoveUsersFromGroup($GroupId, $UserIds)
4088: {
4089: if (!$this->getConfig('AllowGroups', false)) {
4090: throw new ApiException(Notifications::MethodAccessDenied);
4091: }
4092:
4093: $mResult = false;
4094:
4095: Api::checkUserRoleIsAtLeast(UserRole::TenantAdmin);
4096:
4097: $oGroup = Group::find($GroupId);
4098: if ($oGroup) {
4099: $oUser = Api::getAuthenticatedUser();
4100: if ($oUser && $oUser->Role === UserRole::TenantAdmin && $oGroup->TenantId !== $oUser->IdTenant) {
4101: throw new ApiException(Notifications::AccessDenied);
4102: }
4103:
4104: $oGroup->Users()->detach($UserIds);
4105: $mResult = true;
4106: }
4107:
4108: return $mResult;
4109: }
4110:
4111: public function UpdateUserGroups($UserId, $GroupIds)
4112: {
4113: if (!$this->getConfig('AllowGroups', false)) {
4114: throw new ApiException(Notifications::MethodAccessDenied);
4115: }
4116:
4117: $mResult = false;
4118:
4119: Api::checkUserRoleIsAtLeast(UserRole::TenantAdmin);
4120: $oAuthUser = Api::getAuthenticatedUser();
4121: $oUser = User::find($UserId);
4122:
4123: if ($oAuthUser && $oAuthUser->Role === UserRole::TenantAdmin && $oAuthUser->TenantId !== $oUser->IdTenant) {
4124: throw new ApiException(Notifications::AccessDenied);
4125: }
4126: if ($oUser) {
4127: $aGroupIds = Group::where('IsAll', false)->whereIn('Id', $GroupIds)->get(['Id'])->map(function ($oGroup) {
4128: return $oGroup->Id;
4129: });
4130: $oUser->Groups()->sync($aGroupIds);
4131: $mResult = true;
4132: }
4133:
4134: return $mResult;
4135: }
4136: /***** public functions might be called with web API *****/
4137: }
4138: