diff --git a/.invenio/.gitignore b/.invenio/.gitignore index ed8ebf583f771da9150c35db3955987b7d757904..150c6f7559b9b2d2589bf19527624f975d3b8d81 100644 --- a/.invenio/.gitignore +++ b/.invenio/.gitignore @@ -1 +1,3 @@ -__pycache__ \ No newline at end of file +__pycache__ + +features.csv \ No newline at end of file diff --git a/.invenio/api_authentication/configuration.py b/.invenio/api_authentication/configuration.py index a35f4efa83f8e7872add91b87e3820876cd4a034..2638b5e36f20bba23c9228abf90fd54e7d31fd14 100644 --- a/.invenio/api_authentication/configuration.py +++ b/.invenio/api_authentication/configuration.py @@ -46,7 +46,7 @@ class Configuration(six.with_metaclass(TypeWithDefault, object)): def __init__(self): """Constructor""" # Default Base url - self.host = "http://localhost:9097" + self.host = "http://localhost:9095" # Temp file folder for downloading files self.temp_folder_path = None diff --git a/.invenio/api_container/configuration.py b/.invenio/api_container/configuration.py index b93a7ea5d39b5f221247b3f99ad776ebdc36311c..23d21b83810a226c542b2172f81bcb8fc607ce8b 100644 --- a/.invenio/api_container/configuration.py +++ b/.invenio/api_container/configuration.py @@ -46,7 +46,7 @@ class Configuration(six.with_metaclass(TypeWithDefault, object)): def __init__(self): """Constructor""" # Default Base url - self.host = "http://localhost:9091" + self.host = "http://localhost:9095" # Temp file folder for downloading files self.temp_folder_path = None diff --git a/.invenio/api_database/configuration.py b/.invenio/api_database/configuration.py index 758efb3300d9922238fe802fcd68b162b1d5e3ad..5ee4406b932b0def43900eedf1c962a85da65c16 100644 --- a/.invenio/api_database/configuration.py +++ b/.invenio/api_database/configuration.py @@ -46,7 +46,7 @@ class Configuration(six.with_metaclass(TypeWithDefault, object)): def __init__(self): """Constructor""" # Default Base url - self.host = "http://localhost:9092" + self.host = "http://localhost:9095" # Temp file folder for downloading files self.temp_folder_path = None diff --git a/.invenio/api_document/configuration.py b/.invenio/api_document/configuration.py index bb7e50accfb91635831106693aeab48db409982c..3acecd4c60c1c9dd69a43e7a6e6c8ca2b748127f 100644 --- a/.invenio/api_document/configuration.py +++ b/.invenio/api_document/configuration.py @@ -46,7 +46,7 @@ class Configuration(six.with_metaclass(TypeWithDefault, object)): def __init__(self): """Constructor""" # Default Base url - self.host = "http://localhost:9099" + self.host = "http://localhost:9095" # Temp file folder for downloading files self.temp_folder_path = None diff --git a/.invenio/api_identifier/configuration.py b/.invenio/api_identifier/configuration.py index 7845c1cc68b9f2bd55aadd1c1facc1520d51a416..28b5cf87552aa2b12278480c89b594d8332d847b 100644 --- a/.invenio/api_identifier/configuration.py +++ b/.invenio/api_identifier/configuration.py @@ -46,7 +46,7 @@ class Configuration(six.with_metaclass(TypeWithDefault, object)): def __init__(self): """Constructor""" # Default Base url - self.host = "http://localhost:9096" + self.host = "http://localhost:9095" # Temp file folder for downloading files self.temp_folder_path = None diff --git a/.invenio/api_query/api/table_data_endpoint_api.py b/.invenio/api_query/api/table_data_endpoint_api.py index 12101dabc2a0badc252bd2c4801258eed30cd414..34b6434bf0480fb38772c7920fab94c0754393de 100644 --- a/.invenio/api_query/api/table_data_endpoint_api.py +++ b/.invenio/api_query/api/table_data_endpoint_api.py @@ -259,7 +259,7 @@ class TableDataEndpointApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/api/container/{id}/database/{databaseId}/table/{tableId}/data', 'HEAD', + '/api/container/{id}/database/{databaseId}/table/{tableId}/data', 'GET', path_params, query_params, header_params, @@ -380,7 +380,7 @@ class TableDataEndpointApi(object): auth_settings = [] # noqa: E501 return self.api_client.call_api( - '/api/container/{id}/database/{databaseId}/table/{tableId}/data', 'GET', + '/api/container/{id}/database/{databaseId}/table/{tableId}/data', 'HEAD', path_params, query_params, header_params, diff --git a/.invenio/api_query/configuration.py b/.invenio/api_query/configuration.py index 1b566374df8cf6e9fac26244c8a29c2ffd3e7f1d..2991fff8bf4bb94a0f13898b2c1332ee3644ca45 100644 --- a/.invenio/api_query/configuration.py +++ b/.invenio/api_query/configuration.py @@ -46,7 +46,7 @@ class Configuration(six.with_metaclass(TypeWithDefault, object)): def __init__(self): """Constructor""" # Default Base url - self.host = "http://localhost:9093" + self.host = "http://localhost:9095" # Temp file folder for downloading files self.temp_folder_path = None diff --git a/.invenio/api_table/configuration.py b/.invenio/api_table/configuration.py index f24b34599fae66af44bb081f816e9f88a90bd103..557adf4db5a7409e3736e03ecbe0380531dac8a6 100644 --- a/.invenio/api_table/configuration.py +++ b/.invenio/api_table/configuration.py @@ -46,7 +46,7 @@ class Configuration(six.with_metaclass(TypeWithDefault, object)): def __init__(self): """Constructor""" # Default Base url - self.host = "http://localhost:9094" + self.host = "http://localhost:9095" # Temp file folder for downloading files self.temp_folder_path = None diff --git a/.invenio/analyze.ipynb b/.invenio/deposit.ipynb similarity index 82% rename from .invenio/analyze.ipynb rename to .invenio/deposit.ipynb index 542a3613a68536dffacff19325129ed71a2bbda4..6fe7d9c7706b1dfac15d7cbff01c8769512480ac 100644 --- a/.invenio/analyze.ipynb +++ b/.invenio/deposit.ipynb @@ -2,15 +2,11 @@ "cells": [ { "cell_type": "markdown", + "source": [], "metadata": { - "collapsed": true, - "pycharm": { - "name": "#%% md\n" - } + "collapsed": false }, - "source": [ - "# Test" - ] + "outputs": [] } ], "metadata": { diff --git a/.invenio/dev.py b/.invenio/dev.py old mode 100644 new mode 100755 index aa0cb1af32c8d6baf25176689b9de61bc2186f00..81a94da41ad4d186fda1f9ec340391ceae4e7f9e --- a/.invenio/dev.py +++ b/.invenio/dev.py @@ -1,67 +1,34 @@ #!/usr/bin/env python3 -import json - +import re +import csv import requests -from api_authentication.api.authentication_endpoint_api import AuthenticationEndpointApi -from api_authentication.api.user_endpoint_api import UserEndpointApi -from api_container.api.container_endpoint_api import ContainerEndpointApi -from api_database.api.container_database_endpoint_api import ContainerDatabaseEndpointApi +doi = '10.5281/zenodo.5649276' +headers = { + 'Authorize': 'Bearer djCvqkoOW69keHajybZiwE8bBjyir2QSZOLKpAtc4S1Wp17KXgcHmMoWJwft' +} -authentication = AuthenticationEndpointApi() -user = UserEndpointApi() -container = ContainerEndpointApi() -database = ContainerDatabaseEndpointApi() +# Resolve DOI +response = requests.get('https://doi.org/' + doi) +id = re.findall('/([a-z0-9-]+)$', response.url)[0] +host = re.findall('^https?:\/\/([a-z0-9]+\.[a-z]+)', response.url)[0] +print("Resolved DOI to", host, "and record id", id) -# # Create account -# response = user.register({ -# 'username': 'mweise', -# 'password': 'fda', -# 'email': 'martin.weise@tuwien.ac.at' -# }) -# print('Created account with username %s' % response.username) -# -# # Create authentication -# response = authentication.authenticate_user1({ -# 'username': 'mweise', -# 'password': 'fda' -# }) -# container.api_client.default_headers = { -# 'Authorization': 'Bearer ' + response.token -# } -# database.api_client.default_headers = { -# 'Authorization': 'Bearer ' + response.token -# } -# -# # Create container -# response = container.create1({ -# 'name': 'MIR ' + str(uuid.uuid1()), -# 'repository': 'mariadb', -# 'tag': '10.5' -# }) -# cid = response.id -# print('Created container with id %d' % cid) -# -# # Start container -# response = container.modify({ -# 'action': 'START' -# }, cid) -# time.sleep(5) -# print('Started container with id %d' % cid) -# -# # Create database -# response = database.create({ -# 'name': 'MIR ' + str(uuid.uuid1()), -# 'description': 'Music Information Retrieval', -# 'is_public': True -# }, cid) -# dbid = response.id -# print('Created database with id %d' % dbid) +# Find files +url = 'https://' + host + '/api/records/' + id +response = requests.get(url, headers=headers) +record = response.json() -# Analyse Table -response = requests.post('http://localhost:5000/api/analyse/determinedt', json={ - 'filepath': '/tmp/test.csv', -}) -data = json.loads(response.content) -print('Determined data types') -print(response) +# Write some .csv +i = 0 +with open('./features.csv', 'w') as f: + writer = csv.writer(f) + writer.writerow(['key', 'size', 'link']) + for file in record['files']: + requests.get(file['links']['self']) + print("... feature extract from", file['links']['self']) + writer.writerow([file['key'], file['size'], file['links']['self']]) + i += 1 + if i > 10: + break +print("Generated a feature .csv") diff --git a/.invenio/feature_extract.ipynb b/.invenio/feature_extract.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..9de40c112c0b206df177dac3ba2fd34bb6819f52 --- /dev/null +++ b/.invenio/feature_extract.ipynb @@ -0,0 +1,367 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true, + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "# Feature Extraction & Deposit\n", + "\n", + "In this notebook we define an example of creating a database from a .csv and perform feature extraction of audio files. The APIs are auto-generated from the Swagger Endpoint documentations using [`generate.sh`](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-docs/-/blob/master/swagger/generate.sh). Steps we perform:\n", + "\n", + " 1. Download a music file from a public repository\n", + " 2. Perform feature extraction\n", + " 3. Create an account at DBRepo\n", + " 4. Create an authentication token\n", + " 5. Create a mariadb container\n", + " 6. Start the mariadb container\n", + " 7. Create a database within the mariadb container\n", + " 8. Import the feature .csv (manually)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "outputs": [], + "source": [ + "import os.path\n", + "import uuid\n", + "import time\n", + "import re\n", + "import csv\n", + "import requests as rq\n", + "from api_authentication.api.authentication_endpoint_api import AuthenticationEndpointApi\n", + "from api_authentication.api.user_endpoint_api import UserEndpointApi\n", + "from api_container.api.container_endpoint_api import ContainerEndpointApi\n", + "from api_database.api.container_database_endpoint_api import ContainerDatabaseEndpointApi\n", + "from api_table.api.table_endpoint_api import TableEndpointApi\n", + "\n", + "authentication = AuthenticationEndpointApi()\n", + "user = UserEndpointApi()\n", + "container = ContainerEndpointApi()\n", + "database = ContainerDatabaseEndpointApi()\n", + "table = TableEndpointApi()\n", + "\n", + "doi = \"10.5281/zenodo.5649276\"\n", + "email = \"some@example.com\"" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "## 1. Download wav\n", + "\n", + "Resolve the DOI to URI" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 21, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Resolved DOI to zenodo.org and record id 5649276\n" + ] + } + ], + "source": [ + "response = rq.get(\"https://doi.org/\" + doi)\n", + "id = re.findall(\"/([a-z0-9-]+)$\", response.url)[0]\n", + "host = re.findall(\"^https?:\\/\\/([a-z0-9]+\\.[a-z]+)\", response.url)[0]\n", + "print(\"Resolved DOI to\", host, \"and record id\", id)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "## 2. Perform feature extraction" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 22, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "... feature extract from https://zenodo.org/api/files/22d69a63-2aff-47ae-b818-be78a23e9889/colive.0044_20200518133554_1_m4a_1.wav\n", + "... feature extract from https://zenodo.org/api/files/22d69a63-2aff-47ae-b818-be78a23e9889/colive.0044_20200518133554_2_m4a_1.wav\n", + "... feature extract from https://zenodo.org/api/files/22d69a63-2aff-47ae-b818-be78a23e9889/colive.0066_20200611134530_1_m4a_0.wav\n", + "... feature extract from https://zenodo.org/api/files/22d69a63-2aff-47ae-b818-be78a23e9889/colive.0066_20200611134530_2_m4a_0.wav\n", + "... feature extract from https://zenodo.org/api/files/22d69a63-2aff-47ae-b818-be78a23e9889/colive.0066_20200612072315_1_m4a_0.wav\n", + "... feature extract from https://zenodo.org/api/files/22d69a63-2aff-47ae-b818-be78a23e9889/colive.0066_20200612072315_2_m4a_0.wav\n", + "... feature extract from https://zenodo.org/api/files/22d69a63-2aff-47ae-b818-be78a23e9889/colive.0066_20200613082517_1_m4a_0.wav\n", + "... feature extract from https://zenodo.org/api/files/22d69a63-2aff-47ae-b818-be78a23e9889/colive.0066_20200613082517_2_m4a_0.wav\n", + "... feature extract from https://zenodo.org/api/files/22d69a63-2aff-47ae-b818-be78a23e9889/colive.0066_20200614080017_1_m4a_0.wav\n", + "... feature extract from https://zenodo.org/api/files/22d69a63-2aff-47ae-b818-be78a23e9889/colive.0066_20200614080017_2_m4a_0.wav\n", + "... feature extract from https://zenodo.org/api/files/22d69a63-2aff-47ae-b818-be78a23e9889/colive.0066_20200615070238_1_m4a_0.wav\n", + "Generated a feature .csv in your home directory\n" + ] + } + ], + "source": [ + "response = rq.get(\"https://\" + host + \"/api/records/\" + id)\n", + "record = response.json()\n", + "\n", + "i = 0\n", + "with open(os.path.expanduser(\"~/features.csv\"), \"w\") as f:\n", + " writer = csv.writer(f)\n", + " writer.writerow([\"key\", \"size\", \"link\"])\n", + " for file in record[\"files\"]:\n", + " rq.get(file[\"links\"][\"self\"])\n", + " print(\"... feature extract from\", file[\"links\"][\"self\"])\n", + " writer.writerow([file[\"key\"], file[\"size\"], file[\"links\"][\"self\"]])\n", + " i += 1\n", + " if i > 10:\n", + " break\n", + "print(\"Generated a feature .csv in your home directory\")" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "## 3. Create an account at DBRepo" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 23, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'authorities': [{'authority': 'ROLE_RESEARCHER'}],\n", + " 'containers': None,\n", + " 'databases': None,\n", + " 'email': 'martinweiseat@gmail.com',\n", + " 'firstname': None,\n", + " 'id': 2,\n", + " 'identifiers': None,\n", + " 'lastname': None,\n", + " 'titles_after': None,\n", + " 'titles_before': None,\n", + " 'username': 'user'}\n" + ] + } + ], + "source": [ + "response = user.register({\n", + " \"username\": \"user\",\n", + " \"password\": \"user\",\n", + " \"email\": email\n", + "})\n", + "print(response)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "## 4. Create an authentication token" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 24, + "outputs": [], + "source": [ + "response = authentication.authenticate_user1({\n", + " \"username\": \"user\",\n", + " \"password\": \"user\"\n", + "})\n", + "container.api_client.default_headers = {\"Authorization\": \"Bearer \" + response.token}\n", + "database.api_client.default_headers = {\"Authorization\": \"Bearer \" + response.token}\n", + "table.api_client.default_headers = {\"Authorization\": \"Bearer \" + response.token}" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "## 5. Create a mariadb container" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 25, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'hash': 'f5a649a71aae3748e62228721c44627ffc866f665d677bb890c37b9111590ffa',\n", + " 'id': 2,\n", + " 'internal_name': 'fda-userdb-mir-1010b964-f6fa-11ec-9f77-64bc58900b78',\n", + " 'is_public': None,\n", + " 'name': 'MIR 1010b964-f6fa-11ec-9f77-64bc58900b78'}\n" + ] + } + ], + "source": [ + "response = container.create1({\n", + " \"name\": \"MIR \" + str(uuid.uuid1()),\n", + " \"repository\": \"mariadb\",\n", + " \"tag\": \"10.5\"\n", + "})\n", + "container_id = response.id\n", + "print(response)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "## 6. Start the mariadb container" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 26, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'hash': 'f5a649a71aae3748e62228721c44627ffc866f665d677bb890c37b9111590ffa',\n", + " 'id': 2,\n", + " 'internal_name': 'fda-userdb-mir-1010b964-f6fa-11ec-9f77-64bc58900b78',\n", + " 'is_public': None,\n", + " 'name': 'MIR 1010b964-f6fa-11ec-9f77-64bc58900b78'}\n" + ] + } + ], + "source": [ + "response = container.modify({\n", + " \"action\": \"START\"\n", + "}, container_id)\n", + "time.sleep(5)\n", + "print(response)" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "## 7. Create a database within the mariadb container" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": 27, + "outputs": [], + "source": [ + "response = database.create({\n", + " \"name\": \"MIR \" + str(uuid.uuid1()),\n", + " \"description\": \"Music Information Retrieval\",\n", + " \"is_public\": True\n", + "}, container_id)\n", + "database_id = response.id" + ], + "metadata": { + "collapsed": false, + "pycharm": { + "name": "#%%\n" + } + } + }, + { + "cell_type": "markdown", + "source": [ + "## 8. Import the feature .csv\n", + "\n", + "Now open [http://localhost:3000/](http://localhost:3000/) and import the .csv file by clicking the database. After successful creation of the table, come back here." + ], + "metadata": { + "collapsed": false + } + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/.invenio/requirements.txt b/.invenio/requirements.txt index 47f78a7d8881dd86110db66b62b8dbe2d9f2332c..cead3141b668dc1ff86be21106936bad117b97a9 100644 --- a/.invenio/requirements.txt +++ b/.invenio/requirements.txt @@ -1,2 +1 @@ -invenio-client==0.1.0 -six==1.16.0 \ No newline at end of file +requests==2.28.0 \ No newline at end of file diff --git a/fda-document-service/rest-service/src/main/java/at/tuwien/endpoints/DocumentEndpoint.java b/fda-document-service/rest-service/src/main/java/at/tuwien/endpoints/DocumentEndpoint.java index 2436b9748bc4e11979c02f8f947e99e481da8287..395e77b5a34dafbf16d3b1bd1026029c1f5348d8 100644 --- a/fda-document-service/rest-service/src/main/java/at/tuwien/endpoints/DocumentEndpoint.java +++ b/fda-document-service/rest-service/src/main/java/at/tuwien/endpoints/DocumentEndpoint.java @@ -1,7 +1,7 @@ package at.tuwien.endpoints; import at.tuwien.api.document.record.CreateDraftDto; -import at.tuwien.api.document.record.DraftDto; +import at.tuwien.api.document.record.RecordDto; import at.tuwien.exception.DraftRecordCreateException; import at.tuwien.service.DocumentService; import io.swagger.v3.oas.annotations.Operation; @@ -20,9 +20,8 @@ import java.security.Principal; @Log4j2 -@RestController @CrossOrigin(origins = "*") -@ControllerAdvice +@RestController @RequestMapping("/api/document") public class DocumentEndpoint { @@ -37,9 +36,9 @@ public class DocumentEndpoint { @PreAuthorize("hasRole('ROLE_RESEARCHER')") @Transactional(readOnly = true) @Operation(summary = "Create a draft", security = @SecurityRequirement(name = "bearerAuth")) - public ResponseEntity<DraftDto> create(@NotNull @Valid @RequestBody CreateDraftDto data, + public ResponseEntity<RecordDto> create(@NotNull @Valid @RequestBody CreateDraftDto data, @NotNull Principal principal) throws DraftRecordCreateException { - final DraftDto document = documentService.create(data, principal); + final RecordDto document = documentService.create(data, principal); return ResponseEntity.status(HttpStatus.CREATED) .body(document); } @@ -48,22 +47,33 @@ public class DocumentEndpoint { @PreAuthorize("hasRole('ROLE_RESEARCHER')") @Transactional(readOnly = true) @Operation(summary = "Find a draft", security = @SecurityRequirement(name = "bearerAuth")) - public ResponseEntity<DraftDto> find(@NotNull @PathVariable("id") String documentId, + public ResponseEntity<RecordDto> find(@NotNull @PathVariable("id") String documentId, @NotNull Principal principal) throws DraftRecordCreateException { - final DraftDto document = documentService.findById(documentId, principal); + final RecordDto document = documentService.findById(documentId, principal); log.info("Found draft record with id {}", documentId); log.debug("found draft record {}", document); return ResponseEntity.status(HttpStatus.OK) .body(document); } + @PutMapping("/{id}/publish") + @PreAuthorize("hasRole('ROLE_RESEARCHER')") + @Transactional(readOnly = true) + @Operation(summary = "Publish a draft", security = @SecurityRequirement(name = "bearerAuth")) + public ResponseEntity<RecordDto> publish(@NotNull @PathVariable("id") String documentId, + @NotNull Principal principal) throws DraftRecordCreateException { + final RecordDto document = documentService.publish(documentId, principal); + return ResponseEntity.status(HttpStatus.ACCEPTED) + .body(document); + } + @PostMapping("/{id}") @PreAuthorize("hasRole('ROLE_RESEARCHER')") @Transactional(readOnly = true) @Operation(summary = "Reserve draft DOI", security = @SecurityRequirement(name = "bearerAuth")) - public ResponseEntity<DraftDto> reserve(@NotNull @PathVariable("id") String documentId, + public ResponseEntity<RecordDto> reserve(@NotNull @PathVariable("id") String documentId, @NotNull Principal principal) throws DraftRecordCreateException { - final DraftDto document = documentService.reserveDoi(documentId, principal); + final RecordDto document = documentService.reserveDoi(documentId, principal); return ResponseEntity.status(HttpStatus.CREATED) .body(document); } diff --git a/fda-document-service/rest-service/src/main/java/at/tuwien/endpoints/FileEndpoint.java b/fda-document-service/rest-service/src/main/java/at/tuwien/endpoints/FileEndpoint.java index 5457e3c67a4485f99eb79fbf6c1241d5e189b960..402d37ed3b6b1a25360b845fda3edb8081377c6f 100644 --- a/fda-document-service/rest-service/src/main/java/at/tuwien/endpoints/FileEndpoint.java +++ b/fda-document-service/rest-service/src/main/java/at/tuwien/endpoints/FileEndpoint.java @@ -1,6 +1,8 @@ package at.tuwien.endpoints; -import at.tuwien.api.document.file.FileStartDto; +import at.tuwien.api.document.file.FileDto; +import at.tuwien.exception.FileUploadException; +import at.tuwien.exception.CommitFileUploadException; import at.tuwien.exception.DraftRecordCreateException; import at.tuwien.service.FileService; import io.swagger.v3.oas.annotations.Operation; @@ -12,6 +14,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.validation.constraints.NotNull; import java.security.Principal; @@ -20,7 +23,6 @@ import java.security.Principal; @Log4j2 @RestController @CrossOrigin(origins = "*") -@ControllerAdvice @RequestMapping("/api/document/{id}/file") public class FileEndpoint { @@ -34,11 +36,14 @@ public class FileEndpoint { @PostMapping @PreAuthorize("hasRole('ROLE_RESEARCHER')") @Transactional(readOnly = true) - @Operation(summary = "Start draft files", security = @SecurityRequirement(name = "bearerAuth")) - public ResponseEntity<FileStartDto> start(@NotNull @PathVariable("id") String documentId, - @NotNull Principal principal) throws DraftRecordCreateException { - final FileStartDto document = fileService.start(documentId, principal); - return ResponseEntity.status(HttpStatus.CREATED) + @Operation(summary = "Upload file", security = @SecurityRequirement(name = "bearerAuth")) + public ResponseEntity<FileDto> uploadFile(@NotNull @PathVariable("id") String documentId, + @NotNull @RequestParam("file") MultipartFile file, + @NotNull Principal principal) + throws DraftRecordCreateException, CommitFileUploadException, FileUploadException, + org.apache.tomcat.util.http.fileupload.FileUploadException { + final FileDto document = fileService.uploadFile(documentId, file, principal); + return ResponseEntity.status(HttpStatus.ACCEPTED) .body(document); } diff --git a/fda-document-service/rest-service/src/main/resources/application-docker.yml b/fda-document-service/rest-service/src/main/resources/application-docker.yml index 46f56dc08b4dff9989e3e1d942e2253678759f7a..6cc0944799641089de2168f1d4338b96254ddb11 100644 --- a/fda-document-service/rest-service/src/main/resources/application-docker.yml +++ b/fda-document-service/rest-service/src/main/resources/application-docker.yml @@ -30,5 +30,6 @@ eureka: fda: mount.path: /tmp ready.path: /ready + gateway.endpoint: http://fda-gateway-service:9095 document.endpoint: https://test.researchdata.tuwien.ac.at dev.token: "${TOKEN}" \ No newline at end of file diff --git a/fda-document-service/rest-service/src/main/resources/application.yml b/fda-document-service/rest-service/src/main/resources/application.yml index 47db505983d03a94640962f3b394da6c91bd3ac7..bf035c9f11d39d0f054bd52677fae08c245eac85 100644 --- a/fda-document-service/rest-service/src/main/resources/application.yml +++ b/fda-document-service/rest-service/src/main/resources/application.yml @@ -7,7 +7,7 @@ spring: username: postgres password: postgres jpa: - show-sql: false + show-sql: true database-platform: org.hibernate.dialect.PostgreSQLDialect hibernate: ddl-auto: validate @@ -16,7 +16,6 @@ spring: name: fda-document-service cloud: loadbalancer.ribbon.enabled: false -springdoc.swagger-ui.enabled: true server.port: 9099 logging: pattern.console: "%d %highlight(%-5level) %msg%n" @@ -31,5 +30,6 @@ eureka: fda: mount.path: /tmp ready.path: ./ready + gateway.endpoint: http://localhost:9095 document.endpoint: https://test.researchdata.tuwien.ac.at dev.token: "${TOKEN}" \ No newline at end of file diff --git a/fda-document-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java b/fda-document-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java index 7f4f0cc7ebc0635d6e11bbccd62c25dbae8dd6da..c772a6be5d7e3f96631d333d187ba7fcff475af5 100644 --- a/fda-document-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java +++ b/fda-document-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java @@ -2,6 +2,8 @@ package at.tuwien; import at.tuwien.api.document.metadata.*; import at.tuwien.api.document.record.*; +import at.tuwien.api.user.UserDetailsDto; +import org.springframework.security.core.userdetails.UserDetails; import org.springframework.test.context.TestPropertySource; import java.time.Instant; @@ -11,30 +13,58 @@ import java.util.List; @TestPropertySource(locations = "classpath:application.properties") public abstract class BaseUnitTest { + public final static Long USER_1_ID = 1L; public final static String USER_1_USERNAME = "junit"; + public final static UserDetails USER_1_DETAILS = UserDetailsDto.builder() + .id(USER_1_ID) + .username(USER_1_USERNAME) + .build(); + public final static AccessTypeDto DOCUMENT_1_RECORD_TYPE = AccessTypeDto.PUBLIC; public final static FileTypeDto DOCUMENT_1_FILE_TYPE = FileTypeDto.PUBLIC; + public final static AccessTypeDto DOCUMENT_2_RECORD_TYPE = AccessTypeDto.PUBLIC; + public final static FileTypeDto DOCUMENT_2_FILE_TYPE = FileTypeDto.RESTRICTED; + public final static AccessOptionsDto DOCUMENT_1_ACCESS_OPTIONS = AccessOptionsDto.builder() .record(DOCUMENT_1_RECORD_TYPE) .files(DOCUMENT_1_FILE_TYPE) .build(); - public final static Boolean DOCUMENT_1_FILES_ENABLED = true; + public final static AccessOptionsDto DOCUMENT_2_ACCESS_OPTIONS = AccessOptionsDto.builder() + .record(DOCUMENT_2_RECORD_TYPE) + .files(DOCUMENT_2_FILE_TYPE) + .build(); + + public final static Boolean DOCUMENT_1_FILES_ENABLED = false; + + public final static Boolean DOCUMENT_2_FILES_ENABLED = true; public final static FilesOptionsDto DOCUMENT_1_FILES_OPTIONS = FilesOptionsDto.builder() .enabled(DOCUMENT_1_FILES_ENABLED) .build(); - public final static String DOCUMENT_1_TITLE = "Test Draft"; + public final static FilesOptionsDto DOCUMENT_2_FILES_OPTIONS = FilesOptionsDto.builder() + .enabled(DOCUMENT_2_FILES_ENABLED) + .build(); + + public final static String DOCUMENT_1_TITLE = "Public Test-Record"; public final static String DOCUMENT_1_RESOURCE_TYPE_TYPE = "other"; public final static Date DOCUMENT_1_PUBLICATION_DATE = Date.from(Instant.now()); + public final static String DOCUMENT_2_TITLE = "Restricted Test-Record"; + public final static String DOCUMENT_2_RESOURCE_TYPE_TYPE = "other"; + public final static Date DOCUMENT_2_PUBLICATION_DATE = Date.from(Instant.now()); + public final static ResourceTypeDto DOCUMENT_1_RESOURCE_TYPE = ResourceTypeDto.builder() .id(DOCUMENT_1_RESOURCE_TYPE_TYPE) .build(); + public final static ResourceTypeDto DOCUMENT_2_RESOURCE_TYPE = ResourceTypeDto.builder() + .id(DOCUMENT_2_RESOURCE_TYPE_TYPE) + .build(); + public final static String IDENTIFIER_1_IDENTIFIER = "0000-0003-4216-302X"; public final static IdentifierTypeDto IDENTIFIER_1_TYPE = IdentifierTypeDto.ORCID; @@ -72,10 +102,23 @@ public abstract class BaseUnitTest { .creators(List.of(CREATOR_1)) .build(); + public final static MetadataDto DOCUMENT_2_METADATA = MetadataDto.builder() + .title(DOCUMENT_2_TITLE) + .resourceType(DOCUMENT_2_RESOURCE_TYPE) + .publicationDate(DOCUMENT_2_PUBLICATION_DATE) + .creators(List.of(CREATOR_1)) + .build(); + public final static CreateDraftDto DOCUMENT_1_CREATE_DRAFT = CreateDraftDto.builder() .access(DOCUMENT_1_ACCESS_OPTIONS) .files(DOCUMENT_1_FILES_OPTIONS) .metadata(DOCUMENT_1_METADATA) .build(); + public final static CreateDraftDto DOCUMENT_2_CREATE_DRAFT = CreateDraftDto.builder() + .access(DOCUMENT_2_ACCESS_OPTIONS) + .files(DOCUMENT_2_FILES_OPTIONS) + .metadata(DOCUMENT_2_METADATA) + .build(); + } diff --git a/fda-document-service/rest-service/src/test/java/at/tuwien/endpoint/DocumentEndpointUnitTest.java b/fda-document-service/rest-service/src/test/java/at/tuwien/endpoint/DocumentEndpointUnitTest.java index 0965a30b1e3fe46573e7e50f798b044d9af81cc4..534038dbadbb0e1a3224c5d092719c825be0d1d1 100644 --- a/fda-document-service/rest-service/src/test/java/at/tuwien/endpoint/DocumentEndpointUnitTest.java +++ b/fda-document-service/rest-service/src/test/java/at/tuwien/endpoint/DocumentEndpointUnitTest.java @@ -1,13 +1,52 @@ package at.tuwien.endpoint; import at.tuwien.BaseUnitTest; +import at.tuwien.api.document.record.CreateDraftDto; +import at.tuwien.api.document.record.RecordDto; +import at.tuwien.endpoints.DocumentEndpoint; +import at.tuwien.exception.DraftRecordCreateException; +import at.tuwien.gateway.AuthenticationServiceGateway; +import org.apache.http.auth.BasicUserPrincipal; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit.jupiter.SpringExtension; +import java.security.Principal; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + @ExtendWith(SpringExtension.class) @SpringBootTest public class DocumentEndpointUnitTest extends BaseUnitTest { + @Autowired + private DocumentEndpoint documentEndpoint; + + @MockBean + private AuthenticationServiceGateway authenticationServiceGateway; + + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"ROLE_RESEARCHER"}) + public void create_succeed() throws DraftRecordCreateException { + final CreateDraftDto request = DOCUMENT_1_CREATE_DRAFT; + final Principal principal = new BasicUserPrincipal(USER_1_USERNAME); + + /* mock */ + when(authenticationServiceGateway.validate(anyString())) + .thenReturn(USER_1_DETAILS); + + /* test */ + final ResponseEntity<RecordDto> response = documentEndpoint.create(request, principal); + assertEquals(HttpStatus.CREATED, response.getStatusCode()); + } } diff --git a/fda-document-service/rest-service/src/test/java/at/tuwien/service/DocumentServiceIntegrationTest.java b/fda-document-service/rest-service/src/test/java/at/tuwien/service/DocumentServiceIntegrationTest.java index 055fd45ca2538f514c3391c5263899d77c96645e..cdef81d0dc3c76705f8f6fba770e1291cd90874a 100644 --- a/fda-document-service/rest-service/src/test/java/at/tuwien/service/DocumentServiceIntegrationTest.java +++ b/fda-document-service/rest-service/src/test/java/at/tuwien/service/DocumentServiceIntegrationTest.java @@ -2,7 +2,7 @@ package at.tuwien.service; import at.tuwien.BaseUnitTest; import at.tuwien.api.document.record.CreateDraftDto; -import at.tuwien.api.document.record.DraftDto; +import at.tuwien.api.document.record.RecordDto; import at.tuwien.exception.DraftRecordCreateException; import lombok.extern.log4j.Log4j2; import org.apache.http.auth.BasicUserPrincipal; @@ -35,7 +35,7 @@ public class DocumentServiceIntegrationTest extends BaseUnitTest { /* mock */ /* test */ - final DraftDto response = documentService.create(request, principal); + final RecordDto response = documentService.create(request, principal); assertEquals(DOCUMENT_1_TITLE, response.getMetadata().getTitle()); } @@ -47,8 +47,8 @@ public class DocumentServiceIntegrationTest extends BaseUnitTest { /* mock */ /* test */ - final DraftDto document = documentService.create(request, principal); - final DraftDto response = documentService.reserveDoi(document.getId(), principal); + final RecordDto document = documentService.create(request, principal); + final RecordDto response = documentService.reserveDoi(document.getId(), principal); assertNotNull(response.getPids().getDoi()); } diff --git a/fda-document-service/rest-service/src/test/java/at/tuwien/service/FileServiceIntegrationTest.java b/fda-document-service/rest-service/src/test/java/at/tuwien/service/FileServiceIntegrationTest.java index 91728896171d4d8f798c288f690daf5edc859388..b694b019aac679f968767d37c6bb716943a2802f 100644 --- a/fda-document-service/rest-service/src/test/java/at/tuwien/service/FileServiceIntegrationTest.java +++ b/fda-document-service/rest-service/src/test/java/at/tuwien/service/FileServiceIntegrationTest.java @@ -1,21 +1,31 @@ package at.tuwien.service; import at.tuwien.BaseUnitTest; -import at.tuwien.api.document.file.FileStartDto; +import at.tuwien.api.document.file.FileDto; import at.tuwien.api.document.record.CreateDraftDto; -import at.tuwien.api.document.record.DraftDto; +import at.tuwien.api.document.record.RecordDto; +import at.tuwien.exception.FileUploadException; +import at.tuwien.exception.CommitFileUploadException; import at.tuwien.exception.DraftRecordCreateException; import lombok.extern.log4j.Log4j2; +import org.apache.commons.io.FileUtils; import org.apache.http.auth.BasicUserPrincipal; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.web.multipart.MultipartFile; +import java.io.File; +import java.io.IOException; import java.security.Principal; +import static org.junit.jupiter.api.Assertions.*; + + @Log4j2 @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) @ExtendWith(SpringExtension.class) @@ -29,15 +39,35 @@ public class FileServiceIntegrationTest extends BaseUnitTest { private FileService fileService; @Test - public void start_succeeds() throws DraftRecordCreateException { + public void upload_succeeds() + throws DraftRecordCreateException, IOException, CommitFileUploadException, FileUploadException { + final CreateDraftDto request = DOCUMENT_2_CREATE_DRAFT; + final Principal principal = new BasicUserPrincipal(USER_1_USERNAME); + final File mockFile = new File("src/test/resources/images/mock.png"); + + /* mock */ + final MultipartFile file = new MockMultipartFile(mockFile.getName(), FileUtils.openInputStream(mockFile) + .readAllBytes()); + final RecordDto document = documentService.create(request, principal); + assertFalse(document.getIsPublished()); + + /* test */ + final FileDto response = fileService.uploadFile(document.getId(), file, principal); + assertEquals(file.getName(), response.getKey()); + } + @Test + public void publish_succeeds() + throws DraftRecordCreateException { final CreateDraftDto request = DOCUMENT_1_CREATE_DRAFT; final Principal principal = new BasicUserPrincipal(USER_1_USERNAME); /* mock */ - final DraftDto document = documentService.create(request, principal); + final RecordDto document = documentService.create(request, principal); /* test */ - final FileStartDto response = fileService.start(document.getId(), principal); + final RecordDto response = documentService.publish(document.getId(), principal); + assertTrue(response.getIsPublished()); + assertNotNull(response.getPids().getDoi()); } } diff --git a/fda-document-service/rest-service/src/test/resources/images/mock.png b/fda-document-service/rest-service/src/test/resources/images/mock.png new file mode 100644 index 0000000000000000000000000000000000000000..4094aa6f22d95544339040f01f4f3d19f587d1d3 Binary files /dev/null and b/fda-document-service/rest-service/src/test/resources/images/mock.png differ diff --git a/fda-document-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java b/fda-document-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java index e33f0dba4dddf90216af08dbb5ec98b184fbf6f6..4d819a17867603ab7f017a9f678f387cce38ef87 100644 --- a/fda-document-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java +++ b/fda-document-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java @@ -55,4 +55,4 @@ public class AuthTokenFilter extends OncePerRequestFilter { } return null; } -} \ No newline at end of file +} diff --git a/fda-document-service/services/src/main/java/at/tuwien/config/GatewayConfig.java b/fda-document-service/services/src/main/java/at/tuwien/config/GatewayConfig.java index 006541ad8cd45351c455e1bf03b4c546acf3a6e8..776e4aa5d865bcfafa7768fb43c1b0f67fadb4a6 100644 --- a/fda-document-service/services/src/main/java/at/tuwien/config/GatewayConfig.java +++ b/fda-document-service/services/src/main/java/at/tuwien/config/GatewayConfig.java @@ -9,11 +9,21 @@ import org.springframework.web.util.DefaultUriBuilderFactory; @Configuration public class GatewayConfig { + @Value("${fda.gateway.endpoint}") + private String gatewayEndpoint; + @Value("${fda.document.endpoint}") private String documentEndpoint; @Bean - public RestTemplate restTemplate() { + public RestTemplate gatewayRestTemplate() { + final RestTemplate restTemplate = new RestTemplate(); + restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(gatewayEndpoint)); + return restTemplate; + } + + @Bean + public RestTemplate documentRestTemplate() { final RestTemplate restTemplate = new RestTemplate(); restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(documentEndpoint)); return restTemplate; diff --git a/fda-document-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java b/fda-document-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java index 70dac68fcd138939eaa08a33a7789bd5830b369d..472089fc210e9f5abc231a766e173a7b14e18123 100644 --- a/fda-document-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java +++ b/fda-document-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java @@ -65,7 +65,6 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { /* set permissions on endpoints */ http.authorizeRequests() /* our public endpoints */ - .antMatchers(HttpMethod.GET, "/api/document/**").permitAll() .antMatchers("/v3/api-docs.yaml", "/v3/api-docs/**", "/swagger-ui/**", diff --git a/fda-document-service/services/src/main/java/at/tuwien/exception/CommitFileUploadException.java b/fda-document-service/services/src/main/java/at/tuwien/exception/CommitFileUploadException.java new file mode 100644 index 0000000000000000000000000000000000000000..430f7bba544ef114e88e86279331d13b695ca48a --- /dev/null +++ b/fda-document-service/services/src/main/java/at/tuwien/exception/CommitFileUploadException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.CONFLICT) +public class CommitFileUploadException extends Exception { + + public CommitFileUploadException(String msg) { + super(msg); + } + + public CommitFileUploadException(String msg, Throwable thr) { + super(msg, thr); + } + + public CommitFileUploadException(Throwable thr) { + super(thr); + } + +} diff --git a/fda-document-service/services/src/main/java/at/tuwien/exception/FileUploadException.java b/fda-document-service/services/src/main/java/at/tuwien/exception/FileUploadException.java new file mode 100644 index 0000000000000000000000000000000000000000..590060826fb56e84a06df5d59c8828e336d130d3 --- /dev/null +++ b/fda-document-service/services/src/main/java/at/tuwien/exception/FileUploadException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.FAILED_DEPENDENCY) +public class FileUploadException extends Exception { + + public FileUploadException(String msg) { + super(msg); + } + + public FileUploadException(String msg, Throwable thr) { + super(msg, thr); + } + + public FileUploadException(Throwable thr) { + super(thr); + } + +} diff --git a/fda-document-service/services/src/main/java/at/tuwien/gateway/DocumentGateway.java b/fda-document-service/services/src/main/java/at/tuwien/gateway/DocumentGateway.java index fe6a27d6d509c7d224013b9a3f9a6a909436595b..36d86d6d02ad31e95ab64e8a3807d7aff637533f 100644 --- a/fda-document-service/services/src/main/java/at/tuwien/gateway/DocumentGateway.java +++ b/fda-document-service/services/src/main/java/at/tuwien/gateway/DocumentGateway.java @@ -1,18 +1,26 @@ package at.tuwien.gateway; -import at.tuwien.api.document.file.FileStartDto; +import at.tuwien.api.document.file.FileDto; import at.tuwien.api.document.record.CreateDraftDto; -import at.tuwien.api.document.record.DraftDto; +import at.tuwien.api.document.record.RecordDto; +import at.tuwien.exception.FileUploadException; +import at.tuwien.exception.CommitFileUploadException; import at.tuwien.exception.DraftRecordCreateException; +import org.springframework.web.multipart.MultipartFile; public interface DocumentGateway { - DraftDto createDraft(CreateDraftDto data, String token) throws DraftRecordCreateException; + RecordDto createDraft(CreateDraftDto data, String token) throws DraftRecordCreateException; - DraftDto reserveDraftDoi(String id, String token) throws DraftRecordCreateException; + RecordDto reserveDraftDoi(String id, String token) throws DraftRecordCreateException; - DraftDto findDraft(String id, String token) throws DraftRecordCreateException; + RecordDto findDraft(String id, String token) throws DraftRecordCreateException; - FileStartDto startUpload(String id, String token) throws DraftRecordCreateException; + RecordDto publishDraft(String id, String token) throws DraftRecordCreateException; + + FileDto uploadFile(String id, MultipartFile file, String token) + throws DraftRecordCreateException, FileUploadException, + org.apache.tomcat.util.http.fileupload.FileUploadException, + CommitFileUploadException; void delete(String id, String token) throws DraftRecordCreateException; } diff --git a/fda-document-service/services/src/main/java/at/tuwien/gateway/impl/AuthenticationServiceGatewayImpl.java b/fda-document-service/services/src/main/java/at/tuwien/gateway/impl/AuthenticationServiceGatewayImpl.java index 56d691a6c825b473029c8f1dcd320c949cdcf177..549223342060b34913be4b0ab82a38e054838518 100644 --- a/fda-document-service/services/src/main/java/at/tuwien/gateway/impl/AuthenticationServiceGatewayImpl.java +++ b/fda-document-service/services/src/main/java/at/tuwien/gateway/impl/AuthenticationServiceGatewayImpl.java @@ -18,20 +18,20 @@ import org.springframework.web.client.RestTemplate; public class AuthenticationServiceGatewayImpl implements AuthenticationServiceGateway { private final UserMapper userMapper; - private final RestTemplate restTemplate; + private final RestTemplate gatewayRestTemplate; @Autowired - public AuthenticationServiceGatewayImpl(UserMapper userMapper, RestTemplate restTemplate) { + public AuthenticationServiceGatewayImpl(UserMapper userMapper, RestTemplate gatewayRestTemplate) { this.userMapper = userMapper; - this.restTemplate = restTemplate; + this.gatewayRestTemplate = gatewayRestTemplate; } @Override public UserDetails validate(String token) { final HttpHeaders headers = new HttpHeaders(); headers.set("Authorization", "Bearer " + token); - final ResponseEntity<UserDto> response = restTemplate.exchange("/api/auth", HttpMethod.PUT, - new HttpEntity<>("", headers), UserDto.class); + final ResponseEntity<UserDto> response = gatewayRestTemplate.exchange("/api/auth", HttpMethod.PUT, + new HttpEntity<>(null, headers), UserDto.class); return userMapper.userDtoToUserDetailsDto(response.getBody()); } diff --git a/fda-document-service/services/src/main/java/at/tuwien/gateway/impl/InvenioDocumentGatewayImpl.java b/fda-document-service/services/src/main/java/at/tuwien/gateway/impl/InvenioDocumentGatewayImpl.java index 318594ee12efef1f9f0d3fd6c9e2539181469770..bca9d5b863c9261e7cef4217925c331b9937b65f 100644 --- a/fda-document-service/services/src/main/java/at/tuwien/gateway/impl/InvenioDocumentGatewayImpl.java +++ b/fda-document-service/services/src/main/java/at/tuwien/gateway/impl/InvenioDocumentGatewayImpl.java @@ -1,36 +1,49 @@ package at.tuwien.gateway.impl; -import at.tuwien.api.document.file.FileStartDto; +import at.tuwien.api.document.file.FileAnnounceDto; +import at.tuwien.api.document.file.FileDto; +import at.tuwien.api.document.file.FileKeyDto; import at.tuwien.api.document.record.CreateDraftDto; -import at.tuwien.api.document.record.DraftDto; +import at.tuwien.api.document.record.RecordDto; +import at.tuwien.exception.FileUploadException; +import at.tuwien.exception.CommitFileUploadException; import at.tuwien.exception.DraftRecordCreateException; import at.tuwien.gateway.DocumentGateway; +import at.tuwien.mapper.DocumentMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.*; import org.springframework.stereotype.Component; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.List; @Slf4j @Component public class InvenioDocumentGatewayImpl implements DocumentGateway { - private RestTemplate restTemplate; + private final static String OCTET_STREAM = "application/octet-stream"; + + private final DocumentMapper documentMapper; + private final RestTemplate documentRestTemplate; @Autowired - public InvenioDocumentGatewayImpl(RestTemplate restTemplate) { - this.restTemplate = restTemplate; + public InvenioDocumentGatewayImpl(DocumentMapper documentMapper, RestTemplate documentRestTemplate) { + this.documentMapper = documentMapper; + this.documentRestTemplate = documentRestTemplate; } @Override - public DraftDto createDraft(CreateDraftDto data, String token) throws DraftRecordCreateException { + public RecordDto createDraft(CreateDraftDto data, String token) throws DraftRecordCreateException { log.trace("sending {}", data); final String url = "/api/records"; - final ResponseEntity<DraftDto> response; + final ResponseEntity<RecordDto> response; try { - response = restTemplate.exchange(url, HttpMethod.POST, - new HttpEntity<>(data, headers(token)), DraftDto.class); + response = documentRestTemplate.exchange(url, HttpMethod.POST, + new HttpEntity<>(data, headers(token)), RecordDto.class); } catch (HttpClientErrorException.BadRequest e) { log.error("Failed to create draft record"); throw new DraftRecordCreateException("Failed to create draft record", e); @@ -39,12 +52,12 @@ public class InvenioDocumentGatewayImpl implements DocumentGateway { } @Override - public DraftDto reserveDraftDoi(String id, String token) throws DraftRecordCreateException { + public RecordDto reserveDraftDoi(String id, String token) throws DraftRecordCreateException { final String url = "/api/records/" + id + "/draft/pids/doi"; - final ResponseEntity<DraftDto> response; + final ResponseEntity<RecordDto> response; try { - response = restTemplate.exchange(url, HttpMethod.POST, - new HttpEntity<>(null, headers(token)), DraftDto.class); + response = documentRestTemplate.exchange(url, HttpMethod.POST, + new HttpEntity<>(null, headers(token)), RecordDto.class); } catch (HttpClientErrorException.BadRequest e) { log.error("Failed to reserve draft doi"); throw new DraftRecordCreateException("Failed to reserve draft doi", e); @@ -53,12 +66,12 @@ public class InvenioDocumentGatewayImpl implements DocumentGateway { } @Override - public DraftDto findDraft(String id, String token) throws DraftRecordCreateException { + public RecordDto findDraft(String id, String token) throws DraftRecordCreateException { final String url = "/api/records/" + id + "/draft"; - final ResponseEntity<DraftDto> response; + final ResponseEntity<RecordDto> response; try { - response = restTemplate.exchange(url, HttpMethod.GET, - new HttpEntity<>(null, headers(token)), DraftDto.class); + response = documentRestTemplate.exchange(url, HttpMethod.GET, + new HttpEntity<>(null, headers(token)), RecordDto.class); } catch (HttpClientErrorException.BadRequest e) { log.error("Failed to find draft record"); throw new DraftRecordCreateException("Failed to create find record", e); @@ -67,24 +80,76 @@ public class InvenioDocumentGatewayImpl implements DocumentGateway { } @Override - public FileStartDto startUpload(String id, String token) throws DraftRecordCreateException { - final String url = "/api/records/" + id + "/draft/files"; - final ResponseEntity<FileStartDto> response; + public RecordDto publishDraft(String id, String token) throws DraftRecordCreateException { + final String url = "/api/records/" + id + "/draft/actions/publish"; + final ResponseEntity<RecordDto> response; try { - response = restTemplate.exchange(url, HttpMethod.POST, - new HttpEntity<>(null, headers(token)), FileStartDto.class); + response = documentRestTemplate.exchange(url, HttpMethod.POST, + new HttpEntity<>(null, headers(token)), RecordDto.class); } catch (HttpClientErrorException.BadRequest e) { - log.error("Failed to start draft files"); - throw new DraftRecordCreateException("Failed to start draft files", e); + log.error("Failed to publish draft record"); + throw new DraftRecordCreateException("Failed to publish find record", e); } return response.getBody(); } + @Override + public FileDto uploadFile(String id, MultipartFile file, String token) + throws FileUploadException { + /* announce */ + final String url1 = "/api/records/" + id + "/draft/files"; + final List<FileKeyDto> files = List.of(documentMapper.stringToFileKeyDto(file.getName())); + final ResponseEntity<FileAnnounceDto> response1; + try { + response1 = documentRestTemplate.exchange(url1, HttpMethod.POST, + new HttpEntity<>(files, headers(token)), FileAnnounceDto.class); + } catch (HttpClientErrorException.BadRequest e) { + log.error("Failed to announce draft file"); + throw new FileUploadException("Failed to announce draft file", e); + } + if (response1.getStatusCode() != HttpStatus.CREATED) { + log.error("Failed to announce file upload"); + throw new FileUploadException("Failed to announce file upload"); + } + /* upload */ + final String url2 = "/api/records/" + id + "/draft/files/" + file.getName() + "/content"; + final ResponseEntity<Void> response2; + try { + response2 = documentRestTemplate.exchange(url2, HttpMethod.PUT, + new HttpEntity<>(file.getBytes(), headers(token, OCTET_STREAM)), Void.class); + } catch (HttpClientErrorException.BadRequest e) { + log.error("Failed to upload draft file"); + throw new FileUploadException("Failed to upload draft file", e); + } catch (IOException e) { + log.error("Failed to get draft file bytes"); + throw new FileUploadException("Failed to get draft file bytes", e); + } + if (response2.getStatusCode() != HttpStatus.OK) { + log.error("Failed to upload file"); + throw new FileUploadException("Failed to upload file"); + } + /* commit */ + final String url3 = "/api/records/" + id + "/draft/files/" + file.getName() + "/commit"; + final ResponseEntity<FileDto> response3; + try { + response3 = documentRestTemplate.exchange(url3, HttpMethod.POST, + new HttpEntity<>(null, headers(token)), FileDto.class); + } catch (HttpClientErrorException.BadRequest e) { + log.error("Failed to commit draft file"); + throw new FileUploadException("Failed to commit draft file", e); + } + if (response3.getStatusCode() != HttpStatus.OK) { + log.error("Failed to commit file"); + throw new FileUploadException("Failed to commit file"); + } + return response3.getBody(); + } + @Override public void delete(String id, String token) throws DraftRecordCreateException { final String url = "/api/records" + id + "/draft"; try { - restTemplate.exchange(url, HttpMethod.DELETE, + documentRestTemplate.exchange(url, HttpMethod.DELETE, new HttpEntity<>(null, headers(token)), Void.class); } catch (HttpClientErrorException.BadRequest e) { log.error("Failed to delete draft record"); @@ -99,9 +164,20 @@ public class InvenioDocumentGatewayImpl implements DocumentGateway { * @return The headers. */ private HttpHeaders headers(String token) { + return headers(token, "application/json"); + } + + /** + * Prepares the headers for all requests to authorize with the bearer token and content type. + * + * @param token The token. + * @param contentType The content type. + * @return The headers. + */ + private HttpHeaders headers(String token, String contentType) { final HttpHeaders headers = new HttpHeaders(); headers.add("Authorization", "Bearer " + token); - headers.add("Content-Type", "application/json"); + headers.add("Content-Type", contentType); return headers; } } diff --git a/fda-document-service/services/src/main/java/at/tuwien/mapper/DocumentMapper.java b/fda-document-service/services/src/main/java/at/tuwien/mapper/DocumentMapper.java index 0132073b6294cdb9be25a589d4d253fd06ed5b6c..2457da7cecbb72312d72293e54fd0720e750e75e 100644 --- a/fda-document-service/services/src/main/java/at/tuwien/mapper/DocumentMapper.java +++ b/fda-document-service/services/src/main/java/at/tuwien/mapper/DocumentMapper.java @@ -1,10 +1,16 @@ package at.tuwien.mapper; +import at.tuwien.api.document.file.FileKeyDto; import org.mapstruct.*; @Mapper(componentModel = "spring") public interface DocumentMapper { + default FileKeyDto stringToFileKeyDto(String data) { + return FileKeyDto.builder() + .key(data) + .build(); + } } diff --git a/fda-document-service/services/src/main/java/at/tuwien/service/DocumentService.java b/fda-document-service/services/src/main/java/at/tuwien/service/DocumentService.java index 5d102b335c226e599fb92bdbc44f7db856240fe3..182feb2d5b0d627ce42bbfca39ecda83341235ce 100644 --- a/fda-document-service/services/src/main/java/at/tuwien/service/DocumentService.java +++ b/fda-document-service/services/src/main/java/at/tuwien/service/DocumentService.java @@ -1,18 +1,20 @@ package at.tuwien.service; import at.tuwien.api.document.record.CreateDraftDto; -import at.tuwien.api.document.record.DraftDto; +import at.tuwien.api.document.record.RecordDto; import at.tuwien.exception.DraftRecordCreateException; import java.security.Principal; public interface DocumentService { - DraftDto findById(String id, Principal principal) throws DraftRecordCreateException; + RecordDto findById(String id, Principal principal) throws DraftRecordCreateException; - DraftDto create(CreateDraftDto data, Principal principal) throws DraftRecordCreateException; + RecordDto create(CreateDraftDto data, Principal principal) throws DraftRecordCreateException; - DraftDto reserveDoi(String id, Principal principal) throws DraftRecordCreateException; + RecordDto publish(String id, Principal principal) throws DraftRecordCreateException; + + RecordDto reserveDoi(String id, Principal principal) throws DraftRecordCreateException; void delete(String id, Principal principal) throws DraftRecordCreateException; } diff --git a/fda-document-service/services/src/main/java/at/tuwien/service/FileService.java b/fda-document-service/services/src/main/java/at/tuwien/service/FileService.java index 5113be20f9cc2700e4c128785ad05020b39c1c2d..67fb8932b57eac8afefa48b5331585b5b2460e8e 100644 --- a/fda-document-service/services/src/main/java/at/tuwien/service/FileService.java +++ b/fda-document-service/services/src/main/java/at/tuwien/service/FileService.java @@ -1,11 +1,17 @@ package at.tuwien.service; -import at.tuwien.api.document.file.FileStartDto; +import at.tuwien.api.document.file.FileDto; +import at.tuwien.exception.FileUploadException; +import at.tuwien.exception.CommitFileUploadException; import at.tuwien.exception.DraftRecordCreateException; +import org.springframework.web.multipart.MultipartFile; import java.security.Principal; public interface FileService { - FileStartDto start(String id, Principal principal) throws DraftRecordCreateException; + + FileDto uploadFile(String id, MultipartFile file, Principal principal) + throws DraftRecordCreateException, CommitFileUploadException, FileUploadException, + org.apache.tomcat.util.http.fileupload.FileUploadException; } diff --git a/fda-document-service/services/src/main/java/at/tuwien/service/impl/InvenioDraftServiceImpl.java b/fda-document-service/services/src/main/java/at/tuwien/service/impl/InvenioDraftServiceImpl.java index 456fd6b540ee01387bccec7ee51a07bbde66b867..06c038521a7b2224b12de6f4811958deb80b729f 100644 --- a/fda-document-service/services/src/main/java/at/tuwien/service/impl/InvenioDraftServiceImpl.java +++ b/fda-document-service/services/src/main/java/at/tuwien/service/impl/InvenioDraftServiceImpl.java @@ -1,7 +1,7 @@ package at.tuwien.service.impl; import at.tuwien.api.document.record.CreateDraftDto; -import at.tuwien.api.document.record.DraftDto; +import at.tuwien.api.document.record.RecordDto; import at.tuwien.config.InvenioConfig; import at.tuwien.exception.DraftRecordCreateException; import at.tuwien.gateway.DocumentGateway; @@ -26,27 +26,37 @@ public class InvenioDraftServiceImpl implements DocumentService { } @Override - public DraftDto findById(String id, Principal principal) throws DraftRecordCreateException { + public RecordDto findById(String id, Principal principal) throws DraftRecordCreateException { /* get token */ /* remote */ return documentGateway.findDraft(id, invenioConfig.getDebugToken()); } @Override - public DraftDto create(CreateDraftDto data, Principal principal) throws DraftRecordCreateException { + public RecordDto create(CreateDraftDto data, Principal principal) throws DraftRecordCreateException { /* get token */ /* remote */ - final DraftDto document = documentGateway.createDraft(data, invenioConfig.getDebugToken()); + final RecordDto document = documentGateway.createDraft(data, invenioConfig.getDebugToken()); log.info("Created draft record with id {}", document.getId()); log.debug("created draft record {}", document); return document; } @Override - public DraftDto reserveDoi(String id, Principal principal) throws DraftRecordCreateException { + public RecordDto publish(String id, Principal principal) throws DraftRecordCreateException { /* get token */ /* remote */ - final DraftDto document = documentGateway.reserveDraftDoi(id, invenioConfig.getDebugToken()); + final RecordDto document = documentGateway.publishDraft(id, invenioConfig.getDebugToken()); + log.info("Published draft record with id {}", document.getId()); + log.debug("published draft record {}", document); + return document; + } + + @Override + public RecordDto reserveDoi(String id, Principal principal) throws DraftRecordCreateException { + /* get token */ + /* remote */ + final RecordDto document = documentGateway.reserveDraftDoi(id, invenioConfig.getDebugToken()); log.info("Reserved DOI {} for draft record with id {}", document.getPids().getDoi(), document.getId()); log.debug("reserved PID {} for draft record with id {}", document.getPids(), document); return document; diff --git a/fda-document-service/services/src/main/java/at/tuwien/service/impl/InvenioFileServiceImpl.java b/fda-document-service/services/src/main/java/at/tuwien/service/impl/InvenioFileServiceImpl.java index 459454f3462f78715d1a5a89d13696e10e2aefee..4110d0784614f364a6a529065b285349b4a00be9 100644 --- a/fda-document-service/services/src/main/java/at/tuwien/service/impl/InvenioFileServiceImpl.java +++ b/fda-document-service/services/src/main/java/at/tuwien/service/impl/InvenioFileServiceImpl.java @@ -1,13 +1,16 @@ package at.tuwien.service.impl; -import at.tuwien.api.document.file.FileStartDto; +import at.tuwien.api.document.file.FileDto; import at.tuwien.config.InvenioConfig; +import at.tuwien.exception.FileUploadException; +import at.tuwien.exception.CommitFileUploadException; import at.tuwien.exception.DraftRecordCreateException; import at.tuwien.gateway.DocumentGateway; import at.tuwien.service.FileService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; import java.security.Principal; @@ -25,12 +28,14 @@ public class InvenioFileServiceImpl implements FileService { } @Override - public FileStartDto start(String id, Principal principal) throws DraftRecordCreateException { + public FileDto uploadFile(String id, MultipartFile file, Principal principal) + throws DraftRecordCreateException, CommitFileUploadException, FileUploadException, + org.apache.tomcat.util.http.fileupload.FileUploadException { /* get token */ /* remote */ - final FileStartDto document = documentGateway.startUpload(id, invenioConfig.getDebugToken()); - log.info("Started draft files with id {}", id); - log.debug("started draft files {}", document); + final FileDto document = documentGateway.uploadFile(id, file, invenioConfig.getDebugToken()); + log.info("Deposited draft file content for record with id {}", id); + log.debug("Deposited draft file content for record {}", document); return document; } diff --git a/fda-gateway-service/gateway/src/main/java/at/tuwien/gatewayservice/config/GatewayConfig.java b/fda-gateway-service/gateway/src/main/java/at/tuwien/gatewayservice/config/GatewayConfig.java index 040bbb0e969ed5e8276618238d70cf0726d33a24..27a3863e809929f10fe5550b139a51b05f4e2ba2 100644 --- a/fda-gateway-service/gateway/src/main/java/at/tuwien/gatewayservice/config/GatewayConfig.java +++ b/fda-gateway-service/gateway/src/main/java/at/tuwien/gatewayservice/config/GatewayConfig.java @@ -56,6 +56,11 @@ public class GatewayConfig { .method("POST", "GET", "PUT", "DELETE") .and() .uri("lb://fda-units-service")) + .route("fda-document-service", r -> r.path("/api/document/**") + .and() + .method("POST", "GET", "PUT", "DELETE") + .and() + .uri("lb://fda-document-service")) .build(); } diff --git a/fda-identifier-service/rest-service/src/main/java/at/tuwien/FdaIdentifierServiceApplication.java b/fda-identifier-service/rest-service/src/main/java/at/tuwien/FdaIdentifierServiceApplication.java index 185a41efc0b3900e7aa9b47f188e8cb30bc4d170..56712b0f03861daf0c381a949b6d3252b2843c41 100644 --- a/fda-identifier-service/rest-service/src/main/java/at/tuwien/FdaIdentifierServiceApplication.java +++ b/fda-identifier-service/rest-service/src/main/java/at/tuwien/FdaIdentifierServiceApplication.java @@ -8,7 +8,6 @@ import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.transaction.annotation.EnableTransactionManagement; - @SpringBootApplication @EnableJpaAuditing @EnableTransactionManagement diff --git a/fda-identifier-service/rest-service/src/main/resources/application.yml b/fda-identifier-service/rest-service/src/main/resources/application.yml index 11335fa111792cbd07a41a804b21e496d3cfec90..e71ce69b3fe660d786ba6dab44a19407bd1b2b22 100644 --- a/fda-identifier-service/rest-service/src/main/resources/application.yml +++ b/fda-identifier-service/rest-service/src/main/resources/application.yml @@ -22,6 +22,7 @@ logging: level: root: warn at.tuwien.: debug + at.tuwien.gateway.: trace org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver: debug eureka: instance.hostname: fda-identifier-service diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/file/FileAnnounceDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/file/FileAnnounceDto.java new file mode 100644 index 0000000000000000000000000000000000000000..c2941ccdeca9d5556ca203eecf5b99a2b5210733 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/file/FileAnnounceDto.java @@ -0,0 +1,37 @@ + +package at.tuwien.api.document.file; + +import at.tuwien.api.document.links.LinksDto; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class FileAnnounceDto { + + @JsonProperty("default_preview") + @Parameter(name = "file name") + private String defaultPreview; + + @NotNull + @Parameter(name = "file enabled") + private Boolean enabled; + + @NotNull + @Parameter(name = "file entries") + private List<FileEntryDto> entries; + + @Parameter(name = "file links") + private LinksDto links; + +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/file/FileDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/file/FileDto.java new file mode 100644 index 0000000000000000000000000000000000000000..63f820e3724f03190b932614a119b96277cfd7f0 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/file/FileDto.java @@ -0,0 +1,72 @@ +package at.tuwien.api.document.file; + +import at.tuwien.api.document.links.LinksDto; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.Instant; + + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class FileDto { + + @NotBlank + @JsonProperty("bucket_id") + @Parameter(name = "bucket id", description = "Bucket id.") + private String bucketId; + + @NotBlank + @Parameter(name = "file checksum", description = "File checksum.", example = "md5:ef8fcf1f046bb24f1db1f1a376ddbfbb") + private String checksum; + + @NotNull + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX", timezone = "UTC+2") + @Parameter(name = "file creation timestamp") + private Instant created; + + @NotNull + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX", timezone = "UTC+2") + @Parameter(name = "file updated timestamp") + private Instant updated; + + @NotBlank + @JsonProperty("file_id") + @Parameter(name = "file id") + private String fileId; + + @NotBlank + @Parameter(name = "file key", example = "mock.png") + private String key; + + @NotNull + @Parameter(name = "file links") + private LinksDto links; + + @Parameter(name = "file mimetype") + private String mimetype; + + @Parameter(name = "file size") + private Long size; + + @Parameter(name = "file status") + private String status; + + @JsonProperty("storage_class") + @Parameter(name = "file storage class", example = "S") + private String storageClass; + + @JsonProperty("version_id") + @Parameter(name = "file version id") + private String versionId; +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/file/FileEntryDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/file/FileEntryDto.java new file mode 100644 index 0000000000000000000000000000000000000000..d4c7909d5a1d0f075ca474c60610a2b1dfbe1cea --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/file/FileEntryDto.java @@ -0,0 +1,43 @@ + +package at.tuwien.api.document.file; + +import at.tuwien.api.document.links.LinksDto; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.time.Instant; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class FileEntryDto { + + @NotBlank + @Parameter(name = "file name", description = "Name of the file.") + private String key; + + @NotNull + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX", timezone = "UTC+2") + @Parameter(name = "file updated") + private Instant updated; + + @NotNull + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX", timezone = "UTC+2") + @Parameter(name = "file created") + private Instant created; + + @Parameter(name = "file status") + private String status; + + @Parameter(name = "file links") + private LinksDto links; + +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/file/FileKeyDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/file/FileKeyDto.java new file mode 100644 index 0000000000000000000000000000000000000000..79c7f3d7b7d1a6d620edd505543f27fd3c1dc9c0 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/file/FileKeyDto.java @@ -0,0 +1,23 @@ + +package at.tuwien.api.document.file; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + +import javax.validation.constraints.NotBlank; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class FileKeyDto { + + @NotBlank + @Parameter(name = "file name", description = "Name of the file.", example = "mock.png") + private String key; + +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/DraftDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/RecordDto.java similarity index 98% rename from fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/DraftDto.java rename to fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/RecordDto.java index d754f22fce839fe952e855fff31903dc0194dc27..0f41c523bb4fa2a31dc9446681bc3c5e372d33c1 100644 --- a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/DraftDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/RecordDto.java @@ -18,7 +18,7 @@ import java.time.Instant; @AllArgsConstructor @NoArgsConstructor @JsonInclude(JsonInclude.Include.NON_NULL) -public class DraftDto { +public class RecordDto { @NotNull(message = "access is required") @Parameter(name = "access") diff --git a/fda-ui/server-middleware/index.js b/fda-ui/server-middleware/index.js index b74dab08920ad0f14cc1b38e15ee3b7216b90361..819f649f24a9ac7eb00f1d5a9a1b95e9475c7b19 100644 --- a/fda-ui/server-middleware/index.js +++ b/fda-ui/server-middleware/index.js @@ -25,6 +25,7 @@ app.post('/table_from_csv', upload.single('file'), async (req, res) => { // send path to analyse service let analysis + let json try { const analyseUrl = `${process.env.API}/api/analyse/determinedt` analysis = await fetch(analyseUrl, { @@ -35,9 +36,8 @@ app.post('/table_from_csv', upload.single('file'), async (req, res) => { console.error('data type determination failed', error) throw error }) - const json = await analysis.json() - analysis = JSON.parse(json) - if (!analysis.columns) { + json = await analysis.json() + if (!json.columns) { return res.json({ success: false, message: 'Columns array missing' }) } } catch (error) { @@ -47,7 +47,7 @@ app.post('/table_from_csv', upload.single('file'), async (req, res) => { // map messytables / CoMi's `determine_dt` column types to ours // e.g. "Integer" -> "NUMBER" - let entries = Object.entries(analysis.columns) + let entries = Object.entries(json.columns) entries = entries.map(([k, v]) => { if (colTypeMap[v]) { v = colTypeMap[v]