getHeader()->set('Content-Type', MimeType::M_JSON, true); $response->set( $request->getUri()->__toString(), \array_values( MediaMapper::find((string) ($request->getData('search') ?? '')) ) ); } /** * Api method to upload media file. * * @param RequestAbstract $request Request * @param ResponseAbstract $response Response * @param mixed $data Generic data * * @return void * * @api * * @since 1.0.0 */ public function apiMediaUpload(RequestAbstract $request, ResponseAbstract $response, $data = null) : void { $uploads = $this->uploadFiles( $request->getData('name') === null || $request->getFiles() !== null ? '' : $request->getData('name'), $request->getFiles(), $request->getHeader()->getAccount(), (string) ($request->getData('path') ?? __DIR__ . '/../../../Modules/Media/Files'), (string) ($request->getData('virtualPath') ?? ''), (string) ($request->getData('password') ?? ''), (string) ($request->getData('encrypt') ?? ''), (int) ($request->getData('pathsettings') ?? PathSettings::RANDOM_PATH) ); $ids = []; foreach ($uploads as $file) { $ids[] = $file->getId(); } $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Media', 'Media successfully created.', $ids); } /** * Upload a media file * * @param string $name Name * @param array $files Files * @param int $account Uploader * @param string $basePath Base path. The path which is used for the upload. * @param string $virtualPath Virtual path The path which is used to visually structure the files, like directories. * The file storage on the system can be different * @param string $password File password. The password to protect the file (only database) * @param string $encryptionKey Encryption key. Used to encrypt the file on the local file storage. * @param int $pathSettings Settings which describe where the file should be uploaded to (physically) * RANDOM_PATH = random location in the base path * FILE_PATH = combination of base path and virtual path * * @return array * * @since 1.0.0 */ public function uploadFiles( string $name, array $files, int $account, string $basePath = 'Modules/Media/Files', string $virtualPath = '', string $password = '', string $encryptionKey = '', int $pathSettings = PathSettings::RANDOM_PATH ) : array { $mediaCreated = []; if (!empty($files)) { $outputDir = ''; $absolute = false; if ($pathSettings === PathSettings::RANDOM_PATH) { $outputDir = self::createMediaPath($basePath); } elseif ($pathSettings === PathSettings::FILE_PATH) { $outputDir = $basePath . $virtualPath; $absolute = true; } else { return $mediaCreated; } $upload = new UploadFile(); $upload->setOutputDir($outputDir); $status = $upload->upload($files, $name, $absolute, $encryptionKey); $mediaCreated = $this->createDbEntries($status, $account, $virtualPath); } return $mediaCreated; } /** * Create a random file path to store media files * * @param string $basePath Base path for file storage * * @return string Random path to store media files * * @since 1.0.0 */ public static function createMediaPath(string $basePath = 'Modules/Media/Files') : string { $rndPath = \str_pad(\dechex(\mt_rand(0, 65535)), 4, '0', \STR_PAD_LEFT); return $basePath . '/' . $rndPath[0] . $rndPath[1] . '/' . $rndPath[2] . $rndPath[3]; } /** * @param array $status Files * @param int $account Uploader * * @return Media[] * * @since 1.0.0 */ public function createDbEntries(array $status, int $account, string $virtualPath = '') : array { $mediaCreated = []; foreach ($status as $uFile) { if (($created = self::createDbEntry($uFile, $account, $virtualPath)) !== null) { $mediaCreated[] = $created; $this->app->moduleManager->get('Admin')->createAccountModelPermission( new AccountPermission( $account, $this->app->orgId, $this->app->appName, self::MODULE_NAME, PermissionState::MEDIA, $created->getId(), null, PermissionType::READ | PermissionType::MODIFY | PermissionType::DELETE | PermissionType::PERMISSION ), $account ); } } return $mediaCreated; } /** * Create db entry for uploaded file * * @param array $status Files * @param int $account Uploader * @param string $virtualPath Virtual path (not on the hard-drive) * * @return null|Media * * @since 1.0.0 */ public static function createDbEntry(array $status, int $account, string $virtualPath = '') : ?Media { $media = null; if ($status['status'] === UploadStatus::OK) { $media = new Media(); $media->setPath(self::normalizeDbPath($status['path']) . '/' . $status['filename']); $media->setName($status['name']); $media->setSize($status['size']); $media->setCreatedBy(new NullAccount($account)); $media->setExtension($status['extension']); $media->setVirtualPath($virtualPath); MediaMapper::create($media); } return $media; } /** * Normalize the file path * * @param string $path Path to the file * * @return string * * @since 1.0.0 */ private static function normalizeDbPath(string $path) : string { $realpath = \realpath(__DIR__ . '/../../../'); if ($realpath === false) { throw new \Exception(); } return \str_replace('\\', '/', \str_replace($realpath, '', \rtrim($path, '/') ) ); } /** * Api method to update media. * * @param RequestAbstract $request Request * @param ResponseAbstract $response Response * @param mixed $data Generic data * * @return void * * @api * * @since 1.0.0 */ public function apiMediaUpdate(RequestAbstract $request, ResponseAbstract $response, $data = null) : void { $old = clone MediaMapper::get((int) $request->getData('id')); $new = $this->updateMediaFromRequest($request); $this->updateModel($request->getHeader()->getAccount(), $old, $new, MediaMapper::class, 'media'); $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Media', 'Media successfully updated', $new); } /** * Method to update media from request. * * @param RequestAbstract $request Request * * @return Media * * @since 1.0.0 */ private function updateMediaFromRequest(RequestAbstract $request) : Media { $media = MediaMapper::get((int) $request->getData('id')); $media->setName((string) ($request->getData('name') ?? $media->getName())); $media->setVirtualPath((string) ($request->getData('virtualpath') ?? $media->getVirtualPath())); if ($request->getData('content') !== null) { \file_put_contents( $media->isAbsolute() ? $media->getPath() : __DIR__ . '/../../../' . \ltrim($media->getPath(), '/'), $request->getData('content') ); $media->setSize(\strlen($request->getData('content'))); } return $media; } /** * Api method to create a collection. * * @param RequestAbstract $request Request * @param ResponseAbstract $response Response * @param mixed $data Generic data * * @return void * * @api * * @since 1.0.0 */ public function apiCollectionCreate(RequestAbstract $request, ResponseAbstract $response, $data = null) : void { if (!empty($val = $this->validateCollectionCreate($request))) { $response->set('collection_create', new FormValidation($val)); return; } $collection = $this->createCollectionFromRequest($request); $this->createModel($request->getHeader()->getAccount(), $collection, CollectionMapper::class, 'collection'); $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Collection', 'Collection successfully created.', $collection); } /** * Validate collection create request * * @param RequestAbstract $request Request * * @return array Returns the validation array of the request * * @since 1.0.0 */ private function validateCollectionCreate(RequestAbstract $request) : array { $val = []; if (($val['name'] = empty($request->getData('name'))) || ($val['media'] = empty($request->getDataJson('media-list'))) ) { return $val; } return []; } /** * Method to create collection from request. * * @param RequestAbstract $request Request * * @return Collection Returns the collection from the request * * @since 1.0.0 */ private function createCollectionFromRequest(RequestAbstract $request) : Collection { $mediaCollection = new Collection(); $mediaCollection->setName($request->getData('name') ?? ''); $mediaCollection->setDescription($description = Markdown::parse($request->getData('description') ?? '')); $mediaCollection->setDescriptionRaw($description); $mediaCollection->setCreatedBy(new NullAccount($request->getHeader()->getAccount())); $media = $request->getDataJson('media-list'); foreach ($media as $file) { $mediaCollection->addSource(new NullMedia((int) $file)); } $mediaCollection->setVirtualPath($request->getData('virtualpath') ?? '/'); $mediaCollection->setPath($request->getData('virtualpath') ?? '/'); CollectionMapper::create($mediaCollection); return $mediaCollection; } /** * Method to create media collection from request. * * @param string $name Collection name * @param string $description Description * @param Media[] $media Media files to create the collection from * @param int $account Account Id * * @return Collection * * @since 1.0.0 */ public function createMediaCollectionFromMedia(string $name, string $description, array $media, int $account) : Collection { if (empty($media)) { return new NullCollection(); } // is allowed to create media file if (!$this->app->accountManager->get($account)->hasPermission( PermissionType::CREATE, $this->app->orgId, null, self::MODULE_NAME, PermissionState::COLLECTION, null) ) { return new NullCollection(); } /* Create collection */ $mediaCollection = new Collection(); $mediaCollection->setName($name); $mediaCollection->setDescription(Markdown::parse($description)); $mediaCollection->setDescriptionRaw($description); $mediaCollection->setCreatedBy(new NullAccount($account)); $mediaCollection->setSources($media); $mediaCollection->setVirtualPath('/Modules/Helper'); $mediaCollection->setPath('/Modules/Helper'); CollectionMapper::create($mediaCollection); return $mediaCollection; } /** * Api method to create media file. * * @param RequestAbstract $request Request * @param ResponseAbstract $response Response * @param mixed $data Generic data * * @return void * * @api * * @since 1.0.0 */ public function apiMediaCreate(RequestAbstract $request, ResponseAbstract $response, $data = null) : void { $virtualPath = (string) ($request->getData('path') ?? ''); $fileName = (string) ($request->getData('fileName') ?? ''); $pathSettings = (int) ($request->getData('pathsettings') ?? PathSettings::RANDOM_PATH); $outputDir = ''; if ($pathSettings === PathSettings::RANDOM_PATH) { $outputDir = self::createMediaPath(__DIR__ . '/../../../Modules/Media/Files'); } elseif ($pathSettings === PathSettings::FILE_PATH) { $outputDir = __DIR__ . '/../../../Modules/Media/Files/' . \ltrim($virtualPath, '\\/'); } \file_put_contents($outputDir . '/' . $fileName, (string) ($request->getData('content') ?? '')); $status = [ [ 'status' => UploadStatus::OK, 'path' => $outputDir . '/' . $fileName, 'filename' => $fileName, 'name' => $request->getData('name') ?? '', 'size' => \strlen((string) ($request->getData('content') ?? '')), 'extension' => \substr($fileName, \strripos($fileName, '.')), ], ]; $created = $this->createDbEntries($status, $request->getHeader()->getAccount(), $virtualPath); $ids = []; foreach ($created as $file) { $ids[] = $file->getId(); } $this->fillJsonResponse($request, $response, NotificationLevel::OK, 'Media', 'Media successfully created.', $ids); } }