From 47f80c5e673100acabc11a6ef6104371d26486a6 Mon Sep 17 00:00:00 2001 From: Awilum Date: Mon, 29 Jun 2020 19:52:03 +0300 Subject: [PATCH] feat(media): general code updates for media apis #428 --- src/flextype/bootstrap.php | 1 + src/flextype/core/Media/MediaFilesMeta.php | 23 +- src/flextype/core/Media/MediaFolders.php | 79 +++++ src/flextype/core/Media/MediaFoldersMeta.php | 17 ++ src/flextype/endpoints/files.php | 286 ++++++++++++++++++- src/flextype/endpoints/folders.php | 102 +++++++ 6 files changed, 498 insertions(+), 10 deletions(-) create mode 100644 src/flextype/endpoints/folders.php diff --git a/src/flextype/bootstrap.php b/src/flextype/bootstrap.php index 7afb0adc..cb5dc826 100755 --- a/src/flextype/bootstrap.php +++ b/src/flextype/bootstrap.php @@ -133,6 +133,7 @@ include_once 'endpoints/entries.php'; include_once 'endpoints/registry.php'; include_once 'endpoints/config.php'; include_once 'endpoints/files.php'; +include_once 'endpoints/folders.php'; include_once 'endpoints/images.php'; /** diff --git a/src/flextype/core/Media/MediaFilesMeta.php b/src/flextype/core/Media/MediaFilesMeta.php index 69180ec8..3a60d186 100644 --- a/src/flextype/core/Media/MediaFilesMeta.php +++ b/src/flextype/core/Media/MediaFilesMeta.php @@ -17,6 +17,23 @@ use Slim\Http\Uri; class MediaFilesMeta { + /** + * Flextype Dependency Container + * + * @access private + */ + private $flextype; + + /** + * Constructor + * + * @access public + */ + public function __construct($flextype) + { + $this->flextype = $flextype; + } + /** * Update file meta information * @@ -28,7 +45,7 @@ class MediaFilesMeta * * @access public */ - public function updateMeta(string $id, string $field, string $value) : bool + public function update(string $id, string $field, string $value) : bool { $file_data = $this->flextype['serializer']->decode(Filesystem::read($this->getFileMetaLocation($id)), 'yaml'); @@ -51,7 +68,7 @@ class MediaFilesMeta * * @access public */ - public function addMeta(string $id, string $field, string $value) : bool + public function add(string $id, string $field, string $value) : bool { $file_data = $this->flextype['serializer']->decode(Filesystem::read($this->getFileMetaLocation($id)), 'yaml'); @@ -73,7 +90,7 @@ class MediaFilesMeta * * @access public */ - public function deleteMeta(string $id, string $field) : bool + public function delete(string $id, string $field) : bool { $file_data = $this->flextype['serializer']->decode(Filesystem::read($this->getFileMetaLocation($id)), 'yaml'); diff --git a/src/flextype/core/Media/MediaFolders.php b/src/flextype/core/Media/MediaFolders.php index 05f396d5..4e79beb0 100644 --- a/src/flextype/core/Media/MediaFolders.php +++ b/src/flextype/core/Media/MediaFolders.php @@ -34,6 +34,85 @@ class MediaFolders $this->flextype = $flextype; } + /** + * Fetch folders(s) + * + * @param string $path The path of directory to list. + * @param string $mode The mode, collection or single + * + * @return array A list of file(s) metadata. + */ + public function fetch(string $path, string $mode = 'collection') : array + { + if ($mode == 'collection') { + $result = $this->fetchCollection($path); + } elseif ($mode == 'single') { + $result = $this->fetchSingle($path); + } + + return $result; + } + + /** + * Fetch single folder + * + * @param string $path The path to file. + * + * @return array A file metadata. + */ + public function fetchsingle(string $path) : array + { + $result = []; + + if (Filesystem::has($this->flextype['media_folders_meta']->getDirMetaLocation($path))) { + + $result['path'] = $path; + $result['full_path'] = str_replace("/.meta", "", $this->flextype['media_folders_meta']->getDirMetaLocation($path)); + $result['url'] = 'project/uploads/' . $path; + + if ($this->flextype['registry']->has('flextype.settings.url') && $this->flextype['registry']->get('flextype.settings.url') != '') { + $full_url = $this->flextype['registry']->get('flextype.settings.url'); + } else { + $full_url = Uri::createFromEnvironment(new Environment($_SERVER))->getBaseUrl(); + } + + $result['full_url'] = $full_url . '/project/uploads/' . $path; + } + + return $result; + } + + /** + * Fetch folder collection + * + * @param string $path The path to files collection. + * + * @return array A list of files metadata. + */ + public function fetchCollection(string $path) : array + { + $result = []; + + foreach (Filesystem::listContents($this->flextype['media_folders_meta']->getDirMetaLocation($path)) as $folder) { + if ($folder['type'] == 'dir') { + + $result[$folder['dirname']]['full_path'] = str_replace("/.meta", "", $this->flextype['media_folders_meta']->getDirMetaLocation($folder['dirname'])); + $result[$folder['dirname']]['url'] = 'project/uploads/' . $folder['dirname']; + + if ($this->flextype['registry']->has('flextype.settings.url') && $this->flextype['registry']->get('flextype.settings.url') != '') { + $full_url = $this->flextype['registry']->get('flextype.settings.url'); + } else { + $full_url = Uri::createFromEnvironment(new Environment($_SERVER))->getBaseUrl(); + } + + $result[$folder['dirname']]['full_url'] = $full_url . '/project/uploads/' . $folder['dirname']; + } + } + + return $result; + } + + /** * Create folder * diff --git a/src/flextype/core/Media/MediaFoldersMeta.php b/src/flextype/core/Media/MediaFoldersMeta.php index fa8ea7fe..93d49a57 100644 --- a/src/flextype/core/Media/MediaFoldersMeta.php +++ b/src/flextype/core/Media/MediaFoldersMeta.php @@ -11,6 +11,23 @@ namespace Flextype; class MediaFoldersMeta { + /** + * Flextype Dependency Container + * + * @access private + */ + private $flextype; + + /** + * Constructor + * + * @access public + */ + public function __construct($flextype) + { + $this->flextype = $flextype; + } + /** * Get files directory meta location * diff --git a/src/flextype/endpoints/files.php b/src/flextype/endpoints/files.php index b0d6571e..e9c809b5 100644 --- a/src/flextype/endpoints/files.php +++ b/src/flextype/endpoints/files.php @@ -281,7 +281,7 @@ $app->put('/api/files', function (Request $request, Response $response) use ($fl /** * Delete file * - * endpoint: DELETE /api/entries + * endpoint: DELETE /api/files * * Body: * id - [REQUIRED] - Unique identifier of the file. @@ -291,7 +291,7 @@ $app->put('/api/files', function (Request $request, Response $response) use ($fl * Returns: * Returns an empty body with HTTP status 204 */ -$app->delete('/api/entries', function (Request $request, Response $response) use ($flextype) { +$app->delete('/api/files', function (Request $request, Response $response) use ($flextype) { // Get Post Data $post_data = $request->getParsedBody(); @@ -301,14 +301,14 @@ $app->delete('/api/entries', function (Request $request, Response $response) use $access_token = $post_data['access_token']; $id = $post_data['id']; - if ($flextype['registry']->get('flextype.settings.api.entries.enabled')) { + if ($flextype['registry']->get('flextype.settings.api.files.enabled')) { - // Validate entries and access token - if (validate_entries_token($token) && validate_access_token($access_token)) { - $files_token_file_path = PATH['project'] . '/tokens/entries/' . $token . '/token.yaml'; + // Validate files and access token + if (validate_files_token($token) && validate_access_token($access_token)) { + $files_token_file_path = PATH['project'] . '/tokens/files/' . $token . '/token.yaml'; $access_token_file_path = PATH['project'] . '/tokens/access/' . $access_token . '/token.yaml'; - // Set entries and access token file + // Set files and access token file if (($files_token_file_data = $flextype['serializer']->decode(Filesystem::read($files_token_file_path), 'yaml')) && ($access_token_file_data = $flextype['serializer']->decode(Filesystem::read($access_token_file_path), 'yaml'))) { @@ -354,3 +354,275 @@ $app->delete('/api/entries', function (Request $request, Response $response) use return $response ->withJson($api_sys_messages['AccessTokenInvalid'], 401); }); + +/** + * Update file meta information + * + * endpoint: PATCH /api/files/meta + * + * Body: + * path - [REQUIRED] - File path. + * field - [REQUIRED] - Field name. + * value - [REQUIRED] - Field value. + * token - [REQUIRED] - Valid Entries token. + * access_token - [REQUIRED] - Valid Access token. + * + * Returns: + * Returns the file object for the file that was just created. + */ +$app->patch('/api/files/meta', function (Request $request, Response $response) use ($flextype, $api_sys_messages) { + + // Get Post Data + $post_data = $request->getParsedBody(); + + // Set variables + $token = $post_data['token']; + $access_token = $post_data['access_token']; + $path = $post_data['path']; + $field = $post_data['field']; + $value = $post_data['value']; + + if ($flextype['registry']->get('flextype.settings.api.files.enabled')) { + + // Validate files and access token + if (validate_files_token($token) && validate_access_token($access_token)) { + $files_token_file_path = PATH['project'] . '/tokens/files/' . $token . '/token.yaml'; + $access_token_file_path = PATH['project'] . '/tokens/access/' . $access_token . '/token.yaml'; + + // Set files and access token file + if (($files_token_file_data = $flextype['serializer']->decode(Filesystem::read($files_token_file_path), 'yaml')) && + ($access_token_file_data = $flextype['serializer']->decode(Filesystem::read($access_token_file_path), 'yaml'))) { + + if ($files_token_file_data['state'] === 'disabled' || + ($files_token_file_data['limit_calls'] !== 0 && $files_token_file_data['calls'] >= $files_token_file_data['limit_calls'])) { + return $response->withJson($api_sys_messages['AccessTokenInvalid'], 401); + } + + if ($access_token_file_data['state'] === 'disabled' || + ($access_token_file_data['limit_calls'] !== 0 && $access_token_file_data['calls'] >= $access_token_file_data['limit_calls'])) { + return $response->withJson($api_sys_messages['AccessTokenInvalid'], 401); + } + + // Update file meta + $update_file_meta = $flextype['media_files_meta']->update($path, $field, $value); + + if ($update_file_meta) { + $response_data['data'] = $flextype['media_files']->fetch($path); + } else { + $response_data['data'] = []; + } + + // Set response code + $response_code = ($update_file_meta) ? 200 : 404; + + // Return response + return $response + ->withJson($response_data, $response_code); + + // Update calls counter + Filesystem::write($files_token_file_path, $flextype['serializer']->encode(array_replace_recursive($files_token_file_data, ['calls' => $files_token_file_data['calls'] + 1]), 'yaml')); + + if ($response_code == 404) { + + // Return response + return $response + ->withJson($api_sys_messages['NotFound'], $response_code); + } + + // Return response + return $response + ->withJson($response_data, $response_code); + } + + return $response + ->withJson($api_sys_messages['AccessTokenInvalid'], 401); + } + + return $response + ->withJson($api_sys_messages['AccessTokenInvalid'], 401); + } + + return $response + ->withJson($api_sys_messages['AccessTokenInvalid'], 401); +}); + +/** + * Add file meta information + * + * endpoint: POST /api/files/meta + * + * Body: + * path - [REQUIRED] - File path. + * field - [REQUIRED] - Field name. + * value - [REQUIRED] - Field value. + * token - [REQUIRED] - Valid Entries token. + * access_token - [REQUIRED] - Valid Access token. + * + * Returns: + * Returns the file object for the file that was just created. + */ +$app->post('/api/files/meta', function (Request $request, Response $response) use ($flextype, $api_sys_messages) { + + // Get Post Data + $post_data = $request->getParsedBody(); + + // Set variables + $token = $post_data['token']; + $access_token = $post_data['access_token']; + $path = $post_data['path']; + $field = $post_data['field']; + $value = $post_data['value']; + + if ($flextype['registry']->get('flextype.settings.api.files.enabled')) { + + // Validate files and access token + if (validate_files_token($token) && validate_access_token($access_token)) { + $files_token_file_path = PATH['project'] . '/tokens/files/' . $token . '/token.yaml'; + $access_token_file_path = PATH['project'] . '/tokens/access/' . $access_token . '/token.yaml'; + + // Set files and access token file + if (($files_token_file_data = $flextype['serializer']->decode(Filesystem::read($files_token_file_path), 'yaml')) && + ($access_token_file_data = $flextype['serializer']->decode(Filesystem::read($access_token_file_path), 'yaml'))) { + + if ($files_token_file_data['state'] === 'disabled' || + ($files_token_file_data['limit_calls'] !== 0 && $files_token_file_data['calls'] >= $files_token_file_data['limit_calls'])) { + return $response->withJson($api_sys_messages['AccessTokenInvalid'], 401); + } + + if ($access_token_file_data['state'] === 'disabled' || + ($access_token_file_data['limit_calls'] !== 0 && $access_token_file_data['calls'] >= $access_token_file_data['limit_calls'])) { + return $response->withJson($api_sys_messages['AccessTokenInvalid'], 401); + } + + // Add file meta + $add_file_meta = $flextype['media_files_meta']->add($path, $field, $value); + + if ($add_file_meta) { + $response_data['data'] = $flextype['media_files']->fetch($path); + } else { + $response_data['data'] = []; + } + + // Set response code + $response_code = ($add_file_meta) ? 200 : 404; + + // Return response + return $response + ->withJson($response_data, $response_code); + + // Update calls counter + Filesystem::write($files_token_file_path, $flextype['serializer']->encode(array_replace_recursive($files_token_file_data, ['calls' => $files_token_file_data['calls'] + 1]), 'yaml')); + + if ($response_code == 404) { + + // Return response + return $response + ->withJson($api_sys_messages['NotFound'], $response_code); + } + + // Return response + return $response + ->withJson($response_data, $response_code); + } + + return $response + ->withJson($api_sys_messages['AccessTokenInvalid'], 401); + } + + return $response + ->withJson($api_sys_messages['AccessTokenInvalid'], 401); + } + + return $response + ->withJson($api_sys_messages['AccessTokenInvalid'], 401); +}); + + +/** + * Add file meta information + * + * endpoint: DELETE /api/files/meta + * + * Body: + * path - [REQUIRED] - File path. + * field - [REQUIRED] - Field name. + * token - [REQUIRED] - Valid Entries token. + * access_token - [REQUIRED] - Valid Access token. + * + * Returns: + * Returns the file object for the file that was just created. + */ +$app->delete('/api/files/meta', function (Request $request, Response $response) use ($flextype, $api_sys_messages) { + + // Get Post Data + $post_data = $request->getParsedBody(); + + // Set variables + $token = $post_data['token']; + $access_token = $post_data['access_token']; + $path = $post_data['path']; + $field = $post_data['field']; + + if ($flextype['registry']->get('flextype.settings.api.files.enabled')) { + + // Validate files and access token + if (validate_files_token($token) && validate_access_token($access_token)) { + $files_token_file_path = PATH['project'] . '/tokens/files/' . $token . '/token.yaml'; + $access_token_file_path = PATH['project'] . '/tokens/access/' . $access_token . '/token.yaml'; + + // Set files and access token file + if (($files_token_file_data = $flextype['serializer']->decode(Filesystem::read($files_token_file_path), 'yaml')) && + ($access_token_file_data = $flextype['serializer']->decode(Filesystem::read($access_token_file_path), 'yaml'))) { + + if ($files_token_file_data['state'] === 'disabled' || + ($files_token_file_data['limit_calls'] !== 0 && $files_token_file_data['calls'] >= $files_token_file_data['limit_calls'])) { + return $response->withJson($api_sys_messages['AccessTokenInvalid'], 401); + } + + if ($access_token_file_data['state'] === 'disabled' || + ($access_token_file_data['limit_calls'] !== 0 && $access_token_file_data['calls'] >= $access_token_file_data['limit_calls'])) { + return $response->withJson($api_sys_messages['AccessTokenInvalid'], 401); + } + + // Delete file meta + $delete_file_meta = $flextype['media_files_meta']->delete($path, $field); + + if ($delete_file_meta) { + $response_data['data'] = $flextype['media_files']->fetch($path); + } else { + $response_data['data'] = []; + } + + // Set response code + $response_code = ($delete_file_meta) ? 200 : 404; + + // Return response + return $response + ->withJson($response_data, $response_code); + + // Update calls counter + Filesystem::write($files_token_file_path, $flextype['serializer']->encode(array_replace_recursive($files_token_file_data, ['calls' => $files_token_file_data['calls'] + 1]), 'yaml')); + + if ($response_code == 404) { + + // Return response + return $response + ->withJson($api_sys_messages['NotFound'], $response_code); + } + + // Return response + return $response + ->withJson($response_data, $response_code); + } + + return $response + ->withJson($api_sys_messages['AccessTokenInvalid'], 401); + } + + return $response + ->withJson($api_sys_messages['AccessTokenInvalid'], 401); + } + + return $response + ->withJson($api_sys_messages['AccessTokenInvalid'], 401); +}); diff --git a/src/flextype/endpoints/folders.php b/src/flextype/endpoints/folders.php new file mode 100644 index 00000000..71beaf74 --- /dev/null +++ b/src/flextype/endpoints/folders.php @@ -0,0 +1,102 @@ +get('/api/folders', function (Request $request, Response $response) use ($flextype, $api_sys_messages) { + + // Get Query Params + $query = $request->getQueryParams(); + + // Set variables + $path = $query['path']; + $mode = $query['mode']; + $token = $query['token']; + + if ($flextype['registry']->get('flextype.settings.api.folders.enabled')) { + + // Validate delivery token + if (validate_folders_token($token)) { + $folders_token_file_path = PATH['project'] . '/tokens/folders/' . $token. '/token.yaml'; + + // Set delivery token file + if ($folders_token_file_data = $flextype['serializer']->decode(Filesystem::read($folders_token_file_path), 'yaml')) { + if ($folders_token_file_data['state'] === 'disabled' || + ($folders_token_file_data['limit_calls'] !== 0 && $folders_token_file_data['calls'] >= $folders_token_file_data['limit_calls'])) { + return $response->withJson($api_sys_messages['AccessTokenInvalid'], 401); + } + + // Create folders array + $folders = []; + + // Get list if folder or fodlers for specific folder + if ($mode == 'collection') { + $folders = $flextype['media_folders']->fetchCollection($path); + } elseif ($mode == 'single') { + $folders = $flextype['media_folders']->fetchSingle($path); + } + + // Write response data + $response_data['data'] = $folders; + + // Set response code + $response_code = count($response_data['data']) > 0 ? 200 : 404; + + // Update calls counter + Filesystem::write($folders_token_file_path, $flextype['serializer']->encode(array_replace_recursive($folders_token_file_data, ['calls' => $folders_token_file_data['calls'] + 1]), 'yaml')); + + if ($response_code == 404) { + + // Return response + return $response + ->withJson($api_sys_messages['NotFound'], $response_code); + } + + // Return response + return $response + ->withJson($response_data, $response_code); + } + + return $response + ->withJson($api_sys_messages['AccessTokenInvalid'], 401); + } + + return $response + ->withJson($api_sys_messages['AccessTokenInvalid'], 401); + } + + return $response + ->withJson($api_sys_messages['AccessTokenInvalid'], 401); +});