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