diff --git a/.jupyter/api_authentication/__init__.py b/.jupyter/api_authentication/__init__.py index 2c48db22770b0ebd34d7872a2dc7cd1416837ec2..1caebb3b03385e64cd4896ea7b633296e3edd37a 100644 --- a/.jupyter/api_authentication/__init__.py +++ b/.jupyter/api_authentication/__init__.py @@ -43,4 +43,5 @@ from api_authentication.models.user_forgot_dto import UserForgotDto from api_authentication.models.user_password_dto import UserPasswordDto from api_authentication.models.user_reset_dto import UserResetDto from api_authentication.models.user_roles_dto import UserRolesDto +from api_authentication.models.user_theme_set_dto import UserThemeSetDto from api_authentication.models.user_update_dto import UserUpdateDto diff --git a/.jupyter/api_authentication/api/user_endpoint_api.py b/.jupyter/api_authentication/api/user_endpoint_api.py index 91343f15a8384bb3dffbbb29f01fb7fa93e51591..40ba9632a02912ec9fd5d6167d27b8b14ebe7760 100644 --- a/.jupyter/api_authentication/api/user_endpoint_api.py +++ b/.jupyter/api_authentication/api/user_endpoint_api.py @@ -920,3 +920,108 @@ class UserEndpointApi(object): _preload_content=params.get('_preload_content', True), _request_timeout=params.get('_request_timeout'), collection_formats=collection_formats) + + def update_theme(self, body, id, **kwargs): # noqa: E501 + """Update user theme # 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_theme(body, id, async_req=True) + >>> result = thread.get() + + :param async_req bool + :param UserThemeSetDto body: (required) + :param int 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_theme_with_http_info(body, id, **kwargs) # noqa: E501 + else: + (data) = self.update_theme_with_http_info(body, id, **kwargs) # noqa: E501 + return data + + def update_theme_with_http_info(self, body, id, **kwargs): # noqa: E501 + """Update user theme # 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_theme_with_http_info(body, id, async_req=True) + >>> result = thread.get() + + :param async_req bool + :param UserThemeSetDto body: (required) + :param int id: (required) + :return: None + If the method is called asynchronously, + returns the request thread. + """ + + all_params = ['body', '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_theme" % 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_theme`") # 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_theme`") # noqa: E501 + + collection_formats = {} + + path_params = {} + if 'id' in params: + path_params['id'] = params['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/user/{id}/theme', '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_authentication/models/__init__.py b/.jupyter/api_authentication/models/__init__.py index 11e22a17bacc695efc8b6692fac98724d7c4c9a2..0cd55935b61999c415fd3e89ff72c48c4effe5f6 100644 --- a/.jupyter/api_authentication/models/__init__.py +++ b/.jupyter/api_authentication/models/__init__.py @@ -35,4 +35,5 @@ from api_authentication.models.user_forgot_dto import UserForgotDto from api_authentication.models.user_password_dto import UserPasswordDto from api_authentication.models.user_reset_dto import UserResetDto from api_authentication.models.user_roles_dto import UserRolesDto +from api_authentication.models.user_theme_set_dto import UserThemeSetDto from api_authentication.models.user_update_dto import UserUpdateDto diff --git a/.jupyter/api_query/api/table_data_endpoint_api.py b/.jupyter/api_query/api/table_data_endpoint_api.py index 5cfffc839b17b76394c5abd0592da4b8df92e7fd..31b90e9df370ce626ce7767d44cdef26d2f1b7d7 100644 --- a/.jupyter/api_query/api/table_data_endpoint_api.py +++ b/.jupyter/api_query/api/table_data_endpoint_api.py @@ -259,7 +259,7 @@ class TableDataEndpointApi(object): auth_settings = ['bearerAuth'] # 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, @@ -380,7 +380,7 @@ class TableDataEndpointApi(object): auth_settings = ['bearerAuth'] # 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, diff --git a/.jupyter/api_table/__init__.py b/.jupyter/api_table/__init__.py index beaceff5a74771307782fed7d105c64f63e06540..37441edea5b7655b2a5337e45897d5860cd36e48 100644 --- a/.jupyter/api_table/__init__.py +++ b/.jupyter/api_table/__init__.py @@ -24,7 +24,6 @@ from api_table.models.api_error_dto import ApiErrorDto from api_table.models.column_create_dto import ColumnCreateDto from api_table.models.column_dto import ColumnDto from api_table.models.concept_dto import ConceptDto -from api_table.models.granted_authority_dto import GrantedAuthorityDto from api_table.models.image_date_dto import ImageDateDto from api_table.models.table_brief_dto import TableBriefDto from api_table.models.table_create_dto import TableCreateDto diff --git a/.jupyter/api_table/models/__init__.py b/.jupyter/api_table/models/__init__.py index c7a86dfadf16101370f746da857eca3f44cac6a1..65818bef09589a604af11a71cac062d8ca9b09de 100644 --- a/.jupyter/api_table/models/__init__.py +++ b/.jupyter/api_table/models/__init__.py @@ -18,7 +18,6 @@ from api_table.models.api_error_dto import ApiErrorDto from api_table.models.column_create_dto import ColumnCreateDto from api_table.models.column_dto import ColumnDto from api_table.models.concept_dto import ConceptDto -from api_table.models.granted_authority_dto import GrantedAuthorityDto from api_table.models.image_date_dto import ImageDateDto from api_table.models.table_brief_dto import TableBriefDto from api_table.models.table_create_dto import TableCreateDto diff --git a/.jupyter/load_test.py b/.jupyter/load_test.py new file mode 100644 index 0000000000000000000000000000000000000000..4f395a950b82a9bde1010cb4c6a4a4c7672aa248 --- /dev/null +++ b/.jupyter/load_test.py @@ -0,0 +1,273 @@ +#!/bin/env python3 + +import time +import os +import shutil +import uuid +import sys + +import api_query.rest +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 +from api_table.api.table_endpoint_api import TableEndpointApi +from api_query.api.table_data_endpoint_api import TableDataEndpointApi +from api_query.api.query_endpoint_api import QueryEndpointApi +from api_identifier.api.identifier_endpoint_api import IdentifierEndpointApi +from api_identifier.api.persistence_endpoint_api import PersistenceEndpointApi + +authentication = AuthenticationEndpointApi() +user = UserEndpointApi() +container = ContainerEndpointApi() +database = ContainerDatabaseEndpointApi() +table = TableEndpointApi() +query = QueryEndpointApi() +data = TableDataEndpointApi() +identifier = IdentifierEndpointApi() +persistence = PersistenceEndpointApi() + +token = "" + + +def create_user(username): + response = user.register({ + "username": username, + "password": username, + "email": username + "@gmail.com" + }) + print("created user") + return response + + +def auth_user(username): + response = authentication.authenticate_user1({ + "username": username, + "password": username + }) + print("authenticated user") + token = response.token + container.api_client.default_headers = {"Authorization": "Bearer " + token} + database.api_client.default_headers = {"Authorization": "Bearer " + token} + table.api_client.default_headers = {"Authorization": "Bearer " + token} + data.api_client.default_headers = {"Authorization": "Bearer " + token} + query.api_client.default_headers = {"Authorization": "Bearer " + token} + identifier.api_client.default_headers = {"Authorization": "Bearer " + token} + user.api_client.default_headers = {"Authorization": "Bearer " + token} + persistence.api_client.default_headers = {"Authorization": "Bearer " + token} + return response + + +def create_container(): + response = container.create1({ + "name": "Airquality " + str(uuid.uuid1()), + "repository": "mariadb", + "tag": "10.5" + }) + print("created container") + return response + + +def start_container(container_id): + response = container.modify({ + "action": "start" + }, container_id) + time.sleep(5) + print("started container") + return response + + +def create_database(container_id, is_public=True): + response = database.create({ + "name": "Airquality " + str(uuid.uuid1()), + "description": "Hourly measurements in Zürich, Switzerland", + "is_public": is_public + }, container_id) + print("created database") + return response + + +def update_database(container_id, database_id, is_public=True): + response = database.update({ + "description": "This dataset includes daily values from 1983 to the current day, divided into annual files. This includes the maximum hourly average and the number of times the hourly average limit value for ozone was exceeded and the daily averages for sulfur dioxide (SO2), carbon monoxide (CO), nitrogen oxide (NOx), nitrogen monoxide (NO), nitrogen dioxide (NO2), particulate matter (PM10 and PM2.5). ) and particle number (PN), provided that they are of sufficient quality. The values of the completed day for the current year are updated every 30 minutes after midnight (UTC+1).", + "publisher": "Technical University of Vienna", + "license": { + "identifier": "CC0-1.0", + "uri": "https://creativecommons.org/publicdomain/zero/1.0/legalcode" + }, + "language": "en", + "is_public": is_public, + "publication": "2022-07-19" + }, container_id, database_id) + print("updated database") + return response + + +def create_table(container_id, database_id, columns=None): + if columns is None: + columns = [{ + "name": "Date", + "type": "date", + "dfid": 1, + "unique": False, + "primary_key": False, + "null_allowed": True, + }, { + "name": "Location", + "type": "string", + "unique": False, + "primary_key": False, + "null_allowed": True, + }, { + "name": "Parameter", + "type": "string", + "unique": False, + "primary_key": False, + "null_allowed": True, + }, { + "name": "Interval", + "type": "string", + "unique": False, + "primary_key": False, + "null_allowed": True, + }, { + "name": "Unit", + "type": "string", + "unique": False, + "primary_key": False, + "null_allowed": True, + }, { + "name": "Value", + "type": "decimal", + "unique": False, + "primary_key": False, + "null_allowed": True, + }, { + "name": "Status", + "type": "string", + "unique": False, + "primary_key": False, + "null_allowed": True, + }] + response = table.create({ + "name": "Airquality " + str(uuid.uuid1()), + "description": "Airquality in Zürich, Switzerland", + "columns": columns + }, container_id, database_id) + print("created table") + return response + + +def find_table(container_id, database_id, table_id): + response = table.find_by_id(container_id, database_id, table_id) + print("found table") + return response + + +def fill_table(container_id, database_id, table_id): + shutil.copyfile(os.getcwd() + "/resources/ugz_ogd_air_h1_2021.csv", "/tmp/ugz_ogd_air_h1_2021.csv") + response = data.import_csv({ + "location": "/tmp/ugz_ogd_air_h1_2021.csv", + "separator": ",", + "quote": "\"", + "skip_lines": 1 + }, container_id, database_id, table_id) + print("filled table") + return response + + +def create_query(container_id, database_id, statement, page=0, size=3): + try: + response = query.execute({ + "statement": statement + }, container_id, database_id, page=page, size=size) + print("executed query") + return response + except api_query.rest.ApiException as e: + print(e) + + +def create_identifier(container_id, database_id, query_id, visibility="everyone"): + response = identifier.create({ + "qid": query_id, + "title": "Airquality", + "description": "Subset used for a scientific article", + "visibility": visibility, + "creators": [{ + "name": "Weise, Martin", + "affiliation": "TU Wien", + "orcid": "0000-0003-4216-302X" + }, { + "name": "Rauber, Andreas", + "affiliation": "TU Wien", + "orcid": "0000-0002-9272-6225" + }], + "publication": "2022-07-16", + "related_identifiers": [{ + "value": "http://localhost:3000/container/" + str(container_id) + "/database/" + str(database_id), + "type": "URL", + "relation": "IsCitedBy" + }] + }, token, container_id, database_id) + print("created identifier") + return response + + +if __name__ == '__main__': + # + # create 1 user and 3 containers (public, private, public) + # + create_user("test1") + auth_user("test1") + # container 1 + cid = create_container().id + start_container(cid) + dbid = create_database(cid).id + update_database(cid, dbid) + tid = create_table(cid, dbid).id + tname = find_table(cid, dbid, tid).internal_name + fill_table(cid, dbid, tid) + create_query(cid, dbid, "select `id` from `" + tname + "`") + create_query(cid, dbid, "select `date` from `" + tname + "`") + qid = create_query(cid, dbid, "select `date`, `location`, `status` from `" + tname + "`").id + create_query(cid, dbid, "select `foo` from `" + tname + "`") + create_identifier(cid, dbid, qid) + # container 2 (=private) + cid = create_container().id + start_container(cid) + dbid = create_database(cid, False).id + update_database(cid, dbid, is_public=False) + tid = create_table(cid, dbid).id + tname = find_table(cid, dbid, tid).internal_name + fill_table(cid, dbid, tid) + qid = create_query(cid, dbid, "select `id` from `" + tname + "`").id + create_identifier(cid, dbid, qid, visibility="self") + qid = create_query(cid, dbid, "select `id` from `" + tname + "`").id + create_identifier(cid, dbid, qid) + # container 3 with 3 tables + cid = create_container().id + start_container(cid) + dbid = create_database(cid).id + update_database(cid, dbid) + create_table(cid, dbid, columns=[]) + create_table(cid, dbid, columns=[{ + "name": "primary", + "type": "string", + "unique": True, + "primary_key": True, + "null_allowed": False, + }]) + create_table(cid, dbid, columns=[{ + "name": "primary", + "type": "number", + "unique": True, + "primary_key": True, + "null_allowed": False, + }]) + create_table(cid, dbid, columns=[{ + "name": "primary", + "type": "date", + "unique": True, + "primary_key": True, + "null_allowed": False, + }]) diff --git a/.jupyter/test.ipynb b/.jupyter/test.ipynb deleted file mode 100644 index 7c276b67efa8dde9fe2e055e7b7b669244e8a5f8..0000000000000000000000000000000000000000 --- a/.jupyter/test.ipynb +++ /dev/null @@ -1,1013 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "# Test Jupyter Notebook" - ] - }, - { - "cell_type": "code", - "execution_count": 113, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [], - "source": [ - "import time\n", - "import os\n", - "import shutil\n", - "import uuid\n", - "\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", - "from api_query.api.table_data_endpoint_api import TableDataEndpointApi\n", - "from api_query.api.query_endpoint_api import QueryEndpointApi\n", - "from api_identifier.api.identifier_endpoint_api import IdentifierEndpointApi\n", - "from api_identifier.api.persistence_endpoint_api import PersistenceEndpointApi\n", - "\n", - "authentication = AuthenticationEndpointApi()\n", - "user = UserEndpointApi()\n", - "container = ContainerEndpointApi()\n", - "database = ContainerDatabaseEndpointApi()\n", - "table = TableEndpointApi()\n", - "query = QueryEndpointApi()\n", - "data = TableDataEndpointApi()\n", - "identifier = IdentifierEndpointApi()\n", - "persistence = PersistenceEndpointApi()\n", - "\n", - "username = \"user\"\n", - "password = \"user\"\n", - "email = \"someone@example.com\"" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "pycharm": { - "name": "#%% md\n" - } - }, - "source": [ - "Create user" - ] - }, - { - "cell_type": "code", - "execution_count": 114, - "metadata": { - "pycharm": { - "name": "#%%\n" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'affiliation': None,\n", - " 'authorities': [{'authority': 'ROLE_RESEARCHER'}],\n", - " 'containers': None,\n", - " 'databases': None,\n", - " 'email': 'someone@example.com',\n", - " 'email_verified': False,\n", - " 'firstname': None,\n", - " 'id': 2,\n", - " 'identifiers': None,\n", - " 'lastname': None,\n", - " 'orcid': None,\n", - " 'theme_dark': False,\n", - " 'titles_after': None,\n", - " 'titles_before': None,\n", - " 'username': 'user'}\n" - ] - } - ], - "source": [ - "response = user.register({\n", - " \"username\": username,\n", - " \"password\": password,\n", - " \"email\": email\n", - "})\n", - "print(response)" - ] - }, - { - "cell_type": "markdown", - "source": [ - "Create token" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%% md\n" - } - } - }, - { - "cell_type": "code", - "execution_count": 115, - "outputs": [], - "source": [ - "response = authentication.authenticate_user1({\n", - " \"username\": username,\n", - " \"password\": password\n", - "})\n", - "user_id = response.id\n", - "token = response.token\n", - "container.api_client.default_headers = {\"Authorization\": \"Bearer \" + token}\n", - "database.api_client.default_headers = {\"Authorization\": \"Bearer \" + token}\n", - "table.api_client.default_headers = {\"Authorization\": \"Bearer \" + token}\n", - "data.api_client.default_headers = {\"Authorization\": \"Bearer \" + token}\n", - "query.api_client.default_headers = {\"Authorization\": \"Bearer \" + token}\n", - "identifier.api_client.default_headers = {\"Authorization\": \"Bearer \" + token}\n", - "user.api_client.default_headers = {\"Authorization\": \"Bearer \" + token}\n", - "persistence.api_client.default_headers = {\"Authorization\": \"Bearer \" + token}" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } - }, - { - "cell_type": "markdown", - "source": [ - "Create container" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%% md\n" - } - } - }, - { - "cell_type": "code", - "execution_count": 116, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'created': datetime.datetime(2022, 7, 26, 13, 5, 36, 339000, tzinfo=tzutc()),\n", - " 'creator': {'affiliation': None,\n", - " 'authorities': None,\n", - " 'email': 'someone@example.com',\n", - " 'email_verified': False,\n", - " 'firstname': None,\n", - " 'id': 2,\n", - " 'lastname': None,\n", - " 'orcid': None,\n", - " 'theme_dark': False,\n", - " 'titles_after': None,\n", - " 'titles_before': None,\n", - " 'username': 'user'},\n", - " 'hash': '5dc114629602472d0bb93f4aedd6a38f161dd59ed129247511c83767fcba0a19',\n", - " 'id': 1,\n", - " 'internal_name': 'fda-userdb-airquality',\n", - " 'is_public': None,\n", - " 'name': 'Airquality'}\n" - ] - } - ], - "source": [ - "response = container.create1({\n", - " \"name\": \"Airquality\",\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": [ - "Start container" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%% md\n" - } - } - }, - { - "cell_type": "code", - "execution_count": 117, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'created': datetime.datetime(2022, 7, 26, 13, 5, 36, 339000, tzinfo=tzutc()),\n", - " 'creator': {'affiliation': None,\n", - " 'authorities': None,\n", - " 'email': 'someone@example.com',\n", - " 'email_verified': False,\n", - " 'firstname': None,\n", - " 'id': 2,\n", - " 'lastname': None,\n", - " 'orcid': None,\n", - " 'theme_dark': False,\n", - " 'titles_after': None,\n", - " 'titles_before': None,\n", - " 'username': 'user'},\n", - " 'hash': '5dc114629602472d0bb93f4aedd6a38f161dd59ed129247511c83767fcba0a19',\n", - " 'id': 1,\n", - " 'internal_name': 'fda-userdb-airquality',\n", - " 'is_public': None,\n", - " 'name': 'Airquality'}\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": [ - "Create database" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%% md\n" - } - } - }, - { - "cell_type": "code", - "execution_count": 118, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'container': {'created': datetime.datetime(2022, 7, 26, 13, 5, 36, 339000, tzinfo=tzutc()),\n", - " 'creator': {'affiliation': None,\n", - " 'authorities': None,\n", - " 'email': 'someone@example.com',\n", - " 'email_verified': False,\n", - " 'firstname': None,\n", - " 'id': 2,\n", - " 'lastname': None,\n", - " 'orcid': None,\n", - " 'theme_dark': False,\n", - " 'titles_after': None,\n", - " 'titles_before': None,\n", - " 'username': 'user'},\n", - " 'hash': '5dc114629602472d0bb93f4aedd6a38f161dd59ed129247511c83767fcba0a19',\n", - " 'id': 1,\n", - " 'internal_name': 'fda-userdb-airquality',\n", - " 'is_public': None,\n", - " 'name': 'Airquality'},\n", - " 'created': datetime.datetime(2022, 7, 26, 13, 5, 42, 453000, tzinfo=tzutc()),\n", - " 'creator': {'affiliation': None,\n", - " 'authorities': None,\n", - " 'email': 'someone@example.com',\n", - " 'email_verified': False,\n", - " 'firstname': None,\n", - " 'id': 2,\n", - " 'lastname': None,\n", - " 'orcid': None,\n", - " 'theme_dark': False,\n", - " 'titles_after': None,\n", - " 'titles_before': None,\n", - " 'username': 'user'},\n", - " 'description': 'Hourly measurements in Zürich, Switzerland',\n", - " 'engine': 'mariadb:10.5',\n", - " 'id': 1,\n", - " 'is_public': True,\n", - " 'name': 'Airquality'}\n" - ] - } - ], - "source": [ - "response = database.create({\n", - " \"name\": \"Airquality\",\n", - " \"description\": \"Hourly measurements in Zürich, Switzerland\",\n", - " \"is_public\": True\n", - "}, container_id)\n", - "database_id = response.id\n", - "print(response)" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } - }, - { - "cell_type": "markdown", - "source": [ - "Inspect database" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%% md\n" - } - } - }, - { - "cell_type": "code", - "execution_count": 119, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'contact': None,\n", - " 'container': {'created': datetime.datetime(2022, 7, 26, 13, 5, 36, 339000, tzinfo=tzutc()),\n", - " 'databases': None,\n", - " 'hash': '5dc114629602472d0bb93f4aedd6a38f161dd59ed129247511c83767fcba0a19',\n", - " 'id': 1,\n", - " 'image': {'id': 1, 'repository': 'mariadb', 'tag': '10.5'},\n", - " 'internal_name': 'fda-userdb-airquality',\n", - " 'ip_address': None,\n", - " 'is_public': None,\n", - " 'name': 'Airquality',\n", - " 'port': 35358,\n", - " 'state': None},\n", - " 'created': datetime.datetime(2022, 7, 26, 13, 5, 42, 453000, tzinfo=tzutc()),\n", - " 'creator': {'affiliation': None,\n", - " 'authorities': None,\n", - " 'containers': None,\n", - " 'databases': None,\n", - " 'email': 'someone@example.com',\n", - " 'email_verified': False,\n", - " 'firstname': None,\n", - " 'id': 2,\n", - " 'identifiers': None,\n", - " 'lastname': None,\n", - " 'orcid': None,\n", - " 'theme_dark': False,\n", - " 'titles_after': None,\n", - " 'titles_before': None,\n", - " 'username': 'user'},\n", - " 'deleted': None,\n", - " 'description': 'Hourly measurements in Zürich, Switzerland',\n", - " 'exchange': 'airquality',\n", - " 'id': 1,\n", - " 'image': {'compiled': None,\n", - " 'date_formats': [{'created_at': datetime.datetime(2022, 7, 26, 13, 1, 15, 747000, tzinfo=tzutc()),\n", - " 'database_format': '%Y-%c-%d',\n", - " 'example': '2022-01-30',\n", - " 'has_time': False,\n", - " 'id': 1,\n", - " 'unix_format': 'yyyy-MM-dd'},\n", - " {'created_at': datetime.datetime(2022, 7, 26, 13, 1, 15, 753000, tzinfo=tzutc()),\n", - " 'database_format': '%d.%c.%Y',\n", - " 'example': '30.01.2022',\n", - " 'has_time': False,\n", - " 'id': 2,\n", - " 'unix_format': 'yyyy-MM-dd'},\n", - " {'created_at': datetime.datetime(2022, 7, 26, 13, 1, 15, 756000, tzinfo=tzutc()),\n", - " 'database_format': '%d.%c.%y',\n", - " 'example': '30.01.22',\n", - " 'has_time': False,\n", - " 'id': 3,\n", - " 'unix_format': 'yyyy-MM-dd'},\n", - " {'created_at': datetime.datetime(2022, 7, 26, 13, 1, 15, 759000, tzinfo=tzutc()),\n", - " 'database_format': '%c/%d/%Y',\n", - " 'example': '01/30/2022',\n", - " 'has_time': False,\n", - " 'id': 4,\n", - " 'unix_format': 'yyyy-MM-dd'},\n", - " {'created_at': datetime.datetime(2022, 7, 26, 13, 1, 15, 762000, tzinfo=tzutc()),\n", - " 'database_format': '%c/%d/%y',\n", - " 'example': '01/30/22',\n", - " 'has_time': False,\n", - " 'id': 5,\n", - " 'unix_format': 'yyyy-MM-dd'},\n", - " {'created_at': datetime.datetime(2022, 7, 26, 13, 1, 15, 765000, tzinfo=tzutc()),\n", - " 'database_format': '%Y-%c-%d %H:%i:%S.%f',\n", - " 'example': '2022-01-30 13:44:25.0',\n", - " 'has_time': True,\n", - " 'id': 6,\n", - " 'unix_format': 'yyyy-MM-dd HH:mm:ss.SSSSSS'},\n", - " {'created_at': datetime.datetime(2022, 7, 26, 13, 1, 15, 767000, tzinfo=tzutc()),\n", - " 'database_format': '%Y-%c-%d %H:%i:%S',\n", - " 'example': '2022-01-30 13:44:25',\n", - " 'has_time': True,\n", - " 'id': 7,\n", - " 'unix_format': 'yyyy-MM-dd HH:mm:ss'},\n", - " {'created_at': datetime.datetime(2022, 7, 26, 13, 1, 15, 770000, tzinfo=tzutc()),\n", - " 'database_format': '%d.%c.%Y %H:%i:%S',\n", - " 'example': '30.01.2022 13:44:25',\n", - " 'has_time': True,\n", - " 'id': 8,\n", - " 'unix_format': 'dd.MM.yyyy HH:mm:ss'}],\n", - " 'default_port': 3306,\n", - " 'dialect': 'org.hibernate.dialect.MariaDBDialect',\n", - " 'driver_class': 'org.mariadb.jdbc.Driver',\n", - " 'environment': [{'iid': 1,\n", - " 'key': 'ROOT',\n", - " 'type': 'PRIVILEGED_USERNAME',\n", - " 'value': 'root'},\n", - " {'iid': 1,\n", - " 'key': 'MARIADB_ROOT_PASSWORD',\n", - " 'type': 'PRIVILEGED_PASSWORD',\n", - " 'value': 'mariadb'},\n", - " {'iid': 1,\n", - " 'key': 'MARIADB_USER',\n", - " 'type': 'USERNAME',\n", - " 'value': 'mariadb'},\n", - " {'iid': 1,\n", - " 'key': 'MARIADB_PASSWORD',\n", - " 'type': 'PASSWORD',\n", - " 'value': 'mariadb'}],\n", - " 'hash': None,\n", - " 'id': 1,\n", - " 'jdbc_method': 'mariadb',\n", - " 'repository': 'mariadb',\n", - " 'size': None,\n", - " 'tag': '10.5'},\n", - " 'internal_name': 'airquality',\n", - " 'is_public': True,\n", - " 'language': None,\n", - " 'license': None,\n", - " 'name': 'Airquality',\n", - " 'publication': None,\n", - " 'publisher': None,\n", - " 'subjects': [],\n", - " 'tables': []}\n" - ] - } - ], - "source": [ - "response = database.find_by_id(container_id, database_id)\n", - "database_exchange = response.exchange\n", - "print(response)" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } - }, - { - "cell_type": "markdown", - "source": [ - "Add metadata to database" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%% md\n" - } - } - }, - { - "cell_type": "code", - "execution_count": 120, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'container': {'created': datetime.datetime(2022, 7, 26, 13, 5, 36, 339000, tzinfo=tzutc()),\n", - " 'creator': {'affiliation': None,\n", - " 'authorities': None,\n", - " 'email': 'someone@example.com',\n", - " 'email_verified': False,\n", - " 'firstname': None,\n", - " 'id': 2,\n", - " 'lastname': None,\n", - " 'orcid': None,\n", - " 'theme_dark': False,\n", - " 'titles_after': None,\n", - " 'titles_before': None,\n", - " 'username': 'user'},\n", - " 'hash': '5dc114629602472d0bb93f4aedd6a38f161dd59ed129247511c83767fcba0a19',\n", - " 'id': 1,\n", - " 'internal_name': 'fda-userdb-airquality',\n", - " 'is_public': None,\n", - " 'name': 'Airquality'},\n", - " 'created': datetime.datetime(2022, 7, 26, 13, 5, 42, 453000, tzinfo=tzutc()),\n", - " 'creator': {'affiliation': None,\n", - " 'authorities': None,\n", - " 'email': 'someone@example.com',\n", - " 'email_verified': False,\n", - " 'firstname': None,\n", - " 'id': 2,\n", - " 'lastname': None,\n", - " 'orcid': None,\n", - " 'theme_dark': False,\n", - " 'titles_after': None,\n", - " 'titles_before': None,\n", - " 'username': 'user'},\n", - " 'description': 'This dataset includes daily values from 1983 to the current '\n", - " 'day, divided into annual files. This includes the maximum '\n", - " 'hourly average and the number of times the hourly average '\n", - " 'limit value for ozone was exceeded and the daily averages for '\n", - " 'sulfur dioxide (SO2), carbon monoxide (CO), nitrogen oxide '\n", - " '(NOx), nitrogen monoxide (NO), nitrogen dioxide (NO2), '\n", - " 'particulate matter (PM10 and PM2.5). ) and particle number '\n", - " '(PN), provided that they are of sufficient quality. The '\n", - " 'values of the completed day for the current year are updated '\n", - " 'every 30 minutes after midnight (UTC+1).',\n", - " 'engine': 'mariadb:10.5',\n", - " 'id': 1,\n", - " 'is_public': True,\n", - " 'name': 'Airquality'}\n" - ] - } - ], - "source": [ - "response = database.update({\n", - " \"description\": \"This dataset includes daily values from 1983 to the current day, divided into annual files. This includes the maximum hourly average and the number of times the hourly average limit value for ozone was exceeded and the daily averages for sulfur dioxide (SO2), carbon monoxide (CO), nitrogen oxide (NOx), nitrogen monoxide (NO), nitrogen dioxide (NO2), particulate matter (PM10 and PM2.5). ) and particle number (PN), provided that they are of sufficient quality. The values of the completed day for the current year are updated every 30 minutes after midnight (UTC+1).\",\n", - " \"publisher\": \"Technical University of Vienna\",\n", - " \"license\": {\n", - " \"identifier\": \"CC0-1.0\",\n", - " \"uri\": \"https://creativecommons.org/publicdomain/zero/1.0/legalcode\"\n", - " },\n", - " \"language\": \"en\",\n", - " \"is_public\": True,\n", - " \"publication\": \"2022-07-19\"\n", - "}, container_id, database_id)\n", - "print(response)" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } - }, - { - "cell_type": "markdown", - "source": [ - "Create table" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%% md\n" - } - } - }, - { - "cell_type": "code", - "execution_count": 121, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'creator': {'affiliation': None,\n", - " 'authorities': None,\n", - " 'email': 'someone@example.com',\n", - " 'email_verified': False,\n", - " 'firstname': None,\n", - " 'id': 2,\n", - " 'lastname': None,\n", - " 'orcid': None,\n", - " 'theme_dark': False,\n", - " 'titles_after': None,\n", - " 'titles_before': None,\n", - " 'username': 'user'},\n", - " 'id': 1,\n", - " 'internal_name': 'airquality_a7a429a6-0ce3-11ed-9462-8c8caada74c3',\n", - " 'name': 'Airquality a7a429a6-0ce3-11ed-9462-8c8caada74c3'}\n" - ] - } - ], - "source": [ - "response = table.create({\n", - " \"name\": \"Airquality \" + str(uuid.uuid1()),\n", - " \"description\": \"Airquality in Zürich, Switzerland\",\n", - " \"columns\": [{\n", - " \"name\": \"Date\",\n", - " \"type\": \"date\",\n", - " \"dfid\": 1,\n", - " \"unique\": False,\n", - " \"primary_key\": False,\n", - " \"null_allowed\": True,\n", - " }, {\n", - " \"name\": \"Location\",\n", - " \"type\": \"string\",\n", - " \"unique\": False,\n", - " \"primary_key\": False,\n", - " \"null_allowed\": True,\n", - " }, {\n", - " \"name\": \"Parameter\",\n", - " \"type\": \"string\",\n", - " \"unique\": False,\n", - " \"primary_key\": False,\n", - " \"null_allowed\": True,\n", - " }, {\n", - " \"name\": \"Interval\",\n", - " \"type\": \"string\",\n", - " \"unique\": False,\n", - " \"primary_key\": False,\n", - " \"null_allowed\": True,\n", - " }, {\n", - " \"name\": \"Unit\",\n", - " \"type\": \"string\",\n", - " \"unique\": False,\n", - " \"primary_key\": False,\n", - " \"null_allowed\": True,\n", - " }, {\n", - " \"name\": \"Value\",\n", - " \"type\": \"decimal\",\n", - " \"unique\": False,\n", - " \"primary_key\": False,\n", - " \"null_allowed\": True,\n", - " }, {\n", - " \"name\": \"Status\",\n", - " \"type\": \"string\",\n", - " \"unique\": False,\n", - " \"primary_key\": False,\n", - " \"null_allowed\": True,\n", - " }]\n", - "}, container_id, database_id)\n", - "table_id = response.id\n", - "print(response)" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } - }, - { - "cell_type": "markdown", - "source": [ - "Inspect table" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%% md\n" - } - } - }, - { - "cell_type": "code", - "execution_count": 122, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'columns': [{'auto_generated': True,\n", - " 'check_expression': None,\n", - " 'column_concept': None,\n", - " 'column_type': 'number',\n", - " 'date_format': None,\n", - " 'decimal_digits_after': None,\n", - " 'decimal_digits_before': None,\n", - " 'enum_values': [],\n", - " 'foreign_key': None,\n", - " 'id': 1,\n", - " 'internal_name': 'id',\n", - " 'is_null_allowed': False,\n", - " 'is_primary_key': True,\n", - " 'name': 'id',\n", - " 'references': None,\n", - " 'unique': True},\n", - " {'auto_generated': False,\n", - " 'check_expression': None,\n", - " 'column_concept': None,\n", - " 'column_type': 'date',\n", - " 'date_format': {'created_at': datetime.datetime(2022, 7, 26, 13, 1, 15, 747000, tzinfo=tzutc()),\n", - " 'database_format': '%Y-%c-%d',\n", - " 'example': '2022-01-30',\n", - " 'has_time': False,\n", - " 'id': 1,\n", - " 'unix_format': 'yyyy-MM-dd'},\n", - " 'decimal_digits_after': None,\n", - " 'decimal_digits_before': None,\n", - " 'enum_values': [],\n", - " 'foreign_key': None,\n", - " 'id': 2,\n", - " 'internal_name': 'date',\n", - " 'is_null_allowed': True,\n", - " 'is_primary_key': False,\n", - " 'name': 'Date',\n", - " 'references': None,\n", - " 'unique': False},\n", - " {'auto_generated': False,\n", - " 'check_expression': None,\n", - " 'column_concept': None,\n", - " 'column_type': 'string',\n", - " 'date_format': None,\n", - " 'decimal_digits_after': None,\n", - " 'decimal_digits_before': None,\n", - " 'enum_values': [],\n", - " 'foreign_key': None,\n", - " 'id': 3,\n", - " 'internal_name': 'location',\n", - " 'is_null_allowed': True,\n", - " 'is_primary_key': False,\n", - " 'name': 'Location',\n", - " 'references': None,\n", - " 'unique': False},\n", - " {'auto_generated': False,\n", - " 'check_expression': None,\n", - " 'column_concept': None,\n", - " 'column_type': 'string',\n", - " 'date_format': None,\n", - " 'decimal_digits_after': None,\n", - " 'decimal_digits_before': None,\n", - " 'enum_values': [],\n", - " 'foreign_key': None,\n", - " 'id': 4,\n", - " 'internal_name': 'parameter',\n", - " 'is_null_allowed': True,\n", - " 'is_primary_key': False,\n", - " 'name': 'Parameter',\n", - " 'references': None,\n", - " 'unique': False},\n", - " {'auto_generated': False,\n", - " 'check_expression': None,\n", - " 'column_concept': None,\n", - " 'column_type': 'string',\n", - " 'date_format': None,\n", - " 'decimal_digits_after': None,\n", - " 'decimal_digits_before': None,\n", - " 'enum_values': [],\n", - " 'foreign_key': None,\n", - " 'id': 5,\n", - " 'internal_name': 'interval',\n", - " 'is_null_allowed': True,\n", - " 'is_primary_key': False,\n", - " 'name': 'Interval',\n", - " 'references': None,\n", - " 'unique': False},\n", - " {'auto_generated': False,\n", - " 'check_expression': None,\n", - " 'column_concept': None,\n", - " 'column_type': 'string',\n", - " 'date_format': None,\n", - " 'decimal_digits_after': None,\n", - " 'decimal_digits_before': None,\n", - " 'enum_values': [],\n", - " 'foreign_key': None,\n", - " 'id': 6,\n", - " 'internal_name': 'unit',\n", - " 'is_null_allowed': True,\n", - " 'is_primary_key': False,\n", - " 'name': 'Unit',\n", - " 'references': None,\n", - " 'unique': False},\n", - " {'auto_generated': False,\n", - " 'check_expression': None,\n", - " 'column_concept': None,\n", - " 'column_type': 'decimal',\n", - " 'date_format': None,\n", - " 'decimal_digits_after': None,\n", - " 'decimal_digits_before': None,\n", - " 'enum_values': [],\n", - " 'foreign_key': None,\n", - " 'id': 7,\n", - " 'internal_name': 'value',\n", - " 'is_null_allowed': True,\n", - " 'is_primary_key': False,\n", - " 'name': 'Value',\n", - " 'references': None,\n", - " 'unique': False},\n", - " {'auto_generated': False,\n", - " 'check_expression': None,\n", - " 'column_concept': None,\n", - " 'column_type': 'string',\n", - " 'date_format': None,\n", - " 'decimal_digits_after': None,\n", - " 'decimal_digits_before': None,\n", - " 'enum_values': [],\n", - " 'foreign_key': None,\n", - " 'id': 8,\n", - " 'internal_name': 'status',\n", - " 'is_null_allowed': True,\n", - " 'is_primary_key': False,\n", - " 'name': 'Status',\n", - " 'references': None,\n", - " 'unique': False}],\n", - " 'created': datetime.datetime(2022, 7, 26, 13, 5, 43, 660000, tzinfo=tzutc()),\n", - " 'description': 'Airquality in Zürich, Switzerland',\n", - " 'id': 1,\n", - " 'internal_name': 'airquality_a7a429a6-0ce3-11ed-9462-8c8caada74c3',\n", - " 'name': 'Airquality a7a429a6-0ce3-11ed-9462-8c8caada74c3',\n", - " 'topic': 'airquality_a7a429a6-0ce3-11ed-9462-8c8caada74c3'}\n" - ] - } - ], - "source": [ - "response = table.find_by_id(container_id, database_id, table_id)\n", - "table_internal_name = response.internal_name\n", - "table_topic = response.topic\n", - "print(response)" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } - }, - { - "cell_type": "markdown", - "source": [ - "Import .csv" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%% md\n" - } - } - }, - { - "cell_type": "code", - "execution_count": 123, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "None\n" - ] - } - ], - "source": [ - "shutil.copyfile(os.getcwd() + \"/resources/ugz_ogd_air_h1_2021.csv\", \"/tmp/ugz_ogd_air_h1_2021.csv\")\n", - "response = data.import_csv({\n", - " \"location\": \"/tmp/ugz_ogd_air_h1_2021.csv\",\n", - " \"separator\": \",\",\n", - " \"quote\": \"\\\"\",\n", - " \"skip_lines\": 1\n", - "}, container_id, database_id, table_id)\n", - "print(response)" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } - }, - { - "cell_type": "markdown", - "source": [ - "Create subset" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%% md\n" - } - } - }, - { - "cell_type": "code", - "execution_count": 124, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'id': 1,\n", - " 'result': [{'date': '2021-01-01T00:00:00Z',\n", - " 'interval': 'h1',\n", - " 'location': 'Schimmelstrasse',\n", - " 'parameter': 'NOx',\n", - " 'status': 'tentative',\n", - " 'unit': 'ppb',\n", - " 'value': 41.66},\n", - " {'date': '2021-01-01T00:00:00Z',\n", - " 'interval': 'h1',\n", - " 'location': 'Schimmelstrasse',\n", - " 'parameter': 'NO',\n", - " 'status': 'tentative',\n", - " 'unit': 'µg/m3',\n", - " 'value': 21.64},\n", - " {'date': '2021-01-01T00:00:00Z',\n", - " 'interval': 'h1',\n", - " 'location': 'Schimmelstrasse',\n", - " 'parameter': 'NO2',\n", - " 'status': 'tentative',\n", - " 'unit': 'µg/m3',\n", - " 'value': 46.49}],\n", - " 'result_number': 52548}\n" - ] - } - ], - "source": [ - "response = query.execute({\n", - " \"statement\": \"select `date`, `location`, `parameter`, `interval`, `unit`, `value`, `status` from `\" + table_internal_name + \"` where `location` = 'Schimmelstrasse'\"\n", - "}, container_id, database_id, page=0, size=3)\n", - "query_id = response.id\n", - "print(response)" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } - }, - { - "cell_type": "markdown", - "source": [ - "Create invalid subset" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%% md\n" - } - } - }, - { - "cell_type": "code", - "execution_count": 125, - "outputs": [ - { - "ename": "ApiException", - "evalue": "(400)\nReason: Bad Request\nHTTP response headers: HTTPHeaderDict({'transfer-encoding': 'chunked', 'Vary': 'Origin, Access-Control-Request-Method, Access-Control-Request-Headers', 'X-Content-Type-Options': 'nosniff', 'X-XSS-Protection': '1; mode=block', 'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'X-Frame-Options': 'DENY', 'Content-Type': 'application/json', 'Date': 'Tue, 26 Jul 2022 13:05:46 GMT'})\nHTTP response body: b'{\"status\":\"BAD_REQUEST\",\"message\":\"Failed to execute and map time-versioned query\",\"code\":\"error.table.malformed\"}'\n", - "output_type": "error", - "traceback": [ - "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", - "\u001B[0;31mApiException\u001B[0m Traceback (most recent call last)", - "Input \u001B[0;32mIn [125]\u001B[0m, in \u001B[0;36m<cell line: 1>\u001B[0;34m()\u001B[0m\n\u001B[0;32m----> 1\u001B[0m response \u001B[38;5;241m=\u001B[39m \u001B[43mquery\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mexecute\u001B[49m\u001B[43m(\u001B[49m\u001B[43m{\u001B[49m\n\u001B[1;32m 2\u001B[0m \u001B[43m \u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mstatement\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m:\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mselect `date`, `location`, `parameter`, `interval`, `unit`, `value`, `status` from `\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m \u001B[49m\u001B[38;5;241;43m+\u001B[39;49m\u001B[43m \u001B[49m\u001B[43mtable_internal_name\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m+\u001B[39;49m\u001B[43m \u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43m` where `foo` = \u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43mbar\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\n\u001B[1;32m 3\u001B[0m \u001B[43m}\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mcontainer_id\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mdatabase_id\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mpage\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;241;43m0\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43msize\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;241;43m3\u001B[39;49m\u001B[43m)\u001B[49m\n\u001B[1;32m 4\u001B[0m \u001B[38;5;28mprint\u001B[39m(response)\n", - "File \u001B[0;32m~/Projects/fda-services/.jupyter/api_query/api/query_endpoint_api.py:57\u001B[0m, in \u001B[0;36mQueryEndpointApi.execute\u001B[0;34m(self, body, id, database_id, **kwargs)\u001B[0m\n\u001B[1;32m 55\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mexecute_with_http_info(body, \u001B[38;5;28mid\u001B[39m, database_id, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs) \u001B[38;5;66;03m# noqa: E501\u001B[39;00m\n\u001B[1;32m 56\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[0;32m---> 57\u001B[0m (data) \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mexecute_with_http_info\u001B[49m\u001B[43m(\u001B[49m\u001B[43mbody\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;28;43mid\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mdatabase_id\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43mkwargs\u001B[49m\u001B[43m)\u001B[49m \u001B[38;5;66;03m# noqa: E501\u001B[39;00m\n\u001B[1;32m 58\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m data\n", - "File \u001B[0;32m~/Projects/fda-services/.jupyter/api_query/api/query_endpoint_api.py:140\u001B[0m, in \u001B[0;36mQueryEndpointApi.execute_with_http_info\u001B[0;34m(self, body, id, database_id, **kwargs)\u001B[0m\n\u001B[1;32m 137\u001B[0m \u001B[38;5;66;03m# Authentication setting\u001B[39;00m\n\u001B[1;32m 138\u001B[0m auth_settings \u001B[38;5;241m=\u001B[39m [\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mbearerAuth\u001B[39m\u001B[38;5;124m'\u001B[39m] \u001B[38;5;66;03m# noqa: E501\u001B[39;00m\n\u001B[0;32m--> 140\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mapi_client\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcall_api\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 141\u001B[0m \u001B[43m \u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43m/api/container/\u001B[39;49m\u001B[38;5;132;43;01m{id}\u001B[39;49;00m\u001B[38;5;124;43m/database/\u001B[39;49m\u001B[38;5;132;43;01m{databaseId}\u001B[39;49;00m\u001B[38;5;124;43m/query\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43mPUT\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[1;32m 142\u001B[0m \u001B[43m \u001B[49m\u001B[43mpath_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 143\u001B[0m \u001B[43m \u001B[49m\u001B[43mquery_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 144\u001B[0m \u001B[43m \u001B[49m\u001B[43mheader_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 145\u001B[0m \u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mbody_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 146\u001B[0m \u001B[43m \u001B[49m\u001B[43mpost_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mform_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 147\u001B[0m \u001B[43m \u001B[49m\u001B[43mfiles\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mlocal_var_files\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 148\u001B[0m \u001B[43m \u001B[49m\u001B[43mresponse_type\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43mQueryResultDto\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;66;43;03m# noqa: E501\u001B[39;49;00m\n\u001B[1;32m 149\u001B[0m \u001B[43m \u001B[49m\u001B[43mauth_settings\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mauth_settings\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 150\u001B[0m \u001B[43m \u001B[49m\u001B[43masync_req\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mparams\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mget\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43masync_req\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 151\u001B[0m \u001B[43m \u001B[49m\u001B[43m_return_http_data_only\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mparams\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mget\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43m_return_http_data_only\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 152\u001B[0m \u001B[43m \u001B[49m\u001B[43m_preload_content\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mparams\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mget\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43m_preload_content\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;28;43;01mTrue\u001B[39;49;00m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 153\u001B[0m \u001B[43m \u001B[49m\u001B[43m_request_timeout\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mparams\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mget\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43m_request_timeout\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 154\u001B[0m \u001B[43m \u001B[49m\u001B[43mcollection_formats\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mcollection_formats\u001B[49m\u001B[43m)\u001B[49m\n", - "File \u001B[0;32m~/Projects/fda-services/.jupyter/api_query/api_client.py:316\u001B[0m, in \u001B[0;36mApiClient.call_api\u001B[0;34m(self, resource_path, method, path_params, query_params, header_params, body, post_params, files, response_type, auth_settings, async_req, _return_http_data_only, collection_formats, _preload_content, _request_timeout)\u001B[0m\n\u001B[1;32m 279\u001B[0m \u001B[38;5;124;03m\"\"\"Makes the HTTP request (synchronous) and returns deserialized data.\u001B[39;00m\n\u001B[1;32m 280\u001B[0m \n\u001B[1;32m 281\u001B[0m \u001B[38;5;124;03mTo make an async request, set the async_req parameter.\u001B[39;00m\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 313\u001B[0m \u001B[38;5;124;03m then the method will return the response directly.\u001B[39;00m\n\u001B[1;32m 314\u001B[0m \u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[1;32m 315\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m async_req:\n\u001B[0;32m--> 316\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m__call_api\u001B[49m\u001B[43m(\u001B[49m\u001B[43mresource_path\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mmethod\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 317\u001B[0m \u001B[43m \u001B[49m\u001B[43mpath_params\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mquery_params\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mheader_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 318\u001B[0m \u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mpost_params\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mfiles\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 319\u001B[0m \u001B[43m \u001B[49m\u001B[43mresponse_type\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mauth_settings\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 320\u001B[0m \u001B[43m \u001B[49m\u001B[43m_return_http_data_only\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mcollection_formats\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 321\u001B[0m \u001B[43m \u001B[49m\u001B[43m_preload_content\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43m_request_timeout\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 322\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[1;32m 323\u001B[0m thread \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mpool\u001B[38;5;241m.\u001B[39mapply_async(\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m__call_api, (resource_path,\n\u001B[1;32m 324\u001B[0m method, path_params, query_params,\n\u001B[1;32m 325\u001B[0m header_params, body,\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 329\u001B[0m collection_formats,\n\u001B[1;32m 330\u001B[0m _preload_content, _request_timeout))\n", - "File \u001B[0;32m~/Projects/fda-services/.jupyter/api_query/api_client.py:148\u001B[0m, in \u001B[0;36mApiClient.__call_api\u001B[0;34m(self, resource_path, method, path_params, query_params, header_params, body, post_params, files, response_type, auth_settings, _return_http_data_only, collection_formats, _preload_content, _request_timeout)\u001B[0m\n\u001B[1;32m 145\u001B[0m url \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mconfiguration\u001B[38;5;241m.\u001B[39mhost \u001B[38;5;241m+\u001B[39m resource_path\n\u001B[1;32m 147\u001B[0m \u001B[38;5;66;03m# perform request and return response\u001B[39;00m\n\u001B[0;32m--> 148\u001B[0m response_data \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mrequest\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 149\u001B[0m \u001B[43m \u001B[49m\u001B[43mmethod\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mquery_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mquery_params\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mheaders\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mheader_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 150\u001B[0m \u001B[43m \u001B[49m\u001B[43mpost_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mpost_params\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mbody\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 151\u001B[0m \u001B[43m \u001B[49m\u001B[43m_preload_content\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_preload_content\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 152\u001B[0m \u001B[43m \u001B[49m\u001B[43m_request_timeout\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_request_timeout\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 154\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mlast_response \u001B[38;5;241m=\u001B[39m response_data\n\u001B[1;32m 156\u001B[0m return_data \u001B[38;5;241m=\u001B[39m response_data\n", - "File \u001B[0;32m~/Projects/fda-services/.jupyter/api_query/api_client.py:366\u001B[0m, in \u001B[0;36mApiClient.request\u001B[0;34m(self, method, url, query_params, headers, post_params, body, _preload_content, _request_timeout)\u001B[0m\n\u001B[1;32m 358\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mrest_client\u001B[38;5;241m.\u001B[39mPOST(url,\n\u001B[1;32m 359\u001B[0m query_params\u001B[38;5;241m=\u001B[39mquery_params,\n\u001B[1;32m 360\u001B[0m headers\u001B[38;5;241m=\u001B[39mheaders,\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 363\u001B[0m _request_timeout\u001B[38;5;241m=\u001B[39m_request_timeout,\n\u001B[1;32m 364\u001B[0m body\u001B[38;5;241m=\u001B[39mbody)\n\u001B[1;32m 365\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m method \u001B[38;5;241m==\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mPUT\u001B[39m\u001B[38;5;124m\"\u001B[39m:\n\u001B[0;32m--> 366\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mrest_client\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mPUT\u001B[49m\u001B[43m(\u001B[49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 367\u001B[0m \u001B[43m \u001B[49m\u001B[43mquery_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mquery_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 368\u001B[0m \u001B[43m \u001B[49m\u001B[43mheaders\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mheaders\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 369\u001B[0m \u001B[43m \u001B[49m\u001B[43mpost_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mpost_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 370\u001B[0m \u001B[43m \u001B[49m\u001B[43m_preload_content\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_preload_content\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 371\u001B[0m \u001B[43m \u001B[49m\u001B[43m_request_timeout\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_request_timeout\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 372\u001B[0m \u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mbody\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 373\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m method \u001B[38;5;241m==\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mPATCH\u001B[39m\u001B[38;5;124m\"\u001B[39m:\n\u001B[1;32m 374\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mrest_client\u001B[38;5;241m.\u001B[39mPATCH(url,\n\u001B[1;32m 375\u001B[0m query_params\u001B[38;5;241m=\u001B[39mquery_params,\n\u001B[1;32m 376\u001B[0m headers\u001B[38;5;241m=\u001B[39mheaders,\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 379\u001B[0m _request_timeout\u001B[38;5;241m=\u001B[39m_request_timeout,\n\u001B[1;32m 380\u001B[0m body\u001B[38;5;241m=\u001B[39mbody)\n", - "File \u001B[0;32m~/Projects/fda-services/.jupyter/api_query/rest.py:273\u001B[0m, in \u001B[0;36mRESTClientObject.PUT\u001B[0;34m(self, url, headers, query_params, post_params, body, _preload_content, _request_timeout)\u001B[0m\n\u001B[1;32m 271\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mPUT\u001B[39m(\u001B[38;5;28mself\u001B[39m, url, headers\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, query_params\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, post_params\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m,\n\u001B[1;32m 272\u001B[0m body\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, _preload_content\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m, _request_timeout\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m):\n\u001B[0;32m--> 273\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mrequest\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mPUT\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 274\u001B[0m \u001B[43m \u001B[49m\u001B[43mheaders\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mheaders\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 275\u001B[0m \u001B[43m \u001B[49m\u001B[43mquery_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mquery_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 276\u001B[0m \u001B[43m \u001B[49m\u001B[43mpost_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mpost_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 277\u001B[0m \u001B[43m \u001B[49m\u001B[43m_preload_content\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_preload_content\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 278\u001B[0m \u001B[43m \u001B[49m\u001B[43m_request_timeout\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_request_timeout\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 279\u001B[0m \u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mbody\u001B[49m\u001B[43m)\u001B[49m\n", - "File \u001B[0;32m~/Projects/fda-services/.jupyter/api_query/rest.py:222\u001B[0m, in \u001B[0;36mRESTClientObject.request\u001B[0;34m(self, method, url, query_params, headers, body, post_params, _preload_content, _request_timeout)\u001B[0m\n\u001B[1;32m 219\u001B[0m logger\u001B[38;5;241m.\u001B[39mdebug(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mresponse body: \u001B[39m\u001B[38;5;132;01m%s\u001B[39;00m\u001B[38;5;124m\"\u001B[39m, r\u001B[38;5;241m.\u001B[39mdata)\n\u001B[1;32m 221\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;241m200\u001B[39m \u001B[38;5;241m<\u001B[39m\u001B[38;5;241m=\u001B[39m r\u001B[38;5;241m.\u001B[39mstatus \u001B[38;5;241m<\u001B[39m\u001B[38;5;241m=\u001B[39m \u001B[38;5;241m299\u001B[39m:\n\u001B[0;32m--> 222\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m ApiException(http_resp\u001B[38;5;241m=\u001B[39mr)\n\u001B[1;32m 224\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m r\n", - "\u001B[0;31mApiException\u001B[0m: (400)\nReason: Bad Request\nHTTP response headers: HTTPHeaderDict({'transfer-encoding': 'chunked', 'Vary': 'Origin, Access-Control-Request-Method, Access-Control-Request-Headers', 'X-Content-Type-Options': 'nosniff', 'X-XSS-Protection': '1; mode=block', 'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'X-Frame-Options': 'DENY', 'Content-Type': 'application/json', 'Date': 'Tue, 26 Jul 2022 13:05:46 GMT'})\nHTTP response body: b'{\"status\":\"BAD_REQUEST\",\"message\":\"Failed to execute and map time-versioned query\",\"code\":\"error.table.malformed\"}'\n" - ] - } - ], - "source": [ - "response = query.execute({\n", - " \"statement\": \"select `date`, `location`, `parameter`, `interval`, `unit`, `value`, `status` from `\" + table_internal_name + \"` where `foo` = 'bar'\"\n", - "}, container_id, database_id, page=0, size=3)\n", - "print(response)" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.4" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} \ No newline at end of file diff --git a/fda-authentication-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java b/fda-authentication-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java index aa3e3a1cf0c1bb564942a7ddbe6d877ca72f0dae..0ea6bd53e646275bfa3e38c1cde19f7c9bfb3532 100644 --- a/fda-authentication-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java +++ b/fda-authentication-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java @@ -155,6 +155,17 @@ public class UserEndpoint { .body(userMapper.userToUserDto(entity)); } + @PutMapping("/{id}/theme") + @Transactional + @PreAuthorize("hasPermission(#id, 'UPDATE_THEME')") + @Operation(summary = "Update user theme", security = @SecurityRequirement(name = "bearerAuth")) + public ResponseEntity<Void> updateTheme(@NotNull @PathVariable("id") Long id, + @NotNull @Valid @RequestBody UserThemeSetDto data) throws UserNotFoundException { + userService.updateTheme(id, data); + return ResponseEntity.accepted() + .build(); + } + @PutMapping("/{id}/password") @Transactional @PreAuthorize("hasRole('ROLE_DEVELOPER') or hasPermission(#id, 'UPDATE_PASSWORD')") diff --git a/fda-authentication-service/services/src/main/java/at/tuwien/service/UserService.java b/fda-authentication-service/services/src/main/java/at/tuwien/service/UserService.java index d7877d78a2494ffcb6e9274b3dd705299437c9a2..695ff08f25832da78fe5d1e15cd5a5675d647df4 100644 --- a/fda-authentication-service/services/src/main/java/at/tuwien/service/UserService.java +++ b/fda-authentication-service/services/src/main/java/at/tuwien/service/UserService.java @@ -88,6 +88,15 @@ public interface UserService { User updateRoles(Long id, UserRolesDto data) throws UserNotFoundException, RoleNotFoundException, RoleUniqueException; + /** + * Sets the theme for the provided user. + * + * @param id The user id. + * @param data The theme. + * @throws UserNotFoundException The user was not found. + */ + void updateTheme(Long id, UserThemeSetDto data) throws UserNotFoundException; + /** * Updates a user with the given id and updated password. * diff --git a/fda-authentication-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java b/fda-authentication-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java index e508c53cbd3ad921afb8af81567862f114d3581d..4ab0e32aa20abd20574fa5d752336041d9aa02a1 100644 --- a/fda-authentication-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java +++ b/fda-authentication-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java @@ -19,7 +19,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.validation.ConstraintViolationException; -import java.security.Principal; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -212,6 +211,18 @@ public class UserServiceImpl implements UserService { return entity; } + @Override + @Transactional + public void updateTheme(Long id, UserThemeSetDto data) throws UserNotFoundException { + /* check */ + final User user = find(id); + /* save */ + user.setThemeDark(data.getThemeDark()); + final User entity = userRepository.save(user); + log.info("Updated user with id {}", entity.getId()); + log.debug("updated user {}", entity); + } + @Override @Transactional public User updatePassword(Long id, UserPasswordDto data) throws UserNotFoundException { diff --git a/fda-identifier-service/services/src/main/java/at/tuwien/gateway/QueryServiceGateway.java b/fda-identifier-service/services/src/main/java/at/tuwien/gateway/QueryServiceGateway.java index 715611d99b4e860c9c2ad919f5c7157f3098aca6..aadd8f21329f157e70b42f972a578eb7a4ac08cc 100644 --- a/fda-identifier-service/services/src/main/java/at/tuwien/gateway/QueryServiceGateway.java +++ b/fda-identifier-service/services/src/main/java/at/tuwien/gateway/QueryServiceGateway.java @@ -21,6 +21,5 @@ public interface QueryServiceGateway { * @throws RemoteUnavailableException The remote service is not available. */ QueryDto find(Long containerId, Long databaseId, IdentifierCreateDto identifier, String authorization) - throws QueryNotFoundException, - RemoteUnavailableException; + throws QueryNotFoundException, RemoteUnavailableException; } diff --git a/fda-identifier-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java b/fda-identifier-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java index f96736a2e8c772446a74cb099d8e75b17873464f..6058d35080688b094666b947385dd2a986ac3b7d 100644 --- a/fda-identifier-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java +++ b/fda-identifier-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java @@ -126,6 +126,7 @@ public class IdentifierServiceImpl implements IdentifierService { relatedIdentifierRepository.save(id); }); } + entity.setQueryNormalized(query.getQueryNormalized()); final Identifier identifier = identifierRepository.save(entity); log.info("Created identifier with id {}", identifier.getId()); log.debug("created identifier {}", identifier); diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserBriefDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserBriefDto.java index 1b27ee0e2228c2aafb310611f148bfb1d1aa1aa9..464843d2fb8cc14872dda8b624c1a9d3d7aa688f 100644 --- a/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserBriefDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserBriefDto.java @@ -1,12 +1,10 @@ package at.tuwien.api.user; -import com.fasterxml.jackson.annotation.JsonIgnore; 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 @@ -20,10 +18,6 @@ public class UserBriefDto { @Parameter(name = "id") private Long id; - @ToString.Exclude - @Parameter(name = "user authorities") - private List<GrantedAuthorityDto> authorities; - @NotNull @Parameter(name = "user name") private String username; @@ -53,12 +47,4 @@ public class UserBriefDto { @Parameter(name = "theme dark") private Boolean themeDark; - @NotNull - @Parameter(name = "mail address") - private String email; - - @JsonProperty("email_verified") - @Parameter(name = "mail address verified") - private Boolean emailVerified; - } diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserThemeSetDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserThemeSetDto.java new file mode 100644 index 0000000000000000000000000000000000000000..e329522dcd5394a849daae10259ae7b135a180e7 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserThemeSetDto.java @@ -0,0 +1,22 @@ +package at.tuwien.api.user; + +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; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class UserThemeSetDto { + + @NotNull + @JsonProperty("theme_dark") + @Parameter(name = "theme dark") + private Boolean themeDark; +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserUpdateDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserUpdateDto.java index ecff2599956860bb4aad94293e721b207c3c6ad4..e7fb05063f277a21a62fd8bf0a4d11764c34d244 100644 --- a/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserUpdateDto.java +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/user/UserUpdateDto.java @@ -37,9 +37,4 @@ public class UserUpdateDto { @Parameter(name = "orcid") private String orcid; - @NotNull - @JsonProperty("theme_dark") - @Parameter(name = "theme dark") - private Boolean themeDark; - } 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 65a1b63b168d1df492debd2b7f627e4fabe05bb6..d065595722184c2a426faadf375b7cf385b9c9a0 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 @@ -41,7 +41,7 @@ public abstract class AbstractEndpoint { return true; } /* view-only operations are allowed on public databases */ - if (database.getIsPublic() && List.of("DATA_EXPORT", "DATA_VIEW", "DATA_HISTORY").contains(permissionCode)) { + 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; } @@ -76,7 +76,7 @@ public abstract class AbstractEndpoint { return true; } /* view-only operations are allowed on public databases */ - if (database.getIsPublic() && List.of("QUERY_VIEW_ALL", "QUERY_VIEW", "QUERY_EXPORT").contains( + if (database.getIsPublic() && List.of("QUERY_VIEW_ALL", "QUERY_VIEW", "QUERY_EXPORT", "QUERY_RE_EXECUTE").contains( permissionCode)) { log.debug("grant permission {} because database is public", permissionCode); return true; diff --git a/fda-query-service/services/src/main/java/at/tuwien/mapper/StoreMapper.java b/fda-query-service/services/src/main/java/at/tuwien/mapper/StoreMapper.java index 9fdb2e03a6fdaf53685580d72f488d1e49b749fd..783f2242a4c1d88155e273aa5291469005e0fa40 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/mapper/StoreMapper.java +++ b/fda-query-service/services/src/main/java/at/tuwien/mapper/StoreMapper.java @@ -165,6 +165,7 @@ public interface StoreMapper { .lastModified(data.getTimestamp(7) != null ? data.getTimestamp(7) .toInstant() : null) .query(data.getString(8)) + .queryNormalized(data.getString(8)) .queryHash(data.getString(9)) .resultHash(data.getString(10) != null ? data.getString(10) : null) .resultNumber(data.getLong(11)) diff --git a/fda-query-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java b/fda-query-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java index 64dd9d603cc3caef2249c0ab4f2fd7da5c2077c1..159549e16c45ac5ab2a31558014db12060945de5 100644 --- a/fda-query-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java +++ b/fda-query-service/services/src/main/java/at/tuwien/service/impl/QueryServiceImpl.java @@ -177,9 +177,8 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService @Override @Transactional(readOnly = true) public ExportResource findOne(Long containerId, Long databaseId, Long queryId) - throws DatabaseNotFoundException, ImageNotSupportedException, - ContainerNotFoundException, FileStorageException, QueryStoreException, QueryNotFoundException, - QueryMalformedException, DatabaseConnectionException { + throws DatabaseNotFoundException, ImageNotSupportedException, FileStorageException, QueryStoreException, + QueryNotFoundException, QueryMalformedException, DatabaseConnectionException { final String filename = RandomStringUtils.randomAlphabetic(40) + ".csv"; /* find */ final Database database = databaseService.find(containerId, databaseId); @@ -210,8 +209,8 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService @Override @Transactional public Long count(Long containerId, Long databaseId, Long tableId, Instant timestamp) - throws DatabaseNotFoundException, TableNotFoundException, - ImageNotSupportedException, DatabaseConnectionException, QueryMalformedException, QueryStoreException, TableMalformedException { + throws DatabaseNotFoundException, TableNotFoundException, ImageNotSupportedException, + DatabaseConnectionException, QueryMalformedException, QueryStoreException, TableMalformedException { /* find */ final Database database = databaseService.find(containerId, databaseId); final Table table = tableService.find(containerId, databaseId, tableId); @@ -277,7 +276,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService for (int i = 0; i < data.getKeys().size(); i++) { preparedStatement.setObject(i, values.get(i)); } - } catch(SQLException e) { + } catch (SQLException e) { log.error("Failed to delete tuples"); throw new TableMalformedException("Failed to delete tuples"); } finally { @@ -306,7 +305,7 @@ public class QueryServiceImpl extends HibernateConnector implements QueryService .executeUpdate(); queryMapper.dropTemporaryTableSQL(connection, table) .executeUpdate(); - } catch(SQLException e) { + } catch (SQLException e) { log.error("Failed to create/insert/drop temporary table"); throw new TableMalformedException("Failed to create/insert/drop temporary table"); } finally { diff --git a/fda-ui/layouts/default.vue b/fda-ui/layouts/default.vue index 292f620d62a1a2d506d05a386a85d3f797c0b075..132f3ead0c48c307d6a029fe67fabcd2809bae20 100644 --- a/fda-ui/layouts/default.vue +++ b/fda-ui/layouts/default.vue @@ -1,5 +1,5 @@ <template> - <v-app dark> + <v-app> <v-navigation-drawer v-model="drawer" fixed app> <v-img contain @@ -104,6 +104,10 @@ export default { data () { return { drawer: false, + user: { + theme_dark: null + }, + loadingUser: true, items: [ { icon: mdiHome, @@ -157,9 +161,6 @@ export default { username () { return this.$store.state.user && this.$store.state.user.username }, - nextTheme () { - return this.$vuetify.theme.dark ? 'Light' : 'Dark' - }, container () { return this.$store.state.container }, @@ -171,15 +172,29 @@ export default { }, db () { return this.$store.state.db + }, + config () { + if (this.token === null) { + return {} + } + return { + headers: { Authorization: `Bearer ${this.token}` } + } } }, watch: { $route () { this.loadDB() + if (this.token) { + this.loadUser() + .then(() => this.setTheme()) + } } }, mounted () { this.loadDB() + this.loadUser() + .then(() => this.setTheme()) }, methods: { logout () { @@ -197,6 +212,25 @@ export default { console.error('Failed to load database', err) } } + }, + async loadUser () { + if (!this.token) { + return + } + try { + this.loadingUser = true + const res = await this.$axios.put('/api/auth', {}, this.config) + console.debug('user data', res.data) + this.user = res.data + } catch (err) { + console.error('user data', err) + this.$toast.error('Failed to load user') + this.error = true + } + this.loadingUser = false + }, + setTheme () { + this.$vuetify.theme.dark = this.user.theme_dark } } } diff --git a/fda-ui/pages/container/_container_id/database/_database_id/sql.vue b/fda-ui/pages/container/_container_id/database/_database_id/sql.vue deleted file mode 100644 index b11cc07697de23ce1e449cfc8276a5a5c2cbb3f8..0000000000000000000000000000000000000000 --- a/fda-ui/pages/container/_container_id/database/_database_id/sql.vue +++ /dev/null @@ -1,26 +0,0 @@ -<template> - <div> - <h3> - SQL - </h3> - ... - </div> -</template> -<script> - -export default { - name: 'SQL', - components: { - }, - data () { - return {} - }, - mounted () { - }, - methods: { - } -} -</script> - -<style> -</style> diff --git a/fda-ui/pages/container/index.vue b/fda-ui/pages/container/index.vue index ab3e7495d41acd87d006a2245be7cba31cebf512..b855d8dda518eb7c6be34c1f82288add90b58321 100644 --- a/fda-ui/pages/container/index.vue +++ b/fda-ui/pages/container/index.vue @@ -18,6 +18,7 @@ <thead> <tr> <th>Name</th> + <th>Visibility</th> <th>Engine</th> <th>Creator</th> <th>Created</th> @@ -25,7 +26,7 @@ </thead> <tbody> <tr v-if="containers.length === 0" aria-readonly="true"> - <td colspan="4"> + <td colspan="5"> <span v-if="!loading">(no databases)</span> </td> </tr> @@ -35,6 +36,13 @@ class="database" @click="loadDatabase(item)"> <td>{{ item.name }}</td> + <td> + <v-skeleton-loader v-if="!item.database" type="text" width="50" class="mt-1" /> + <span v-if="item.database"> + <span v-if="item.database.is_public">Public</span> + <span v-if="!item.database.is_public">Private <v-icon right>mdi-eye-off</v-icon></span> + </span> + </td> <td> <span v-if="item.database">{{ item.database.engine }}</span> <v-skeleton-loader v-if="!item.database" type="text" width="100" class="mt-1" /> diff --git a/fda-ui/pages/login.vue b/fda-ui/pages/login.vue index b4eddfafe1a17f9132fa8b374b9419f81d9ab18c..07539ffc0f51a7b1766c21b04db7cec1b7bd1371 100644 --- a/fda-ui/pages/login.vue +++ b/fda-ui/pages/login.vue @@ -87,10 +87,9 @@ export default { this.$refs.form.validate() }, async login () { - const url = '/api/auth' try { this.loading = true - const res = await this.$axios.post(url, this.loginAccount) + const res = await this.$axios.post('/api/auth', this.loginAccount) console.debug('login user', res.data) this.$store.commit('SET_TOKEN', res.data.token) const user = { ...res.data } diff --git a/fda-ui/pages/user/index.vue b/fda-ui/pages/user/index.vue index b90d1ffd8403ef33c4ab6700f810435462e54135..b6222f1bf74cf28538e4c13abfbf338be915f513 100644 --- a/fda-ui/pages/user/index.vue +++ b/fda-ui/pages/user/index.vue @@ -114,14 +114,6 @@ label="ORCID" /> </v-col> </v-row> - <v-row dense> - <v-col cols="5"> - <v-switch - v-model="user.theme_dark" - inset - label="Dark Mode" /> - </v-col> - </v-row> <v-row dense> <v-col cols="5"> <v-btn @@ -164,6 +156,23 @@ <pre>{{ $refs.form3 }}</pre> </v-form> </v-card-text> + <v-divider /> + <v-card-title>Theme</v-card-title> + <v-card-text> + <v-form v-model="valid4" @submit.prevent="submit"> + <v-row dense> + <v-col cols="5"> + <v-switch + v-model="user.theme_dark" + inset + label="Dark Mode" + :disabled="error" + :loading="loadingTheme" + @click="toggleTheme" /> + </v-col> + </v-row> + </v-form> + </v-card-text> </v-card> <v-breadcrumbs :items="items" class="pa-0 mt-2" /> </div> @@ -198,6 +207,7 @@ export default { { text: 'Databases', to: '/container', activeClass: '' } ], loading: false, + loadingTheme: false, error: false } }, @@ -275,7 +285,7 @@ export default { async changePassword () { try { this.loading = true - const res = await this.$axios.put('/api/user/' + this.user.id + '/password', this.reset, this.config) + const res = await this.$axios.put(`/api/user/${this.user.id}/password`, this.reset, this.config) console.debug('password', res.data) this.error = false this.$toast.success('Successfully changed the password') @@ -288,7 +298,7 @@ export default { async updateInfo () { try { this.loading = true - const res = await this.$axios.put('/api/user/' + this.user.id, { + const res = await this.$axios.put(`/api/user/${this.user.id}`, { titles_before: this.user.titles_before, titles_after: this.user.titles_after, firstname: this.user.firstname, @@ -305,6 +315,24 @@ export default { this.error = true } this.loading = false + }, + async toggleTheme () { + if (this.loading) { + return + } + try { + this.loadingTheme = true + const res = await this.$axios.put(`/api/user/${this.user.id}/theme`, { + theme_dark: this.user.theme_dark + }, this.config) + console.debug('theme set', res.data) + this.$vuetify.theme.dark = this.user.theme_dark + } catch (err) { + console.error('theme set', err) + this.$toast.error('Failed to update theme') + this.error = true + } + this.loadingTheme = false } } }