From 267a6d42661c1115743df8fae39b85b01c578aa7 Mon Sep 17 00:00:00 2001 From: jjrom Date: Tue, 11 Jun 2024 17:12:00 +0200 Subject: [PATCH] Move STACCatalog functions to STAC class --- app/resto/core/RestoRouter.php | 8 +- app/resto/core/addons/STAC.php | 317 ++++++++++++++++ app/resto/core/addons/STACCatalog.php | 357 ------------------ .../core/dbfunctions/CatalogsFunctions.php | 3 +- 4 files changed, 321 insertions(+), 364 deletions(-) delete mode 100644 app/resto/core/addons/STACCatalog.php diff --git a/app/resto/core/RestoRouter.php b/app/resto/core/RestoRouter.php index 3bf81229..1d273c27 100755 --- a/app/resto/core/RestoRouter.php +++ b/app/resto/core/RestoRouter.php @@ -119,11 +119,9 @@ class RestoRouter array('GET', RestoRouter::ROUTE_TO_STAC_QUERYABLES, false, 'STAC::getQueryables'), // STAC/OAFeature API - Queryables array('GET', RestoRouter::ROUTE_TO_STAC_SEARCH, false, 'STAC::search'), // STAC API - core search (GET) array('POST', RestoRouter::ROUTE_TO_STAC_SEARCH, false, 'STAC::search'), // STAC API - core search (POST) - - // STAC Catalog - array('POST', RestoRouter::ROUTE_TO_CATALOGS , true , 'STACCatalog::addCatalog'), // STAC - Add a catalog - array('PUT' , RestoRouter::ROUTE_TO_CATALOGS . '/*', true , 'STACCatalog::updateCatalog'), // STAC - Update a catalog - array('DELETE', RestoRouter::ROUTE_TO_CATALOGS . '/*', true , 'STACCatalog::removeCatalog') // STAC - Remove a catalog + array('POST', RestoRouter::ROUTE_TO_CATALOGS , true , 'STAC::addCatalog'), // STAC - Add a catalog + array('PUT' , RestoRouter::ROUTE_TO_CATALOGS . '/*', true , 'STAC::updateCatalog'), // STAC - Update a catalog + array('DELETE', RestoRouter::ROUTE_TO_CATALOGS . '/*', true , 'STAC::removeCatalog') // STAC - Remove a catalog ); /* diff --git a/app/resto/core/addons/STAC.php b/app/resto/core/addons/STAC.php index 0c4c0e5d..d6596c24 100644 --- a/app/resto/core/addons/STAC.php +++ b/app/resto/core/addons/STAC.php @@ -289,6 +289,295 @@ public function getCatalogs($params) return $this->processPath($params['segments'], $params); } + /** + * Add a catalog + * + * @OA\Post( + * path="/catalogs/*", + * summary="Add a STAC catalog", + * description="Add a STAC catalog", + * tags={"STAC"}, + * @OA\RequestBody( + * description="A valid STAC Catalog", + * required=true, + * @OA\JsonContent(ref="#/components/schemas/Catalog") + * ), + * @OA\Response( + * response="200", + * description="The catalog is created", + * @OA\JsonContent( + * @OA\Property( + * property="status", + * type="string", + * description="Status is *success*" + * ), + * @OA\Property( + * property="message", + * type="string", + * description="Message information" + * ), + * example={ + * "status": "success", + * "message": "Catalog created" + * } + * ) + * ), + * @OA\Response( + * response="400", + * description="Missing one of the mandatory input property", + * @OA\JsonContent(ref="#/components/schemas/BadRequestError") + * ), + * @OA\Response( + * response="401", + * description="Unauthorized", + * @OA\JsonContent(ref="#/components/schemas/UnauthorizedError") + * ), + * @OA\Response( + * response="403", + * description="Only user with *createCatalog* rights can create a catalog", + * @OA\JsonContent(ref="#/components/schemas/ForbiddenError") + * ), + * security={ + * {"basicAuth":{}, "bearerAuth":{}, "queryAuth":{}} + * } + * ) + * + * @param array $params + * @param array $body + */ + public function addCatalog($params, $body) + { + + if (!$this->user->hasRightsTo(RestoUser::CREATE_CATALOG)) { + return RestoLogUtil::httpError(403); + } + + /* + * Check mandatory properties + */ + /*if ( isset($body['stac_version']) ) { + return RestoLogUtil::httpError(400, 'Missing mandatory catalog stac_version - should be set to ' . STAC::STAC_VERSION ); + }*/ + if ( !isset($body['id']) ) { + return RestoLogUtil::httpError(400, 'Missing mandatory catalog id'); + } + if ( !isset($body['description']) ) { + return RestoLogUtil::httpError(400, 'Missing mandatory description'); + } + if ( !isset($body['links']) ) { + $body['links'] = array(); + } + + /* + * Convert input catalog to resto:catalog + * i.e. add rtype and hashtag properties and convert id to a path + */ + $body['rtype'] = 'catalog'; + $body['hashtag'] = 'catalog' . RestoConstants::TAG_SEPARATOR . $body['id']; + $body['id'] = $this->getIdPath($body); + + if ($this->catalogsFunctions->getCatalog($body['id']) !== null) { + RestoLogUtil::httpError(409, 'Catalog ' . $body['id'] . ' already exists'); + } + $baseUrl = $this->context->core['baseUrl']; + return RestoLogUtil::success('Catalog added', $this->catalogsFunctions->storeCatalog($body, $this->user->profile['id'], $baseUrl, null, null)); + + } + + /** + * Update catalog + * + * @OA\Put( + * path="/catalogs/*", + * summary="Update catalog", + * description="Update catalog", + * tags={"STAC"}, + * @OA\Parameter( + * name="catalogId", + * in="path", + * required=true, + * description="Catalog identifier", + * @OA\Schema( + * type="string" + * ) + * ), + * @OA\RequestBody( + * description="Catalog fields to be update limited to title and description", + * required=true, + * @OA\JsonContent(ref="#/components/schemas/Catalog") + * ), + * @OA\Response( + * response="200", + * description="Catalog is updated", + * @OA\JsonContent( + * @OA\Property( + * property="status", + * type="string", + * description="Status is *success*" + * ), + * @OA\Property( + * property="message", + * type="string", + * description="Message information" + * ), + * example={ + * "status": "success", + * "message": "Catalog updated" + * } + * ) + * ), + * @OA\Response( + * response="404", + * description="Not found", + * @OA\JsonContent(ref="#/components/schemas/NotFoundError") + * ), + * @OA\Response( + * response="401", + * description="Unauthorized", + * @OA\JsonContent(ref="#/components/schemas/UnauthorizedError") + * ), + * @OA\Response( + * response="403", + * description="Only user with *updateCatalog* rights can update a catalog", + * @OA\JsonContent(ref="#/components/schemas/ForbiddenError") + * ), + * security={ + * {"basicAuth":{}, "bearerAuth":{}, "queryAuth":{}} + * } + * ) + * + * @param array $params + * @param array $body + */ + public function updateCatalog($params, $body) + { + + // Get catalogs and childs + $catalogs = $this->catalogsFunctions->getCatalogs(array( + 'id' => join('/', $params['segments']) + ), true); + + if ( count($catalogs) === 0 ){ + RestoLogUtil::httpError(404); + } + + + // If user has not the right to update catalog then 403 + if ( !$this->user->hasRightsTo(RestoUser::UPDATE_CATALOG, array('catalog' => $catalogs[0])) ) { + return RestoLogUtil::httpError(403); + } + + $updatable = array('title', 'description', 'owner'); + for ($i = count($updatable); $i--;) { + if ( isset($body[$updatable[$i]]) ) { + $catalogs[0][$updatable[$i]] = $body[$updatable[$i]]; + } + } + + return RestoLogUtil::success('Catalog updated', $this->catalogsFunctions->updateCatalog($catalogs[0])); + } + + /** + * Delete catalog + * + * @OA\Delete( + * path="/catalogs/*", + * summary="Delete catalog", + * description="Delete catalog", + * tags={"STAC"}, + * @OA\Parameter( + * name="catalogId", + * in="path", + * required=true, + * description="Catalog identifier", + * @OA\Schema( + * type="string" + * ) + * ), + * @OA\Parameter( + * name="force", + * in="query", + * description="Force catalog removal even if this catalog has child. In this case, catalogs childs are attached to the remove catalog parent", + * @OA\Schema( + * type="boolean" + * ) + * ), + * @OA\Response( + * response="200", + * description="Catalog deleted", + * @OA\JsonContent( + * @OA\Property( + * property="status", + * type="string", + * description="Status is *success*" + * ), + * @OA\Property( + * property="message", + * type="string", + * description="Message information" + * ), + * example={ + * "status": "success", + * "message": "Catalog deleted", + * "featuresUpdated": 345 + * } + * ) + * ), + * @OA\Response( + * response="404", + * description="Not found", + * @OA\JsonContent(ref="#/components/schemas/NotFoundError") + * ), + * @OA\Response( + * response="401", + * description="Unauthorized", + * @OA\JsonContent(ref="#/components/schemas/UnauthorizedError") + * ), + * @OA\Response( + * response="403", + * description="Only user with *deleteCatalog* rights can delete a catalog", + * @OA\JsonContent(ref="#/components/schemas/ForbiddenError") + * ), + * security={ + * {"basicAuth":{}, "bearerAuth":{}, "queryAuth":{}} + * } + * ) + * + * @param array $params + * @param array $body + */ + public function removeCatalog($params) + { + + // Get catalogs and childs + $catalogs = $this->catalogsFunctions->getCatalogs(array( + 'id' => join('/', $params['segments']) + ), true); + + if ( count($catalogs) === 0 ){ + RestoLogUtil::httpError(404); + } + + // If user has not the right to delete catalog then 403 + if ( !$this->user->hasRightsTo(RestoUser::DELETE_CATALOG, array('catalog' => $catalogs[0])) ) { + return RestoLogUtil::httpError(403); + } + + // If catalog has childs it cannot be removed + for ($i = 1, $ii = count($catalogs); $i < $ii; $i--) { + if (isset($params['force']) && filter_var($params['force'], FILTER_VALIDATE_BOOLEAN) === true) { + return RestoLogUtil::httpError(400, 'TODO - force removal of non empty catalog is not implemented'); + } + else { + return RestoLogUtil::httpError(400, 'The catalog cannot be deleted because it has ' . (count($catalogs) - 1) . ' childs'); + } + } + + return RestoLogUtil::success('Catalog deleted', $this->catalogsFunctions->removeCatalog($catalogs[0]['id'])); + + } + + /** * * Return an asset href within an HTTP 301 Redirect message @@ -1294,4 +1583,32 @@ private function getRootCatalogLinks() return $links; } + /** + * Return path identifier from input catlaog + * + * @param array $catalog + * @return string + */ + private function getIdPath($catalog) + { + + $parentId = ''; + + // Retrieve parent if any + for ($i = 0, $ii = count($catalog['links']); $i < $ii; $i++ ) { + if ( isset($catalog['links'][$i]['rel']) &&$catalog['links'][$i]['rel'] === 'parent' ) { + $theoricalUrl = $this->context->core['baseUrl'] . RestoRouter::ROUTE_TO_CATALOGS; + $exploded = explode($theoricalUrl, $catalog['links'][$i]['href']); + if (count($exploded) !== 2) { + return RestoLogUtil::httpError(400, 'Parent link is set but it\'s url is invalid - should starts with ' . $theoricalUrl); + } + $parentId = str_starts_with($exploded[1], '/') ? substr($exploded[1], 1) : $exploded[1]; + break; + } + } + + return ($parentId === '' ? '' : $parentId . '/') . $catalog['id']; + + } + } diff --git a/app/resto/core/addons/STACCatalog.php b/app/resto/core/addons/STACCatalog.php deleted file mode 100644 index 6f01fe84..00000000 --- a/app/resto/core/addons/STACCatalog.php +++ /dev/null @@ -1,357 +0,0 @@ -catalogsFunctions = new CatalogsFunctions($this->context->dbDriver); - } - - /** - * Add a catalog - * - * @OA\Post( - * path="/catalogs/*", - * summary="Add a STAC catalog", - * description="Add a STAC catalog", - * tags={"STAC"}, - * @OA\RequestBody( - * description="A valid STAC Catalog", - * required=true, - * @OA\JsonContent(ref="#/components/schemas/Catalog") - * ), - * @OA\Response( - * response="200", - * description="The catalog is created", - * @OA\JsonContent( - * @OA\Property( - * property="status", - * type="string", - * description="Status is *success*" - * ), - * @OA\Property( - * property="message", - * type="string", - * description="Message information" - * ), - * example={ - * "status": "success", - * "message": "Catalog created" - * } - * ) - * ), - * @OA\Response( - * response="400", - * description="Missing one of the mandatory input property", - * @OA\JsonContent(ref="#/components/schemas/BadRequestError") - * ), - * @OA\Response( - * response="401", - * description="Unauthorized", - * @OA\JsonContent(ref="#/components/schemas/UnauthorizedError") - * ), - * @OA\Response( - * response="403", - * description="Only user with *createCatalog* rights can create a catalog", - * @OA\JsonContent(ref="#/components/schemas/ForbiddenError") - * ), - * security={ - * {"basicAuth":{}, "bearerAuth":{}, "queryAuth":{}} - * } - * ) - * - * @param array $params - * @param array $body - */ - public function addCatalog($params, $body) - { - - if (!$this->user->hasRightsTo(RestoUser::CREATE_CATALOG)) { - return RestoLogUtil::httpError(403); - } - - /* - * Check mandatory properties - */ - /*if ( isset($body['stac_version']) ) { - return RestoLogUtil::httpError(400, 'Missing mandatory catalog stac_version - should be set to ' . STAC::STAC_VERSION ); - }*/ - if ( !isset($body['id']) ) { - return RestoLogUtil::httpError(400, 'Missing mandatory catalog id'); - } - if ( !isset($body['description']) ) { - return RestoLogUtil::httpError(400, 'Missing mandatory description'); - } - if ( !isset($body['links']) ) { - $body['links'] = array(); - } - - /* - * Convert input catalog to resto:catalog - * i.e. add rtype and hashtag properties and convert id to a path - */ - $body['rtype'] = 'catalog'; - $body['hashtag'] = 'catalog' . RestoConstants::TAG_SEPARATOR . $body['id']; - $body['id'] = $this->getIdPath($body); - - if ($this->catalogsFunctions->getCatalog($body['id']) !== null) { - RestoLogUtil::httpError(409, 'Catalog ' . $body['id'] . ' already exists'); - } - $baseUrl = $this->context->core['baseUrl']; - return RestoLogUtil::success('Catalog added', $this->catalogsFunctions->storeCatalog($body, $this->user->profile['id'], $baseUrl, null, null)); - - } - - /** - * Update catalog - * - * @OA\Put( - * path="/catalogs/*", - * summary="Update catalog", - * description="Update catalog", - * tags={"STAC"}, - * @OA\Parameter( - * name="catalogId", - * in="path", - * required=true, - * description="Catalog identifier", - * @OA\Schema( - * type="string" - * ) - * ), - * @OA\RequestBody( - * description="Catalog fields to be update limited to title and description", - * required=true, - * @OA\JsonContent(ref="#/components/schemas/Catalog") - * ), - * @OA\Response( - * response="200", - * description="Catalog is updated", - * @OA\JsonContent( - * @OA\Property( - * property="status", - * type="string", - * description="Status is *success*" - * ), - * @OA\Property( - * property="message", - * type="string", - * description="Message information" - * ), - * example={ - * "status": "success", - * "message": "Catalog updated" - * } - * ) - * ), - * @OA\Response( - * response="404", - * description="Not found", - * @OA\JsonContent(ref="#/components/schemas/NotFoundError") - * ), - * @OA\Response( - * response="401", - * description="Unauthorized", - * @OA\JsonContent(ref="#/components/schemas/UnauthorizedError") - * ), - * @OA\Response( - * response="403", - * description="Only user with *updateCatalog* rights can update a catalog", - * @OA\JsonContent(ref="#/components/schemas/ForbiddenError") - * ), - * security={ - * {"basicAuth":{}, "bearerAuth":{}, "queryAuth":{}} - * } - * ) - * - * @param array $params - * @param array $body - */ - public function updateCatalog($params, $body) - { - - // Get catalogs and childs - $catalogs = $this->catalogsFunctions->getCatalogs(array( - 'id' => join('/', $params['segments']) - ), true); - - if ( count($catalogs) === 0 ){ - RestoLogUtil::httpError(404); - } - - - // If user has not the right to update catalog then 403 - if ( !$this->user->hasRightsTo(RestoUser::UPDATE_CATALOG, array('catalog' => $catalogs[0])) ) { - return RestoLogUtil::httpError(403); - } - - $updatable = array('title', 'description', 'owner'); - for ($i = count($updatable); $i--;) { - if ( isset($body[$updatable[$i]]) ) { - $catalogs[0][$updatable[$i]] = $body[$updatable[$i]]; - } - } - - return RestoLogUtil::success('Catalog updated', $this->catalogsFunctions->updateCatalog($catalogs[0])); - } - - /** - * Delete catalog - * - * @OA\Delete( - * path="/catalogs/*", - * summary="Delete catalog", - * description="Delete catalog", - * tags={"STAC"}, - * @OA\Parameter( - * name="catalogId", - * in="path", - * required=true, - * description="Catalog identifier", - * @OA\Schema( - * type="string" - * ) - * ), - * @OA\Parameter( - * name="force", - * in="query", - * description="Force catalog removal even if this catalog has child. In this case, catalogs childs are attached to the remove catalog parent", - * @OA\Schema( - * type="boolean" - * ) - * ), - * @OA\Response( - * response="200", - * description="Catalog deleted", - * @OA\JsonContent( - * @OA\Property( - * property="status", - * type="string", - * description="Status is *success*" - * ), - * @OA\Property( - * property="message", - * type="string", - * description="Message information" - * ), - * example={ - * "status": "success", - * "message": "Catalog deleted", - * "featuresUpdated": 345 - * } - * ) - * ), - * @OA\Response( - * response="404", - * description="Not found", - * @OA\JsonContent(ref="#/components/schemas/NotFoundError") - * ), - * @OA\Response( - * response="401", - * description="Unauthorized", - * @OA\JsonContent(ref="#/components/schemas/UnauthorizedError") - * ), - * @OA\Response( - * response="403", - * description="Only user with *deleteCatalog* rights can delete a catalog", - * @OA\JsonContent(ref="#/components/schemas/ForbiddenError") - * ), - * security={ - * {"basicAuth":{}, "bearerAuth":{}, "queryAuth":{}} - * } - * ) - * - * @param array $params - * @param array $body - */ - public function removeCatalog($params) - { - - // Get catalogs and childs - $catalogs = $this->catalogsFunctions->getCatalogs(array( - 'id' => join('/', $params['segments']) - ), true); - - if ( count($catalogs) === 0 ){ - RestoLogUtil::httpError(404); - } - - // If user has not the right to delete catalog then 403 - if ( !$this->user->hasRightsTo(RestoUser::DELETE_CATALOG, array('catalog' => $catalogs[0])) ) { - return RestoLogUtil::httpError(403); - } - - // If catalog has childs it cannot be removed - for ($i = 1, $ii = count($catalogs); $i < $ii; $i--) { - if (isset($params['force']) && filter_var($params['force'], FILTER_VALIDATE_BOOLEAN) === true) { - return RestoLogUtil::httpError(400, 'TODO - force removal of non empty catalog is not implemented'); - } - else { - return RestoLogUtil::httpError(400, 'The catalog cannot be deleted because it has ' . (count($catalogs) - 1) . ' childs'); - } - } - - return RestoLogUtil::success('Catalog deleted', $this->catalogsFunctions->removeCatalog($catalogs[0]['id'])); - - } - - /** - * Return path identifier from input catlaog - * - * @param array $catalog - * @return string - */ - private function getIdPath($catalog) - { - - $parentId = ''; - - // Retrieve parent if any - for ($i = 0, $ii = count($catalog['links']); $i < $ii; $i++ ) { - if ( isset($catalog['links'][$i]['rel']) &&$catalog['links'][$i]['rel'] === 'parent' ) { - $theoricalUrl = $this->context->core['baseUrl'] . RestoRouter::ROUTE_TO_CATALOGS; - $exploded = explode($theoricalUrl, $catalog['links'][$i]['href']); - if (count($exploded) !== 2) { - return RestoLogUtil::httpError(400, 'Parent link is set but it\'s url is invalid - should starts with ' . $theoricalUrl); - } - $parentId = str_starts_with($exploded[1], '/') ? substr($exploded[1], 1) : $exploded[1]; - break; - } - } - - return ($parentId === '' ? '' : $parentId . '/') . $catalog['id']; - - } - - -} diff --git a/app/resto/core/dbfunctions/CatalogsFunctions.php b/app/resto/core/dbfunctions/CatalogsFunctions.php index d3904ca1..ab972132 100755 --- a/app/resto/core/dbfunctions/CatalogsFunctions.php +++ b/app/resto/core/dbfunctions/CatalogsFunctions.php @@ -341,8 +341,7 @@ public function updateCatalog($catalog) 'catalogsUpdated' => 0 ); } - print_r($set); - print_r($values); + $results = $this->dbDriver->fetch($this->dbDriver->pQuery('UPDATE ' . $this->dbDriver->targetSchema . '.catalog SET ' . join(',', $set) . ' WHERE public.normalize(id)=public.normalize($1) RETURNING id', $values, 500, 'Cannot update facet ' . $catalog['id'])); return array(