diff --git a/.jupyter/api_authentication/__init__.py b/.jupyter/api_authentication/__init__.py index 1caebb3b03385e64cd4896ea7b633296e3edd37a..c20f434f5ee3610077bb2fd6ec91f8a21f5ca08a 100644 --- a/.jupyter/api_authentication/__init__.py +++ b/.jupyter/api_authentication/__init__.py @@ -23,8 +23,6 @@ from api_authentication.api_client import ApiClient from api_authentication.configuration import Configuration # import models into sdk package from api_authentication.models.api_error_dto import ApiErrorDto -from api_authentication.models.column_dto import ColumnDto -from api_authentication.models.concept_dto import ConceptDto from api_authentication.models.container_dto import ContainerDto from api_authentication.models.database_dto import DatabaseDto from api_authentication.models.granted_authority_dto import GrantedAuthorityDto @@ -36,7 +34,8 @@ from api_authentication.models.jwt_response_dto import JwtResponseDto from api_authentication.models.license_dto import LicenseDto from api_authentication.models.login_request_dto import LoginRequestDto from api_authentication.models.signup_request_dto import SignupRequestDto -from api_authentication.models.table_dto import TableDto +from api_authentication.models.table_brief_dto import TableBriefDto +from api_authentication.models.user_brief_dto import UserBriefDto from api_authentication.models.user_dto import UserDto from api_authentication.models.user_email_dto import UserEmailDto from api_authentication.models.user_forgot_dto import UserForgotDto diff --git a/.jupyter/api_authentication/models/__init__.py b/.jupyter/api_authentication/models/__init__.py index 0cd55935b61999c415fd3e89ff72c48c4effe5f6..fc192aa3f48fc29eb41b993849da77e1a52b8001 100644 --- a/.jupyter/api_authentication/models/__init__.py +++ b/.jupyter/api_authentication/models/__init__.py @@ -15,8 +15,6 @@ from __future__ import absolute_import # import models into model package from api_authentication.models.api_error_dto import ApiErrorDto -from api_authentication.models.column_dto import ColumnDto -from api_authentication.models.concept_dto import ConceptDto from api_authentication.models.container_dto import ContainerDto from api_authentication.models.database_dto import DatabaseDto from api_authentication.models.granted_authority_dto import GrantedAuthorityDto @@ -28,7 +26,8 @@ from api_authentication.models.jwt_response_dto import JwtResponseDto from api_authentication.models.license_dto import LicenseDto from api_authentication.models.login_request_dto import LoginRequestDto from api_authentication.models.signup_request_dto import SignupRequestDto -from api_authentication.models.table_dto import TableDto +from api_authentication.models.table_brief_dto import TableBriefDto +from api_authentication.models.user_brief_dto import UserBriefDto from api_authentication.models.user_dto import UserDto from api_authentication.models.user_email_dto import UserEmailDto from api_authentication.models.user_forgot_dto import UserForgotDto diff --git a/.jupyter/api_authentication/models/database_dto.py b/.jupyter/api_authentication/models/database_dto.py index c5ef5bef663b50bce516fe7f217fb773a9b74273..3ff298f11a16adbbd8a8362d7d80d3b14139dec2 100644 --- a/.jupyter/api_authentication/models/database_dto.py +++ b/.jupyter/api_authentication/models/database_dto.py @@ -38,7 +38,7 @@ class DatabaseDto(object): 'description': 'str', 'publisher': 'str', 'contact': 'UserDto', - 'tables': 'list[TableDto]', + 'tables': 'list[TableBriefDto]', 'image': 'ImageDto', 'container': 'ContainerDto', 'created': 'datetime', @@ -352,7 +352,7 @@ class DatabaseDto(object): :return: The tables of this DatabaseDto. # noqa: E501 - :rtype: list[TableDto] + :rtype: list[TableBriefDto] """ return self._tables @@ -362,7 +362,7 @@ class DatabaseDto(object): :param tables: The tables of this DatabaseDto. # noqa: E501 - :type: list[TableDto] + :type: list[TableBriefDto] """ self._tables = tables diff --git a/.jupyter/api_container/__init__.py b/.jupyter/api_container/__init__.py index d659282125f720eb4fac3822eca06b9c9aed2145..e8c65699a9aec6d7e0fb978d8754509fb3ea5b55 100644 --- a/.jupyter/api_container/__init__.py +++ b/.jupyter/api_container/__init__.py @@ -22,8 +22,6 @@ from api_container.api_client import ApiClient from api_container.configuration import Configuration # import models into sdk package from api_container.models.api_error_dto import ApiErrorDto -from api_container.models.column_dto import ColumnDto -from api_container.models.concept_dto import ConceptDto from api_container.models.container_brief_dto import ContainerBriefDto from api_container.models.container_change_dto import ContainerChangeDto from api_container.models.container_create_request_dto import ContainerCreateRequestDto @@ -37,6 +35,6 @@ from api_container.models.image_date_dto import ImageDateDto from api_container.models.image_dto import ImageDto from api_container.models.image_env_item_dto import ImageEnvItemDto from api_container.models.license_dto import LicenseDto -from api_container.models.table_dto import TableDto +from api_container.models.table_brief_dto import TableBriefDto from api_container.models.user_brief_dto import UserBriefDto from api_container.models.user_dto import UserDto diff --git a/.jupyter/api_container/models/__init__.py b/.jupyter/api_container/models/__init__.py index 9f7e2ea74892493aa95f3dbda75793dc6216d075..563386400df8bac3bf6baa005dffcc98e331ee88 100644 --- a/.jupyter/api_container/models/__init__.py +++ b/.jupyter/api_container/models/__init__.py @@ -15,8 +15,6 @@ from __future__ import absolute_import # import models into model package from api_container.models.api_error_dto import ApiErrorDto -from api_container.models.column_dto import ColumnDto -from api_container.models.concept_dto import ConceptDto from api_container.models.container_brief_dto import ContainerBriefDto from api_container.models.container_change_dto import ContainerChangeDto from api_container.models.container_create_request_dto import ContainerCreateRequestDto @@ -30,6 +28,6 @@ from api_container.models.image_date_dto import ImageDateDto from api_container.models.image_dto import ImageDto from api_container.models.image_env_item_dto import ImageEnvItemDto from api_container.models.license_dto import LicenseDto -from api_container.models.table_dto import TableDto +from api_container.models.table_brief_dto import TableBriefDto from api_container.models.user_brief_dto import UserBriefDto from api_container.models.user_dto import UserDto diff --git a/.jupyter/api_container/models/database_dto.py b/.jupyter/api_container/models/database_dto.py index 20dd3f3b565be8fdee78cc1da5f48c53833756a1..408803f482399398888727d762da195cac706c9b 100644 --- a/.jupyter/api_container/models/database_dto.py +++ b/.jupyter/api_container/models/database_dto.py @@ -38,7 +38,7 @@ class DatabaseDto(object): 'description': 'str', 'publisher': 'str', 'contact': 'UserDto', - 'tables': 'list[TableDto]', + 'tables': 'list[TableBriefDto]', 'image': 'ImageDto', 'container': 'ContainerDto', 'created': 'datetime', @@ -352,7 +352,7 @@ class DatabaseDto(object): :return: The tables of this DatabaseDto. # noqa: E501 - :rtype: list[TableDto] + :rtype: list[TableBriefDto] """ return self._tables @@ -362,7 +362,7 @@ class DatabaseDto(object): :param tables: The tables of this DatabaseDto. # noqa: E501 - :type: list[TableDto] + :type: list[TableBriefDto] """ self._tables = tables diff --git a/.jupyter/api_database/__init__.py b/.jupyter/api_database/__init__.py index 8c1403ffcfb84a6edfa6d3f031569274f0a79d5f..5da8bf97a428a1bc5e19898c594a8cd20c729876 100644 --- a/.jupyter/api_database/__init__.py +++ b/.jupyter/api_database/__init__.py @@ -22,8 +22,6 @@ from api_database.api_client import ApiClient from api_database.configuration import Configuration # import models into sdk package from api_database.models.api_error_dto import ApiErrorDto -from api_database.models.column_dto import ColumnDto -from api_database.models.concept_dto import ConceptDto from api_database.models.container_brief_dto import ContainerBriefDto from api_database.models.container_dto import ContainerDto from api_database.models.database_brief_dto import DatabaseBriefDto @@ -36,6 +34,6 @@ from api_database.models.image_date_dto import ImageDateDto from api_database.models.image_dto import ImageDto from api_database.models.image_env_item_dto import ImageEnvItemDto from api_database.models.license_dto import LicenseDto -from api_database.models.table_dto import TableDto +from api_database.models.table_brief_dto import TableBriefDto from api_database.models.user_brief_dto import UserBriefDto from api_database.models.user_dto import UserDto diff --git a/.jupyter/api_database/models/__init__.py b/.jupyter/api_database/models/__init__.py index 918bf85903ca098384536a216e26c12ccfd983ac..17ab89a69b0183bc10388c23d898f30aaf44f6be 100644 --- a/.jupyter/api_database/models/__init__.py +++ b/.jupyter/api_database/models/__init__.py @@ -15,8 +15,6 @@ from __future__ import absolute_import # import models into model package from api_database.models.api_error_dto import ApiErrorDto -from api_database.models.column_dto import ColumnDto -from api_database.models.concept_dto import ConceptDto from api_database.models.container_brief_dto import ContainerBriefDto from api_database.models.container_dto import ContainerDto from api_database.models.database_brief_dto import DatabaseBriefDto @@ -29,6 +27,6 @@ from api_database.models.image_date_dto import ImageDateDto from api_database.models.image_dto import ImageDto from api_database.models.image_env_item_dto import ImageEnvItemDto from api_database.models.license_dto import LicenseDto -from api_database.models.table_dto import TableDto +from api_database.models.table_brief_dto import TableBriefDto from api_database.models.user_brief_dto import UserBriefDto from api_database.models.user_dto import UserDto diff --git a/.jupyter/api_database/models/database_dto.py b/.jupyter/api_database/models/database_dto.py index eb17e89e25ccb7ac37f89925288f714fe8dfa294..6e1826899a9a28567c481c497616b41e3213b6ef 100644 --- a/.jupyter/api_database/models/database_dto.py +++ b/.jupyter/api_database/models/database_dto.py @@ -38,7 +38,7 @@ class DatabaseDto(object): 'description': 'str', 'publisher': 'str', 'contact': 'UserDto', - 'tables': 'list[TableDto]', + 'tables': 'list[TableBriefDto]', 'image': 'ImageDto', 'container': 'ContainerDto', 'created': 'datetime', @@ -352,7 +352,7 @@ class DatabaseDto(object): :return: The tables of this DatabaseDto. # noqa: E501 - :rtype: list[TableDto] + :rtype: list[TableBriefDto] """ return self._tables @@ -362,7 +362,7 @@ class DatabaseDto(object): :param tables: The tables of this DatabaseDto. # noqa: E501 - :type: list[TableDto] + :type: list[TableBriefDto] """ self._tables = tables diff --git a/.jupyter/api_identifier/__init__.py b/.jupyter/api_identifier/__init__.py index 588a1b3d2e5d606eceab7ad2a056157c2d000d5d..004d1c92b4090d4278f7b889ddf19bcceed7077e 100644 --- a/.jupyter/api_identifier/__init__.py +++ b/.jupyter/api_identifier/__init__.py @@ -22,8 +22,6 @@ from api_identifier.api_client import ApiClient from api_identifier.configuration import Configuration # import models into sdk package from api_identifier.models.api_error_dto import ApiErrorDto -from api_identifier.models.column_dto import ColumnDto -from api_identifier.models.concept_dto import ConceptDto from api_identifier.models.container_dto import ContainerDto from api_identifier.models.creator_create_dto import CreatorCreateDto from api_identifier.models.creator_dto import CreatorDto @@ -38,5 +36,6 @@ from api_identifier.models.image_env_item_dto import ImageEnvItemDto from api_identifier.models.license_dto import LicenseDto from api_identifier.models.related_identifier_create_dto import RelatedIdentifierCreateDto from api_identifier.models.related_identifier_dto import RelatedIdentifierDto -from api_identifier.models.table_dto import TableDto +from api_identifier.models.table_brief_dto import TableBriefDto +from api_identifier.models.user_brief_dto import UserBriefDto from api_identifier.models.user_dto import UserDto diff --git a/.jupyter/api_identifier/models/__init__.py b/.jupyter/api_identifier/models/__init__.py index e39aeeecc9d92c71faa0920063ab564ed64ad624..10de3f2d883f13ef5e5b73c543d8a8c8b770850d 100644 --- a/.jupyter/api_identifier/models/__init__.py +++ b/.jupyter/api_identifier/models/__init__.py @@ -15,8 +15,6 @@ from __future__ import absolute_import # import models into model package from api_identifier.models.api_error_dto import ApiErrorDto -from api_identifier.models.column_dto import ColumnDto -from api_identifier.models.concept_dto import ConceptDto from api_identifier.models.container_dto import ContainerDto from api_identifier.models.creator_create_dto import CreatorCreateDto from api_identifier.models.creator_dto import CreatorDto @@ -31,5 +29,6 @@ from api_identifier.models.image_env_item_dto import ImageEnvItemDto from api_identifier.models.license_dto import LicenseDto from api_identifier.models.related_identifier_create_dto import RelatedIdentifierCreateDto from api_identifier.models.related_identifier_dto import RelatedIdentifierDto -from api_identifier.models.table_dto import TableDto +from api_identifier.models.table_brief_dto import TableBriefDto +from api_identifier.models.user_brief_dto import UserBriefDto from api_identifier.models.user_dto import UserDto diff --git a/.jupyter/api_query/__init__.py b/.jupyter/api_query/__init__.py index 125c6c436bf1a5a5bfd5c3c754895194c4450090..b0dc0ccd7f926900b7edacab3b971d555f4d9152 100644 --- a/.jupyter/api_query/__init__.py +++ b/.jupyter/api_query/__init__.py @@ -25,8 +25,6 @@ from api_query.api_client import ApiClient from api_query.configuration import Configuration # import models into sdk package from api_query.models.api_error_dto import ApiErrorDto -from api_query.models.column_dto import ColumnDto -from api_query.models.concept_dto import ConceptDto from api_query.models.container_dto import ContainerDto from api_query.models.database_dto import DatabaseDto from api_query.models.execute_statement_dto import ExecuteStatementDto @@ -39,8 +37,10 @@ from api_query.models.import_dto import ImportDto from api_query.models.license_dto import LicenseDto from api_query.models.query_dto import QueryDto from api_query.models.query_result_dto import QueryResultDto +from api_query.models.table_brief_dto import TableBriefDto from api_query.models.table_csv_delete_dto import TableCsvDeleteDto from api_query.models.table_csv_dto import TableCsvDto -from api_query.models.table_dto import TableDto +from api_query.models.table_csv_update_dto import TableCsvUpdateDto from api_query.models.table_history_dto import TableHistoryDto +from api_query.models.user_brief_dto import UserBriefDto from api_query.models.user_dto import UserDto diff --git a/.jupyter/api_query/api/query_endpoint_api.py b/.jupyter/api_query/api/query_endpoint_api.py index 74bda079d95417f5be1f97e03ef2500bb04ce6ca..158773461bef14884a5b792f1283b191d6c199d7 100644 --- a/.jupyter/api_query/api/query_endpoint_api.py +++ b/.jupyter/api_query/api/query_endpoint_api.py @@ -361,7 +361,7 @@ class QueryEndpointApi(object): ['*/*']) # noqa: E501 # Authentication setting - auth_settings = [] # noqa: E501 + auth_settings = ['bearerAuth'] # noqa: E501 return self.api_client.call_api( '/api/container/{id}/database/{databaseId}/query/{queryId}', 'PUT', diff --git a/.jupyter/api_query/api/table_data_endpoint_api.py b/.jupyter/api_query/api/table_data_endpoint_api.py index 31b90e9df370ce626ce7767d44cdef26d2f1b7d7..632bf0023c0c979119e43647dec551cf4bc744ad 100644 --- a/.jupyter/api_query/api/table_data_endpoint_api.py +++ b/.jupyter/api_query/api/table_data_endpoint_api.py @@ -636,3 +636,124 @@ class TableDataEndpointApi(object): _preload_content=params.get('_preload_content', True), _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) + + def update(self, body, id, database_id, table_id, **kwargs): # noqa: E501 + """Update data # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + >>> thread = api.update(body, id, database_id, table_id, async_req=True) + >>> result = thread.get() + + :param async_req bool + :param TableCsvUpdateDto body: (required) + :param int id: (required) + :param int database_id: (required) + :param int table_id: (required) + :return: None + If the method is called asynchronously, + returns the request thread. + """ + kwargs['_return_http_data_only'] = True + if kwargs.get('async_req'): + return self.update_with_http_info(body, id, database_id, table_id, **kwargs) # noqa: E501 + else: + (data) = self.update_with_http_info(body, id, database_id, table_id, **kwargs) # noqa: E501 + return data + + def update_with_http_info(self, body, id, database_id, table_id, **kwargs): # noqa: E501 + """Update data # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + >>> thread = api.update_with_http_info(body, id, database_id, table_id, async_req=True) + >>> result = thread.get() + + :param async_req bool + :param TableCsvUpdateDto body: (required) + :param int id: (required) + :param int database_id: (required) + :param int table_id: (required) + :return: None + If the method is called asynchronously, + returns the request thread. + """ + + all_params = ['body', 'id', 'database_id', 'table_id'] # noqa: E501 + all_params.append('async_req') + all_params.append('_return_http_data_only') + all_params.append('_preload_content') + all_params.append('_request_timeout') + + params = locals() + for key, val in six.iteritems(params['kwargs']): + if key not in all_params: + raise TypeError( + "Got an unexpected keyword argument '%s'" + " to method update" % key + ) + params[key] = val + del params['kwargs'] + # verify the required parameter 'body' is set + if ('body' not in params or + params['body'] is None): + raise ValueError("Missing the required parameter `body` when calling `update`") # noqa: E501 + # verify the required parameter 'id' is set + if ('id' not in params or + params['id'] is None): + raise ValueError("Missing the required parameter `id` when calling `update`") # noqa: E501 + # verify the required parameter 'database_id' is set + if ('database_id' not in params or + params['database_id'] is None): + raise ValueError("Missing the required parameter `database_id` when calling `update`") # noqa: E501 + # verify the required parameter 'table_id' is set + if ('table_id' not in params or + params['table_id'] is None): + raise ValueError("Missing the required parameter `table_id` when calling `update`") # noqa: E501 + + collection_formats = {} + + path_params = {} + if 'id' in params: + path_params['id'] = params['id'] # noqa: E501 + if 'database_id' in params: + path_params['databaseId'] = params['database_id'] # noqa: E501 + if 'table_id' in params: + path_params['tableId'] = params['table_id'] # noqa: E501 + + query_params = [] + + header_params = {} + + form_params = [] + local_var_files = {} + + body_params = None + if 'body' in params: + body_params = params['body'] + # HTTP header `Accept` + header_params['Accept'] = self.api_client.select_header_accept( + ['*/*']) # noqa: E501 + + # HTTP header `Content-Type` + header_params['Content-Type'] = self.api_client.select_header_content_type( # noqa: E501 + ['application/json']) # noqa: E501 + + # Authentication setting + auth_settings = ['bearerAuth'] # noqa: E501 + + return self.api_client.call_api( + '/api/container/{id}/database/{databaseId}/table/{tableId}/data', 'PUT', + path_params, + query_params, + header_params, + body=body_params, + post_params=form_params, + files=local_var_files, + response_type=None, # noqa: E501 + auth_settings=auth_settings, + async_req=params.get('async_req'), + _return_http_data_only=params.get('_return_http_data_only'), + _preload_content=params.get('_preload_content', True), + _request_timeout=params.get('_request_timeout'), + collection_formats=collection_formats) diff --git a/.jupyter/api_query/models/__init__.py b/.jupyter/api_query/models/__init__.py index 2ce6fd387583c2a36c1cf6d2f4cfda8c070b0e4a..947ce39c5dbb0d5aeac633d99c8d0e0b68818e03 100644 --- a/.jupyter/api_query/models/__init__.py +++ b/.jupyter/api_query/models/__init__.py @@ -15,8 +15,6 @@ from __future__ import absolute_import # import models into model package from api_query.models.api_error_dto import ApiErrorDto -from api_query.models.column_dto import ColumnDto -from api_query.models.concept_dto import ConceptDto from api_query.models.container_dto import ContainerDto from api_query.models.database_dto import DatabaseDto from api_query.models.execute_statement_dto import ExecuteStatementDto @@ -29,8 +27,10 @@ from api_query.models.import_dto import ImportDto from api_query.models.license_dto import LicenseDto from api_query.models.query_dto import QueryDto from api_query.models.query_result_dto import QueryResultDto +from api_query.models.table_brief_dto import TableBriefDto from api_query.models.table_csv_delete_dto import TableCsvDeleteDto from api_query.models.table_csv_dto import TableCsvDto -from api_query.models.table_dto import TableDto +from api_query.models.table_csv_update_dto import TableCsvUpdateDto from api_query.models.table_history_dto import TableHistoryDto +from api_query.models.user_brief_dto import UserBriefDto from api_query.models.user_dto import UserDto diff --git a/.jupyter/api_query/models/database_dto.py b/.jupyter/api_query/models/database_dto.py index b1dbaea6d8ef56c428e3ca8cfa458fd63d5ad949..6cb99a24159f1d25fba0d919a86917f761598b94 100644 --- a/.jupyter/api_query/models/database_dto.py +++ b/.jupyter/api_query/models/database_dto.py @@ -38,7 +38,7 @@ class DatabaseDto(object): 'description': 'str', 'publisher': 'str', 'contact': 'UserDto', - 'tables': 'list[TableDto]', + 'tables': 'list[TableBriefDto]', 'image': 'ImageDto', 'container': 'ContainerDto', 'created': 'datetime', @@ -352,7 +352,7 @@ class DatabaseDto(object): :return: The tables of this DatabaseDto. # noqa: E501 - :rtype: list[TableDto] + :rtype: list[TableBriefDto] """ return self._tables @@ -362,7 +362,7 @@ class DatabaseDto(object): :param tables: The tables of this DatabaseDto. # noqa: E501 - :type: list[TableDto] + :type: list[TableBriefDto] """ self._tables = tables diff --git a/.jupyter/load_test.py b/.jupyter/load_test.py index 688fa6dd8be8212d70db479e8d06f19144f5d81c..bdf47dee1dcb92117e56a8bd362e247f2d9f1156 100644 --- a/.jupyter/load_test.py +++ b/.jupyter/load_test.py @@ -4,6 +4,7 @@ import time import os import shutil import uuid +from postgres import Postgres import api_query.rest from api_authentication.api.authentication_endpoint_api import AuthenticationEndpointApi @@ -219,6 +220,27 @@ def delete_tuple(container_id, database_id, table_id, keys): return response +def update_user(user_id): + response = user.update({ + "firstname": "Josiah", + "lastname": "Carberry", + "affiliation": "Wesleyan University", + "orcid": "0000-0002-1825-0097", + "titles_after": "PhD" + }, user_id) + print("updated user with id %d" % user_id) + + +def update_theme(user_id): + response = user.update_theme({ + "theme_dark": True + }, user_id) + print("updated theme user with id %d" % user_id) + +def verify_user(user_id): + db = Postgres("dbname=fda user=postgres password=postgres") + token = db.one("SELECT ") + if __name__ == '__main__': # # create 1 user and 3 containers (public, private, public) @@ -310,3 +332,10 @@ if __name__ == '__main__': tname = find_table(1, 1, 1).internal_name qid = create_query(1, 1, "select `id` from `" + tname + "`").id create_identifier(1, 1, qid) + # + # create 1 user and modify information + # + uid = create_user("test3").id + auth_user("test3") + update_user(uid) + update_theme(uid) diff --git a/.jupyter/requirements.txt b/.jupyter/requirements.txt index 2a252d8604d7e5efc1b8b241ca1f93bb006dd87c..1ea469ff4a0a04b6fbdc486eba98da9be95b38d2 100644 --- a/.jupyter/requirements.txt +++ b/.jupyter/requirements.txt @@ -1,2 +1,3 @@ requests>=2.28.0 -pandas>=1.4.3 \ No newline at end of file +pandas>=1.4.3 +postgres>=4.0 \ No newline at end of file diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/DatabaseDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/DatabaseDto.java index 5da1350e8f3f4e785c53c6339b0d1999744e021f..7a3b8c47c00e1237b880e6815559a9648776f88e 100644 --- a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/DatabaseDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/DatabaseDto.java @@ -2,8 +2,10 @@ package at.tuwien.api.database; import at.tuwien.api.container.ContainerDto; import at.tuwien.api.container.image.ImageDto; +import at.tuwien.api.database.table.TableBriefDto; import at.tuwien.api.database.table.TableDto; import at.tuwien.api.identifier.CreatorDto; +import at.tuwien.api.user.UserBriefDto; import at.tuwien.api.user.UserDto; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; @@ -37,7 +39,7 @@ public class DatabaseDto { @NotNull @Parameter(name = "database creator") - private UserDto creator; + private UserBriefDto creator; @NotBlank @JsonProperty("internal_name") @@ -67,7 +69,7 @@ public class DatabaseDto { private String publication; @Parameter(name = "tables") - private List<TableDto> tables; + private List<TableBriefDto> tables; @JsonProperty("is_public") @Parameter(name = "database public") diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/table/TableDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/table/TableDto.java index b739f660d4412ced2f48185343ce844eedb223f6..07c3205f3c71d111d08957ec4289eefb22e37591 100644 --- a/fda-metadata-db/api/src/main/java/at/tuwien/api/database/table/TableDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/database/table/TableDto.java @@ -1,6 +1,7 @@ package at.tuwien.api.database.table; import at.tuwien.api.database.table.columns.ColumnDto; +import at.tuwien.api.user.UserBriefDto; import at.tuwien.api.user.UserDto; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; @@ -10,6 +11,7 @@ import lombok.*; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import java.time.Instant; +import java.util.List; @Getter @Setter @@ -32,6 +34,10 @@ public class TableDto { @Parameter(name = "table internal name", example = "weather_australia") private String internalName; + @NotNull + @Parameter(name = "database creator") + private UserBriefDto creator; + @NotBlank @Parameter(name = "topic name", example = "fda.c1.d1.t1") private String topic; @@ -46,6 +52,6 @@ public class TableDto { @NotNull @Parameter(name = "table columns") - private ColumnDto[] columns; + private List<ColumnDto> columns; } diff --git a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/AbstractEndpoint.java b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/AbstractEndpoint.java index d065595722184c2a426faadf375b7cf385b9c9a0..fc367c723ed3d77bd49745ad86b87691f194bddc 100644 --- a/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/AbstractEndpoint.java +++ b/fda-query-service/rest-service/src/main/java/at/tuwien/endpoint/AbstractEndpoint.java @@ -36,28 +36,29 @@ public abstract class AbstractEndpoint { log.debug("failed to find database with id {}", databaseId); return false; } - if (principal != null && database.getCreator().getUsername().equals(principal.getName())) { - log.debug("grant permission {} because user is creator of database with id {}", permissionCode, databaseId); - return true; - } /* view-only operations are allowed on public databases */ if (database.getIsPublic() && List.of("DATA_EXPORT", "DATA_VIEW", "DATA_HISTORY", "QUERY_VIEW_ALL").contains(permissionCode)) { log.debug("grant permission {} because database is public", permissionCode); return true; } - /* modification operations are limited to the creator */ if (principal == null) { log.debug("failed to grant permission {} because principal is null", permissionCode); return false; } + /* modification operations are limited to the creator */ + if (database.getCreator().getUsername().equals(principal.getName())) { + log.debug("grant permission {} because user {} is creator {}", permissionCode, principal.getName(), + database.getCreator().getUsername()); + return true; + } final Authentication authentication = (Authentication) principal /* with pre-authorization this always holds */; if (authentication.getAuthorities().stream().noneMatch(a -> a.getAuthority().equals("ROLE_RESEARCHER"))) { log.debug("failed to grant permission {} because current user misses authority 'ROLE_RESEARCHER'", permissionCode); return false; } - log.debug("grant permission {} because user is creator", permissionCode); - return true; + log.debug("failed to grant permission {} because database is not owner by the current user", permissionCode); + return false; } protected Boolean hasQueryPermission(Long containerId, Long databaseId, Long queryId, String permissionCode, Principal principal) { @@ -97,8 +98,7 @@ public abstract class AbstractEndpoint { permissionCode); return true; } - log.debug("failed to grant permission {} because database is private and creator is not the " + - "current user", permissionCode); + log.debug("failed to grant permission {} because database is private and creator is not the current user", permissionCode); return false; } @@ -138,8 +138,7 @@ public abstract class AbstractEndpoint { permissionCode); return true; } - log.debug("failed to grant permission {} because database is private and identifier creator is not the " + - "current user", permissionCode); + log.debug("failed to grant permission {} because database is private and identifier creator is not the current user", permissionCode); return false; } diff --git a/fda-query-service/rest-service/src/main/resources/application-docker.yml b/fda-query-service/rest-service/src/main/resources/application-docker.yml index 955a46143cacbf54298714e9e6f4854f3d29ebef..5fe20159177864b2bd60a1cecf0de464fed7969d 100644 --- a/fda-query-service/rest-service/src/main/resources/application-docker.yml +++ b/fda-query-service/rest-service/src/main/resources/application-docker.yml @@ -30,7 +30,7 @@ logging: level: root: warn at.tuwien.: debug - at.tuwien.mapper.: trace + at.tuwien.mapper.: debug at.tuwien.service.: debug at.tuwien.config.: debug at.tuwien.auth.UserPermissionEvaluator: trace diff --git a/fda-query-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java b/fda-query-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java index fab90ea031913a3c81414114341ad9a0534f2fb8..f1bc79f8191c512c2ba38a221853ea3292b03367 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java +++ b/fda-query-service/services/src/main/java/at/tuwien/mapper/QueryMapper.java @@ -403,8 +403,7 @@ public interface QueryMapper { log.debug("failed to map column names, tuple contains columns names that are not present in the database, tuple column names are {}", data.getData().keySet()); throw new TableMalformedException("Failed to map column names"); } - ps.setObject(idx[0]++, dataColumnToObject(tuple.get() - .getValue(), column)); + prepareStatementWithColumnTypeObject(ps, column.getColumnType(), idx[0]++, tuple.get().getValue()); } return ps; } catch (SQLException e) { diff --git a/fda-table-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java b/fda-table-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java index 101c2d82e41f013a5c5940e2fb5ae93d73f0bd20..c9d53209169d32e3e8b84043ebd592c5ab41b3a4 100644 --- a/fda-table-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java +++ b/fda-table-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java @@ -93,9 +93,9 @@ public class TableEndpoint extends AbstractEndpoint { throw new NotAllowedException("Missing table view permission"); } final Table table = tableService.findById(containerId, databaseId, tableId, principal); - log.debug(table); - TableDto tableDto = tableMapper.tableToTableDto(table); - log.debug(tableDto); + log.info("Found table with id {}", tableId); + log.debug("found table {}", table); + final TableDto tableDto = tableMapper.tableToTableDto(table); return ResponseEntity.ok(tableDto); } diff --git a/fda-table-service/services/src/main/java/at/tuwien/mapper/TableMapper.java b/fda-table-service/services/src/main/java/at/tuwien/mapper/TableMapper.java index cbb946cfc04cbff4edf24d390ce3d48cabf3cb9c..4df1d5f36226fd67bdf0f277c5c97821ca764110 100644 --- a/fda-table-service/services/src/main/java/at/tuwien/mapper/TableMapper.java +++ b/fda-table-service/services/src/main/java/at/tuwien/mapper/TableMapper.java @@ -51,11 +51,7 @@ public interface TableMapper { /* keep */ @Mappings({ - @Mapping(target = "name", expression = "java(data.getName())"), - @Mapping(target = "internalName", expression = "java(data.getInternalName())"), @Mapping(target = "unique", source = "isUnique"), - @Mapping(target = "checkExpression", expression = "java(data.getCheckExpression())"), - @Mapping(target = "foreignKey", expression = "java(data.getForeignKey())") }) ColumnDto tableColumnToColumnDto(TableColumn data); diff --git a/fda-ui/components/TableList.vue b/fda-ui/components/TableList.vue index e7168b8a15b84f18cb6450a4b608e49a21001b80..a5149bccf7fe396516727933c1af88a46459c398 100644 --- a/fda-ui/components/TableList.vue +++ b/fda-ui/components/TableList.vue @@ -97,6 +97,7 @@ <v-data-table class="full-width" disable-sort + :loading="loadingDetails" hide-default-footer :headers="headers" :items="tableDetails.columns"> @@ -134,7 +135,7 @@ <v-dialog v-model="unitDialog" max-width="600px"> - <DialogsColumnUnit :concept="unit" :table-id="tableDetails.id" @close="closed" /> + <DialogsColumnUnit :column="column" :table-id="tableDetails.id" @close="closed" /> </v-dialog> <v-dialog v-model="dialogDelete" max-width="640"> <v-card> @@ -164,10 +165,11 @@ export default { data () { return { loading: false, + loadingDetails: false, error: false, tables: [], panel: null, - unit: null, + column: null, unitDialog: false, database: { exchange: null, @@ -230,7 +232,7 @@ export default { }, methods: { pickUnit (item) { - this.unit = item.column_concept + this.column = item this.unitDialog = true console.debug('select', this.unit) }, @@ -255,12 +257,20 @@ export default { } return column.column_type }, - details (tableId) { - const select = this.tables.filter(t => t.id === tableId) - if (select.length > 0) { - this.tableDetails = select[0] + async details (tableId) { + try { + this.loadingDetails = true + const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${tableId}`, this.config) + this.tableDetails = res.data console.debug('table details', this.tableDetails) + if (tableId) { + this.openPanelByTableId(tableId) + } + } catch (err) { + this.$toast.error('Failed to load table details') + console.error('Failed to load table details', err) } + this.loadingDetails = false }, closed (data) { console.debug('closed dialog', data) diff --git a/fda-ui/components/dialogs/ColumnUnit.vue b/fda-ui/components/dialogs/ColumnUnit.vue index 24fde4976dd943eb00d806106ffb7160fac42227..896d201784db61a5faac47a162abbd8e2809fcc2 100644 --- a/fda-ui/components/dialogs/ColumnUnit.vue +++ b/fda-ui/components/dialogs/ColumnUnit.vue @@ -1,84 +1,91 @@ <template> <div> - <v-card> - <v-card-title> - Assign Unit of Measurement - </v-card-title> - <v-card-text> - <v-autocomplete - v-model="model" - solo - clearable - auto-select-first - :cache-items="false" - autofocus - :search-input.sync="search" - :items="items" - hide-no-data - hide-details - dense> - <template - v-slot:item="{ item, attrs, on }"> - <v-list-item v-bind="attrs" v-on="on"> + <v-form v-model="valid"> + <v-card> + <v-card-title> + Unit of Measurement + </v-card-title> + <v-card-subtitle> + Assign a unit of measurement to column <strong>{{ column.name }}</strong> + </v-card-subtitle> + <v-card-text> + <v-autocomplete + v-model="model" + solo + clearable + auto-select-first + :cache-items="false" + autofocus + :loading="isLoading" + placeholder="Search Unit of Measurements" + :search-input.sync="search" + :items="items" + hide-no-data + hide-details + dense> + <template + v-slot:item="{ item, attrs, on }"> + <v-list-item v-bind="attrs" v-on="on"> + <v-list-item-content> + <v-list-item-title>{{ item.value.name }}</v-list-item-title> + <v-list-item-subtitle>{{ item.value.comment }}</v-list-item-subtitle> + </v-list-item-content> + </v-list-item> + </template> + </v-autocomplete> + </v-card-text> + <v-expand-transition> + <v-list v-if="model" class="lighten-3" subheader three-line> + <v-list-item v-if="model.name"> <v-list-item-content> - <v-list-item-title>{{ item.value.name }}</v-list-item-title> - <v-list-item-subtitle>{{ item.value.comment }}</v-list-item-subtitle> + <v-list-item-title>Name</v-list-item-title> + <v-list-item-subtitle>{{ model.name }}</v-list-item-subtitle> </v-list-item-content> </v-list-item> - </template> - </v-autocomplete> - </v-card-text> - <v-expand-transition> - <v-list v-if="model" class="lighten-3" subheader three-line> - <v-list-item v-if="model.name"> - <v-list-item-content> - <v-list-item-title>Name</v-list-item-title> - <v-list-item-subtitle>{{ model.name }}</v-list-item-subtitle> - </v-list-item-content> - </v-list-item> - <v-list-item v-if="model.symbol"> - <v-list-item-content> - <v-list-item-title>Symbol</v-list-item-title> - <v-list-item-subtitle>{{ model.symbol }}</v-list-item-subtitle> - </v-list-item-content> - </v-list-item> - <v-list-item v-if="model.comment"> - <v-list-item-content> - <v-list-item-title>Comment</v-list-item-title> - <v-list-item-subtitle>{{ model.comment }}</v-list-item-subtitle> - </v-list-item-content> - </v-list-item> - <v-list-item v-if="model.uri" three-line> - <v-list-item-content> - <v-list-item-title>URI</v-list-item-title> - <v-list-item-subtitle>{{ model.uri }}</v-list-item-subtitle> - </v-list-item-content> - </v-list-item> - </v-list> - </v-expand-transition> - <v-card-actions> - <v-spacer /> - <v-btn - class="mb-2 mr-2" - @click="cancel"> - Cancel - </v-btn> - <v-btn - color="primary" - class="mb-2" - :disabled="!model" - @click="save"> - Save - </v-btn> - </v-card-actions> - </v-card> + <v-list-item v-if="model.symbol"> + <v-list-item-content> + <v-list-item-title>Symbol</v-list-item-title> + <v-list-item-subtitle>{{ model.symbol }}</v-list-item-subtitle> + </v-list-item-content> + </v-list-item> + <v-list-item v-if="model.comment"> + <v-list-item-content> + <v-list-item-title>Comment</v-list-item-title> + <v-list-item-subtitle>{{ model.comment }}</v-list-item-subtitle> + </v-list-item-content> + </v-list-item> + <v-list-item v-if="uri" three-line> + <v-list-item-content> + <v-list-item-title>URI</v-list-item-title> + <v-list-item-subtitle>{{ uri }}</v-list-item-subtitle> + </v-list-item-content> + </v-list-item> + </v-list> + </v-expand-transition> + <v-card-actions> + <v-spacer /> + <v-btn + class="mb-2" + @click="cancel"> + Cancel + </v-btn> + <v-btn + color="primary" + class="mb-2 mr-2" + :disabled="!model || !uri" + @click="save"> + Save + </v-btn> + </v-card-actions> + </v-card> + </v-form> </div> </template> <script> export default { props: { - concept: { + column: { type: Object, default: () => ({}) }, @@ -89,13 +96,15 @@ export default { dialog: false, isLoading: false, saved: false, + valid: false, model: { name: null, - uri: null, - symbol: null + symbol: null, + comment: null }, uri: null, search: null, + searchTerm: null, entries: [] } }, @@ -117,25 +126,35 @@ export default { concept (newVal, oldVal) { this.loadConcept(newVal) }, + model (newVal, oldVal) { + console.debug('selected concept', newVal) + this.loadConcept(newVal) + }, async search (val) { - if (this.isLoading) { return } - if (!val || !val.length) { return } + if (!val) { + return + } + this.searchTerm = val this.isLoading = true + await new Promise(resolve => setTimeout(resolve, 1000)) + if (val !== this.searchTerm) { + return + } try { const res = await this.$axios.post('/api/units/suggest', { offset: 0, - ustring: this.search + ustring: val }) this.entries = res.data + console.debug('suggest', res.data) } catch (err) { - this.$toast.error('Could not load unit suggestions.') - console.log(err) + console.error('suggest', err) } this.isLoading = false } }, mounted () { - this.loadConcept(this.concept) + this.loadConcept(this.column) }, methods: { cancel () { @@ -148,30 +167,42 @@ export default { return } this.model = concept - console.debug('load concept', concept) + console.debug('loading concept', concept) try { const res = await this.$axios.get(`/api/units/uri/${concept.name}`) - this.model.uri = res.data.URI + if (!res.data) { + console.warn('concept', concept.name, 'returned invalid data') + console.debug('concept', concept, 'returned', res.data) + return + } + this.uri = res.data.URI + console.debug('uri loaded', this.uri) } catch (err) { this.$toast.error(`Could not load URI of unit "${concept.name}"`) - console.log(err) + console.error('load concept', err) } }, async save () { const payload = { name: this.model.name, - uri: this.model.uri + uri: this.uri } + /* save concept */ try { console.debug('save', payload) - await this.$axios.post('/api/units/saveconcept', payload) + const res = await this.$axios.post('/api/units/saveconcept', payload) + console.info('Concept saved') + console.debug('concept saved', res.data) } catch (error) { const { status } = error.response - if (status !== 201 && status !== 400) { + if (status === 409) { + console.debug('concept already saved, skipping.') + } else { this.$toast.error('Could not save concept.') - console.log(error) + console.error('save', error) } } + /* save concept */ try { const res = await this.$axios.post('/api/units/savecolumnsconcept', { cdbid: Number(this.$route.params.database_id), @@ -183,6 +214,7 @@ export default { this.column.column_concept.name = this.model.name this.dialog = false this.saved = true + this.$toast.success(`Assigned unit ${this.model.name}`) this.$emit('close', { success: true, concept: res.data @@ -190,7 +222,7 @@ export default { console.debug('column', this.column) } catch (err) { this.$toast.error('Could not save column unit.') - console.log(err) + console.error('save', err) } } } diff --git a/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/index.vue b/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/index.vue index 229c195476198aa1e05f2a62fd195537c9a72742..4ea69814bb271e55f6df987bce6e150813a6e5a3 100644 --- a/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/index.vue +++ b/fda-ui/pages/container/_container_id/database/_database_id/table/_table_id/index.vue @@ -12,13 +12,13 @@ </v-toolbar-title> <v-spacer /> <v-toolbar-title> - <v-btn color="primary" :disabled="!token" class="mr-2" @click="addTuple"> + <v-btn v-if="is_owner" color="primary" class="mr-2" @click="addTuple"> <v-icon left>mdi-plus</v-icon> Add </v-btn> - <v-btn v-if="canEdit" :disabled="!token" color="warning" class="mr-2 mb-1" @click="editTupleDialog = true"> + <v-btn v-if="is_owner && canEdit" color="warning" class="mr-2 mb-1" @click="editTupleDialog = true"> <v-icon left>mdi-pencil</v-icon> Edit </v-btn> - <v-btn v-if="canDelete" :disabled="!token" color="error" class="mr-2 mb-1" @click="deleteItems"> + <v-btn v-if="is_owner && canDelete" color="error" class="mr-2 mb-1" @click="deleteItems"> <v-icon left>mdi-delete</v-icon> Delete<span v-if="selection.length > 1"> {{ selection.length }}</span> </v-btn> <v-btn :disabled="!token" :to="`/container/${$route.params.container_id}/database/${$route.params.database_id}/query/create?tid=${$route.params.table_id}`" color="secondary" class="mr-2 mb-1" @click="deleteItems"> @@ -66,7 +66,7 @@ :options.sync="options" :server-items-length="total" :footer-props="footerProps"> - <template v-if="token" v-slot:item.selection="{ item }"> + <template v-if="is_owner" v-slot:item.selection="{ item }"> <input v-model="selection" type="checkbox" :value="item" @click="edit = true"> </template> </v-data-table> @@ -106,6 +106,9 @@ export default { pickVersionDialog: null, version: null, edit: false, + user: { + username: null + }, error: false, // XXX: `error` is never changed options: { page: 1, @@ -115,7 +118,10 @@ export default { table: { name: null, description: null, - columns: [] + columns: [], + creator: { + username: null + } }, items: [ { text: 'Databases', to: '/container', activeClass: '' }, @@ -166,6 +172,9 @@ export default { }, canDelete () { return this.selection.length !== 0 + }, + is_owner () { + return this.token && this.table.creator.username === this.user.username } }, watch: { @@ -180,6 +189,7 @@ export default { mounted () { this.loadProperties() this.loadData() + this.loadUser() }, methods: { async download () { @@ -255,7 +265,8 @@ export default { try { const res = await this.$axios.get(`/api/container/${this.$route.params.container_id}/database/${this.$route.params.database_id}/table/${this.$route.params.table_id}`, this.config) this.table = res.data - console.debug('headers', res.data.columns, 'table', this.table) + console.debug('headers', res.data.columns) + console.debug('table', this.table) this.headers = [{ value: 'selection', text: '', sortable: false }] res.data.columns.map((c) => { return { @@ -301,6 +312,16 @@ export default { this.$toast.error('Could not load table data.') } this.loadingData = false + }, + async loadUser () { + try { + const res = await this.$axios.put('/api/auth', {}, this.config) + this.user = res.data + console.debug('user', this.user) + } catch (err) { + this.$toast.error('Failed to get user details') + console.error('Failed to get user details', err) + } } } } diff --git a/fda-ui/pages/container/index.vue b/fda-ui/pages/container/index.vue index c4eabf788c745cb6342aed107d8029887e86bd57..7ef5bd92806eab9ac7c0a83adf60070aac201d03 100644 --- a/fda-ui/pages/container/index.vue +++ b/fda-ui/pages/container/index.vue @@ -48,8 +48,8 @@ </sup> </td> <td> - <v-icon v-if="!item.is_public" color="primary" class="private-icon" right>mdi-lock-outline</v-icon> - <v-icon v-if="item.is_public" class="private-icon" right>mdi-lock-open-outline</v-icon> + <v-icon v-if="!item.is_public" color="primary" title="Private" class="private-icon" right>mdi-lock-outline</v-icon> + <v-icon v-if="item.is_public" class="private-icon" title="Public" right>mdi-lock-open-outline</v-icon> </td> <td> {{ createdUTC(item.created) }} diff --git a/fda-units-service/app.py b/fda-units-service/app.py index 8e88836b92f12e3185d54d63526d4916bef2cebb..85fbc5ae8c31634b1132c82fa8ebe6b21c57db13 100644 --- a/fda-units-service/app.py +++ b/fda-units-service/app.py @@ -104,7 +104,7 @@ def saveconcept(): logging.info(f"Inserted values {uri}, {c_name} into mdb_concepts.") return jsonify({'uri': uri}), 201 else: - return jsonify({'status': 'error'}), 400 + return jsonify({'status': 'error'}), 409 except Exception as e: logging.error(e) res = {"success": False, "message": str(e)} @@ -123,7 +123,7 @@ def savecolumnconcept(): logging.info(f"Inserted values {uri},{cid},{tid},{cdbid} into mdb_columns_concepts.") return jsonify({'uri': uri}), 201 else: - return jsonify({'status': 'error'}), 400 + return jsonify({'status': 'error'}), 409 except Exception as e: print(e) res = {"success": False, "message": str(e)} diff --git a/fda-units-service/us-yml/savecolumnsconcept.yml b/fda-units-service/us-yml/savecolumnsconcept.yml index ec662c1a3c5871956887fbf7fba7e530609304bd..b391fd4f77c1819565dc8cd6ae533cc566c38b9b 100644 --- a/fda-units-service/us-yml/savecolumnsconcept.yml +++ b/fda-units-service/us-yml/savecolumnsconcept.yml @@ -27,5 +27,10 @@ parameters: responses: 200: description: "OK" + 201: + description: "Created" 405: description: "Invalid input" + 409: + description: "Concept already assigned" + diff --git a/fda-units-service/us-yml/saveconcept.yml b/fda-units-service/us-yml/saveconcept.yml index 22144651f10048e2c2b8b440ce888735764f19ea..509b71efb4c2798c2baa8e68b1a6750e41fdc330 100644 --- a/fda-units-service/us-yml/saveconcept.yml +++ b/fda-units-service/us-yml/saveconcept.yml @@ -19,7 +19,11 @@ parameters: type: "string" example: "metre" responses: - 200: + 200: description: "OK" + 201: + description: "Created" 405: description: "Invalid input" + 409: + description: "Concept already present"