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\Files;
9:
10: use Afterlogic\DAV\Constants;
11: use Afterlogic\DAV\Server;
12: use Aurora\Api;
13: use Aurora\Modules\Core\Models\User;
14: use Aurora\Modules\Core\Models\Tenant;
15: use Aurora\Modules\Core\Module as CoreModule;
16: use Aurora\Modules\Files\Enums\ErrorCodes;
17: use Aurora\System\Classes\InheritedAttributes;
18: use Aurora\System\EventEmitter;
19: use Aurora\System\Exceptions\ApiException;
20:
21: /**
22: * Main Files module. It provides PHP and Web APIs for managing files.
23: *
24: * @license https://www.gnu.org/licenses/agpl-3.0.html AGPL-3.0
25: * @license https://afterlogic.com/products/common-licensing Afterlogic Software License
26: * @copyright Copyright (c) 2023, Afterlogic Corp.
27: *
28: * @property Settings $oModuleSettings
29: *
30: * @package Modules
31: */
32: class Module extends \Aurora\System\Module\AbstractModule
33: {
34: protected static $sStorageType = '';
35:
36: /*
37: * @var $oApiFileCache \Aurora\System\Managers\Filecache
38: */
39: public $oApiFileCache = null;
40:
41: /**
42: *
43: * @var \Aurora\Modules\Min\Module
44: */
45: protected $oMinModuleDecorator = null;
46:
47: public function getFilecacheManager()
48: {
49: if ($this->oApiFileCache === null) {
50: $this->oApiFileCache = new \Aurora\System\Managers\Filecache();
51: }
52:
53: return $this->oApiFileCache;
54: }
55:
56: /**
57: * @return Module
58: */
59: public static function getInstance()
60: {
61: return parent::getInstance();
62: }
63:
64: /**
65: * @return Module
66: */
67: public static function Decorator()
68: {
69: return parent::Decorator();
70: }
71:
72: /**
73: * @return Settings
74: */
75: public function getModuleSettings()
76: {
77: return $this->oModuleSettings;
78: }
79:
80:
81: /***** private functions *****/
82: /**
83: * Initializes Files Module.
84: *
85: * @ignore
86: */
87: public function init()
88: {
89: $this->subscribeEvent('Files::GetStorages::after', array($this, 'onAfterGetStorages'), 1000);
90: $this->subscribeEvent('Core::CreateUser::after', array($this, 'onAfterCreateUser'), 1000);
91: $this->subscribeEvent('Files::Rename::after', array($this, 'onAfterRename'), 1000);
92: $this->subscribeEvent('Files::Move::after', array($this, 'onAfterMove'), 1000);
93:
94: $this->AddEntries(
95: array(
96: 'upload' => 'UploadFileData',
97: 'download-file' => 'EntryDownloadFile'
98: )
99: );
100: $this->denyMethodsCallByWebApi(['getRawFile', 'getRawFileData', 'GetItems']);
101:
102: $this->aErrors = [
103: Enums\ErrorCodes::NotFound => $this->i18N('INFO_NOTFOUND'),
104: Enums\ErrorCodes::NotPermitted => $this->i18N('INFO_NOTPERMITTED'),
105: Enums\ErrorCodes::AlreadeExists => $this->i18N('ERROR_ITEM_ALREADY_EXISTS'),
106: Enums\ErrorCodes::CantDeleteSharedItem => $this->i18N('ERROR_CANNOT_DELETE_SHARED_ITEM'),
107: Enums\ErrorCodes::CannotCopyOrMoveItemToItself => $this->i18N('ERROR_CANNOT_COPY_OR_MOVE_ITEM_TO_ITSELF'),
108: Enums\ErrorCodes::NotPossibleToMoveSharedFileToCorporateStorage => $this->i18N('ERROR_NOT_POSSIBLE_TO_MOVE_SHARED_FILE_OR_DIR_TO_CORPORATE_STORAGE'),
109: ];
110:
111: InheritedAttributes::addAttributes(User::class, ['Files::UserSpaceLimitMb']);
112: InheritedAttributes::addAttributes(Tenant::class, ['Files::UserSpaceLimitMb', 'Files::TenantSpaceLimitMb']);
113: }
114:
115: /**
116: * Returns Min module decorator.
117: *
118: * @return \Aurora\Modules\Min\Module
119: */
120: private function getMinModuleDecorator()
121: {
122: return \Aurora\System\Api::GetModuleDecorator('Min');
123: }
124:
125: /**
126: * Checks if storage type is personal or corporate.
127: *
128: * @param string $Type Storage type.
129: * @return bool
130: */
131: protected function checkStorageType($Type)
132: {
133: return $Type === static::$sStorageType;
134: }
135:
136: public function getRawFileData($iUserId, $sType, $sPath, $sFileName, $SharedHash = null, $sAction = '', $iOffset = 0, $iChunkSize = 0)
137: {
138: $bDownload = true;
139: $bThumbnail = false;
140: $mResult = false;
141:
142: switch ($sAction) {
143: case 'view':
144: $bDownload = false;
145: $bThumbnail = false;
146: break;
147: case 'thumb':
148: $bDownload = false;
149: $bThumbnail = true;
150: break;
151: case 'download':
152: $bDownload = true;
153: $bThumbnail = false;
154:
155: break;
156: default:
157: $bDownload = true;
158: $bThumbnail = false;
159: break;
160: }
161: if (!$bDownload || $iChunkSize == 0) {
162: $iLength = -1;
163: $iOffset = -1;
164: } else {
165: $iLength = $iChunkSize;
166: $iOffset = $iChunkSize * $iOffset;
167: }
168:
169: $oModuleDecorator = $this->getMinModuleDecorator();
170: $mMin = ($oModuleDecorator && $SharedHash !== null) ? $oModuleDecorator->GetMinByHash($SharedHash) : array();
171:
172: $iUserId = (!empty($mMin['__hash__'])) ? $mMin['UserId'] : $iUserId;
173:
174: try {
175: if ($iUserId && $SharedHash !== null) {
176: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
177: \Afterlogic\DAV\Server::setUser($iUserId);
178: } else {
179: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
180: if ($iUserId !== \Aurora\System\Api::getAuthenticatedUserId()) {
181: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::AccessDenied);
182: }
183: }
184: } catch (\Aurora\System\Exceptions\ApiException $oEx) {
185: echo 'Access denied';
186: exit();
187: }
188:
189: if (isset($sType, $sPath, $sFileName)) {
190: $sContentType = (empty($sFileName)) ? 'text/plain' : \MailSo\Base\Utils::MimeContentType($sFileName);
191:
192: $mResult = false;
193: if ($bThumbnail) {
194: $sRawKey = (string) \Aurora\System\Router::getItemByIndex(1, '');
195: if (!empty($sRawKey)) {
196: \Aurora\System\Managers\Response::verifyCacheByKey($sRawKey);
197: }
198: $mResult = \Aurora\System\Managers\Thumb::GetResourceCache($iUserId, $sFileName);
199: }
200: if (!$mResult) {
201: $aArgs = array(
202: 'UserId' => $iUserId,
203: 'Type' => $sType,
204: 'Path' => $sPath,
205: 'Name' => &$sFileName,
206: 'Id' => $sFileName,
207: 'IsThumb' => $bThumbnail,
208: 'Offset' => $iOffset,
209: 'ChunkSize' => $iChunkSize
210: );
211: $this->broadcastEvent(
212: 'GetFile',
213: $aArgs,
214: $mResult
215: );
216: }
217: }
218:
219: return $mResult;
220: }
221:
222: /**
223: * Downloads file, views file or makes thumbnail for file.
224: *
225: * @param int $iUserId User identifier.
226: * @param string $sType Storage type - personal, corporate.
227: * @param string $sPath Path to folder contained file.
228: * @param string $sFileName File name.
229: * @param string $SharedHash Indicates if file should be downloaded or viewed.
230: * @param string $sAction Indicates if thumbnail should be created for file.
231: *
232: * @return void
233: */
234: public function getRawFile($iUserId, $sType, $sPath, $sFileName, $SharedHash = null, $sAction = '', $iOffset = 0, $iChunkSize = 0, $bShared = false)
235: {
236: // SVG files should not be viewed because they may contain JS
237: if ($sAction !== 'download' && strtolower(pathinfo($sFileName, PATHINFO_EXTENSION)) === 'svg') {
238: $this->oHttp->StatusHeader(403);
239: exit();
240: }
241:
242: $bDownload = true;
243: $bThumbnail = false;
244:
245: switch ($sAction) {
246: case 'view':
247: $bDownload = false;
248: $bThumbnail = false;
249: break;
250: case 'thumb':
251: $bDownload = false;
252: $bThumbnail = true;
253: break;
254: case 'download':
255: $bDownload = true;
256: $bThumbnail = false;
257:
258: break;
259: default:
260: $bDownload = true;
261: $bThumbnail = false;
262: break;
263: }
264: if (!$bDownload || $iChunkSize == 0) {
265: $iLength = -1;
266: $iOffset = -1;
267: } else {
268: $iLength = $iChunkSize;
269: $iOffset = $iChunkSize * $iOffset;
270: }
271:
272: $oModuleDecorator = $this->getMinModuleDecorator();
273: $mMin = ($oModuleDecorator && $SharedHash !== null) ? $oModuleDecorator->GetMinByHash($SharedHash) : array();
274:
275: $iUserId = (!empty($mMin['__hash__'])) ? $mMin['UserId'] : $iUserId;
276:
277: try {
278: if ($iUserId && $SharedHash !== null) {
279: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
280: \Afterlogic\DAV\Server::setUser($iUserId);
281: } else {
282: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
283: if ($iUserId !== \Aurora\System\Api::getAuthenticatedUserId()) {
284: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::AccessDenied);
285: }
286: }
287: } catch (\Aurora\System\Exceptions\ApiException $oEx) {
288: // echo(\Aurora\System\Managers\Response::GetJsonFromObject('Json', \Aurora\System\Managers\Response::FalseResponse(__METHOD__, 403, 'Access denied')));
289: $this->oHttp->StatusHeader(403);
290: exit;
291: }
292:
293: if ($sType) {
294: $sContentType = ($sFileName === '') ? 'text/plain' : \MailSo\Base\Utils::MimeContentType($sFileName);
295:
296: $mResult = false;
297: if ($bThumbnail) {
298: $sRawKey = (string) \Aurora\System\Router::getItemByIndex(1, '');
299: if (!empty($sRawKey)) {
300: \Aurora\System\Managers\Response::verifyCacheByKey($sRawKey);
301: }
302: $mResult = \Aurora\System\Managers\Thumb::GetResourceCache($iUserId, $sFileName);
303: if ($mResult) {
304: $sContentType = \MailSo\Base\Utils::MimeContentType($sFileName);
305: \Aurora\System\Managers\Response::OutputHeaders($bDownload, $sContentType, $sFileName);
306: echo $mResult;
307: exit();
308: }
309: }
310:
311: if (!$mResult) {
312: $aArgs = array(
313: 'UserId' => $iUserId,
314: 'Type' => $sType,
315: 'Path' => $sPath,
316: 'Name' => &$sFileName,
317: 'Id' => $sFileName,
318: 'IsThumb' => $bThumbnail,
319: 'Offset' => $iOffset,
320: 'ChunkSize' => $iChunkSize,
321: 'Shared' => $bShared
322: );
323: $this->broadcastEvent(
324: 'GetFile',
325: $aArgs,
326: $mResult
327: );
328: }
329:
330: if (false !== $mResult) {
331: if (is_resource($mResult)) {
332: $sFileName = \trim($sFileName, DIRECTORY_SEPARATOR);
333: $sContentType = \MailSo\Base\Utils::MimeContentType($sFileName);
334: \Aurora\System\Managers\Response::OutputHeaders($bDownload, $sContentType, $sFileName);
335:
336: \header('Cache-Control: no-cache', true);
337:
338: if ($bThumbnail) {
339: return \Aurora\System\Managers\Thumb::GetResource(
340: $iUserId,
341: $mResult,
342: $sFileName
343: );
344: } elseif ($sContentType === 'text/html' && !$bDownload) {
345: echo(\MailSo\Base\HtmlUtils::ClearHtmlSimple(stream_get_contents($mResult, $iLength, $iOffset)));
346: } elseif ($sContentType === 'text/plain') {
347: echo(stream_get_contents($mResult, $iLength, $iOffset));
348: } elseif ($iLength > -1 && $iOffset > -1) {
349: \MailSo\Base\Utils::GetFilePart($mResult, $iLength, $iOffset);
350: } else {
351: \MailSo\Base\Utils::FpassthruWithTimeLimitReset($mResult);
352: }
353:
354: @fclose($mResult);
355: } else {
356: // echo(\Aurora\System\Managers\Response::GetJsonFromObject('Json', \Aurora\System\Managers\Response::FalseResponse(__METHOD__, 403, 'Not Found')));
357: $this->oHttp->StatusHeader(404);
358: exit;
359: }
360: }
361: }
362: }
363: /***** private functions *****/
364:
365: /***** public functions *****/
366:
367: /***** public functions might be called with web API *****/
368: /**
369: * Uploads file from client side.
370: *
371: * echo string "true" or "false"
372: * @throws \Aurora\System\Exceptions\ApiException
373: */
374: public function UploadFileData()
375: {
376: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
377: $mResult = false;
378: $aPaths = \Aurora\System\Application::GetPaths();
379: if (isset($aPaths[1]) && strtolower($aPaths[1]) === strtolower(self::GetName())) {
380: $sType = isset($aPaths[2]) ? strtolower($aPaths[2]) : 'personal';
381: $rData = fopen("php://input", "r");
382: $aFilePath = array_slice($aPaths, 3);
383: $sFilePath = urldecode(implode('/', $aFilePath));
384:
385: $bOverwrite = true;
386: if (strpos($sFilePath, '!') === 0) {
387: $sFilePath = substr($sFilePath, 1);
388: $bOverwrite = false;
389: }
390:
391: $iUserId = \Aurora\System\Api::getAuthenticatedUserId(
392: \Aurora\System\Api::getAuthTokenFromHeaders()
393: );
394: $oUser = \Aurora\System\Api::getAuthenticatedUser($iUserId);
395: if ($oUser) {
396: if ($rData) {
397: $aArgs = array(
398: 'UserId' => $oUser->UUID,
399: 'Type' => $sType,
400: 'Path' => dirname($sFilePath),
401: 'Name' => basename($sFilePath),
402: 'Data' => $rData,
403: 'Overwrite' => $bOverwrite,
404: 'RangeType' => 0,
405: 'Offset' => 0,
406: 'ExtendedProps' => array()
407: );
408: $this->broadcastEvent(
409: 'CreateFile',
410: $aArgs,
411: $mResult
412: );
413: } else {
414: $mResult = false;
415: }
416: } else {
417: $mResult = false;
418: }
419: }
420: if ($mResult) {
421: echo 'true';
422: } else {
423: echo 'false';
424: }
425: }
426:
427: /**
428: * @apiDefine Files Files Module
429: * Main Files module. It provides PHP and Web APIs for managing files.
430: */
431:
432: /**
433: * @api {post} ?/Api/ GetSettings
434: * @apiName GetSettings
435: * @apiGroup Files
436: * @apiDescription Obtains list of module settings for authenticated user.
437: *
438: * @apiHeader {string} [Authorization] "Bearer " + Authentication token which was received as the result of Core.Login method.
439: * @apiHeaderExample {json} Header-Example:
440: * {
441: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
442: * }
443: *
444: * @apiParam {string=Files} Module Module name
445: * @apiParam {string=GetSettings} Method Method name
446: *
447: * @apiParamExample {json} Request-Example:
448: * {
449: * Module: 'Files',
450: * Method: 'GetSettings'
451: * }
452: *
453: * @apiSuccess {object[]} Result Array of response objects.
454: * @apiSuccess {string} Result.Module Module name.
455: * @apiSuccess {string} Result.Method Method name.
456: * @apiSuccess {mixed} Result.Result List of module settings in case of success, otherwise **false**.
457: * @apiSuccess {bool} Result.Result.EnableUploadSizeLimit=false Indicates if upload size limit is enabled.
458: * @apiSuccess {int} Result.Result.UploadSizeLimitMb=0 Value of upload size limit in Mb.
459: * @apiSuccess {string} Result.Result.CustomTabTitle=&quot;&quot; Custom tab title.
460: * @apiSuccess {string} [Result.Result.PublicHash=&quot;&quot;] Public hash.
461: * @apiSuccess {string} [Result.Result.PublicFolderName=&quot;&quot;] Public folder name.
462: * @apiSuccess {int} [Result.ErrorCode] Error code
463: *
464: * @apiSuccessExample {json} Success response example:
465: * {
466: * Module: 'Files',
467: * Method: 'GetSettings',
468: * Result: { EnableUploadSizeLimit: true, UploadSizeLimitMb: 5,
469: * CustomTabTitle: "", PublicHash: "", PublicFolderName: "" }
470: * }
471: *
472: * @apiSuccessExample {json} Error response example:
473: * {
474: * Module: 'Files',
475: * Method: 'GetSettings',
476: * Result: false,
477: * ErrorCode: 102
478: * }
479: */
480: /**
481: * Obtains list of module settings for authenticated user.
482: *
483: * @return array
484: */
485: public function GetSettings()
486: {
487: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
488:
489: $iPostMaxSize = (int) ini_get('post_max_size');
490: $iUploadMaxFilesize = (int) ini_get('upload_max_filesize');
491:
492: $aAppData = array(
493: 'EnableUploadSizeLimit' => $this->oModuleSettings->EnableUploadSizeLimit,
494: 'UploadSizeLimitMb' => min([$iPostMaxSize, $iUploadMaxFilesize, $this->oModuleSettings->UploadSizeLimitMb]),
495: 'CustomTabTitle' => $this->oModuleSettings->CustomTabTitle,
496: 'UserSpaceLimitMb' => $this->oModuleSettings->UserSpaceLimitMb,
497: 'TenantSpaceLimitMb' => $this->oModuleSettings->TenantSpaceLimitMb
498: );
499:
500: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
501: if ($oAuthenticatedUser instanceof User
502: && ($oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::NormalUser
503: || $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::TenantAdmin
504: || $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin)) {
505: $aAppData['Storages'] = \Aurora\Modules\Files\Module::Decorator()->GetStorages();
506: }
507:
508: $sPublicHash = \Aurora\System\Router::getItemByIndex(1);
509: if (isset($sPublicHash)) {
510: $aAppData['PublicHash'] = $sPublicHash;
511: $oModuleDecorator = $this->getMinModuleDecorator();
512: $mMin = ($oModuleDecorator && $sPublicHash !== null) ? $oModuleDecorator->GetMinByHash($sPublicHash) : array();
513: if (isset($mMin['__hash__']) && $mMin['IsFolder']) {
514: $aAppData['PublicFolderName'] = $mMin['Name'];
515: }
516: }
517: return $aAppData;
518: }
519:
520: public function GetSettingsForEntity($EntityType, $EntityId)
521: {
522: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
523:
524: $aResult = [];
525: if ($EntityType === 'Tenant') {
526: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
527: $oTenant = \Aurora\Modules\Core\Module::Decorator()->GetTenantWithoutRoleCheck($EntityId);
528: if ($oTenant instanceof Tenant) {
529: $aResult = [
530: 'TenantSpaceLimitMb' => $oTenant->getExtendedProp(self::GetName() . '::TenantSpaceLimitMb'),
531: 'UserSpaceLimitMb' => $oTenant->getExtendedProp(self::GetName() . '::UserSpaceLimitMb'),
532: 'AllocatedSpace' => $this->GetAllocatedSpaceForUsersInTenant($oTenant->Id)
533: ];
534: }
535: }
536: if ($EntityType === 'User') {
537: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
538: $oUser = \Aurora\Modules\Core\Module::Decorator()->GetUserWithoutRoleCheck($EntityId);
539: if ($oUser instanceof User) {
540: $aResult = [
541: 'UserSpaceLimitMb' => $oUser->getExtendedProp(self::GetName() . '::UserSpaceLimitMb'),
542: ];
543: }
544: }
545:
546: return $aResult;
547: }
548:
549: /**
550: * @api {post} ?/Api/ UpdateSettings
551: * @apiName UpdateSettings
552: * @apiGroup Files
553: * @apiDescription Updates module's settings - saves them to config.json file.
554: *
555: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
556: * @apiHeaderExample {json} Header-Example:
557: * {
558: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
559: * }
560: *
561: * @apiParam {string=Files} Module Module name
562: * @apiParam {string=UpdateSettings} Method Method name
563: * @apiParam {string} Parameters JSON.stringified object <br>
564: * {<br>
565: * &emsp; **EnableUploadSizeLimit** *bool* Enable file upload size limit setting.<br>
566: * &emsp; **UploadSizeLimitMb** *int* Upload file size limit setting in Mb.<br>
567: * }
568: *
569: * @apiParamExample {json} Request-Example:
570: * {
571: * Module: 'Files',
572: * Method: 'UpdateSettings',
573: * Parameters: '{ EnableUploadSizeLimit: true, UploadSizeLimitMb: 5 }'
574: * }
575: *
576: * @apiSuccess {object[]} Result Array of response objects.
577: * @apiSuccess {string} Result.Module Module name
578: * @apiSuccess {string} Result.Method Method name
579: * @apiSuccess {bool} Result.Result Indicates if settings were updated successfully.
580: * @apiSuccess {int} [Result.ErrorCode] Error code
581: *
582: * @apiSuccessExample {json} Success response example:
583: * {
584: * Module: 'Files',
585: * Method: 'UpdateSettings',
586: * Result: true
587: * }
588: *
589: * @apiSuccessExample {json} Error response example:
590: * {
591: * Module: 'Files',
592: * Method: 'UpdateSettings',
593: * Result: false,
594: * ErrorCode: 102
595: * }
596: */
597: /**
598: * Updates module's settings - saves them to config.json file.
599: *
600: * @param bool $EnableUploadSizeLimit Enable file upload size limit setting.
601: * @param int $UploadSizeLimitMb Upload file size limit setting in Mb.
602: * @return bool
603: */
604: public function UpdateSettings($EnableUploadSizeLimit, $UploadSizeLimitMb)
605: {
606: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
607:
608: $this->setConfig('EnableUploadSizeLimit', $EnableUploadSizeLimit);
609: $this->setConfig('UploadSizeLimitMb', $UploadSizeLimitMb);
610: return (bool) $this->saveModuleConfig();
611: }
612:
613: /**
614: * @api {post} ?/Upload/ UploadFile
615: * @apiDescription Uploads file from client side.
616: * @apiName UploadFile
617: * @apiGroup Files
618: *
619: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
620: * @apiHeaderExample {json} Header-Example:
621: * {
622: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
623: * }
624: *
625: * @apiParam {string=Files} Module Module name
626: * @apiParam {string=UploadFile} Method Method name
627: * @apiParam {string} Parameters JSON.stringified object <br>
628: * {<br>
629: * &emsp; **Type** *string* Type of storage - personal, corporate.<br>
630: * &emsp; **Path** *string* Path to folder than should contain uploaded file.<br>
631: * &emsp; **UploadData** *string* Uploaded file information. Contains fields size, name, tmp_name.<br>
632: * &emsp; **SubPatha** *string* Relative path to subfolder where file should be uploaded.<br>
633: * }
634: *
635: * @apiSuccess {object[]} Result Array of response objects.
636: * @apiSuccess {string} Result.Module Module name
637: * @apiSuccess {string} Result.Method Method name
638: * @apiSuccess {mixed} Result.Result File object in case of success, otherwise **false**.
639: * @apiSuccess {string} Result.Result.Name Original file name.
640: * @apiSuccess {string} Result.Result.TempName Temporary file name.
641: * @apiSuccess {string} Result.Result.MimeType Mime type of file.
642: * @apiSuccess {int} Result.Result.Size File size.
643: * @apiSuccess {string} Result.Result.Hash Hash used for file download, file view or getting file thumbnail.
644: * @apiSuccess {int} [Result.ErrorCode] Error code
645: *
646: * @apiSuccessExample {json} Success response example:
647: * {
648: * Module: 'Files',
649: * Method: 'UploadFile',
650: * Result: { File: { Name: 'image.png', TempName: 'upload-post-6149f2cda5c58c6951658cce9f2b1378',
651: * MimeType: 'image/png', Size: 1813 } }
652: * }
653: *
654: * @apiSuccessExample {json} Error response example:
655: * {
656: * Module: 'Files',
657: * Method: 'UploadFile',
658: * Result: false,
659: * ErrorCode: 102
660: * }
661: */
662: /**
663: * Uploads file from client side.
664: *
665: * @param int $UserId User identifier.
666: * @param string $Type Type of storage - personal, corporate.
667: * @param string $Path Path to folder than should contain uploaded file.
668: * @param array $UploadData Uploaded file information. Contains fields size, name, tmp_name.
669: * @param string $SubPath Relative path to subfolder where file should be uploaded.
670: * @param bool $Overwrite Overwrite a file if it already exists.
671: * @param int $RangeType The type of update we're doing.
672: * * 0 - overwrite
673: * * 1 - append
674: * * 2 - update based on a start byte
675: * * 3 - update based on an end byte
676: *;
677: * @param int $Offset The start or end byte.
678: * @param array $ExtendedProps Additional parameters.
679: * @return array {
680: * *string* **Name** Original file name.
681: * *string* **TempName** Temporary file name.
682: * *string* **MimeType** Mime type of file.
683: * *int* **Size** File size.
684: * *string* **Hash** Hash used for file download, file view or getting file thumbnail.
685: * }
686: * @throws \Aurora\System\Exceptions\ApiException
687: */
688: public function UploadFile($UserId, $Type, $Path, $UploadData, $SubPath = '', $Overwrite = true, $RangeType = 0, $Offset = 0, $ExtendedProps = [])
689: {
690: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
691:
692: $sUserPublicId = \Aurora\System\Api::getUserPublicIdById($UserId);
693:
694: $sError = '';
695: $mResponse = array();
696:
697: if ($sUserPublicId) {
698: if (is_array($UploadData)) {
699: if (isset($ExtendedProps['FirstChunk']) && $RangeType == 1 && self::Decorator()->IsFileExists($UserId, $Type, $Path, $UploadData['name'])) {// It is forbidden to write first сhunk to the end of a existing file
700: $sError = \Aurora\System\Notifications::FileAlreadyExists;
701: } elseif (!isset($ExtendedProps['FirstChunk']) && $RangeType == 1 && !self::Decorator()->IsFileExists($UserId, $Type, $Path, $UploadData['name'])) { // It is forbidden to write to the end of a nonexistent file
702: $sError = \Aurora\System\Notifications::FileNotFound;
703: } else {
704: $iSize = (int) $UploadData['size'];
705: $iUploadSizeLimitMb = $this->oModuleSettings->UploadSizeLimitMb;
706: if ($iUploadSizeLimitMb > 0 && $iSize / (1024 * 1024) > $iUploadSizeLimitMb) {
707: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::CanNotUploadFileLimit);
708: }
709:
710: if (!self::Decorator()->CheckQuota($UserId, $Type, $iSize)) {
711: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::CanNotUploadFileQuota);
712: }
713:
714: if ($SubPath !== '' && !self::Decorator()->IsFileExists($UserId, $Type, $Path, $SubPath)) {
715: try {
716: self::Decorator()->CreateFolder($UserId, $Type, $Path, $SubPath);
717: } catch (\Exception $oException) {
718: // Cannot catch here \Sabre\DAV\Exception\Conflict
719: // Parallel uplod of files with creation of a subfolder may cause the conflict
720: if ($oException->getMessage() !== 'Can\'t create a directory') {
721: throw $oException;
722: }
723: }
724: }
725:
726: $sUploadName = $UploadData['name'];
727: $sMimeType = \MailSo\Base\Utils::MimeContentType($sUploadName);
728:
729: $sSavedName = 'upload-post-' . md5($UploadData['name'] . $UploadData['tmp_name']);
730: $rData = false;
731: if (\is_resource($UploadData['tmp_name'])) {
732: $rData = $UploadData['tmp_name'];
733: } elseif ($this->getFilecacheManager()->moveUploadedFile($sUserPublicId, $sSavedName, $UploadData['tmp_name'], '', self::GetName())) {
734: $rData = $this->getFilecacheManager()->getFile($sUserPublicId, $sSavedName, '', self::GetName());
735: }
736: if ($rData) {
737: $aArgs = array(
738: 'UserId' => $UserId,
739: 'Type' => $Type,
740: 'Path' => $SubPath === '' ? $Path : $Path . '/' . $SubPath,
741: 'Name' => $sUploadName,
742: 'Data' => $rData,
743: 'Overwrite' => $Overwrite,
744: 'RangeType' => $RangeType,
745: 'Offset' => $Offset,
746: 'ExtendedProps' => $ExtendedProps
747: );
748: $mResult = false;
749: $this->broadcastEvent(
750: 'CreateFile',
751: $aArgs,
752: $mResult
753: );
754:
755: if ($mResult) {
756: $mResponse['File'] = array(
757: 'Name' => $sUploadName,
758: 'TempName' => $sSavedName,
759: 'MimeType' => $sMimeType,
760: 'Size' => (int) $iSize
761: );
762: } else {
763: $mResponse = false;
764: }
765: } else {
766: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::CanNotUploadFileErrorData);
767: }
768: }
769: } else {
770: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
771: }
772: } else {
773: $sError = 'auth';
774: }
775:
776: if (0 < strlen($sError)) {
777: $mResponse['Error'] = $sError;
778: }
779:
780: return $mResponse;
781: }
782:
783: public function EntryDownloadFile()
784: {
785: // checkUserRoleIsAtLeast is called in getRawFile
786:
787: $sHash = (string) \Aurora\System\Router::getItemByIndex(1, '');
788: $sAction = (string) \Aurora\System\Router::getItemByIndex(2, 'download');
789: $iOffset = (int) \Aurora\System\Router::getItemByIndex(3, '');
790: $iChunkSize = (int) \Aurora\System\Router::getItemByIndex(4, '');
791:
792: $aValues = \Aurora\System\Api::DecodeKeyValues($sHash);
793:
794: $iUserId = isset($aValues['UserId']) ? (int) $aValues['UserId'] : 0;
795: $sType = isset($aValues['Type']) ? $aValues['Type'] : '';
796: $sPath = isset($aValues['Path']) ? $aValues['Path'] : '';
797: $sFileName = isset($aValues['Name']) ? $aValues['Name'] : '';
798: $sPublicHash = isset($aValues['PublicHash']) ? $aValues['PublicHash'] : null;
799: $bShared = isset($aValues['Shared']) ? $aValues['Shared'] : null;
800:
801: $this->getRawFile($iUserId, $sType, $sPath, $sFileName, $sPublicHash, $sAction, $iOffset, $iChunkSize, $bShared);
802: }
803:
804: /**
805: * @api {post} ?/Api/ ViewFile
806: * @apiDescription Views file.
807: * @apiName ViewFile
808: * @apiGroup Files
809: *
810: * @apiHeader {string} [Authorization] "Bearer " + Authentication token which was received as the result of Core.Login method.
811: * @apiHeaderExample {json} Header-Example:
812: * {
813: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
814: * }
815: *
816: * @apiParam {string=Files} Module Module name
817: * @apiParam {string=ViewFile} Method Method name
818: * @apiParam {string} Parameters JSON.stringified object <br>
819: * {<br>
820: * &emsp; **Type** *string* Storage type - personal, corporate.<br>
821: * &emsp; **Path** *string* Path to folder contained file.<br>
822: * &emsp; **Name** *string* File name.<br>
823: * &emsp; **SharedHash** *string* Shared hash.<br>
824: * }
825: *
826: * @apiParamExample {json} Request-Example:
827: * {
828: * Module: 'Files',
829: * Method: 'ViewFile',
830: * Parameters: '{ Type: "personal", Path: "", Name: "image.png" }'
831: * }
832: *
833: * @apiSuccess {string} Result Content of the file with headers for view.
834: */
835:
836: /**
837: * Views file.
838: *
839: * @param int $UserId User identifier.
840: * @param string $Type Storage type - personal, corporate.
841: * @param string $Path Path to folder contained file.
842: * @param string $Name File name.
843: * @param string $SharedHash Shared hash.
844: * @return void
845: */
846: public function ViewFile($UserId, $Type, $Path, $Name, $SharedHash)
847: {
848: // checkUserRoleIsAtLeast is called in getRawFile
849: $this->getRawFile(
850: \Aurora\System\Api::getUserPublicIdById($UserId),
851: $Type,
852: $Path,
853: $Name,
854: $SharedHash,
855: false
856: );
857: }
858:
859: /**
860: * @api {post} ?/Api/ GetFileThumbnail
861: * @apiDescription Makes thumbnail for file.
862: * @apiName GetFileThumbnail
863: * @apiGroup Files
864: *
865: * @apiHeader {string} [Authorization] "Bearer " + Authentication token which was received as the result of Core.Login method.
866: * @apiHeaderExample {json} Header-Example:
867: * {
868: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
869: * }
870: *
871: * @apiParam {string=Files} Module Module name
872: * @apiParam {string=GetFileThumbnail} Method Method name
873: * @apiParam {string} Parameters JSON.stringified object <br>
874: * {<br>
875: * &emsp; **Type** *string* Storage type - personal, corporate.<br>
876: * &emsp; **Path** *string* Path to folder contained file.<br>
877: * &emsp; **Name** *string* File name.<br>
878: * &emsp; **SharedHash** *string* Shared hash.<br>
879: * }
880: *
881: * @apiParamExample {json} Request-Example:
882: * {
883: * Module: 'Files',
884: * Method: 'GetFileThumbnail',
885: * Parameters: '{ Type: "personal", Path: "", Name: "image.png" }'
886: * }
887: *
888: * @apiSuccess {string} Result Content of the file thumbnail with headers for view.
889: */
890:
891: /**
892: * Makes thumbnail for file.
893: *
894: * @param int $UserId User identifier.
895: * @param string $Type Storage type - personal, corporate.
896: * @param string $Path Path to folder contained file.
897: * @param string $Name File name.
898: * @param string $SharedHash Shared hash.
899: * @return bool
900: */
901: public function GetFileThumbnail($UserId, $Type, $Path, $Name, $SharedHash)
902: {
903: return false;
904: // checkUserRoleIsAtLeast is called in getRawFile
905: // return \base64_encode(
906: // $this->getRawFile(
907: // \Aurora\System\Api::getUserPublicIdById($UserId),
908: // $Type,
909: // $Path,
910: // $Name,
911: // $SharedHash,
912: // false,
913: // true
914: // )
915: // );
916: }
917:
918: /**
919: * @api {post} ?/Api/ GetStorages
920: * @apiDescription Returns storages available for logged in user.
921: * @apiName GetStorages
922: * @apiGroup Files
923: *
924: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
925: * @apiHeaderExample {json} Header-Example:
926: * {
927: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
928: * }
929: *
930: * @apiParam {string=Files} Module Module name
931: * @apiParam {string=GetStorages} Method Method name
932: *
933: * @apiParamExample {json} Request-Example:
934: * {
935: * Module: 'Files',
936: * Method: 'GetStorages'
937: * }
938: *
939: * @apiSuccess {object[]} Result Array of response objects.
940: * @apiSuccess {string} Result.Module Module name
941: * @apiSuccess {string} Result.Method Method name
942: * @apiSuccess {mixed} Result.Result List of storages in case of success, otherwise **false**.
943: * @apiSuccess {string} Result.Result.Type Storage type - personal, corporate.
944: * @apiSuccess {string} Result.Result.DisplayName Storage display name.
945: * @apiSuccess {bool} Result.Result.IsExternal Indicates if storage external or not.
946: * @apiSuccess {int} [Result.ErrorCode] Error code
947: *
948: * @apiSuccessExample {json} Success response example:
949: * {
950: * Module: 'Files',
951: * Method: 'GetStorages',
952: * Result: [{ Type: "personal", DisplayName: "Personal", IsExternal: false },
953: * { Type: "corporate", DisplayName: "Corporate", IsExternal: false },
954: * { Type: "google", IsExternal: true, DisplayName: "GoogleDrive" }]
955: * }
956: *
957: * @apiSuccessExample {json} Error response example:
958: * {
959: * Module: 'Files',
960: * Method: 'GetStorages',
961: * Result: false,
962: * ErrorCode: 102
963: * }
964: */
965:
966: /**
967: * Returns storages available for logged in user.
968: *
969: * @return array {
970: * *string* **Type** Storage type - personal, corporate.
971: * *string* **DisplayName** Storage display name.
972: * *bool* **IsExternal** Indicates if storage external or not.
973: * }
974: */
975: public function GetStorages()
976: {
977: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
978: return [];
979: }
980:
981: /**
982: * Returns submodules.
983: */
984: public function GetSubModules()
985: {
986: return [];
987: }
988:
989: /**
990: * @api {post} ?/Api/ GetQuota
991: * @apiDescription Returns used space and space limit for specified user.
992: * @apiName GetQuota
993: * @apiGroup Files
994: *
995: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
996: * @apiHeaderExample {json} Header-Example:
997: * {
998: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
999: * }
1000: *
1001: * @apiParam {string=Files} Module Module name
1002: * @apiParam {string=GetQuota} Method Method name
1003: * @apiParam {string} Parameters JSON.stringified object <br>
1004: * {<br>
1005: * &emsp; **UserId** *int* User identifier.<br>
1006: * }
1007: *
1008: * @apiParamExample {json} Request-Example:
1009: * {
1010: * Module: 'Files',
1011: * Method: 'UpdateAccount',
1012: * Parameters: '{ UserId: 123 }'
1013: * }
1014: *
1015: * @apiSuccess {object[]} Result Array of response objects.
1016: * @apiSuccess {string} Result.Module Module name
1017: * @apiSuccess {string} Result.Method Method name
1018: * @apiSuccess {mixed} Result.Result Object in case of success, otherwise **false**.
1019: * @apiSuccess {int} Result.Result.Used Amount of space used by user.
1020: * @apiSuccess {int} Result.Result.Limit Limit of space for user.
1021: * @apiSuccess {int} [Result.ErrorCode] Error code
1022: *
1023: * @apiSuccessExample {json} Success response example:
1024: * {
1025: * Module: 'Files',
1026: * Method: 'GetQuota',
1027: * Result: { Used: 21921, Limit: 62914560 }
1028: * }
1029: *
1030: * @apiSuccessExample {json} Error response example:
1031: * {
1032: * Module: 'Files',
1033: * Method: 'GetQuota',
1034: * Result: false,
1035: * ErrorCode: 102
1036: * }
1037: */
1038: /**
1039: * Returns used space and space limit for specified user.
1040: *
1041: * @param int $UserId User identifier.
1042: * @return array {
1043: * *int* **Used** Amount of space used by user.
1044: * *int* **Limit** Limit of space for user.
1045: * }
1046: */
1047: public function GetQuota($UserId, $Type)
1048: {
1049: return [
1050: 'Limit' => 0,
1051: 'Used' => 0
1052: ];
1053: }
1054:
1055: public function CheckQuota($UserId, $Type, $Size)
1056: {
1057: return false;
1058: }
1059:
1060: public function GetItems($UserId, $Type, $Path, $Pattern, $PublicHash = null, $Shared = false)
1061: {
1062: $aArgs = [
1063: 'UserId' => $UserId,
1064: 'Type' => $Type,
1065: 'Path' => $Path,
1066: 'Pattern' => $Pattern,
1067: 'PublicHash' => $PublicHash,
1068: 'Shared' => $Shared
1069: ];
1070: $mResult = [];
1071:
1072: $this->broadcastEvent('GetItems', $aArgs, $mResult);
1073:
1074: $aItems = [];
1075: if (is_array($mResult)) {
1076: foreach ($mResult as $oItem) {
1077: if ($oItem instanceof Classes\FileItem) {
1078: $aItems[] = self::Decorator()->PopulateFileItem($aArgs['UserId'], $oItem);
1079: }
1080: }
1081:
1082: $mResult = $aItems;
1083: }
1084:
1085: return $aItems;
1086: }
1087:
1088: /**
1089: * @api {post} ?/Api/ GetFiles
1090: * @apiDescription Returns file list and user quota information.
1091: * @apiName GetFiles
1092:
1093: * * @apiGroup Files
1094: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1095: * @apiHeaderExample {json} Header-Example:
1096: * {
1097: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1098: * }
1099: *
1100: * @apiParam {string=Files} Module Module name
1101: * @apiParam {string=GetFiles} Method Method name
1102: * @apiParam {string} Parameters JSON.stringified object <br>
1103: * {<br>
1104: * &emsp; **Type** *string* Type of storage.<br>
1105: * &emsp; **Path** *string* Path to folder files are obtained from.<br>
1106: * &emsp; **Pattern** *string* String for search files and folders with such string in name.<br>
1107: * }
1108: *
1109: * @apiParamExample {json} Request-Example:
1110: * {
1111: * Module: 'Files',
1112: * Method: 'GetFiles',
1113: * Parameters: '{ Type: "personal", Path: "", Pattern: "" }'
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 {mixed} Result.Result Object in case of success, otherwise **false**.
1120: * @apiSuccess {array} Result.Result.Items Array of files objects.
1121: * @apiSuccess {array} Result.Result.Quota Array of items with fields Used, Limit.
1122: * @apiSuccess {int} [Result.ErrorCode] Error code
1123: *
1124: * @apiSuccessExample {json} Success response example:
1125: * {
1126: * Module: 'Files',
1127: * Method: 'GetFiles',
1128: * Result: { Items: [{ Id: "image.png", Type: "personal", Path: "", FullPath: "/image.png",
1129: * Name: "image.png", Size: 1813, IsFolder: false, IsLink: false, LinkType: "", LinkUrl: "",
1130: * LastModified: 1475498855, ContentType: "image/png", Thumb: true, ThumbnailLink: "", OembedHtml: "",
1131: * Shared: false, Owner: "", Content: "", IsExternal: false }], Quota: { Used: 21921, Limit: 62914560 } }
1132: * }
1133: *
1134: * @apiSuccessExample {json} Error response example:
1135: * {
1136: * Module: 'Files',
1137: * Method: 'GetFiles',
1138: * Result: false,
1139: * ErrorCode: 102
1140: * }
1141: */
1142:
1143: /**
1144: * Returns file list and user quota information.
1145: *
1146: * @param int $UserId User identifier.
1147: * @param string $Type Type of storage.
1148: * @param string $Path Path to folder files are obtained from.
1149: * @param string $Pattern String for search files and folders with such string in name.
1150: * @return array {
1151: * *array* **Items** Array of files objects.
1152: * *array* **Quota** Array of items with fields Used, Limit.
1153: * }
1154: * @throws \Aurora\System\Exceptions\ApiException
1155: */
1156: public function GetFiles($UserId, $Type, $Path, $Pattern, $Shared = false)
1157: {
1158: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1159: return [
1160: 'Items' => self::Decorator()->GetItems($UserId, $Type, $Path, $Pattern, null, $Shared),
1161: 'Quota' => self::Decorator()->GetQuota($UserId, $Type)
1162: ];
1163: }
1164:
1165: /**
1166: *
1167: * @param array $aArgs
1168: * @param mixed $mResult
1169: */
1170: public function onAfterGetStorages($aArgs, &$mResult)
1171: {
1172: if (is_array($mResult)) {
1173: \usort($mResult, function ($aItem1, $aItem2) {
1174: $aItem1['Order'] = isset($aItem1['Order']) ? $aItem1['Order'] : 1000;
1175: $aItem2['Order'] = isset($aItem2['Order']) ? $aItem2['Order'] : 1000;
1176:
1177: return ($aItem1['Order'] == $aItem2['Order']) ? 0 : ($aItem1['Order'] > $aItem2['Order'] ? +1 : -1);
1178: });
1179: }
1180: }
1181:
1182: /**
1183: *
1184: * @param int $iUserId
1185: * @param int $sType
1186: * @param string $sPath
1187: * @param string $sName
1188: * @param int $sSize
1189: *
1190: * @return array
1191: */
1192: private function generateMinArray($iUserId, $sType, $sPath, $sName, $sSize, $bIsFolder = false)
1193: {
1194: $aData = null;
1195: if ($iUserId) {
1196: $aData = array(
1197: 'UserId' => $iUserId,
1198: 'Type' => $sType,
1199: 'Path' => $sPath,
1200: 'Name' => $sName,
1201: 'Size' => $sSize,
1202: 'IsFolder' => $bIsFolder
1203: );
1204: }
1205:
1206: return $aData;
1207: }
1208:
1209: protected function updateMinHash($iUserId, $sType, $sPath, $sName, $sNewType, $sNewPath, $sNewName, $bIsFolder)
1210: {
1211: $sUserPublicId = \Aurora\Api::getUserPublicIdById($iUserId);
1212: $sID = \Aurora\Modules\Min\Module::generateHashId([$sUserPublicId, $sType, $sPath, $sName]);
1213: $sNewID = \Aurora\Modules\Min\Module::generateHashId([$sUserPublicId, $sNewType, $sNewPath, $sNewName]);
1214:
1215: $mData = $this->getMinModuleDecorator()->GetMinByID($sID);
1216:
1217: if ($mData) {
1218: $aData = $this->generateMinArray($sUserPublicId, $sNewType, $sNewPath, $sNewName, $mData['Size'], $bIsFolder);
1219: if ($aData) {
1220: $this->getMinModuleDecorator()->UpdateMinByID($sID, $aData, $sNewID);
1221: }
1222: }
1223: }
1224:
1225: /**
1226: *
1227: * @param array $aArgs
1228: * @param mixed $mResult
1229: */
1230: public function onAfterRename($aArgs, &$mResult)
1231: {
1232: if ($mResult && isset($aArgs['UserId'])) {
1233: $this->updateMinHash($aArgs['UserId'], $aArgs['Type'], $aArgs['Path'], $aArgs['Name'], $aArgs['Type'], $aArgs['Path'], $aArgs['NewName'], $aArgs['IsFolder']);
1234: }
1235: }
1236:
1237: public function onAfterMove($aArgs, &$mResult)
1238: {
1239: if ($mResult && isset($aArgs['Files']) && is_array($aArgs['Files']) && count($aArgs['Files']) > 0) {
1240: foreach ($aArgs['Files'] as $aFile) {
1241: $this->updateMinHash(
1242: $aArgs['UserId'],
1243: $aFile['FromType'],
1244: $aFile['FromPath'],
1245: $aFile['Name'],
1246: $aArgs['ToType'],
1247: $aArgs['ToPath'],
1248: $aFile['NewName'],
1249: $aFile['IsFolder']
1250: );
1251: }
1252: }
1253: }
1254:
1255: /**
1256: *
1257: * @param array $aArgs
1258: * @param mixed $mResult
1259: */
1260: public function onAfterCreateUser($aArgs, &$mResult)
1261: {
1262: if ($mResult) {
1263: $oUser = \Aurora\Modules\Core\Module::getInstance()->GetUserWithoutRoleCheck($mResult);
1264: if ($oUser) {
1265: $oTenant = \Aurora\Modules\Core\Module::getInstance()->GetTenantWithoutRoleCheck($oUser->IdTenant);
1266: $oUser->setExtendedProp($this->GetName() . '::UserSpaceLimitMb', $oTenant->getExtendedProp($this->GetName() . '::UserSpaceLimitMb'));
1267: $oUser->save();
1268: }
1269: }
1270: }
1271:
1272: /**
1273: *
1274: * @param array $UserId
1275: * @param mixed $Item
1276: *
1277: * @return mixed
1278: */
1279: public function PopulateFileItem($UserId, $Item)
1280: {
1281: return $Item;
1282: }
1283:
1284: /**
1285: *
1286: * @param int $UserId
1287: * @param mixed $Items
1288: *
1289: * @return mixed
1290: */
1291: public function PopulateFileItems($UserId, $Items)
1292: {
1293: return $Items;
1294: }
1295:
1296: /**
1297: * Return content of a file.
1298: *
1299: * @param int $UserId
1300: * @param string $Type
1301: * @param string $Path
1302: * @param string $Name
1303: */
1304: public function GetFileContent($UserId, $Type, $Path, $Name)
1305: {
1306: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1307: // File content is obtained in subscribers methods
1308: }
1309:
1310: /**
1311: * Return information about file. Subscribers of "Files::GetFileInfo::after" event are used for collecting information.
1312: *
1313: * @param int $UserId
1314: * @param string $Type
1315: * @param string $Path
1316: * @param string $Id
1317: * @return \Aurora\Modules\Files\Classes\FileItem
1318: */
1319: public function GetFileInfo($UserId, $Type, $Path, $Id)
1320: {
1321: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1322:
1323: return null;
1324: }
1325:
1326: /**
1327: * @api {post} ?/Api/ GetPublicFiles
1328: * @apiDescription Returns list of public files.
1329: * @apiName GetPublicFiles
1330: * @apiGroup Files
1331: * @apiParam {string=Files} Module Module name
1332: * @apiParam {string=GetPublicFiles} Method Method name
1333: * @apiParam {string} Parameters JSON.stringified object <br>
1334: * {<br>
1335: * &emsp; **Hash** *string* Hash to identify the list of files to return. Containes information about user identifier, type of storage, path to public folder, name of public folder.<br>
1336: * &emsp; **Path** *string* Path to folder contained files to return.<br>
1337: * }
1338: *
1339: * @apiParamExample {json} Request-Example:
1340: * {
1341: * Module: 'Files',
1342: * Method: 'GetPublicFiles',
1343: * Parameters: '{ Hash: "hash_value", Path: "" }'
1344: * }
1345: *
1346: * @apiSuccess {object[]} Result Array of response objects.
1347: * @apiSuccess {string} Result.Module Module name
1348: * @apiSuccess {string} Result.Method Method name
1349: * @apiSuccess {mixed} Result.Result Object in case of success, otherwise **false**.
1350: * @apiSuccess {array} Result.Result.Items Array of files objects.
1351: * @apiSuccess {int} [Result.ErrorCode] Error code
1352: *
1353: * @apiSuccessExample {json} Success response example:
1354: * {
1355: * Module: 'Files',
1356: * Method: 'GetPublicFiles',
1357: * Result: { Items: [{ Id: "image.png", Type: "personal", Path: "/shared_folder",
1358: * FullPath: "/shared_folder/image.png", Name: "image.png", Size: 43549, IsFolder: false,
1359: * IsLink: false, LinkType: "", LinkUrl: "", LastModified: 1475500277, ContentType: "image/png",
1360: * Thumb: true, ThumbnailLink: "", OembedHtml: "", Shared: false, Owner: "62a6d548-892e-11e6-be21-0cc47a041d39",
1361: * Content: "", IsExternal: false }] }
1362: * }
1363: *
1364: * @apiSuccessExample {json} Error response example:
1365: * {
1366: * Module: 'Files',
1367: * Method: 'GetPublicFiles',
1368: * Result: false,
1369: * ErrorCode: 102
1370: * }
1371: */
1372:
1373: /**
1374: * Returns list of public files.
1375: *
1376: * @param string $Hash Hash to identify the list of files to return. Containes information about user identifier, type of storage, path to public folder, name of public folder.
1377: * @param string $Path Path to folder contained files to return.
1378: * @return array {
1379: * *array* **Items** Array of files objects.
1380: * *array* **Quota** Array of items with fields Used, Limit.
1381: * }
1382: * @throws \Aurora\System\Exceptions\ApiException
1383: */
1384: public function GetPublicFiles($Hash, $Path)
1385: {
1386: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::Anonymous);
1387:
1388: $mResult = [];
1389:
1390: $oMinDecorator = $this->getMinModuleDecorator();
1391: if ($oMinDecorator) {
1392: $mMin = $oMinDecorator->GetMinByHash($Hash);
1393: if (!empty($mMin['__hash__'])) {
1394: $sUserPublicId = $mMin['UserId'];
1395: if ($sUserPublicId) {
1396: $oUser = CoreModule::Decorator()->GetUserByPublicId($sUserPublicId);
1397: if ($oUser) {
1398: $bPrevState = \Aurora\System\Api::skipCheckUserRole(true);
1399: $sMinPath = implode('/', array($mMin['Path'], $mMin['Name']));
1400: $mPos = strpos($Path, $sMinPath);
1401: if ($mPos === 0 || $Path === '') {
1402: if ($mPos !== 0) {
1403: $Path = $sMinPath . $Path;
1404: }
1405: $Path = str_replace('.', '', $Path);
1406: $mResult = [
1407: 'Items' => self::Decorator()->GetItems($oUser->Id, $mMin['Type'], $Path, '', $Hash)
1408: ];
1409: }
1410: \Aurora\System\Api::skipCheckUserRole($bPrevState);
1411: }
1412: }
1413: }
1414: }
1415:
1416: return $mResult;
1417: }
1418:
1419: /**
1420: * @api {post} ?/Api/ CreateFolder
1421: * @apiDescription Creates folder.
1422: * @apiName CreateFolder
1423: * @apiGroup Files
1424: *
1425: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1426: * @apiHeaderExample {json} Header-Example:
1427: * {
1428: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1429: * }
1430: *
1431: * @apiParam {string=Files} Module Module name
1432: * @apiParam {string=CreateFolder} Method Method name
1433: * @apiParam {string} Parameters JSON.stringified object <br>
1434: * {<br>
1435: * &emsp; **Type** *string* Type of storage - personal, corporate.<br>
1436: * &emsp; **Path** *string* Path to new folder.<br>
1437: * &emsp; **FolderName** *string* New folder name.<br>
1438: * }
1439: *
1440: * @apiParamExample {json} Request-Example:
1441: * {
1442: * Module: 'Files',
1443: * Method: 'CreateFolder',
1444: * Parameters: '{ Type: "personal", Path: "", FolderName: "new_folder" }'
1445: * }
1446: *
1447: * @apiSuccess {object[]} Result Array of response objects.
1448: * @apiSuccess {string} Result.Module Module name
1449: * @apiSuccess {string} Result.Method Method name
1450: * @apiSuccess {bool} Result.Result Indicates if folder was created successfully.
1451: * @apiSuccess {int} [Result.ErrorCode] Error code
1452: *
1453: * @apiSuccessExample {json} Success response example:
1454: * {
1455: * Module: 'Files',
1456: * Method: 'CreateFolder',
1457: * Result: true
1458: * }
1459: *
1460: * @apiSuccessExample {json} Error response example:
1461: * {
1462: * Module: 'Files',
1463: * Method: 'CreateFolder',
1464: * Result: false,
1465: * ErrorCode: 102
1466: * }
1467: */
1468:
1469: /**
1470: * Creates folder.
1471: *
1472: * @param int $UserId User identifier.
1473: * @param string $Type Type of storage - personal, corporate.
1474: * @param string $Path Path to new folder.
1475: * @param string $FolderName New folder name.
1476: * @return bool
1477: * @throws \Aurora\System\Exceptions\ApiException
1478: */
1479: public function CreateFolder($UserId, $Type, $Path, $FolderName)
1480: {
1481: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1482:
1483: return false;
1484: }
1485:
1486: /**
1487: * @api {post} ?/Api/ CreateLink
1488: * @apiDescription Creates link.
1489: * @apiName CreateLink
1490: * @apiGroup Files
1491: *
1492: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1493: * @apiHeaderExample {json} Header-Example:
1494: * {
1495: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1496: * }
1497: *
1498: * @apiParam {string=Files} Module Module name
1499: * @apiParam {string=CreateLink} Method Method name
1500: * @apiParam {string} Parameters JSON.stringified object <br>
1501: * {<br>
1502: * &emsp; **Type** *string* Type of storage - personal, corporate.<br>
1503: * &emsp; **Path** *string* Path to new link.<br>
1504: * &emsp; **Link** *string* Link value.<br>
1505: * &emsp; **Name** *string* Link name.<br>
1506: * }
1507: *
1508: * @apiParamExample {json} Request-Example:
1509: * {
1510: * Module: 'Files',
1511: * Method: 'CreateLink',
1512: * Parameters: '{ Type: "personal", Path: "", Link: "link_value", Name: "name_value" }'
1513: * }
1514: *
1515: * @apiSuccess {object[]} Result Array of response objects.
1516: * @apiSuccess {string} Result.Module Module name
1517: * @apiSuccess {string} Result.Method Method name
1518: * @apiSuccess {mixed} Result.Result Link object in case of success, otherwise **false**.
1519: * @apiSuccess {string} Result.Result.Type Type of storage.
1520: * @apiSuccess {string} Result.Result.Path Path to link.
1521: * @apiSuccess {string} Result.Result.Link Link URL.
1522: * @apiSuccess {string} Result.Result.Name Link name.
1523: * @apiSuccess {int} [Result.ErrorCode] Error code.
1524: *
1525: * @apiSuccessExample {json} Success response example:
1526: * {
1527: * Module: 'Files',
1528: * Method: 'CreateLink',
1529: * Result: { Type: "personal", Path: "", Link: "https://www.youtube.com/watch?v=1WPn4NdQnlg&t=1124s",
1530: * Name: "Endless Numbers counting 90 to 100 - Learn 123 Numbers for Kids" }
1531: * }
1532: *
1533: * @apiSuccessExample {json} Error response example:
1534: * {
1535: * Module: 'Files',
1536: * Method: 'CreateLink',
1537: * Result: false,
1538: * ErrorCode: 102
1539: * }
1540: */
1541:
1542: /**
1543: * Creates link.
1544: *
1545: * @param int $UserId User identifier.
1546: * @param string $Type Type of storage - personal, corporate.
1547: * @param string $Path Path to new link.
1548: * @param string $Link Link value.
1549: * @param string $Name Link name.
1550: * @return bool
1551: * @throws \Aurora\System\Exceptions\ApiException
1552: */
1553: public function CreateLink($UserId, $Type, $Path, $Link, $Name)
1554: {
1555: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1556: return false;
1557: }
1558:
1559: /**
1560: * @api {post} ?/Api/ Delete
1561: * @apiDescription Deletes files and folder specified with list.
1562: * @apiName Delete
1563: * @apiGroup Files
1564: *
1565: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1566: * @apiHeaderExample {json} Header-Example:
1567: * {
1568: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1569: * }
1570: *
1571: * @apiParam {string=Files} Module Module name
1572: * @apiParam {string=Delete} Method Method name
1573: * @apiParam {string} Parameters JSON.stringified object <br>
1574: * {<br>
1575: * &emsp; **Type** *string* Type of storage - personal, corporate.<br>
1576: * &emsp; **Items** *array* Array of items to delete.<br>
1577: * }
1578: *
1579: * @apiParamExample {json} Request-Example:
1580: * {
1581: * Module: 'Files',
1582: * Method: 'Delete',
1583: * Parameters: '{ Type: "personal", Items: [{ "Path": "", "Name": "2.png" },
1584: * { "Path": "", "Name": "logo.png" }] }'
1585: * }
1586: *
1587: * @apiSuccess {object[]} Result Array of response objects.
1588: * @apiSuccess {string} Result.Module Module name
1589: * @apiSuccess {string} Result.Method Method name
1590: * @apiSuccess {bool} Result.Result Indicates if files and (or) folders were deleted successfully.
1591: * @apiSuccess {int} [Result.ErrorCode] Error code
1592: *
1593: * @apiSuccessExample {json} Success response example:
1594: * {
1595: * Module: 'Files',
1596: * Method: 'Delete',
1597: * Result: true
1598: * }
1599: *
1600: * @apiSuccessExample {json} Error response example:
1601: * {
1602: * Module: 'Files',
1603: * Method: 'Delete',
1604: * Result: false,
1605: * ErrorCode: 102
1606: * }
1607: */
1608:
1609: /**
1610: * Deletes files and folder specified with list.
1611: *
1612: * @param int $UserId User identifier.
1613: * @param string $Type Type of storage - personal, corporate.
1614: * @param array $Items Array of items to delete.
1615: * @return bool
1616: * @throws \Aurora\System\Exceptions\ApiException
1617: */
1618: public function Delete($UserId, $Type, $Items)
1619: {
1620: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1621:
1622: return false;
1623: }
1624:
1625: /**
1626: * @api {post} ?/Api/ LeaveShare
1627: * @apiDescription leave shared files and folder specified with list.
1628: * @apiName LeaveShare
1629: * @apiGroup Files
1630: *
1631: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1632: * @apiHeaderExample {json} Header-Example:
1633: * {
1634: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1635: * }
1636: *
1637: * @apiParam {string=Files} Module Module name
1638: * @apiParam {string=LeaveShare} Method Method name
1639: * @apiParam {string} Parameters JSON.stringified object <br>
1640: * {<br>
1641: * &emsp; **Type** *string* Type of storage - personal, corporate.<br>
1642: * &emsp; **Items** *array* Array of items to leave share.<br>
1643: * }
1644: *
1645: * @apiParamExample {json} Request-Example:
1646: * {
1647: * Module: 'Files',
1648: * Method: 'LeaveShare',
1649: * Parameters: '{ Type: "personal", Items: [{ "Path": "", "Name": "2.png" },
1650: * { "Path": "", "Name": "logo.png" }] }'
1651: * }
1652: *
1653: * @apiSuccess {object[]} Result Array of response objects.
1654: * @apiSuccess {string} Result.Module Module name
1655: * @apiSuccess {string} Result.Method Method name
1656: * @apiSuccess {bool} Result.Result Indicates if files and (or) folders were leave share successfully.
1657: * @apiSuccess {int} [Result.ErrorCode] Error code
1658: *
1659: * @apiSuccessExample {json} Success response example:
1660: * {
1661: * Module: 'Files',
1662: * Method: 'LeaveShare',
1663: * Result: true
1664: * }
1665: *
1666: * @apiSuccessExample {json} Error response example:
1667: * {
1668: * Module: 'Files',
1669: * Method: 'LeaveShare',
1670: * Result: false,
1671: * ErrorCode: 102
1672: * }
1673: */
1674:
1675: /**
1676: * Leave shared files and folder specified with list.
1677: *
1678: * @param int $UserId User identifier.
1679: * @param string $Type Type of storage - personal, corporate.
1680: * @param array $Items Array of items to leave.
1681: * @return bool
1682: * @throws \Aurora\System\Exceptions\ApiException
1683: */
1684: public function LeaveShare($UserId, $Type, $Items)
1685: {
1686: $aArgs = [
1687: 'UserId' => $UserId,
1688: 'Type' => $Type,
1689: 'Items' => $Items
1690: ];
1691: EventEmitter::getInstance()->emit('Files', 'Delete::before', $aArgs);
1692:
1693: $UserId = $aArgs['UserId'];
1694: $Type = $aArgs['Type'];
1695: $Items = $aArgs['Items'];
1696:
1697: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1698: $aNodes = [];
1699: $aItems = [];
1700: foreach ($Items as $aItem) {
1701: try {
1702: $oNode = Server::getNodeForPath(Constants::FILESTORAGE_PATH_ROOT . '/' . $Type . '/' . $aItem['Path'] . '/' . $aItem['Name']);
1703: $aItems[] = $oNode;
1704: } catch (\Exception $oEx) {
1705: Api::LogException($oEx);
1706: throw new ApiException(ErrorCodes::NotFound);
1707: }
1708:
1709: if (!($oNode instanceof \Afterlogic\DAV\FS\Shared\File || $oNode instanceof \Afterlogic\DAV\FS\Shared\Directory)) {
1710: throw new ApiException(ErrorCodes::CantDeleteSharedItem);
1711: }
1712:
1713: $oItem = new Classes\FileItem();
1714: $oItem->Id = $aItem['Name'];
1715: $oItem->Name = $aItem['Name'];
1716: $oItem->TypeStr = $Type;
1717: $oItem->Path = $aItem['Path'];
1718:
1719: self::Decorator()->DeletePublicLink($UserId, $Type, $aItem['Path'], $aItem['Name']);
1720: \Aurora\System\Managers\Thumb::RemoveFromCache($UserId, $oItem->getHash(), $aItem['Name']);
1721: }
1722:
1723: $aArgs = [
1724: 'UserId' => $UserId,
1725: 'Type' => $Type,
1726: 'Items' => $aItems
1727: ];
1728: $mResult = false;
1729:
1730: EventEmitter::getInstance()->emit('Files', 'LeaveShare', $aArgs, $mResult);
1731:
1732: return $mResult;
1733: }
1734:
1735: /**
1736: * @api {post} ?/Api/ Rename
1737: * @apiDescription Renames folder, file or link.
1738: * @apiName Rename
1739: * @apiGroup Files
1740: *
1741: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1742: * @apiHeaderExample {json} Header-Example:
1743: * {
1744: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1745: * }
1746: *
1747: * @apiParam {string=Files} Module Module name
1748: * @apiParam {string=Rename} Method Method name
1749: * @apiParam {string} Parameters JSON.stringified object <br>
1750: * {<br>
1751: * &emsp; **Type** *string* Type of storage - personal, corporate.<br>
1752: * &emsp; **Path** *string* Path to item to rename.<br>
1753: * &emsp; **Name** *string* Current name of the item.<br>
1754: * &emsp; **NewName** *string* New name of the item.<br>
1755: * &emsp; **IsLink** *bool* Indicates if the item is link or not.<br>
1756: * }
1757: *
1758: * @apiParamExample {json} Request-Example:
1759: * {
1760: * Module: 'Files',
1761: * Method: 'Rename',
1762: * Parameters: '{ Type: "personal", Path: "", Name: "old_name.png", NewName: "new_name.png",
1763: * IsLink: false }'
1764: * }
1765: *
1766: * @apiSuccess {object[]} Result Array of response objects.
1767: * @apiSuccess {string} Result.Module Module name
1768: * @apiSuccess {string} Result.Method Method name
1769: * @apiSuccess {bool} Result.Result Indicates if file or folder was renamed successfully.
1770: * @apiSuccess {int} [Result.ErrorCode] Error code
1771: *
1772: * @apiSuccessExample {json} Success response example:
1773: * {
1774: * Module: 'Files',
1775: * Method: 'Rename',
1776: * Result: true
1777: * }
1778: *
1779: * @apiSuccessExample {json} Error response example:
1780: * {
1781: * Module: 'Files',
1782: * Method: 'Rename',
1783: * Result: false,
1784: * ErrorCode: 102
1785: * }
1786: */
1787:
1788: /**
1789: * Renames folder, file or link.
1790: *
1791: * @param int $UserId User identifier.
1792: * @param string $Type Type of storage - personal, corporate.
1793: * @param string $Path Path to item to rename.
1794: * @param string $Name Current name of the item.
1795: * @param string $NewName New name of the item.
1796: * @param bool $IsLink Indicates if the item is link or not.
1797: * @return bool
1798: * @throws \Aurora\System\Exceptions\ApiException
1799: */
1800: public function Rename($UserId, $Type, $Path, $Name, $NewName, $IsLink)
1801: {
1802: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1803:
1804: if ($Name === '') {
1805: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
1806: }
1807:
1808: $oItem = new Classes\FileItem();
1809: $oItem->Id = $Name;
1810: $oItem->Name = $Name;
1811: $oItem->TypeStr = $Type;
1812: $oItem->Path = $Path;
1813:
1814: \Aurora\System\Managers\Thumb::RemoveFromCache($UserId, $oItem->getHash(), $Name);
1815: // Actual renaming is proceeded in subscribed methods. Look for it by "Files::Rename::after"
1816:
1817: return false;
1818: }
1819:
1820: /**
1821: * @api {post} ?/Api/ Copy
1822: * @apiDescription Copies files and/or folders from one folder to another.
1823: * @apiName Copy
1824: * @apiGroup Files
1825: *
1826: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1827: * @apiHeaderExample {json} Header-Example:
1828: * {
1829: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1830: * }
1831: *
1832: * @apiParam {string=Files} Module Module name
1833: * @apiParam {string=Copy} Method Method name
1834: * @apiParam {string} Parameters JSON.stringified object <br>
1835: * {<br>
1836: * &emsp; **FromType** *string* Storage type of folder items will be copied from.<br>
1837: * &emsp; **ToType** *string* Storage type of folder items will be copied to.<br>
1838: * &emsp; **FromPath** *string* Folder items will be copied from.<br>
1839: * &emsp; **ToPath** *string* Folder items will be copied to.<br>
1840: * &emsp; **Files** *array* List of items to copy<br>
1841: * }
1842: *
1843: * @apiParamExample {json} Request-Example:
1844: * {
1845: * Module: 'Files',
1846: * Method: 'Copy',
1847: * Parameters: '{ FromType: "personal", ToType: "corporate", FromPath: "", ToPath: "",
1848: * Files: [{ Name: "logo.png", IsFolder: false }, { Name: "details.png", IsFolder: false }] }'
1849: * }
1850: *
1851: * @apiSuccess {object[]} Result Array of response objects.
1852: * @apiSuccess {string} Result.Module Module name
1853: * @apiSuccess {string} Result.Method Method name
1854: * @apiSuccess {bool} Result.Result Indicates if files and (or) folders were copied successfully.
1855: * @apiSuccess {int} [Result.ErrorCode] Error code
1856: *
1857: * @apiSuccessExample {json} Success response example:
1858: * {
1859: * Module: 'Files',
1860: * Method: 'Copy',
1861: * Result: true
1862: * }
1863: *
1864: * @apiSuccessExample {json} Error response example:
1865: * {
1866: * Module: 'Files',
1867: * Method: 'Copy',
1868: * Result: false,
1869: * ErrorCode: 102
1870: * }]
1871: * }
1872: */
1873:
1874: /**
1875: * Copies files and/or folders from one folder to another.
1876: *
1877: * @param int $UserId User identifier.
1878: * @param string $FromType storage type of folder items will be copied from.
1879: * @param string $ToType storage type of folder items will be copied to.
1880: * @param string $FromPath folder items will be copied from.
1881: * @param string $ToPath folder items will be copied to.
1882: * @param array $Files list of items to copy {
1883: * *string* **Name** Name of item to copy.
1884: * *bool* **IsFolder** Indicates if the item to copy is folder or not.
1885: * }
1886: * @return bool
1887: * @throws \Aurora\System\Exceptions\ApiException
1888: */
1889: public function Copy($UserId, $FromType, $ToType, $FromPath, $ToPath, $Files)
1890: {
1891: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1892: return null;
1893: }
1894:
1895: /**
1896: * @api {post} ?/Api/ Move
1897: * @apiDescription Moves files and/or folders from one folder to another.
1898: * @apiName Move
1899: * @apiGroup Files
1900: *
1901: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1902: * @apiHeaderExample {json} Header-Example:
1903: * {
1904: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1905: * }
1906: *
1907: * @apiParam {string=Files} Module Module name
1908: * @apiParam {string=Move} Method Method name
1909: * @apiParam {string} Parameters JSON.stringified object <br>
1910: * {<br>
1911: * &emsp; **FromType** *string* Storage type of folder items will be moved from.<br>
1912: * &emsp; **ToType** *string* Storage type of folder items will be moved to.<br>
1913: * &emsp; **FromPath** *string* Folder items will be moved from.<br>
1914: * &emsp; **ToPath** *string* Folder items will be moved to.<br>
1915: * &emsp; **Files** *array* List of items to move<br>
1916: * }
1917: *
1918: * @apiParamExample {json} Request-Example:
1919: * {
1920: * Module: 'Files',
1921: * Method: 'Move',
1922: * Parameters: '{ FromType: "personal", ToType: "corporate", FromPath: "", ToPath: "",
1923: * Files: [{ "Name": "logo.png", "IsFolder": false },
1924: * { "Name": "details.png", "IsFolder": false }] }'
1925: * }
1926: *
1927: * @apiSuccess {object[]} Result Array of response objects.
1928: * @apiSuccess {string} Result.Module Module name
1929: * @apiSuccess {string} Result.Method Method name
1930: * @apiSuccess {bool} Result.Result Indicates if files and (or) folders were moved successfully.
1931: * @apiSuccess {int} [Result.ErrorCode] Error code
1932: *
1933: * @apiSuccessExample {json} Success response example:
1934: * {
1935: * Module: 'Files',
1936: * Method: 'Move',
1937: * Result: true
1938: * }
1939: *
1940: * @apiSuccessExample {json} Error response example:
1941: * {
1942: * Module: 'Files',
1943: * Method: 'Move',
1944: * Result: false,
1945: * ErrorCode: 102
1946: * }
1947: */
1948:
1949: /**
1950: * Moves files and/or folders from one folder to another.
1951: *
1952: * @param int $UserId User identifier.
1953: * @param string $FromType storage type of folder items will be moved from.
1954: * @param string $ToType storage type of folder items will be moved to.
1955: * @param string $FromPath folder items will be moved from.
1956: * @param string $ToPath folder items will be moved to.
1957: * @param array $Files list of items to move {
1958: * *string* **Name** Name of item to copy.
1959: * *bool* **IsFolder** Indicates if the item to copy is folder or not.
1960: * }
1961: * @return bool
1962: * @throws \Aurora\System\Exceptions\ApiException
1963: */
1964: public function Move($UserId, $FromType, $ToType, $FromPath, $ToPath, $Files)
1965: {
1966: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
1967: foreach ($Files as $aFile) {
1968: if (!$aFile['IsFolder']) {
1969: $oItem = new Classes\FileItem();
1970: $oItem->Id = $aFile['Name'];
1971: $oItem->Name = $aFile['Name'];
1972: $oItem->TypeStr = $FromType;
1973: $oItem->Path = $FromPath;
1974:
1975: \Aurora\System\Managers\Thumb::RemoveFromCache($UserId, $oItem->getHash(), $aFile['Name']);
1976: }
1977: }
1978:
1979: return false;
1980: }
1981:
1982: /**
1983: * @api {post} ?/Api/ CreatePublicLink
1984: * @apiDescription Creates public link for file or folder.
1985: * @apiName CreatePublicLink
1986: * @apiGroup Files
1987: *
1988: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
1989: * @apiHeaderExample {json} Header-Example:
1990: * {
1991: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
1992: * }
1993: *
1994: * @apiParam {string=Files} Module Module name
1995: * @apiParam {string=CreatePublicLink} Method Method name
1996: * @apiParam {string} Parameters JSON.stringified object <br>
1997: * {<br>
1998: * &emsp; **Type** *string* Type of storage contains the item.<br>
1999: * &emsp; **Path** *string* Path to the item.<br>
2000: * &emsp; **Name** *string* Name of the item.<br>
2001: * &emsp; **Size** *int* Size of the file.<br>
2002: * &emsp; **IsFolder** *bool* Indicates if the item is folder or not.<br>
2003: * }
2004: *
2005: * @apiParamExample {json} Request-Example:
2006: * {
2007: * Module: 'Files',
2008: * Method: 'CreatePublicLink',
2009: * Parameters: '{ Type: "personal", Path: "", Name: "image.png", Size: 100, "IsFolder": false }'
2010: * }
2011: *
2012: * @apiSuccess {object[]} Result Array of response objects.
2013: * @apiSuccess {string} Result.Module Module name
2014: * @apiSuccess {string} Result.Method Method name
2015: * @apiSuccess {mixed} Result.Result Public link to the item in case of success, otherwise **false**.
2016: * @apiSuccess {int} [Result.ErrorCode] Error code
2017: *
2018: * @apiSuccessExample {json} Success response example:
2019: * {
2020: * Module: 'Files',
2021: * Method: 'CreatePublicLink',
2022: * Result: 'AppUrl/?/files-pub/shared_item_hash/list'
2023: * }
2024: *
2025: * @apiSuccessExample {json} Error response example:
2026: * {
2027: * Module: 'Files',
2028: * Method: 'CreatePublicLink',
2029: * Result: false,
2030: * ErrorCode: 102
2031: * }
2032: */
2033:
2034: /**
2035: * Creates public link for file or folder.
2036: *
2037: * @param int $UserId User identifier.
2038: * @param string $Type Type of storage contains the item.
2039: * @param string $Path Path to the item.
2040: * @param string $Name Name of the item.
2041: * @param int $Size Size of the file.
2042: * @param bool $IsFolder Indicates if the item is folder or not.
2043: * @return string|false Public link to the item.
2044: * @throws \Aurora\System\Exceptions\ApiException
2045: */
2046: public function CreatePublicLink($UserId, $Type, $Path, $Name, $Size, $IsFolder)
2047: {
2048: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2049: return false;
2050: }
2051:
2052: /**
2053: * @api {post} ?/Api/ DeletePublicLink
2054: * @apiDescription Deletes public link from file or folder.
2055: * @apiName DeletePublicLink
2056: * @apiGroup Files
2057: *
2058: * @apiHeader {string} Authorization "Bearer " + Authentication token which was received as the result of Core.Login method.
2059: * @apiHeaderExample {json} Header-Example:
2060: * {
2061: * "Authorization": "Bearer 32b2ecd4a4016fedc4abee880425b6b8"
2062: * }
2063: *
2064: * @apiParam {string=Files} Module Module name
2065: * @apiParam {string=DeletePublicLink} Method Method name
2066: * @apiParam {string} Parameters JSON.stringified object <br>
2067: * {<br>
2068: * &emsp; **Type** *string* Type of storage contains the item.<br>
2069: * &emsp; **Path** *string* Path to the item.<br>
2070: * &emsp; **Name** *string* Name of the item.<br>
2071: * }
2072: *
2073: * @apiParamExample {json} Request-Example:
2074: * {
2075: * Module: 'Files',
2076: * Method: 'DeletePublicLink',
2077: * Parameters: '{ Type: "personal", Path: "", Name: "image.png" }'
2078: * }
2079: *
2080: * @apiSuccess {object[]} Result Array of response objects.
2081: * @apiSuccess {string} Result.Module Module name
2082: * @apiSuccess {string} Result.Method Method name
2083: * @apiSuccess {bool} Result.Result Indicated if public link was deleted successfully.
2084: * @apiSuccess {int} [Result.ErrorCode] Error code
2085: *
2086: * @apiSuccessExample {json} Success response example:
2087: * {
2088: * Module: 'Files',
2089: * Method: 'DeletePublicLink',
2090: * Result: true
2091: * }
2092: *
2093: * @apiSuccessExample {json} Error response example:
2094: * {
2095: * Module: 'Files',
2096: * Method: 'DeletePublicLink',
2097: * Result: false,
2098: * ErrorCode: 102
2099: * }
2100: */
2101:
2102: /**
2103: * Deletes public link from file or folder.
2104: *
2105: * @param int $UserId User identifier.
2106: * @param string $Type Type of storage contains the item.
2107: * @param string $Path Path to the item.
2108: * @param string $Name Name of the item.
2109: * @return bool
2110: * @throws \Aurora\System\Exceptions\ApiException
2111: */
2112: public function DeletePublicLink($UserId, $Type, $Path, $Name)
2113: {
2114: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2115: return false;
2116: }
2117:
2118: /**
2119: * Checks URL and returns information about it.
2120: *
2121: * @param string $Url URL to check.
2122: * @return array|bool {
2123: * Name
2124: * Thumb
2125: * Size
2126: * LinkType
2127: * }
2128: */
2129: public function CheckUrl($Url)
2130: {
2131: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2132: $mResult = false;
2133:
2134: if (substr($Url, 0, 11) === 'javascript:') {
2135: $Url = substr($Url, 11);
2136: }
2137:
2138: $aArgs = array(
2139: 'Url' => $Url
2140: );
2141: $this->broadcastEvent(
2142: 'CheckUrl',
2143: $aArgs,
2144: $mResult
2145: );
2146:
2147: return $mResult;
2148: }
2149:
2150: /**
2151: * @return array
2152: */
2153: public function GetFilesForUpload($UserId, $Hashes = array())
2154: {
2155: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2156: $sUUID = \Aurora\System\Api::getUserUUIDById($UserId);
2157:
2158: $mResult = false;
2159: if (is_array($Hashes) && 0 < count($Hashes)) {
2160: $mResult = array();
2161: foreach ($Hashes as $sHash) {
2162: $aData = \Aurora\System\Api::DecodeKeyValues($sHash);
2163: if (\is_array($aData) && 0 < \count($aData)) {
2164: $oFileInfo = self::Decorator()->GetFileInfo($UserId, $aData['Type'], $aData['Path'], $aData['Id']);
2165:
2166: $aArgs = array(
2167: 'UserId' => $UserId,
2168: 'Type' => $aData['Type'],
2169: 'Path' => $aData['Path'],
2170: 'Name' => $aData['Name'],
2171: 'Id' => $aData['Id']
2172: );
2173: $rFile = false;
2174: $this->broadcastEvent(
2175: 'GetFile',
2176: $aArgs,
2177: $rFile
2178: );
2179:
2180: $sTempName = md5('Files/Tmp/' . $aData['Type'] . $aData['Path'] . $aData['Name'] . microtime(true) . rand(1000, 9999));
2181:
2182: if (is_resource($rFile) && $this->getFilecacheManager()->putFile($sUUID, $sTempName, $rFile)) {
2183: $aItem = array(
2184: 'Name' => $oFileInfo->Name,
2185: 'TempName' => $sTempName,
2186: 'Size' => $oFileInfo->Size,
2187: 'Hash' => $sHash,
2188: 'MimeType' => ''
2189: );
2190:
2191: $aItem['MimeType'] = \MailSo\Base\Utils::MimeContentType($aItem['Name']);
2192: $aItem['NewHash'] = \Aurora\System\Api::EncodeKeyValues(array(
2193: 'TempFile' => true,
2194: 'UserId' => $UserId,
2195: 'Name' => $aItem['Name'],
2196: 'TempName' => $sTempName
2197: ));
2198:
2199: $aActions = array(
2200: 'view' => array(
2201: 'url' => '?file-cache/' . $aItem['NewHash'] . '/view'
2202: ),
2203: 'download' => array(
2204: 'url' => '?file-cache/' . $aItem['NewHash']
2205: )
2206: );
2207: $aItem['Actions'] = $aActions;
2208:
2209: $mResult[] = $aItem;
2210:
2211: if (is_resource($rFile)) {
2212: @fclose($rFile);
2213: }
2214: }
2215: }
2216: }
2217: } else {
2218: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
2219: }
2220:
2221: return $mResult;
2222: }
2223:
2224: /**
2225: * Checks if file exists.
2226: *
2227: * @param int $UserId
2228: * @param string $Type
2229: * @param string $Path
2230: * @param string $Name
2231: */
2232: public function IsFileExists($UserId, $Type, $Path, $Name)
2233: {
2234: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2235: return true;
2236: }
2237:
2238: /**
2239: *
2240: * @param int $UserId
2241: * @param string $Type
2242: * @param string $Path
2243: * @param string $Name
2244: */
2245: public function GetNonExistentFileName($UserId, $Type, $Path, $Name, $WithoutGroup = false)
2246: {
2247: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2248: return $Name;
2249: }
2250:
2251: /**
2252: *
2253: * @param int $UserId
2254: * @param array $Files
2255: */
2256: public function SaveFilesAsTempFiles($UserId, $Files)
2257: {
2258: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2259:
2260: $mResult = false;
2261:
2262: if (is_array($Files) && count($Files) > 0) {
2263: $mResult = array();
2264: foreach ($Files as $aFile) {
2265: $Storage = $aFile['Storage'];
2266: $Path = $aFile['Path'];
2267: $Name = $aFile['Name'];
2268: $Id = $aFile['Name'];
2269:
2270: $aArgs = array(
2271: 'UserId' => $UserId,
2272: 'Type' => $Storage,
2273: 'Path' => $Path,
2274: 'Name' => &$Name,
2275: 'Id' => $Id,
2276: 'IsThumb' => false,
2277: 'Offset' => 0,
2278: 'ChunkSize' => 0
2279: );
2280: $mFileResource = false;
2281: $this->broadcastEvent(
2282: 'GetFile',
2283: $aArgs,
2284: $mFileResource
2285: );
2286:
2287: if (is_resource($mFileResource)) {
2288: $sUUID = \Aurora\System\Api::getUserUUIDById($UserId);
2289: try {
2290: $sTempName = md5($sUUID . $Storage . $Path . $Name);
2291:
2292: if (!$this->getFilecacheManager()->isFileExists($sUUID, $sTempName)) {
2293: $this->getFilecacheManager()->putFile($sUUID, $sTempName, $mFileResource);
2294: }
2295:
2296: if ($this->getFilecacheManager()->isFileExists($sUUID, $sTempName)) {
2297: $mResult[] = \Aurora\System\Utils::GetClientFileResponse(
2298: null,
2299: $UserId,
2300: $Name,
2301: $sTempName,
2302: $this->getFilecacheManager()->fileSize($sUUID, $sTempName)
2303: );
2304: }
2305: } catch (\Exception $oException) {
2306: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::FilesNotAllowed, $oException);
2307: }
2308: }
2309: }
2310: }
2311:
2312: return $mResult;
2313: }
2314:
2315: public function UpdateSettingsForEntity($EntityType, $EntityId, $UserSpaceLimitMb, $TenantSpaceLimitMb)
2316: {
2317: $bResult = false;
2318: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
2319:
2320: if ($EntityType === '') {
2321: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
2322: $this->setConfig('TenantSpaceLimitMb', $TenantSpaceLimitMb);
2323: $this->setConfig('UserSpaceLimitMb', $UserSpaceLimitMb);
2324: return $this->saveModuleConfig();
2325: }
2326: if ($EntityType === 'Tenant') {
2327: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
2328: $oTenant = \Aurora\Modules\Core\Module::Decorator()->GetTenantWithoutRoleCheck($EntityId);
2329:
2330: if ($oTenant instanceof Tenant
2331: && $oAuthenticatedUser instanceof User
2332: && (($oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::TenantAdmin && $oTenant->Id === $oAuthenticatedUser->IdTenant)
2333: || $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin)) {
2334: if ($oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin) {
2335: $oTenant->setExtendedProp(self::GetName() . '::TenantSpaceLimitMb', $TenantSpaceLimitMb);
2336: }
2337: if (is_int($UserSpaceLimitMb)) {
2338: if ($UserSpaceLimitMb <= $TenantSpaceLimitMb || $TenantSpaceLimitMb === 0) {
2339: $oTenant->setExtendedProp(self::GetName() . '::UserSpaceLimitMb', $UserSpaceLimitMb);
2340: } else {
2341: throw new \Aurora\System\Exceptions\ApiException(1, null, 'User space limit must be less then tenant space limit');
2342: }
2343: }
2344:
2345: $bResult = \Aurora\Modules\Core\Module::Decorator()->UpdateTenantObject($oTenant);
2346: }
2347: }
2348: if ($EntityType === 'User') {
2349: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
2350: $oUser = \Aurora\Modules\Core\Module::Decorator()->GetUserWithoutRoleCheck($EntityId);
2351:
2352: if ($oUser instanceof \Aurora\Modules\Core\Models\User
2353: && $oAuthenticatedUser instanceof \Aurora\Modules\Core\Models\User
2354: && (($oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::TenantAdmin && $oUser->IdTenant === $oAuthenticatedUser->IdTenant)
2355: || $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin)) {
2356: $oTenant = \Aurora\Modules\Core\Module::Decorator()->GetTenantWithoutRoleCheck($oUser->IdTenant);
2357:
2358: $iTenantSpaceLimitMb = $oTenant->getExtendedProp(self::GetName() . '::TenantSpaceLimitMb');
2359: if ($iTenantSpaceLimitMb > 0) {
2360: $iAllocatedSpaceForUsersInTenant = $this->GetAllocatedSpaceForUsersInTenant($oUser->IdTenant);
2361: $iNewAllocatedSpaceForUsersInTenant = $iAllocatedSpaceForUsersInTenant - $oUser->getExtendedProp(self::GetName() . '::UserSpaceLimitMb') + $UserSpaceLimitMb;
2362: if ($iNewAllocatedSpaceForUsersInTenant > $iTenantSpaceLimitMb) {
2363: throw new \Aurora\System\Exceptions\ApiException(1, null, 'Over quota');
2364: }
2365: }
2366:
2367: $oUser->setExtendedProp(self::GetName() . '::UserSpaceLimitMb', $UserSpaceLimitMb);
2368:
2369: $bResult = \Aurora\Modules\Core\Module::Decorator()->UpdateUserObject($oUser);
2370: }
2371: }
2372:
2373: return $bResult;
2374: }
2375:
2376: public function UpdateUserSpaceLimit($UserId, $Limit)
2377: {
2378: $mResult = false;
2379: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::TenantAdmin);
2380:
2381: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
2382: $oUser = \Aurora\Modules\Core\Module::Decorator()->GetUserWithoutRoleCheck($UserId);
2383:
2384: if ($oUser instanceof \Aurora\Modules\Core\Models\User && $oAuthenticatedUser instanceof \Aurora\Modules\Core\Models\User && (
2385: ($oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::TenantAdmin && $oUser->IdTenant === $oAuthenticatedUser->IdTenant) ||
2386: $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin
2387: )
2388: ) {
2389: $oUser->setExtendedProp(self::GetName() . '::UserSpaceLimitMb', $Limit);
2390: $mResult = \Aurora\Modules\Core\Module::Decorator()->UpdateUserObject($oUser);
2391: }
2392:
2393: return $mResult;
2394: }
2395:
2396: public function UpdateTenantSpaceLimit($TenantId, $Limit)
2397: {
2398: $mResult = false;
2399: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::SuperAdmin);
2400:
2401: $oAuthenticatedUser = \Aurora\System\Api::getAuthenticatedUser();
2402: $oTenant = \Aurora\Modules\Core\Module::Decorator()->GetTenantWithoutRoleCheck($TenantId);
2403:
2404: if ($oTenant instanceof Tenant && $oAuthenticatedUser instanceof User && (
2405: ($oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::TenantAdmin && $oTenant->Id === $oAuthenticatedUser->IdTenant) ||
2406: $oAuthenticatedUser->Role === \Aurora\System\Enums\UserRole::SuperAdmin
2407: )
2408: ) {
2409: $oTenant->setExtendedProp(self::GetName() . '::UserSpaceLimitMb', $Limit);
2410: $mResult = \Aurora\Modules\Core\Module::Decorator()->UpdateUserObject($oTenant);
2411: }
2412:
2413: return $mResult;
2414: }
2415:
2416: public function GetAllocatedSpaceForUsersInTenant($TenantId)
2417: {
2418: return User::where('IdTenant', $TenantId)->sum('Properties->Files::UserSpaceLimitMb');
2419: }
2420:
2421: public function CheckAllocatedSpaceLimitForUsersInTenant($oTenant, $UserSpaceLimitMb)
2422: {
2423: $iTenantSpaceLimitMb = $oTenant->getExtendedProp(self::GetName() . '::TenantSpaceLimitMb');
2424: $iAllocatedSpaceForUsersInTenant = $this->GetAllocatedSpaceForUsersInTenant($oTenant->Id);
2425:
2426: if ($iTenantSpaceLimitMb > 0 && $iAllocatedSpaceForUsersInTenant + $UserSpaceLimitMb > $iTenantSpaceLimitMb) {
2427: throw new \Aurora\System\Exceptions\ApiException(1, null, 'Over quota');
2428: }
2429: }
2430:
2431: /**
2432: * Update ExtendedProps
2433: *
2434: * @param int $UserId
2435: * @param string $Type Type of storage contains the item.
2436: * @param string $Path Path to the item.
2437: * @param string $Name Name of the item.
2438: * @param array $ExtendedProps
2439: * @return bool
2440: */
2441:
2442: public function UpdateExtendedProps($UserId, $Type, $Path, $Name, $ExtendedProps)
2443: {
2444: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2445:
2446: return false;
2447: // Actual updating is preceded in subscribed methods. Look for it by "Files::UpdateExtendedProps::after"
2448: }
2449:
2450: public function GetExtendedProps($UserId = null, $Type = null, $Path = null, $Name = null)
2451: {
2452: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2453:
2454: if ($UserId === null || $Type === null || $Path === null || $Name === null) {
2455: throw new \Aurora\System\Exceptions\ApiException(\Aurora\System\Notifications::InvalidInputParameter);
2456: }
2457:
2458: return false;
2459: // Actual updating is preceded in subscribed methods. Look for it by "Files::GetExtendedProps::after"
2460: }
2461:
2462: public function GetAccessInfoForPath($UserId, $Type, $Path)
2463: {
2464: \Aurora\System\Api::checkUserRoleIsAtLeast(\Aurora\System\Enums\UserRole::NormalUser);
2465:
2466: // Actual updating is preceded in subscribed methods. Look for it by "Files::GetInfoForPath::after"
2467: return false;
2468: }
2469: /***** public functions might be called with web API *****/
2470: }
2471: