Skip to content

Commit

Permalink
Merge branch 'development' into feature/DIMOC-230/catalogi-org-option
Browse files Browse the repository at this point in the history
  • Loading branch information
RalkeyOfficial committed Aug 9, 2024
2 parents 213de2c + 8a4ae6f commit 120f8d3
Show file tree
Hide file tree
Showing 41 changed files with 1,080 additions and 419 deletions.
20 changes: 10 additions & 10 deletions docs/dcat_example.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
"type": "application/json",
"published": "29-12-2020",
"modified": "30 december 2020, 17:09 (UTC+01:00)",
"accessURL": "https://services.arcgis.com/zP1tGdLpGvt2qNJ6/arcgis/rest/services/Voorlopige_Energielabels_BAG/FeatureServer",
"downloadURL": "https://services.arcgis.com/zP1tGdLpGvt2qNJ6/arcgis/rest/services/Voorlopige_Energielabels_BAG/FeatureServer"
"accessUrl": "https://services.arcgis.com/zP1tGdLpGvt2qNJ6/arcgis/rest/services/Voorlopige_Energielabels_BAG/FeatureServer",
"downloadUrl": "https://services.arcgis.com/zP1tGdLpGvt2qNJ6/arcgis/rest/services/Voorlopige_Energielabels_BAG/FeatureServer"
},
{
"title": "voorlopige energielabels met BAG-kenmerken ",
Expand All @@ -34,8 +34,8 @@
"type": "application/geopackage+sqlite3",
"published": "29-12-2020",
"modified": "30 december 2020, 17:10 (UTC+01:00)",
"accessURL": "file:///P:/Geo_Data/SO/SODA/Data/Energielabels/Data/VoorlopigeLabels/GPKG/Voorlopige-labels-december-2019.gpkg",
"downloadURL": "P:\\Geo_Data\\SO\\SODA\\Data\\Energielabels\\Data\\VoorlopigeLabels\\GPKG\\Voorlopige-labels-december-2019.gpkg"
"accessUrl": "file:///P:/Geo_Data/SO/SODA/Data/Energielabels/Data/VoorlopigeLabels/GPKG/Voorlopige-labels-december-2019.gpkg",
"downloadUrl": "P:\\Geo_Data\\SO\\SODA\\Data\\Energielabels\\Data\\VoorlopigeLabels\\GPKG\\Voorlopige-labels-december-2019.gpkg"
},
{
"title": "voorlopige energielabels met BAG-kenmerken ",
Expand All @@ -44,8 +44,8 @@
"type": "application/vnd.esri.filegdb",
"published": "29-12-2020",
"modified": "30 december 2020, 17:11 (UTC+01:00)",
"accessURL": "file:///P:/Geo_Data/SO/SODA/Data/Energielabels/Data/VoorlopigeLabels/GDB/Voorlopige-labels-december-2019.gdb",
"downloadURL": "P:\\Geo_Data\\SO\\SODA\\Data\\Energielabels\\Data\\VoorlopigeLabels\\GDB\\Voorlopige-labels-december-2019.gdb"
"accessUrl": "file:///P:/Geo_Data/SO/SODA/Data/Energielabels/Data/VoorlopigeLabels/GDB/Voorlopige-labels-december-2019.gdb",
"downloadUrl": "P:\\Geo_Data\\SO\\SODA\\Data\\Energielabels\\Data\\VoorlopigeLabels\\GDB\\Voorlopige-labels-december-2019.gdb"
},
{
"title": "voorlopige energielabels met BAG-kenmerken ",
Expand All @@ -54,8 +54,8 @@
"type": "application/x-shapefile",
"published": "29-12-2020",
"modified": "30 december 2020, 17:11 (UTC+01:00)",
"accessURL": "file:///P:/Geo_Data/SO/SODA/Data/Energielabels/Data/VoorlopigeLabels/GDB/Voorlopige-labels-december-2019.gdb",
"downloadURL": "P:\\Geo_Data\\SO\\SODA\\Data\\Energielabels\\Data\\VoorlopigeLabels\\SHP\\*.shp"
"accessUrl": "file:///P:/Geo_Data/SO/SODA/Data/Energielabels/Data/VoorlopigeLabels/GDB/Voorlopige-labels-december-2019.gdb",
"downloadUrl": "P:\\Geo_Data\\SO\\SODA\\Data\\Energielabels\\Data\\VoorlopigeLabels\\SHP\\*.shp"
},
{
"title": "productbeschrijving: voorlopige energielabels met BAG kenmerken",
Expand All @@ -64,8 +64,8 @@
"type": "text/html",
"published": "7-4-2020",
"modified": "30 december 2020, 17:12 (UTC+01:00)",
"accessURL": "https://rio.rotterdam.nl/Project/SODAStadsOntwikkelingData/Pages/ThoZIFnen0KbY6eBjPvh-A",
"downloadURL": "https://rio.rotterdam.nl/Project/SODAStadsOntwikkelingData/Pages/ThoZIFnen0KbY6eBjPvh-A"
"accessUrl": "https://rio.rotterdam.nl/Project/SODAStadsOntwikkelingData/Pages/ThoZIFnen0KbY6eBjPvh-A",
"downloadUrl": "https://rio.rotterdam.nl/Project/SODAStadsOntwikkelingData/Pages/ThoZIFnen0KbY6eBjPvh-A"
}
],
"attachment_count": 5,
Expand Down
214 changes: 172 additions & 42 deletions lib/Controller/AttachmentsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace OCA\OpenCatalogi\Controller;

use Exception;
use GuzzleHttp\Exception\GuzzleException;
use OCA\OpenCatalogi\Db\AttachmentMapper;
use OCA\OpenCatalogi\Service\ElasticSearchService;
Expand All @@ -12,6 +13,7 @@
use OCP\AppFramework\Http\JSONResponse;
use OCP\IAppConfig;
use OCP\IRequest;
use OCP\IUserSession;
use Symfony\Component\Uid\Uuid;

class AttachmentsController extends Controller
Expand All @@ -23,11 +25,11 @@ public function __construct
IRequest $request,
private readonly IAppConfig $config,
private readonly AttachmentMapper $attachmentMapper,
private readonly FileService $fileService
private readonly FileService $fileService,
private readonly IUserSession $userSession,
)
{
parent::__construct($appName, $request);
$this->fileService->setAppName($appName);
}

private function insertNestedObjects(array $object, ObjectService $objectService, array $config): array
Expand Down Expand Up @@ -94,8 +96,8 @@ public function catalog(string|int $id): TemplateResponse
*/
public function index(ObjectService $objectService): JSONResponse
{
if($this->config->hasKey($this->appName, 'mongoStorage') === false
|| $this->config->getValueString($this->appName, 'mongoStorage') !== '1'
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()]);
}
Expand All @@ -119,14 +121,15 @@ public function index(ObjectService $objectService): JSONResponse
return new JSONResponse($results);
}


/**
* @NoAdminRequired
* @NoCSRFRequired
*/
public function show(string|int $id, ObjectService $objectService): JSONResponse
{
if($this->config->hasKey($this->appName, 'mongoStorage') === false
|| $this->config->getValueString($this->appName, 'mongoStorage') !== '1'
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));
}
Expand All @@ -143,32 +146,157 @@ public function show(string|int $id, ObjectService $objectService): JSONResponse


/**
* @NoAdminRequired
* @NoCSRFRequired
* @throws GuzzleException In case the file upload to NextCloud fails.
* Gets info about the uploaded file from the request body, looks specifically for the field '_file'.
* If there is no file or there is an error loading it this will return an error response.
*
* @return JSONResponse|array An error response or an array containing the info about the uploaded file.
*/
public function create(ObjectService $objectService, ElasticSearchService $elasticSearchService): JSONResponse
{
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);
}

// Check for upload errors
if ($uploadedFile['error'] !== UPLOAD_ERR_OK) {
return new JSONResponse(data: ['error' => 'File upload error: '.$uploadedFile['error']], statusCode: 400);
}

return $uploadedFile;
}

/**
* Gets all params from the request body and then validates if the URL fields are actual valid urls (or null).
*
* @return JSONResponse|array An error response if there are validation errors or an array containing all request body params.
*/
private function checkRequestBody(): JSONResponse|array
{
$data = $this->request->getParams();

$uploadedFile = $this->request->getUploadedFile('_file');
// Todo: $uploadedFile['content'] does not contain the file content...
$this->fileService->uploadFile(content: $uploadedFile['content'], filePath: $uploadedFile['name']);
$data['downloadUrl'] = $this->fileService->createShareLink(path: $uploadedFile['name']);
$errorMsg = [];
if (empty($data['accessUrl']) === false && filter_var(value: $data['accessUrl'], filter: FILTER_VALIDATE_URL) === false) {
$errorMsg[] = "accessUrl is not a valid url";
}

if (empty($data['downloadUrl']) === false && filter_var(value: $data['downloadUrl'], filter: FILTER_VALIDATE_URL) === false) {
$errorMsg[] = "downloadUrl is not a valid url";
}

if (empty($errorMsg) === false) {
return new JSONResponse(data: ['validation_errors' => $errorMsg], statusCode: 400);
}

return $data;
}

/**
* If it does not already exist creates a folder for the publication the new Attachment belongs to in NextCloud,
* so that the uploaded file(s) for that publication can be saved there. After that saves the uploaded file in that folder.
* If the file is created without error this will return the full path to the file from the root/user folder.
*
* @param array $uploadedFile Information about the uploaded file from the request body.
*
* @return JSONResponse|string An error response if creating the file in NextCloud failed or a string path to the created file.
* @throws Exception In case creating a folder or new file fails.
*/
private function handleFile(array $uploadedFile): JSONResponse|string
{
// Create the Attachments folder and the Publication specific folder.
$this->fileService->createFolder(folderPath: 'Attachments');
$publicationFolder = '(' . $this->request->getHeader('Publication-Id') . ') '
. $this->request->getHeader('Publication-Title');
$this->fileService->createFolder(folderPath: "Attachments/$publicationFolder");

// Save the uploaded file
$filePath = "Attachments/$publicationFolder/" . $uploadedFile['name']; // Add a file version to the file name?
$created = $this->fileService->uploadFile(
content: file_get_contents(filename: $uploadedFile['tmp_name']),
filePath: $filePath
);

if ($created === false) {
return new JSONResponse(data: ['error' => "Failed to upload file. This file: $filePath might already exist"], statusCode: 400);
}

return $filePath;
}


/**
* Adds information about the uploaded file to the appropriate Attachment fields. And removes fields we do not want to post.
*
* @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.
* @param string $filePath The full file path to where the file is stored in NextCloud.
*
* @return array The updated $data array
* @throws Exception In case creating the share(link) fails.
*/
private function AddFileInfoToData(array $data, array $uploadedFile, string $filePath): array
{
// Update Attachment data
$currentUser = $this->userSession->getUser();
$userId = $currentUser ? $currentUser->getUID() : 'Guest';
$data['reference'] = "$userId/$filePath";
$data['type'] = $uploadedFile['type'];
$data['size'] = $uploadedFile['size'];
$explodedName = explode('.', $uploadedFile['name']);
$explodedName = explode(separator: '.', string: $uploadedFile['name']);
$data['title'] = $explodedName[0];
$data['extension'] = end($explodedName);
$data['extension'] = end(array: $explodedName);

// Create ShareLink
$shareLink = $this->fileService->createShareLink(path: $filePath);
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($key, '_')) {
if(str_starts_with(haystack: $key, needle: '_')) {
unset($data[$key]);
}
}

if($this->config->hasKey($this->appName, 'mongoStorage') === false
|| $this->config->getValueString($this->appName, 'mongoStorage') !== '1'
return $data;
}


/**
* @NoAdminRequired
* @NoCSRFRequired
* @throws Exception In case creating a new folder, the file upload to NextCloud, or creating the share link fails.
* @throws GuzzleException In case saving the Attachment to MongoDB fails.
*/
public function create(ObjectService $objectService, ElasticSearchService $elasticSearchService): JSONResponse
{
// Check if a file was uploaded
$uploadedFile = $this->checkUploadedFile();
if ($uploadedFile instanceof JSONResponse) {
return $uploadedFile;
}

// Get form-data field/request body.
$data = $this->checkRequestBody();
if ($data instanceof JSONResponse) {
return $data;
}

// 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);

if ($this->config->hasKey(app: $this->appName, key: 'mongoStorage') === false
|| $this->config->getValueString(app: $this->appName, key: 'mongoStorage') !== '1'
) {
return new JSONResponse($this->attachmentMapper->createFromArray(object: $data));
}
Expand All @@ -191,32 +319,22 @@ public function create(ObjectService $objectService, ElasticSearchService $elast
/**
* @NoAdminRequired
* @NoCSRFRequired
* @throws GuzzleException In case updating the file in NextCloud fails.
*/
public function update(string|int $id, ObjectService $objectService, ElasticSearchService $elasticSearchService): JSONResponse
{
$data = $this->request->getParams();

$uploadedFile = $this->request->getUploadedFile('_file');
// Todo: $uploadedFile['content'] does not contain the file content...
$this->fileService->uploadFile(content: $uploadedFile['content'], filePath: $uploadedFile['name'], update: true);
// $data['downloadUrl'] = $this->fileService->createShareLink(path: $uploadedFile['name']);
$data['type'] = $uploadedFile['type'];
$data['size'] = $uploadedFile['size'];
$explodedName = explode('.', $uploadedFile['name']);
$data['title'] = $explodedName[0];
$data['extension'] = end($explodedName);

// Remove fields we should never post
unset($data['id']);
foreach($data as $key => $value) {
if(str_starts_with($key, '_')) {
if(str_starts_with(haystack: $key, needle: '_')) {
unset($data[$key]);
}
}
if (isset($data['id'])) {
unset( $data['id']);
}

if($this->config->hasKey($this->appName, 'mongoStorage') === false
|| $this->config->getValueString($this->appName, 'mongoStorage') !== '1'
if ($this->config->hasKey(app: $this->appName, key: 'mongoStorage') === false
|| $this->config->getValueString(app: $this->appName, key: 'mongoStorage') !== '1'
) {
return new JSONResponse($this->attachmentMapper->updateFromArray(id: (int) $id, object: $data));
}
Expand Down Expand Up @@ -246,14 +364,26 @@ public function update(string|int $id, ObjectService $objectService, ElasticSear
*/
public function destroy(string|int $id, ObjectService $objectService, ElasticSearchService $elasticSearchService): JSONResponse
{
$attachment = $this->show($id, $objectService)->getData()->jsonSerialize();
// Todo: are we sure this is the best way to do this (how do we save the full path to this file in nextCloud)
$this->fileService->deleteFile(filePath: $attachment['title']. '.' .$attachment['extension']);
$attachment = $this->show(id: $id, objectService: $objectService)->getData();
if ($this->config->hasKey(app: $this->appName, key: 'mongoStorage') === false
|| $this->config->getValueString(app: $this->appName, key: 'mongoStorage') !== '1'
) {
$attachment = $attachment->jsonSerialize();
}

if($this->config->hasKey($this->appName, 'mongoStorage') === false
|| $this->config->getValueString($this->appName, 'mongoStorage') !== '1'
// Todo: are we sure this is the best way to do this (how do we save the full path to this file in nextCloud)
// $publicationFolder = '(' . $this->request->getHeader('Publication-Id') . ') '
// . $this->request->getHeader('Publication-Title');
// $this->fileService->deleteFile(filePath: "Attachments/$publicationFolder" . $attachment['title'] . '.' . $attachment['extension']);
$filePath = explode(separator: '/', string: $attachment['reference']);
array_shift(array: $filePath);
$filePath = implode(separator: '/', array: $filePath);
$this->fileService->deleteFile(filePath: $filePath);

if ($this->config->hasKey(app: $this->appName, key: 'mongoStorage') === false
|| $this->config->getValueString(app: $this->appName, key: 'mongoStorage') !== '1'
) {
$this->attachmentMapper->delete($this->attachmentMapper->find((int) $id));
$this->attachmentMapper->delete(entity: $this->attachmentMapper->find(id: (int) $id));

return new JSONResponse([]);
}
Expand Down
2 changes: 2 additions & 0 deletions lib/Controller/CatalogiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ public function create(ObjectService $objectService, DirectoryService $directory
{
$data = $this->request->getParams();

// Remove fields we should never post
unset($data['id']);
foreach ($data as $key => $value) {
if (str_starts_with($key, '_')) {
unset($data[$key]);
Expand Down
4 changes: 1 addition & 3 deletions lib/Controller/ConfigurationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,7 @@ public function index(): JSONResponse
'elasticIndex' => '',
'organisationName' => 'my-organisation',
'organisationOin' => '',
'organisationPki' => '',
'adminUsername' => '',
'adminPassword' => ''
'organisationPki' => ''
];

try {
Expand Down
5 changes: 2 additions & 3 deletions lib/Controller/DirectoryController.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,13 @@ public function update(string|int $id, ObjectService $objectService): JSONRespon

$data = $this->request->getParams();

// Remove fields we should never post
unset($data['id']);
foreach($data as $key => $value) {
if(str_starts_with($key, '_')) {
unset($data[$key]);
}
}
if (isset($data['id'])) {
unset( $data['id']);
}


if($this->config->hasKey($this->appName, 'mongoStorage') === false
Expand Down
Loading

0 comments on commit 120f8d3

Please sign in to comment.