diff --git a/src/flextype/app/Endpoints/config.php b/src/flextype/app/Endpoints/config.php new file mode 100644 index 00000000..89ad8184 --- /dev/null +++ b/src/flextype/app/Endpoints/config.php @@ -0,0 +1,359 @@ +get('/api/config', function (Request $request, Response $response) use ($flextype, $api_errors) { + // Get Query Params + $query = $request->getQueryParams(); + + if (! isset($query['id']) || ! isset($query['config']) || ! isset($query['token'])) { + return $response->withJson($api_errors['0200'], $api_errors['0200']['http_status_code']); + } + + // Set variables + $key = $query['key']; + $config = $query['config']; + $token = $query['token']; + + if ($flextype['registry']->get('flextype.settings.api.config.enabled')) { + // Validate config token + if (validate_config_token($token)) { + $delivery_config_token_file_path = PATH['project'] . '/tokens/config/' . $token . '/token.yaml'; + + // Set delivery token file + if ($delivery_config_token_file_data = $flextype['serializer']->decode(Filesystem::read($delivery_config_token_file_path), 'yaml')) { + if ($delivery_config_token_file_data['state'] === 'disabled' || + ($delivery_config_token_file_data['limit_calls'] !== 0 && $delivery_config_token_file_data['calls'] >= $delivery_config_token_file_data['limit_calls'])) { + return $response->withJson($api_errors['0003'], $api_errors['0003']['http_status_code']); + } + + // Fetch config + if ($flextype['config']->has($config, $key)) { + $response_data['data']['key'] = $key; + $response_data['data']['value'] = $flextype['config']->get($config, $key); + + // Set response code + $response_code = 200; + } else { + $response_data = []; + $response_code = 404; + } + + // Update calls counter + Filesystem::write($delivery_config_token_file_path, $flextype['serializer']->encode(array_replace_recursive($delivery_config_token_file_data, ['calls' => $delivery_config_token_file_data['calls'] + 1]), 'yaml')); + + if ($response_code === 404) { + // Return response + return $response + ->withJson($api_errors['0202'], $api_errors['0202']['http_status_code']); + } + + // Return response + return $response + ->withJson($response_data, $response_code); + } + + return $response + ->withJson($api_errors['0003'], $api_errors['0003']['http_status_code']); + } + + return $response + ->withJson($api_errors['0003'], $api_errors['0003']['http_status_code']); + } + + return $response + ->withJson($api_errors['0003'], $api_errors['0003']['http_status_code']); +}); + + +/** + * Create new item in the config + * + * endpoint: POST /api/config + * + * Body: + * config - [REQUIRED] - Unique identifier of the config namespace. + * token - [REQUIRED] - Valid Config token. + * access_token - [REQUIRED] - Valid Access token. + * data - [REQUIRED] - Data to store for the config. + * + * Returns: + * Returns the config item object for the config item that was just created. + */ +$app->post('/api/config', function (Request $request, Response $response) use ($flextype, $api_errors) { + // Get Post Data + $post_data = $request->getParsedBody(); + + if (! isset($post_data['token']) || ! isset($post_data['access_token']) || ! isset($post_data['config']) || ! isset($post_data['data'])) { + return $response->withJson($api_errors['0201'], $api_errors['0201']['http_status_code']); + } + + // Set variables + $token = $post_data['token']; + $access_token = $post_data['access_token']; + $config = $post_data['config']; + $data = $post_data['data']; + + if ($flextype['registry']->get('flextype.settings.api.config.enabled')) { + // Validate config and access token + if (validate_config_token($token) && validate_access_token($access_token)) { + $config_token_file_path = PATH['project'] . '/tokens/config/' . $token . '/token.yaml'; + $access_token_file_path = PATH['project'] . '/tokens/access/' . $access_token . '/token.yaml'; + + // Set config and access token file + if (($config_token_file_data = $flextype['serializer']->decode(Filesystem::read($config_token_file_path), 'yaml')) && + ($access_token_file_data = $flextype['serializer']->decode(Filesystem::read($access_token_file_path), 'yaml'))) { + if ($config_token_file_data['state'] === 'disabled' || + ($config_token_file_data['limit_calls'] !== 0 && $config_token_file_data['calls'] >= $config_token_file_data['limit_calls'])) { + return $response->withJson($api_errors['0003'], $api_errors['0003']['http_status_code']); + } + + 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_errors['0003'], $api_errors['0003']['http_status_code']); + } + + // Create config + $create_config = $flextype['config']->create($config, $data['key'], $data['value']); + + if ($create_config) { + $response_data['data']['key'] = $data['key']; + $response_data['data']['value'] = $flextype['config']->get($config, $data['key']); + + // Set response code + $response_code = 200; + } else { + $response_data = []; + $response_code = 404; + } + + // Set response code + $response_code = $create_config ? 200 : 404; + + // Update calls counter + Filesystem::write($config_token_file_path, $flextype['serializer']->encode(array_replace_recursive($config_token_file_data, ['calls' => $config_token_file_data['calls'] + 1]), 'yaml')); + + if ($response_code === 404) { + // Return response + return $response + ->withJson($api_errors['0202'], $api_errors['0202']['http_status_code']); + } + + // Return response + return $response + ->withJson($response_data, $response_code); + } + + return $response + ->withJson($api_errors['0003'], $api_errors['0003']['http_status_code']); + } + + return $response + ->withJson($api_errors['0003'], $api_errors['0003']['http_status_code']); + } + + return $response + ->withJson($api_errors['0003'], $api_errors['0003']['http_status_code']); +}); + +/** + * Update config item + * + * endpoint: PATCH /api/config + * + * Body: + * config - [REQUIRED] - Unique identifier of the config namespace. + * token - [REQUIRED] - Valid Config token. + * access_token - [REQUIRED] - Valid Access token. + * data - [REQUIRED] - Data to store for the config. + * + * Returns: + * Returns the config item object for the config item that was just created. + */ +$app->patch('/api/config', function (Request $request, Response $response) use ($flextype, $api_errors) { + // Get Post Data + $post_data = $request->getParsedBody(); + + if (! isset($post_data['token']) || ! isset($post_data['access_token']) || ! isset($post_data['config']) || ! isset($post_data['data'])) { + return $response->withJson($api_errors['0201'], $api_errors['0201']['http_status_code']); + } + + // Set variables + $token = $post_data['token']; + $access_token = $post_data['access_token']; + $data = $post_data['data']; + $config = $post_data['config']; + + if ($flextype['registry']->get('flextype.settings.api.config.enabled')) { + // Validate config and access token + if (validate_config_token($token) && validate_access_token($access_token)) { + $config_token_file_path = PATH['project'] . '/tokens/config/' . $token . '/token.yaml'; + $access_token_file_path = PATH['project'] . '/tokens/access/' . $access_token . '/token.yaml'; + + // Set config and access token file + if (($config_token_file_data = $flextype['serializer']->decode(Filesystem::read($config_token_file_path), 'yaml')) && + ($access_token_file_data = $flextype['serializer']->decode(Filesystem::read($access_token_file_path), 'yaml'))) { + if ($config_token_file_data['state'] === 'disabled' || + ($config_token_file_data['limit_calls'] !== 0 && $config_token_file_data['calls'] >= $config_token_file_data['limit_calls'])) { + return $response->withJson($api_errors['0003'], $api_errors['0003']['http_status_code']); + } + + 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_errors['0003'], $api_errors['0003']['http_status_code']); + } + + // Update config + $update_config = $flextype['config']->update($config, $data['key'], $data['value']); + + if ($update_config) { + $response_data['data']['key'] = $data['key']; + $response_data['data']['value'] = $flextype['config']->get($config, $data['key']); + + // Set response code + $response_code = 200; + } else { + $response_data = []; + $response_code = 404; + } + + // Set response code + $response_code = $update_config ? 200 : 404; + + // Update calls counter + Filesystem::write($config_token_file_path, $flextype['serializer']->encode(array_replace_recursive($config_token_file_data, ['calls' => $config_token_file_data['calls'] + 1]), 'yaml')); + + if ($response_code === 404) { + // Return response + return $response + ->withJson($api_errors['0202'], $api_errors['0202']['http_status_code']); + } + + // Return response + return $response + ->withJson($response_data, $response_code); + } + + return $response + ->withJson($api_errors['0003'], $api_errors['0003']['http_status_code']); + } + + return $response + ->withJson($api_errors['0003'], $api_errors['0003']['http_status_code']); + } + + return $response + ->withJson($api_errors['0003'], $api_errors['0003']['http_status_code']); +}); + +/** + * Delete config item + * + * endpoint: DELETE /api/config + * + * Body: + * config - [REQUIRED] - Unique identifier of the config namespace. + * token - [REQUIRED] - Valid Config token. + * access_token - [REQUIRED] - Valid Access token. + * data - [REQUIRED] - Data to store for the config. + * + * Returns: + * Returns an empty body with HTTP status 204 + */ +$app->delete('/api/config', function (Request $request, Response $response) use ($flextype, $api_errors) { + // Get Post Data + $post_data = $request->getParsedBody(); + + if (! isset($post_data['token']) || ! isset($post_data['access_token']) || ! isset($post_data['config']) || ! isset($post_data['data'])) { + return $response->withJson($api_errors['0201'], $api_errors['0201']['http_status_code']); + } + + // Set variables + $token = $post_data['token']; + $access_token = $post_data['access_token']; + $data = $post_data['data']; + $config = $post_data['config']; + + if ($flextype['registry']->get('flextype.settings.api.config.enabled')) { + // Validate config and access token + if (validate_config_token($token) && validate_access_token($access_token)) { + $config_token_file_path = PATH['project'] . '/tokens/config/' . $token . '/token.yaml'; + $access_token_file_path = PATH['project'] . '/tokens/access/' . $access_token . '/token.yaml'; + + // Set config and access token file + if (($config_token_file_data = $flextype['serializer']->decode(Filesystem::read($config_token_file_path), 'yaml')) && + ($access_token_file_data = $flextype['serializer']->decode(Filesystem::read($access_token_file_path), 'yaml'))) { + if ($config_token_file_data['state'] === 'disabled' || + ($config_token_file_data['limit_calls'] !== 0 && $config_token_file_data['calls'] >= $config_token_file_data['limit_calls'])) { + return $response->withJson($api_errors['0003'], $api_errors['0003']['http_status_code']); + } + + 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_errors['0003'], $api_errors['0003']['http_status_code']); + } + + // Delete entry + $delete_config = $flextype['config']->delete($config, $data['key']); + + // Set response code + $response_code = $delete_config ? 204 : 404; + + // Update calls counter + Filesystem::write($config_token_file_path, $flextype['serializer']->encode(array_replace_recursive($config_token_file_data, ['calls' => $config_token_file_data['calls'] + 1]), 'yaml')); + + if ($response_code === 404) { + // Return response + return $response + ->withJson($api_errors['0202'], $api_errors['0202']['http_status_code']); + } + + // Return response + return $response + ->withJson($delete_config, $response_code); + } + + return $response + ->withJson($api_errors['0003'], $api_errors['0003']['http_status_code']); + } + + return $response + ->withJson($api_errors['0003'], $api_errors['0003']['http_status_code']); + } + + return $response + ->withJson($api_errors['0003'], $api_errors['0003']['http_status_code']); +}); diff --git a/src/flextype/app/Foundation/Config.php b/src/flextype/app/Foundation/Config.php new file mode 100644 index 00000000..6e08ac0d --- /dev/null +++ b/src/flextype/app/Foundation/Config.php @@ -0,0 +1,177 @@ +flextype = $flextype; + } + + /** + * Get item from the config + * + * @param string $config Config namespace. + * @param string $key The key of the config item to get. + * @param mixed $default Default value + * + * @return mixed + */ + public function get(string $config, string $key, $default = null) + { + $config_file = $this->getFileLocation($config); + + if (Filesystem::has($config_file)) { + return Arrays::get($this->flextype->yaml->decode(Filesystem::read($config_file)), $key, $default); + } + } + + /** + * Create new config item + * + * @param string $config Config namespace. + * @param string $key The key of the config item to get. + * @param mixed $value Value + */ + public function create(string $config, string $key, $value) : bool + { + $config_file = $this->getFileLocation($config); + + if (Filesystem::has($config_file)) { + $config_file_data = $this->flextype->yaml->decode(Filesystem::read($config_file)); + + if (! Arrays::has($config_file_data, $key)) { + Arrays::set($config_file_data, $key, $value); + + return Filesystem::write($config_file, $this->flextype->yaml->encode($config_file_data)); + } + + return false; + } + + return false; + } + + /** + * Update config item + * + * @param string $config Config namespace. + * @param string $key The key of the config item to get. + * @param mixed $value Value + */ + public function update(string $config, string $key, $value) : bool + { + $config_file = $this->getFileLocation($config); + + if (Filesystem::has($config_file)) { + $config_file_data = $this->flextype->yaml->decode(Filesystem::read($config_file)); + + if (Arrays::has($config_file_data, $key)) { + Arrays::set($config_file_data, $key, $value); + + return Filesystem::write($config_file, $this->flextype->yaml->encode($config_file_data)); + } + + return false; + } + + return false; + } + + /** + * Delete config item + * + * @param string $config Config namespace. + * @param string $key The key of the config item to get. + */ + public function delete(string $config, string $key) : bool + { + $config_file = $this->getFileLocation($config); + + if (Filesystem::has($config_file)) { + $config_file_data = $this->flextype->yaml->decode(Filesystem::read($config_file)); + + if (Arrays::has($config_file_data, $key)) { + Arrays::delete($config_file_data, $key); + + return Filesystem::write($config_file, $this->flextype->yaml->encode($config_file_data)); + } + + return false; + } + + return false; + } + + /** + * Checks if an config item with this key name is in the config. + * + * @param string $config Config namespace. + * @param string $key The key of the config item to get. + */ + public function has(string $config, string $key) : bool + { + $config_file = $this->getFileLocation($config); + + if (Filesystem::has($config_file)) { + $config_file_data = $this->flextype->yaml->decode(Filesystem::read($config_file)); + + if (Arrays::has($config_file_data, $key)) { + return true; + } + + return false; + } + + return false; + } + + /** + * Get config file location + * + * @param string $config Config namespace. + * + * @return string config file location + * + * @access private + */ + public function getFileLocation(string $config) : string + { + return PATH['project'] . '/config/' . $config . '/settings.yaml'; + } + + /** + * Get config directory location + * + * @param string $config Config namespace. + * + * @return string config directory location + * + * @access private + */ + public function getDirLocation(string $config) : string + { + return PATH['project'] . '/config/' . $config; + } +} diff --git a/src/flextype/dependencies.php b/src/flextype/dependencies.php index c4e7df13..40df2c8f 100644 --- a/src/flextype/dependencies.php +++ b/src/flextype/dependencies.php @@ -12,6 +12,7 @@ namespace Flextype; use Bnf\Slim3Psr15\CallableResolver; use Cocur\Slugify\Slugify; use Flextype\App\Foundation\Cache\Cache; +use Flextype\App\Foundation\Config; use Flextype\App\Foundation\Cors; use Flextype\App\Foundation\Entries\Entries; use Flextype\App\Foundation\Media\MediaFiles; @@ -140,6 +141,13 @@ $flextype['cache'] = function ($container) use ($flextype) { return new Cache($flextype); }; +/** + * Add options service to Flextype container + */ +$flextype['config'] = function ($container) use ($flextype) { + return new Config($flextype); +}; + /** * Add shortcode parser service to Flextype container */