diff --git a/appinfo/routes.php b/appinfo/routes.php index 3a3e2056..a14b912e 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -14,6 +14,7 @@ ['name' => 'dashboard#page', 'url' => '/', 'verb' => 'GET'], ['name' => 'metadata#page', 'url' => '/metadata', 'verb' => 'GET'], ['name' => 'publications#page', 'url' => '/publications', 'verb' => 'GET'], + ['name' => 'publications#attachments', 'url' => '/api/publications/{id}/attachments', 'verb' => 'GET', 'requirements' => ['id' => '.+']], ['name' => 'catalogi#page', 'url' => '/catalogi', 'verb' => 'GET'], ['name' => 'search#index', 'url' => '/search', 'verb' => 'GET'], ['name' => 'search#index', 'url' => '/api/search', 'verb' => 'GET'], diff --git a/lib/Controller/AttachmentsController.php b/lib/Controller/AttachmentsController.php index be2e3d88..c7776c8c 100644 --- a/lib/Controller/AttachmentsController.php +++ b/lib/Controller/AttachmentsController.php @@ -9,6 +9,7 @@ use OCA\OpenCatalogi\Service\FileService; use OCA\OpenCatalogi\Service\ObjectService; use OCP\AppFramework\Controller; +use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Http\JSONResponse; use OCP\IAppConfig; @@ -99,7 +100,7 @@ public function index(ObjectService $objectService): JSONResponse if ($this->config->hasKey(app: $this->appName, key: 'mongoStorage') === false || $this->config->getValueString(app: $this->appName, key: 'mongoStorage') !== '1' ) { - return new JSONResponse(['results' =>$this->attachmentMapper->findAll()]); + return new JSONResponse(['results' => $this->attachmentMapper->findAll()]); } $dbConfig['base_uri'] = $this->config->getValueString(app: $this->appName, key: 'mongodbLocation'); $dbConfig['headers']['api-key'] = $this->config->getValueString(app: $this->appName, key: 'mongodbKey'); @@ -131,7 +132,11 @@ public function show(string|int $id, ObjectService $objectService): JSONResponse if ($this->config->hasKey(app: $this->appName, key: 'mongoStorage') === false || $this->config->getValueString(app: $this->appName, key: 'mongoStorage') !== '1' ) { - return new JSONResponse($this->attachmentMapper->find(id: (int) $id)); + try { + return new JSONResponse($this->attachmentMapper->find(id: (int) $id)); + } catch (DoesNotExistException $exception) { + return new JSONResponse(data: ['error' => 'Not Found'], statusCode: 404); + } } $dbConfig['base_uri'] = $this->config->getValueString(app: $this->appName, key: 'mongodbLocation'); $dbConfig['headers']['api-key'] = $this->config->getValueString(app: $this->appName, key: 'mongodbKey'); @@ -156,7 +161,7 @@ private function checkUploadedFile(): JSONResponse|array $uploadedFile = $this->request->getUploadedFile(key: '_file'); if (empty($uploadedFile) === true) { - return new JSONResponse(data: ['error' => 'No file uploaded for key "_file"'], statusCode: 400); + return new JSONResponse(data: ['error' => 'Please upload a file using key "_file" or give a "downloadUrl"'], statusCode: 400); } // Check for upload errors @@ -168,14 +173,14 @@ private function checkUploadedFile(): JSONResponse|array } /** - * Gets all params from the request body and then validates if the URL fields are actual valid urls (or null). + * Validates if the URL fields are actual valid urls (or null). + * + * @param array $data The form-data fields and their values (/request body). * * @return JSONResponse|array An error response if there are validation errors or an array containing all request body params. */ - private function checkRequestBody(): JSONResponse|array + private function checkRequestBody(array $data): JSONResponse|array { - $data = $this->request->getParams(); - $errorMsg = []; if (empty($data['accessUrl']) === false && filter_var(value: $data['accessUrl'], filter: FILTER_VALIDATE_URL) === false) { $errorMsg[] = "accessUrl is not a valid url"; @@ -226,7 +231,7 @@ private function handleFile(array $uploadedFile): JSONResponse|string /** - * Adds information about the uploaded file to the appropriate Attachment fields. And removes fields we do not want to post. + * Adds information about the uploaded file to the appropriate Attachment fields. * * @param array $data The form-data fields and their values (/request body) that we are going to update before posting the Attachment. * @param array $uploadedFile Information about the uploaded file from the request body. @@ -252,14 +257,8 @@ private function AddFileInfoToData(array $data, array $uploadedFile, string $fil if (empty($data['accessUrl']) === true) { $data['accessUrl'] = $shareLink; } - $data['downloadUrl'] = "$shareLink/download"; - - // Remove fields we should never post - unset($data['id']); - foreach($data as $key => $value) { - if(str_starts_with(haystack: $key, needle: '_')) { - unset($data[$key]); - } + if (empty($data['downloadUrl']) === true) { + $data['downloadUrl'] = "$shareLink/download"; } return $data; @@ -274,26 +273,40 @@ private function AddFileInfoToData(array $data, array $uploadedFile, string $fil */ public function create(ObjectService $objectService, ElasticSearchService $elasticSearchService): JSONResponse { - // Check if a file was uploaded - $uploadedFile = $this->checkUploadedFile(); - if ($uploadedFile instanceof JSONResponse) { - return $uploadedFile; + $data = $this->request->getParams(); + // Uploaded _file and downloadURL are mutually exclusive + if (empty($data['downloadUrl']) === true) { + // Check if a file was uploaded + $uploadedFile = $this->checkUploadedFile(); + if ($uploadedFile instanceof JSONResponse) { + return $uploadedFile; + } } - // Get form-data field/request body. - $data = $this->checkRequestBody(); + // Get form-data field/request body and validate the input. + $data = $this->checkRequestBody($data); if ($data instanceof JSONResponse) { return $data; } - // Handle saving the uploaded file in NextCloud - $filePath = $this->handleFile(uploadedFile: $uploadedFile); - if ($filePath instanceof JSONResponse) { - return $filePath; + if (empty($uploadedFile) === false) { + // Handle saving the uploaded file in NextCloud + $filePath = $this->handleFile(uploadedFile: $uploadedFile); + if ($filePath instanceof JSONResponse) { + return $filePath; + } + + // Update Attachment data + $data = $this->AddFileInfoToData(data: $data, uploadedFile: $uploadedFile, filePath: $filePath); } - // Update Attachment data - $data = $this->AddFileInfoToData(data: $data, uploadedFile: $uploadedFile, filePath: $filePath); + // Remove fields we should never post + unset($data['id']); + foreach($data as $key => $value) { + if(str_starts_with(haystack: $key, needle: '_')) { + unset($data[$key]); + } + } if ($this->config->hasKey(app: $this->appName, key: 'mongoStorage') === false || $this->config->getValueString(app: $this->appName, key: 'mongoStorage') !== '1' diff --git a/lib/Controller/CatalogiController.php b/lib/Controller/CatalogiController.php index e964309a..83f26a89 100644 --- a/lib/Controller/CatalogiController.php +++ b/lib/Controller/CatalogiController.php @@ -7,6 +7,7 @@ use OCA\OpenCatalogi\Service\ObjectService; use OCA\OpenCatalogi\Service\SearchService; use OCP\AppFramework\Controller; +use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Http\JSONResponse; use OCP\IAppConfig; @@ -81,7 +82,11 @@ public function show(string|int $id, ObjectService $objectService): JSONResponse if($this->config->hasKey($this->appName, 'mongoStorage') === false || $this->config->getValueString($this->appName, 'mongoStorage') !== '1' ) { - return new JSONResponse($this->catalogMapper->find(id: (int) $id)); + try { + return new JSONResponse($this->catalogMapper->find(id: (int) $id)); + } catch (DoesNotExistException $exception) { + return new JSONResponse(data: ['error' => 'Not Found'], statusCode: 404); + } } try { diff --git a/lib/Controller/DirectoryController.php b/lib/Controller/DirectoryController.php index b6af3038..53f32965 100644 --- a/lib/Controller/DirectoryController.php +++ b/lib/Controller/DirectoryController.php @@ -7,6 +7,7 @@ use OCA\OpenCatalogi\Service\ObjectService; use OCA\OpenCatalogi\Service\SearchService; use OCP\AppFramework\Controller; +use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Http\JSONResponse; use OCP\IAppConfig; @@ -115,7 +116,11 @@ public function show(string|int $id, ObjectService $objectService, DirectoryServ if($this->config->hasKey($this->appName, 'mongoStorage') === false || $this->config->getValueString($this->appName, 'mongoStorage') !== '1' ) { - return new JSONResponse($this->listingMapper->find(id: (int) $id)); + try { + return new JSONResponse($this->listingMapper->find(id: (int) $id)); + } catch (DoesNotExistException $exception) { + return new JSONResponse(data: ['error' => 'Not Found'], statusCode: 404); + } } $dbConfig['base_uri'] = $this->config->getValueString(app: $this->appName, key: 'mongodbLocation'); $dbConfig['headers']['api-key'] = $this->config->getValueString(app: $this->appName, key: 'mongodbKey'); diff --git a/lib/Controller/MetaDataController.php b/lib/Controller/MetaDataController.php index ace7db19..282ac304 100644 --- a/lib/Controller/MetaDataController.php +++ b/lib/Controller/MetaDataController.php @@ -6,6 +6,7 @@ use OCA\OpenCatalogi\Service\ObjectService; use OCA\OpenCatalogi\Service\SearchService; use OCP\AppFramework\Controller; +use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Http\JSONResponse; use OCP\IAppConfig; @@ -84,7 +85,11 @@ public function show(string|int $id, ObjectService $objectService): JSONResponse if($this->config->hasKey($this->appName, 'mongoStorage') === false || $this->config->getValueString($this->appName, 'mongoStorage') !== '1' ) { - return new JSONResponse($this->metaDataMapper->find(id: (int) $id)); + try { + return new JSONResponse($this->metaDataMapper->find(id: (int) $id)); + } catch (DoesNotExistException $exception) { + return new JSONResponse(data: ['error' => 'Not Found'], statusCode: 404); + } } $dbConfig['base_uri'] = $this->config->getValueString(app: $this->appName, key: 'mongodbLocation'); $dbConfig['headers']['api-key'] = $this->config->getValueString(app: $this->appName, key: 'mongodbKey'); diff --git a/lib/Controller/OrganisationsController.php b/lib/Controller/OrganisationsController.php index 04cbbaf8..5039a395 100644 --- a/lib/Controller/OrganisationsController.php +++ b/lib/Controller/OrganisationsController.php @@ -6,6 +6,7 @@ use OCA\OpenCatalogi\Service\ObjectService; use OCP\AppFramework\Controller; use OCA\OpenCatalogi\Service\SearchService; +use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Http\JSONResponse; use OCP\IAppConfig; @@ -93,7 +94,11 @@ public function show(string $id, ObjectService $objectService): JSONResponse if($this->config->hasKey($this->appName, 'mongoStorage') === false || $this->config->getValueString($this->appName, 'mongoStorage') !== '1' ) { - return new JSONResponse($this->organisationMapper->find(id: (int) $id)); + try { + return new JSONResponse($this->organisationMapper->find(id: (int) $id)); + } catch (DoesNotExistException $exception) { + return new JSONResponse(data: ['error' => 'Not Found'], statusCode: 404); + } } try { diff --git a/lib/Controller/PublicationsController.php b/lib/Controller/PublicationsController.php index 6534ff1d..3111b16e 100644 --- a/lib/Controller/PublicationsController.php +++ b/lib/Controller/PublicationsController.php @@ -2,14 +2,15 @@ namespace OCA\OpenCatalogi\Controller; -use Elastic\Elasticsearch\Client; use GuzzleHttp\Exception\GuzzleException; +use OCA\OpenCatalogi\Db\AttachmentMapper; use OCA\opencatalogi\lib\Db\Publication; use OCA\OpenCatalogi\Db\PublicationMapper; use OCA\OpenCatalogi\Service\ElasticSearchService; use OCA\OpenCatalogi\Service\ObjectService; use OCA\OpenCatalogi\Service\SearchService; use OCP\AppFramework\Controller; +use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Http\JSONResponse; use OCP\IAppConfig; @@ -24,6 +25,7 @@ public function __construct $appName, IRequest $request, private readonly PublicationMapper $publicationMapper, + private readonly AttachmentMapper $attachmentMapper, private readonly IAppConfig $config ) { @@ -83,17 +85,17 @@ public function page(?string $getParameter) * @NoCSRFRequired */ public function catalog(string|int $id): TemplateResponse - { - // The TemplateResponse loads the 'main.php' - // defined in our app's 'templates' folder. - // We pass the $getParameter variable to the template - // so that the value is accessible in the template. - return new TemplateResponse( - $this->appName, - 'PublicationsIndex', - [] - ); - } + { + // The TemplateResponse loads the 'main.php' + // defined in our app's 'templates' folder. + // We pass the $getParameter variable to the template + // so that the value is accessible in the template. + return new TemplateResponse( + $this->appName, + 'PublicationsIndex', + [] + ); + } /** * @NoAdminRequired @@ -112,7 +114,7 @@ public function index(ObjectService $objectService, SearchService $searchService $sort = $searchService->createSortForMySQL(filters: $filters); $filters = $searchService->unsetSpecialQueryParams(filters: $filters); - return new JSONResponse(['results' => $this->publicationMapper->findAll(limit: null, offset: null, filters: $filters, searchConditions: $searchConditions, searchParams: $searchParams, sort: $sort)]); + return new JSONResponse(['results' => $this->publicationMapper->findAll(filters: $filters, searchConditions: $searchConditions, searchParams: $searchParams, sort: $sort)]); } $filters = $searchService->createMongoDBSearchFilter(filters: $filters, fieldsToSearch: $fieldsToSearch); @@ -133,16 +135,55 @@ public function index(ObjectService $objectService, SearchService $searchService return new JSONResponse($results); } + /** + * @NoAdminRequired + * @NoCSRFRequired + */ + public function attachments(string|int $id, ObjectService $objectService): JSONResponse + { + $publication = $this->show($id, $objectService)->getData(); + if ($this->config->hasKey(app: $this->appName, key: 'mongoStorage') === false + || $this->config->getValueString(app: $this->appName, key: 'mongoStorage') !== '1' + ) { + $publication = $publication->jsonSerialize(); + } + + $attachments = $publication['attachments']; + + if ($this->config->hasKey($this->appName, 'mongoStorage') === false + || $this->config->getValueString($this->appName, 'mongoStorage') !== '1' + ) { + return new JSONResponse(['results' => $this->attachmentMapper->findMultiple($attachments)]); + } + + $filters = []; + $filters['id']['$in'] = $attachments; + + $dbConfig['base_uri'] = $this->config->getValueString(app: $this->appName, key: 'mongodbLocation'); + $dbConfig['headers']['api-key'] = $this->config->getValueString(app: $this->appName, key: 'mongodbKey'); + $dbConfig['mongodbCluster'] = $this->config->getValueString(app: $this->appName, key: 'mongodbCluster'); + + $filters['_schema'] = 'attachment'; + + $result = $objectService->findObjects(filters: $filters, config: $dbConfig); + + return new JSONResponse(['results' => $result['documents']]); + } + /** * @NoAdminRequired * @NoCSRFRequired */ public function show(string|int $id, ObjectService $objectService): JSONResponse { - if($this->config->hasKey($this->appName, 'mongoStorage') === false + if ($this->config->hasKey($this->appName, 'mongoStorage') === false || $this->config->getValueString($this->appName, 'mongoStorage') !== '1' ) { - return new JSONResponse($this->publicationMapper->find(id: (int) $id)); + try { + return new JSONResponse($this->publicationMapper->find(id: (int) $id)); + } catch (DoesNotExistException $exception) { + return new JSONResponse(data: ['error' => 'Not Found'], statusCode: 404); + } } $dbConfig['base_uri'] = $this->config->getValueString(app: $this->appName, key: 'mongodbLocation'); diff --git a/lib/Controller/SearchController.php b/lib/Controller/SearchController.php index 7e4fcb90..7eca2aa4 100644 --- a/lib/Controller/SearchController.php +++ b/lib/Controller/SearchController.php @@ -101,8 +101,8 @@ public function index(SearchService $searchService): JSONResponse $searchParams = $searchService->createMySQLSearchParams(filters: $filters); $searchConditions = $searchService->createMySQLSearchConditions(filters: $filters, fieldsToSearch: $fieldsToSearch); - $limit = null; - $offset = null; + $limit = 30; + $offset = 0; if(isset($filters['_limit']) === true) { $limit = $filters['_limit']; @@ -114,9 +114,19 @@ public function index(SearchService $searchService): JSONResponse $filters = $searchService->unsetSpecialQueryParams(filters: $filters); - - - return new JSONResponse(['results' => $this->publicationMapper->findAll(limit: $limit, offset: $offset, filters: $filters, searchConditions: $searchConditions, searchParams: $searchParams)]); + $total = $this->publicationMapper->count($filters); + $results = $this->publicationMapper->findAll(limit: $limit, offset: $offset, filters: $filters, searchConditions: $searchConditions, searchParams: $searchParams); + $pages = (int) ceil($total / $limit); + + return new JSONResponse([ + 'results' => $results, + 'facets' => [], + 'count' => count($results), + 'limit' => $limit, + 'page' => isset($filters['_page']) === true ? $filters['_page'] : 1, + 'pages' => $pages === 0 ? 1 : $pages, + 'total' => $total + ]); } //@TODO: find a better way to get query params. This fixes it for now. diff --git a/lib/Controller/ThemesController.php b/lib/Controller/ThemesController.php index 308c92c6..16454ac4 100644 --- a/lib/Controller/ThemesController.php +++ b/lib/Controller/ThemesController.php @@ -6,6 +6,7 @@ use OCA\OpenCatalogi\Service\ObjectService; use OCA\OpenCatalogi\Service\SearchService; use OCP\AppFramework\Controller; +use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Http\JSONResponse; use OCP\IAppConfig; @@ -107,7 +108,11 @@ public function show(string $id, ObjectService $objectService): JSONResponse if($this->config->hasKey($this->appName, 'mongoStorage') === false || $this->config->getValueString($this->appName, 'mongoStorage') !== '1' ) { - return new JSONResponse($this->themeMapper->find(id: (int) $id)); + try { + return new JSONResponse($this->themeMapper->find(id: (int) $id)); + } catch (DoesNotExistException $exception) { + return new JSONResponse(data: ['error' => 'Not Found'], statusCode: 404); + } } try { diff --git a/lib/Db/Attachment.php b/lib/Db/Attachment.php index ed1c2847..d06d4c0c 100644 --- a/lib/Db/Attachment.php +++ b/lib/Db/Attachment.php @@ -96,8 +96,8 @@ public function jsonSerialize(): array 'hash' => $this->hash, 'anonymization' => $this->anonymization, 'language' => $this->language, - 'modified' => $this->modified->format('c'), - 'published' => $this->published->format('c'), + 'modified' => $this->modified?->format('c'), + 'published' => $this->published?->format('c'), 'license' => $this->license, ]; diff --git a/lib/Db/AttachmentMapper.php b/lib/Db/AttachmentMapper.php index 9e97af7e..9c32b8b6 100644 --- a/lib/Db/AttachmentMapper.php +++ b/lib/Db/AttachmentMapper.php @@ -28,6 +28,17 @@ public function find(int $id): Attachment return $this->findEntity(query: $qb); } + public function findMultiple(array $ids): array + { + $qb = $this->db->getQueryBuilder(); + + $qb->select('*') + ->from('attachments') + ->where($qb->expr()->in('id', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY))); + + return $this->findEntities(query: $qb); + } + public function findAll($limit = null, $offset = null): array { $qb = $this->db->getQueryBuilder(); diff --git a/lib/Db/Catalog.php b/lib/Db/Catalog.php index 05958101..320b0aac 100644 --- a/lib/Db/Catalog.php +++ b/lib/Db/Catalog.php @@ -42,12 +42,6 @@ public function getJsonFields(): array public function hydrate(array $object): self { - - - if(isset($object['metadata']) === false) { - $object['metadata'] = []; - } - $jsonFields = $this->getJsonFields(); foreach($object as $key => $value) { diff --git a/lib/Db/PublicationMapper.php b/lib/Db/PublicationMapper.php index 74f6f0fd..9aa60c71 100644 --- a/lib/Db/PublicationMapper.php +++ b/lib/Db/PublicationMapper.php @@ -28,14 +28,78 @@ public function find(int $id): Publication return $this->findEntity(query: $qb); } - public function findAll( - ?int $limit = null, - ?int $offset = null, - ?array $filters = [], - ?array $searchConditions = [], - ?array $searchParams = [], - ?array $sort = [] - ): array { + private function parseComplexFilter(IQueryBuilder $queryBuilder, array $filter, string $name): IQueryBuilder + { + foreach($filter as $key => $value) { + switch($key) { + case '>=': + case 'after': + $queryBuilder->andWhere($queryBuilder->expr()->gte($name, $queryBuilder->createNamedParameter($value))); + break; + case '>': + case 'strictly_after': + $queryBuilder->andWhere($queryBuilder->expr()->gt($name, $queryBuilder->createNamedParameter($value))); + break; + case '<=': + case 'before': + $queryBuilder->andWhere($queryBuilder->expr()->lte($name, $queryBuilder->createNamedParameter($value))); + break; + case '<': + case 'strictly_before': + $queryBuilder->andWhere($queryBuilder->expr()->lt($name, $queryBuilder->createNamedParameter($value))); + break; + default: + $queryBuilder->andWhere($queryBuilder->expr()->eq($name, $queryBuilder->createNamedParameter($filter))); + } + } + + return $queryBuilder; + } + + private function addFilters(IQueryBuilder $queryBuilder, array $filters): IQueryBuilder + { + foreach($filters as $key => $filter) { + if(is_array($filter) === false) { + $queryBuilder->andWhere($queryBuilder->expr()->eq($key, $queryBuilder->createNamedParameter($key))); + $queryBuilder->setParameter($key, $filter); + continue; + } + + $queryBuilder = $this->parseComplexFilter(queryBuilder: $queryBuilder, filter: $filter, name: $key); + } + + return $queryBuilder; + } + + public function count(?array $filters = [], ?array $searchConditions = [], ?array $searchParams = []): int + { + + + $qb = $this->db->getQueryBuilder(); + + $qb->selectAlias($qb->createFunction('COUNT(*)'), 'count') + ->from('publications'); + + + $qb = $this->addFilters(queryBuilder: $qb, filters: $filters); + + + if (!empty($searchConditions)) { + $qb->andWhere('(' . implode(' OR ', $searchConditions) . ')'); + foreach ($searchParams as $param => $value) { + $qb->setParameter($param, $value); + } + } + + $cursor = $qb->execute(); + $row = $cursor->fetch(); + $cursor->closeCursor(); + + return $row['count']; + } + + public function findAll(?int $limit = null, ?int $offset = null, ?array $filters = [], ?array $searchConditions = [], ?array $searchParams = [], ?array $sort = []): array + { $qb = $this->db->getQueryBuilder(); $qb->select('*') @@ -43,15 +107,7 @@ public function findAll( ->setMaxResults($limit) ->setFirstResult($offset); - foreach($filters as $filter => $value) { - if ($value === 'IS NOT NULL') { - $qb->andWhere($qb->expr()->isNotNull($filter)); - } elseif ($value === 'IS NULL') { - $qb->andWhere($qb->expr()->isNull($filter)); - } else { - $qb->andWhere($qb->expr()->eq($filter, $qb->createNamedParameter($value))); - } - } + $qb = $this->addFilters(queryBuilder: $qb, filters: $filters); if (empty($searchConditions) === false) { $qb->andWhere('(' . implode(' OR ', $searchConditions) . ')'); @@ -66,7 +122,7 @@ public function findAll( $qb->addOrderBy($field, $direction); } } - + return $this->findEntities(query: $qb); } diff --git a/lib/Migration/Version6Date20240723125106.php b/lib/Migration/Version6Date20240723125106.php index d12ccc8d..b04a1818 100644 --- a/lib/Migration/Version6Date20240723125106.php +++ b/lib/Migration/Version6Date20240723125106.php @@ -80,18 +80,18 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt 'notnull' => false, ] ); - $table->addColumn(name: 'organization', typeName: TYPES::JSON, options: [ - 'default' => 'a:0:{}', + $organization = $table->addColumn(name: 'organization', typeName: TYPES::JSON, options: [ 'notnull' => false, ]); - $table->addColumn(name: 'data', typeName: TYPES::JSON, options: [ - 'default' => 'a:0:{}', + $organization->setDefault('{}'); + $data = $table->addColumn(name: 'data', typeName: TYPES::JSON, options: [ 'notnull' => false, ]); - $table->addColumn(name: 'attachments', typeName: TYPES::JSON, options: [ - 'default' => 'a:0:{}', + $data->setDefault('{}'); + $attachments = $table->addColumn(name: 'attachments', typeName: TYPES::JSON, options: [ 'notnull' => false, ]); + $attachments->setDefault('{}'); $table->addColumn(name: 'attachment_count', typeName: TYPES::INTEGER); $table->addColumn(name: 'schema', typeName: TYPES::STRING); $table->addColumn(name: 'status', typeName: TYPES::STRING); diff --git a/lib/Migration/Version6Date20240808085441.php b/lib/Migration/Version6Date20240808085441.php index 28e43b3a..c1a2bea2 100644 --- a/lib/Migration/Version6Date20240808085441.php +++ b/lib/Migration/Version6Date20240808085441.php @@ -53,13 +53,13 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt ]); } if($table->hasColumn(name: 'metadata') === false) { - $table->addColumn( + $metadata = $table->addColumn( name: 'metadata', typeName: Types::JSON, options: [ 'notNull' => false, - 'default' => 'a:0:{}' ]); + $metadata->setDefault('{}'); } } diff --git a/lib/Service/ElasticSearchService.php b/lib/Service/ElasticSearchService.php index ef16edd4..cd133425 100644 --- a/lib/Service/ElasticSearchService.php +++ b/lib/Service/ElasticSearchService.php @@ -91,7 +91,7 @@ public function updateObject(string $id, array $object, array $config): array } } - public function parseFilter(string $name, array $filter): array + public function parseFilter(string $name, array|string $filter): array { if(is_array($filter) === false) { diff --git a/lib/Service/SearchService.php b/lib/Service/SearchService.php index d31d18b1..36e5c759 100644 --- a/lib/Service/SearchService.php +++ b/lib/Service/SearchService.php @@ -74,6 +74,7 @@ public function sortResultArray(array $a, array $b): int return $a['_score'] <=> $b['_score']; } + /** * */ @@ -96,13 +97,14 @@ public function search(array $parameters, array $elasticConfig, array $dbConfig, // $directory = $this->objectService->findObjects(filters: ['_schema' => 'directory'], config: $dbConfig); if(count($directory) === 0) { + $pages = (int) ceil($totalResults / $limit); return [ 'results' => $localResults['results'], 'facets' => $localResults['facets'], 'count' => count($localResults['results']), 'limit' => $limit, 'page' => $page, - 'pages' => ceil($totalResults / $limit), + 'pages' => $pages === 0 ? 1 : $pages, 'total' => $totalResults ]; } @@ -155,13 +157,15 @@ public function search(array $parameters, array $elasticConfig, array $dbConfig, } } + $pages = (int) ceil($totalResults / $limit); + return [ 'results' => $results, 'facets' => $aggregations, 'count' => count($results), 'limit' => $limit, 'page' => $page, - 'pages' => ceil($totalResults / $limit), + 'pages' => $pages === 0 ? 1 : $pages, 'total' => $totalResults ]; } diff --git a/src/dialogs/attachment/CopyAttachmentDialog.vue b/src/dialogs/attachment/CopyAttachmentDialog.vue index f1d4eb4f..3931f851 100644 --- a/src/dialogs/attachment/CopyAttachmentDialog.vue +++ b/src/dialogs/attachment/CopyAttachmentDialog.vue @@ -86,14 +86,11 @@ export default { .then((response) => { this.loading = false this.succes = true - // Lets refresh the attachment list - response.json().then((data) => { - publicationStore.setAttachmentItem(data) - }) - if (publicationStore.publicationItem?.id) { - publicationStore.getPublicationAttachments(publicationStore.publicationItem.id) - // @todo update the publication item + + if (publicationStore.publicationItem) { + publicationStore.getPublicationAttachments(publicationStore.publicationItem) } + // Wait for the user to read the feedback then close the model const self = this setTimeout(function() { diff --git a/src/dialogs/attachment/DeleteAttachmentDialog.vue b/src/dialogs/attachment/DeleteAttachmentDialog.vue index 9d6b36b0..fe2eb88b 100644 --- a/src/dialogs/attachment/DeleteAttachmentDialog.vue +++ b/src/dialogs/attachment/DeleteAttachmentDialog.vue @@ -61,7 +61,7 @@ export default { }, data() { return { - + filterdAttachments: [], loading: false, succes: false, error: false, @@ -83,10 +83,38 @@ export default { this.loading = false this.succes = true // Lets refresh the attachment list - if (publicationStore.publicationItem?.id) { - publicationStore.getPublicationAttachments(publicationStore.publicationItem.id) - // @todo update the publication item + if (publicationStore.publicationItem) { + publicationStore.getPublicationAttachments(publicationStore.publicationItem) + this.filterdAttachments = publicationStore.publicationItem.attachments.filter((attachment) => { return parseInt(attachment) !== parseInt(publicationStore.attachmentItem.id) }) + + fetch( + `/index.php/apps/opencatalogi/api/publications/${publicationStore.publicationItem.id}`, + { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + ...publicationStore.publicationItem, + attachments: [...this.filterdAttachments], + }), + }, + ) + .then((response) => { + this.loading = false + + // Lets refresh the publicationList + publicationStore.refreshPublicationList() + response.json().then((data) => { + publicationStore.setPublicationItem(data) + }) + }) + .catch((err) => { + this.error = err + this.loading = false + }) } + // Wait for the user to read the feedback then close the model const self = this setTimeout(function() { diff --git a/src/dialogs/attachment/DepublishAttachmentDialog.vue b/src/dialogs/attachment/DepublishAttachmentDialog.vue index bf0a2ff1..71f90eb5 100644 --- a/src/dialogs/attachment/DepublishAttachmentDialog.vue +++ b/src/dialogs/attachment/DepublishAttachmentDialog.vue @@ -30,7 +30,7 @@ import { publicationStore, navigationStore } from '../../store/store.js' v-if="!succes" :disabled="loading" type="primary" - @click="CopyAttachment()"> + @click="depublishAttachment()">