From 36710bcd1ab209a94f39563b1cc86c1d465fa145 Mon Sep 17 00:00:00 2001 From: Thomas Threadgold Date: Sun, 14 Jun 2020 11:46:35 +0200 Subject: [PATCH 1/5] feat: create updateConfig handler function --- src/Config/Config.php | 2 +- src/Config/Constants.php | 1 + src/Handlers/ConfigHandler.php | 47 +++++++++++++++++++++++++++++++++- 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/Config/Config.php b/src/Config/Config.php index 12175c5..9ba3bcc 100644 --- a/src/Config/Config.php +++ b/src/Config/Config.php @@ -137,7 +137,7 @@ protected function configureRoute($customRoute = null) // But may want to override it specifically if we've given custom // settings to the Config instance (e.g. for tests) if (isset($customRoute)) { - $this->route = $customRoute; + $this->route = trim($customRoute, '/'); } elseif ($route) { $this->route = trim($route, '/'); } diff --git a/src/Config/Constants.php b/src/Config/Constants.php index 5857170..4cbe1a0 100644 --- a/src/Config/Constants.php +++ b/src/Config/Constants.php @@ -99,6 +99,7 @@ class Constants // Events const EVENT_ON_API_CONFIG_GET_ALL = 'onApiConfigGetAll'; const EVENT_ON_API_CONFIG_GET = 'onApiConfigGet'; + const EVENT_ON_API_CONFIG_UPDATE = 'onApiConfigUpdate'; const EVENT_ON_API_PAGE_GET_ALL = 'onApiPageGetAll'; const EVENT_ON_API_PAGE_GET = 'onApiPageGet'; const EVENT_ON_API_PAGE_FIND = 'onApiPageFind'; diff --git a/src/Handlers/ConfigHandler.php b/src/Handlers/ConfigHandler.php index bbd8f8a..923e692 100644 --- a/src/Handlers/ConfigHandler.php +++ b/src/Handlers/ConfigHandler.php @@ -3,10 +3,13 @@ use GravApi\Responses\Response; use GravApi\Helpers\ConfigHelper; +use GravApi\Helpers\ArrayHelper; use GravApi\Resources\ConfigResource; use GravApi\Resources\ConfigCollectionResource; use GravApi\Config\Constants; +use GravApi\Models\ConfigModel; use RocketTheme\Toolbox\Event\Event; +use RocketTheme\Toolbox\File\YamlFile; /** * Class ConfigHandler @@ -28,7 +31,7 @@ public function getConfigs($request, $response, $args) public function getConfig($request, $response, $args) { if (!isset($args['config'])) { - return $response->withJson(Response::badRequest('No config `id given!'), 400); + return $response->withJson(Response::badRequest('No config `id` given!'), 400); } $config = ConfigHelper::loadConfig($args['config']); @@ -45,4 +48,46 @@ public function getConfig($request, $response, $args) return $response->withJson($resource->toJson()); } + + public function updateConfig($request, $response, $args) + { + if (!isset($args['config'])) { + return $response->withJson(Response::badRequest('No config `id` given!'), 400); + } + + $existingConfig = ConfigHelper::loadConfig($args['config']); + + // If the config doesn't exist, OR it is present on the filter list + // (i.e. we don't want to allow user access to it) + if (!$existingConfig) { + return $response->withJson(Response::notFound(), 404); + } + + $parsedBody = $request->getParsedBody(); + + // Merge the existing config with the new settings + $data = ArrayHelper::merge( + $existingConfig->data, + $parsedBody + ); + + $configModel = new ConfigModel($args['config'], $data); + + // Save the updates to file + $filename = 'config://' . $configModel->id . '.yaml'; + $file = YamlFile::instance( + $this->grav['locator']->findResource($filename, true, true) + ); + $file->save($configModel->data); + $file->free(); + + // Reload the site config after changes are saved + $this->grav['config']->reload(); + + $resource = new ConfigResource($configModel); + + $this->grav->fireEvent(Constants::EVENT_ON_API_CONFIG_UPDATE, new Event(['config' => $configModel->data])); + + return $response->withJson($resource->toJson()); + } } From f3cdae3332a989e59a0eeccd4b40dda8fd5d3d3b Mon Sep 17 00:00:00 2001 From: Thomas Threadgold Date: Sun, 14 Jun 2020 11:48:11 +0200 Subject: [PATCH 2/5] feat: create new configs PATCH endpoint --- api.yaml | 3 +++ grav/config/plugins/api.yaml | 3 +++ src/Api.php | 10 ++++++++++ 3 files changed, 16 insertions(+) diff --git a/api.yaml b/api.yaml index 3445a8b..87b3c75 100644 --- a/api.yaml +++ b/api.yaml @@ -67,3 +67,6 @@ endpoints: # Prevents API from accessing these config files ignore_files: - streams + patch: + enabled: true + auth: true diff --git a/grav/config/plugins/api.yaml b/grav/config/plugins/api.yaml index 8f86862..0acb3b8 100644 --- a/grav/config/plugins/api.yaml +++ b/grav/config/plugins/api.yaml @@ -64,3 +64,6 @@ endpoints: auth: true ignore_files: - streams + patch: + enabled: true + auth: true diff --git a/src/Api.php b/src/Api.php index 9882174..8c47793 100644 --- a/src/Api.php +++ b/src/Api.php @@ -241,6 +241,16 @@ function () use ($config) { ) ); } + + if ($config->configs->patch->enabled) { + $this->patch('/{config}', ConfigHandler::class . ':updateConfig') + ->add( + new AuthMiddleware( + $config->configs->patch, + [Constants::ROLE_CONFIGS_EDIT] + ) + ); + } } ); }); From 728ebd7df34d71280c62c3b009c6f5bf0570f899 Mon Sep 17 00:00:00 2001 From: Thomas Threadgold Date: Sun, 14 Jun 2020 11:48:34 +0200 Subject: [PATCH 3/5] docs: add new configs endpoint to specification --- docs/specification.yaml | 48 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/docs/specification.yaml b/docs/specification.yaml index 68aa2e3..6d528a0 100644 --- a/docs/specification.yaml +++ b/docs/specification.yaml @@ -583,7 +583,7 @@ paths: tags: - plugins summary: Update a specific plugin - description: The request's body JSON should match the config structure of the plugin which you wish to update. If you wish to remove existing properties from the config, you can set their values to `null` and they will be unset. + description: The request's body JSON should match the config structure of the plugin which you wish to update. If you wish to remove existing properties from the config, you can set their values to `null` and they will be unset. Otherwise, the given values will be merged with the existing config. security: - basic: ['api.super', 'admin.super'] parameters: @@ -708,6 +708,52 @@ paths: examples: NotFound: $ref: '#/components/examples/NotFoundResponse' + patch: + tags: + - configs + summary: Update a specific config file + description: The request's body JSON should match the structure of the config file which you wish to update. If you wish to remove existing properties from the config, you can set their values to `null` and they will be unset. Otherwise, the given values will be merged with the existing config. + security: + - basic: ['api.super', 'api.configs_edit'] + parameters: + - name: id + in: path + description: The id of the config file to update + required: true + schema: + type: string + example: site + requestBody: + content: + application/json: + schema: + type: object + description: This JSON structure should match the desired configuration file's options. + responses: + 200: + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/ConfigResponse' + 401: + description: Invalid authentication + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + examples: + InvalidAuth: + $ref: '#/components/examples/InvalidAuthResponse' + 404: + description: Configuration file not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFoundResponse' components: securitySchemes: basic: From 8c894d6e2fb7cb615756e4426a75eb4a62775547 Mon Sep 17 00:00:00 2001 From: Thomas Threadgold Date: Sun, 14 Jun 2020 11:59:18 +0200 Subject: [PATCH 4/5] docs: describe onApiConfigUpdate event --- docs/EVENTS.md | 17 +++++++++++++++++ src/Handlers/ConfigHandler.php | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/EVENTS.md b/docs/EVENTS.md index 8239f9a..3f60132 100644 --- a/docs/EVENTS.md +++ b/docs/EVENTS.md @@ -18,6 +18,7 @@ - [Config](#config) - [onApiConfigGetAll](#onapiconfiggetall) - [onApiConfigGet](#onapiconfigget) + - [onApiConfigUpdate](#onapiconfigupdate) - [Plugin](#plugin) - [onApiPluginGetAll](#onapiplugingetall) - [onApiPluginGet](#onapipluginget) @@ -234,6 +235,7 @@ List of `Config` events: - [onApiConfigGetAll](#onapiconfiggetall) - [onApiConfigGet](#onapiconfigget) + - [onApiConfigUpdate](#onapiconfigupdate) Please refer to the example code provided for full documentation of the available properties for each custom event. @@ -267,6 +269,21 @@ function onApiConfigGet(Event $e) { } ``` +#### onApiConfigUpdate + +This event is fired any time the `PATCH /configs/{id}` endpoint is successfully requested. + +```php +function onApiConfigUpdate(Event $e) { + /** + * The GravApi ConfigModel returned in the API response. + * + * @var \GravApi\Models\ConfigModel + */ + $e['config']; +} +``` + ### Plugin Whenever a `Plugin` resource is succesfully requested, there will be a custom event fired by the API plugin including the affected resource as a property of the `Event` itself. diff --git a/src/Handlers/ConfigHandler.php b/src/Handlers/ConfigHandler.php index 923e692..f884d38 100644 --- a/src/Handlers/ConfigHandler.php +++ b/src/Handlers/ConfigHandler.php @@ -86,7 +86,7 @@ public function updateConfig($request, $response, $args) $resource = new ConfigResource($configModel); - $this->grav->fireEvent(Constants::EVENT_ON_API_CONFIG_UPDATE, new Event(['config' => $configModel->data])); + $this->grav->fireEvent(Constants::EVENT_ON_API_CONFIG_UPDATE, new Event(['config' => $configModel])); return $response->withJson($resource->toJson()); } From a2663569346fefc2c756d86174d4305fa696fbf1 Mon Sep 17 00:00:00 2001 From: Thomas Threadgold Date: Sun, 14 Jun 2020 12:01:16 +0200 Subject: [PATCH 5/5] docs: update postman collection with updateConfig --- docs/postman_collection.json | 51 ++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/docs/postman_collection.json b/docs/postman_collection.json index 7bfa9b1..f97e9da 100644 --- a/docs/postman_collection.json +++ b/docs/postman_collection.json @@ -568,6 +568,57 @@ } }, "response": [] + }, + { + "name": "Update Config", + "request": { + "auth": { + "type": "basic", + "basic": [ + { + "key": "password", + "value": "D3velopment", + "type": "string" + }, + { + "key": "username", + "value": "development", + "type": "string" + } + ] + }, + "method": "PATCH", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"title\": \"new site title\",\n\t\"custom_field\": null\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "localhost:8080/api/configs/site", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "api", + "configs", + "site" + ] + } + }, + "response": [] } ], "protocolProfileBehavior": {}