diff --git a/docker-compose.prod.yml b/.docker/docker-compose.yml similarity index 92% rename from docker-compose.prod.yml rename to .docker/docker-compose.yml index 3f24092344e371430730a450bbda9218b0d19144..d51b00551a3a6af30bbb7d454f6fea00c17e7d65 100644 --- a/docker-compose.prod.yml +++ b/.docker/docker-compose.yml @@ -14,7 +14,7 @@ services: restart: "no" container_name: dbrepo-metadata-db hostname: metadata-db - image: docker.io/dbrepo/metadata-db:latest + image: docker.io/dbrepo/metadata-db:1.4.4 volumes: - metadata-db-data:/bitnami/mariadb - ./dist/2_setup-data.sql:/docker-entrypoint-initdb.d/2_setup-data.sql @@ -76,7 +76,7 @@ services: restart: "no" container_name: dbrepo-auth-service hostname: auth-service - image: docker.io/dbrepo/auth-service:latest + image: docker.io/dbrepo/auth-service:1.4.4 healthcheck: test: curl -sSL 'http://0.0.0.0:8080/realms/dbrepo' | grep "dbrepo" || exit 1 interval: 10s @@ -98,18 +98,19 @@ services: restart: "no" container_name: dbrepo-metadata-service hostname: metadata-service - image: docker.io/dbrepo/metadata-service:latest + image: docker.io/dbrepo/metadata-service:1.4.4 volumes: - "${SHARED_VOLUME:-/tmp}:/tmp" environment: - ADMIN_MAIL: "${ADMIN_MAIL:-noreply@localhost}" + ADMIN_EMAIL: "${ADMIN_EMAIL:-noreply@localhost}" ADMIN_PASSWORD: "${ADMIN_PASSWORD:-admin}" ADMIN_USERNAME: "${ADMIN_USERNAME:-admin}" + ANALYSE_SERVICE_ENDPOINT: "${ANALYSE_SERVICE_ENDPOINT:-http://gateway-service}" AUTH_SERVICE_ADMIN: ${AUTH_SERVICE_ADMIN:-fda} AUTH_SERVICE_ADMIN_PASSWORD: ${AUTH_SERVICE_ADMIN_PASSWORD:-fda} AUTH_SERVICE_CLIENT: ${AUTH_SERVICE_CLIENT:-dbrepo-client} AUTH_SERVICE_CLIENT_SECRET: ${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG} - AUTH_SERVICE_ENDPOINT: ${AUTH_SERVICE_ENDPOINT:-http://auth-service:8080} + AUTH_SERVICE_ENDPOINT: ${AUTH_SERVICE_ENDPOINT:-http://gateway-service/api/auth} BASE_URL: "${BASE_URL:-http://localhost}" BROKER_EXCHANGE_NAME: ${BROKER_EXCHANGE_NAME:-dbrepo} BROKER_QUEUE_NAME: ${BROKER_QUEUE_NAME:-dbrepo} @@ -121,10 +122,9 @@ services: BROKER_VIRTUALHOST: "${BROKER_VIRTUALHOST:-dbrepo}" DATA_SERVICE_ENDPOINT: ${DATA_SERVICE_ENDPOINT:-http://data-service:8080} DELETED_RECORD: "${DELETED_RECORD:-persistent}" - GATEWAY_SERVICE_ENDPOINT: ${GATEWAY_SERVICE_ENDPOINT:-http://gateway-service} GRANULARITY: "${GRANULARITY:-YYYY-MM-DDThh:mm:ssZ}" JWT_PUBKEY: "${JWT_PUBKEY:-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB}" - LOG_LEVEL: ${LOG_LEVEL:-info} + LOG_LEVEL: "${LOG_LEVEL:-info}" METADATA_DB: "${METADATA_DB:-dbrepo}" METADATA_HOST: "${METADATA_HOST:-metadata-db}" METADATA_JDBC_EXTRA_ARGS: "${METADATA_JDBC_EXTRA_ARGS:-}" @@ -132,9 +132,9 @@ services: METADATA_PASSWORD: "${METADATA_PASSWORD:-dbrepo}" PID_BASE: ${PID_BASE:-http://localhost/pid/} REPOSITORY_NAME: "${REPOSITORY_NAME:-Database Repository}" - SEARCH_SERVICE_ENDPOINT: "${SEARCH_SERVICE_ENDPOINT:-http://search-service:8080}" + SEARCH_SERVICE_ENDPOINT: "${SEARCH_SERVICE_ENDPOINT:-http://gateway-service}" S3_ACCESS_KEY_ID: "${S3_ACCESS_KEY_ID:-seaweedfsadmin}" - S3_ENDPOINT: "${S3_ENDPOINT:-http://storage-service:9000}" + S3_ENDPOINT: "${S3_ENDPOINT:-http://gateway-service/api/storage}" S3_EXPORT_BUCKET: "${S3_EXPORT_BUCKET:-dbrepo-download}" S3_IMPORT_BUCKET: "${S3_IMPORT_BUCKET:-dbrepo-upload}" S3_SECRET_ACCESS_KEY: "${S3_SECRET_ACCESS_KEY:-seaweedfsadmin}" @@ -160,7 +160,7 @@ services: restart: "no" container_name: dbrepo-analyse-service hostname: analyse-service - image: docker.io/dbrepo/analyse-service:latest + image: docker.io/dbrepo/analyse-service:1.4.4 environment: ADMIN_PASSWORD: "${ADMIN_PASSWORD:-admin}" ADMIN_USERNAME: "${ADMIN_USERNAME:-admin}" @@ -211,7 +211,7 @@ services: restart: "no" container_name: dbrepo-search-db hostname: search-db - image: docker.io/dbrepo/search-db:latest + image: docker.io/dbrepo/search-db:1.4.4 healthcheck: test: curl -sSL localhost:9200/_plugins/_security/health | jq .status | grep UP interval: 10s @@ -235,7 +235,7 @@ services: restart: "no" container_name: dbrepo-search-service hostname: search-service - image: docker.io/dbrepo/search-service:latest + image: docker.io/dbrepo/search-service:1.4.4 environment: ADMIN_PASSWORD: "${ADMIN_PASSWORD:-admin}" ADMIN_USERNAME: "${ADMIN_USERNAME:-admin}" @@ -253,11 +253,12 @@ services: restart: "no" container_name: dbrepo-data-db-sidecar hostname: data-db-sidecar - image: docker.io/dbrepo/data-db-sidecar:latest + image: docker.io/dbrepo/data-db-sidecar:1.4.4 environment: S3_ACCESS_KEY_ID: "${S3_ACCESS_KEY_ID:-seaweedfsadmin}" S3_ENDPOINT: "${S3_ENDPOINT:-http://storage-service:9000}" S3_EXPORT_BUCKET: "${S3_EXPORT_BUCKET:-dbrepo-download}" + S3_FILE_PATH: "${S3_FILE_PATH:-/tmp}" S3_IMPORT_BUCKET: "${S3_IMPORT_BUCKET:-dbrepo-upload}" S3_SECRET_ACCESS_KEY: "${S3_SECRET_ACCESS_KEY:-seaweedfsadmin}" volumes: @@ -274,7 +275,7 @@ services: restart: "no" container_name: dbrepo-ui hostname: ui - image: docker.io/dbrepo/ui:latest + image: docker.io/dbrepo/ui:1.4.4 depends_on: dbrepo-search-service: condition: service_started @@ -318,7 +319,7 @@ services: restart: "no" container_name: dbrepo-search-service-init hostname: search-service-init - image: docker.io/dbrepo/search-service-init:latest + image: docker.io/dbrepo/search-service-init:1.4.4 environment: GATEWAY_SERVICE_ENDPOINT: ${GATEWAY_SERVICE_ENDPOINT:-http://gateway-service} OPENSEARCH_HOST: ${OPENSEARCH_HOST:-search-db} @@ -353,7 +354,7 @@ services: restart: "no" container_name: dbrepo-storage-service-init hostname: storage-service-init - image: docker.io/dbrepo/storage-service-init:latest + image: docker.io/dbrepo/storage-service-init:1.4.4 environment: SEAWEEDFS_ENDPOINT: "${STORAGE_SEAWEEDFS_ENDPOINT:-storage-service:9333}" depends_on: @@ -390,7 +391,7 @@ services: restart: "no" container_name: dbrepo-data-service hostname: data-service - image: docker.io/dbrepo/data-service:latest + image: docker.io/dbrepo/data-service:1.4.4 volumes: - "${SHARED_VOLUME:-/tmp}:/tmp" environment: @@ -411,7 +412,7 @@ services: BROKER_VIRTUALHOST: "${BROKER_VIRTUALHOST:-dbrepo}" CONNECTION_TIMEOUT: ${CONNECTION_TIMEOUT:-60000} EXCHANGE_NAME: ${EXCHANGE_NAME:-dbrepo} - GATEWAY_SERVICE_ENDPOINT: ${GATEWAY_SERVICE_ENDPOINT:-http://gateway-service} + METADATA_SERVICE_ENDPOINT: ${METADATA_SERVICE_ENDPOINT:-http://gateway-service} GRANT_DEFAULT_READ: "${GRANT_DEFAULT_READ:-SELECT}" GRANT_DEFAULT_WRITE: "${GRANT_DEFAULT_WRITE:-SELECT, CREATE, CREATE VIEW, CREATE ROUTINE, CREATE TEMPORARY TABLES, LOCK TABLES, INDEX, TRIGGER, INSERT, UPDATE, DELETE}" JWT_PUBKEY: "${JWT_PUBKEY:-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB}" @@ -421,7 +422,12 @@ services: QUEUE_NAME: ${QUEUE_NAME:-dbrepo} REQUEUE_REJECTED: ${REQUEUE_REJECTED:-false} ROUTING_KEY: "${ROUTING_KEY:-dbrepo.#}" - STORAGE_SERVICE_ENDPOINT: ${BROKER_SERVICE_ENDPOINT:-http://storage-service:9000} + S3_ACCESS_KEY_ID: "${S3_ACCESS_KEY_ID:-seaweedfsadmin}" + S3_ENDPOINT: "${S3_ENDPOINT:-http://storage-service:9000}" + S3_EXPORT_BUCKET: "${S3_EXPORT_BUCKET:-dbrepo-download}" + S3_FILE_PATH: "${S3_FILE_PATH:-/tmp}" + S3_IMPORT_BUCKET: "${S3_IMPORT_BUCKET:-dbrepo-upload}" + S3_SECRET_ACCESS_KEY: "${S3_SECRET_ACCESS_KEY:-seaweedfsadmin}" healthcheck: test: wget -qO- localhost:8080/actuator/health/readiness | grep -q "UP" || exit 1 interval: 10s diff --git a/.docs/.swagger/api.yaml b/.docs/.swagger/api.yaml index 607276e81a651c7f1fd0b91a1894d7a2c8aef9b4..7ba582ed3fba3ec1282918bff9f937f57dca36e2 100644 --- a/.docs/.swagger/api.yaml +++ b/.docs/.swagger/api.yaml @@ -1,17 +1,4 @@ -components: - securitySchemes: - basicAuth: - in: header - scheme: basic - type: http - bearerAuth: - bearerFormat: JWT - in: header - scheme: bearer - type: http -externalDocs: - description: Sourcecode Documentation - url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/ +openapi: 3.0.3 info: contact: email: andreas.rauber@tuwien.ac.at @@ -19,67 +6,142 @@ info: description: The REST API license: name: Apache 2.0 - url: https://www.apache.org/licenses/LICENSE-2.0 + url: 'https://www.apache.org/licenses/LICENSE-2.0' title: DBRepo REST API version: 1.4.4 -openapi: 3.1.0 servers: - description: Test Instance - url: https://test.dbrepo.tuwien.ac.at + url: 'https://test.dbrepo.tuwien.ac.at' - description: Local Instance - url: http://localhost + url: 'http://localhost' +externalDocs: + description: Sourcecode Documentation + url: 'https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/' paths: - /api/database: - post: - tags: - - database-endpoint - summary: Create database - operationId: create - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/CreateDatabaseDto' - required: true + /api/analyse/datatypes: + get: + consumes: + - application/json + description: This is a simple API which returns the datatypes of a (path) csv file + operationId: analyse_datatypes + parameters: + - example: filename_s3_key + in: query + name: filename + required: true + schema: + type: string + - example: ',' + in: query + name: separator + required: true + schema: + type: string + - example: 'false' + in: query + name: enum + required: false + schema: + type: boolean + - example: '2.5' + in: query + name: enum_tol + required: false + schema: + type: float + produces: + - application/json responses: - "201": - description: Created a database + '202': content: application/json: schema: - $ref: '#/components/schemas/DatabaseDto' - "400": - description: Database create query is malformed or image is not supported + $ref: '#/components/schemas/DataTypesDto' + description: Determined data types successfully + '400': content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "417": - description: Failed to create query store in database + $ref: '#/components/schemas/ErrorDto' + description: Failed to determine data types + '404': content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to communicate with database + $ref: '#/components/schemas/ErrorDto' + description: Failed to find file in Storage Service + '500': content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find container in metadata database + $ref: '#/components/schemas/ErrorDto' + description: Unexpected system error + security: + - bearerAuth: [] + - basicAuth: [] + summary: Determine datatypes + tags: + - analyse-endpoint + /api/analyse/keys: + get: + consumes: + - application/json + description: >- + This is a simple API which returns the primary keys + ranking of a + (path) csv file + operationId: analyse_keys + parameters: + - example: filename_s3_key + in: query + name: filename + required: true + schema: + type: string + - example: ',' + in: query + name: separator + required: true + schema: + type: string + produces: + - application/json + responses: + '202': content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' + $ref: '#/components/schemas/KeysDto' + description: Determined keys successfully + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorDto' + description: Failed to determine keys + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorDto' + description: Failed to find file in Storage Service or is empty + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorDto' + description: Unexpected system error security: + - bearerAuth: [] - basicAuth: [] - /api/database/{databaseId}/access/{userId}: - put: + summary: Determine primary keys tags: - - access-endpoint - summary: Update access to some database - operationId: update_1 + - analyse-endpoint + '/api/database/{databaseId}/view/{viewId}/data': + get: + tags: + - view-endpoint + summary: Retrieve view data + operationId: getData parameters: - name: databaseId in: path @@ -87,58 +149,75 @@ paths: schema: type: integer format: int64 - - name: userId + - name: viewId in: path required: true + schema: + type: integer + format: int64 + - name: page + in: query + required: false + schema: + type: integer + format: int64 + - name: size + in: query + required: false + schema: + type: integer + format: int64 + - name: timestamp + in: query + required: false schema: type: string - format: uuid - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/UpdateDatabaseAccessDto' - required: true + format: date-time responses: - "400": - description: Update access query or database connection is malformed + '200': + description: Retrieved view data + content: + application/json: + schema: + $ref: '#/components/schemas/QueryResultDto' + '400': + description: Request pagination is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "417": - description: Failed to update access in database + '403': + description: Not allowed to retrieve view data content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to establish connection with metadata service + '404': + description: Failed to find view in metadata database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Not allowed to update access + '409': + description: View schema could not be mapped content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find database/user in metadata database + '503': + description: Failed to establish connection with the metadata service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Update access succeeded security: - basicAuth: [] - post: + - bearerAuth: [] + head: tags: - - access-endpoint - summary: Give access to some database - operationId: create_4 + - view-endpoint + summary: Retrieve view data + operationId: getData_1 parameters: - name: databaseId in: path @@ -146,62 +225,76 @@ paths: schema: type: integer format: int64 - - name: userId + - name: viewId in: path required: true + schema: + type: integer + format: int64 + - name: page + in: query + required: false + schema: + type: integer + format: int64 + - name: size + in: query + required: false + schema: + type: integer + format: int64 + - name: timestamp + in: query + required: false schema: type: string - format: uuid - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/UpdateDatabaseAccessDto' - required: true + format: date-time responses: - "417": - description: Failed to give access in the database + '200': + description: Retrieved view data content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Granting access succeeded + $ref: '#/components/schemas/QueryResultDto' + '400': + description: Request pagination is malformed content: - '*/*': + application/json: schema: - type: object - "503": - description: Failed to establish connection to metadata service + $ref: '#/components/schemas/ApiErrorDto' + '403': + description: Not allowed to retrieve view data content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Not allowed to give access + '404': + description: Failed to find view in metadata database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find database/user in metadata database + '409': + description: View schema could not be mapped content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Granting access query or database connection is malformed + '503': + description: Failed to establish connection with the metadata service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - basicAuth: [] - delete: + - bearerAuth: [] + '/api/database/{databaseId}/table/{tableId}/data': + get: tags: - - access-endpoint - summary: Revoke access to some database - operationId: revoke + - table-endpoint + summary: Retrieve table data + operationId: getData_2 parameters: - name: databaseId in: path @@ -209,297 +302,442 @@ paths: schema: type: integer format: int64 - - name: userId + - name: tableId in: path required: true + schema: + type: integer + format: int64 + - name: timestamp + in: query + required: false schema: type: string - format: uuid + format: date-time + - name: page + in: query + required: false + schema: + type: integer + format: int64 + - name: size + in: query + required: false + schema: + type: integer + format: int64 responses: - "400": - description: Revoke access query or database connection is malformed + '200': + description: Retrieved table data content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "417": - description: Failed to revoke access in database + $ref: '#/components/schemas/QueryResultDto' + '400': + description: Request pagination or table data select query is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Not allowed to revoke access + '404': + description: Failed to find table in metadata database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": + '503': description: Failed to establish connection with the metadata service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find database/user in metadata database - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Revoked access successfully - content: - '*/*': - schema: - type: object security: - basicAuth: [] - /api/user/{userId}: - get: + - bearerAuth: [] + put: tags: - - user-endpoint - summary: Get a user info - operationId: find_2 + - table-endpoint + summary: Update a raw data tuple + description: >- + Updates a raw data tuple in a table with at least WRITE_OWN access. Then + update the table statistics. + operationId: updateRawTuple parameters: - - name: userId + - name: databaseId in: path required: true schema: - type: string - format: uuid + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TupleUpdateDto' + required: true responses: - "403": - description: Find user is not permitted + '202': + description: Updated table data + '400': + description: Request pagination or table data select query is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Found user + '403': + description: Update table data not allowed content: application/json: schema: - $ref: '#/components/schemas/UserDto' - "404": - description: User was not found + $ref: '#/components/schemas/ApiErrorDto' + '404': + description: Failed to find table in metadata database + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '503': + description: Failed to establish connection with the metadata service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - - bearerAuth: [] - basicAuth: [] - put: + - bearerAuth: [] + post: tags: - - user-endpoint - summary: Modify user information - operationId: modify + - table-endpoint + summary: Insert a raw data tuple + description: >- + Inserts a raw data tuple into a table with at least WRITE_OWN access. + Then update the table statistics. + operationId: insertRawTuple parameters: - - name: userId + - name: databaseId in: path required: true schema: - type: string - format: uuid + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 requestBody: content: application/json: schema: - $ref: '#/components/schemas/UserUpdateDto' + $ref: '#/components/schemas/TupleDto' required: true responses: - "404": - description: Failed to find database/user in metadata database + '201': + description: Created table data + '400': + description: Request pagination or table data select query is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Not allowed to modify user metadata + '403': + description: Create table data not allowed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Modify user query is malformed + '404': + description: Failed to find table in metadata database or blob in storage service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Modified user information + '503': + description: >- + Failed to establish connection with the metadata service or storage + service content: application/json: schema: - $ref: '#/components/schemas/UserDto' + $ref: '#/components/schemas/ApiErrorDto' security: - - bearerAuth: [] - basicAuth: [] - /api/user/{userId}/password: - put: + - bearerAuth: [] + delete: tags: - - user-endpoint - summary: Modify user password - operationId: password + - table-endpoint + summary: Delete table data + description: >- + Deletes a raw data tuple in a table with at least WRITE_OWN access. Then + update the table statistics. + operationId: deleteRawTuple parameters: - - name: userId + - name: databaseId in: path required: true schema: - type: string - format: uuid + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 requestBody: content: application/json: schema: - $ref: '#/components/schemas/UserPasswordDto' + $ref: '#/components/schemas/TupleDeleteDto' required: true responses: - "403": - description: Not allowed to change foreign user password + '202': + description: Deleted table data + '400': + description: Request pagination or table data select query is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find database/user in metadata database + '403': + description: Delete table data not allowed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to get user in auth service + '404': + description: Failed to find table in metadata database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Modified user password - content: - application/json: - schema: - $ref: '#/components/schemas/UserDto' - "502": - description: Connection to auth service failed + '503': + description: Failed to establish connection with the metadata service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - - bearerAuth: [] - basicAuth: [] - /api/user/token: - put: + - bearerAuth: [] + head: tags: - - user-endpoint - summary: Refresh user token - operationId: refreshToken - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/RefreshTokenRequestDto' - required: true + - table-endpoint + summary: Retrieve table data + operationId: getData_3 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + - name: timestamp + in: query + required: false + schema: + type: string + format: date-time + - name: page + in: query + required: false + schema: + type: integer + format: int64 + - name: size + in: query + required: false + schema: + type: integer + format: int64 responses: - "202": - description: Refreshed user token + '200': + description: Retrieved table data content: application/json: schema: - $ref: '#/components/schemas/TokenDto' - "502": - description: Connection to auth service failed + $ref: '#/components/schemas/QueryResultDto' + '400': + description: Request pagination or table data select query is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Invalid refresh token + '404': + description: Failed to find table in metadata database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - post: - tags: - - user-endpoint - summary: Obtain user token - operationId: getToken - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/LoginRequestDto' - required: true - responses: - "404": - description: Failed to find user in auth database + '503': + description: Failed to establish connection with the metadata service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to get user in auth service + security: + - basicAuth: [] + - bearerAuth: [] + '/api/database/{databaseId}/subset/{subsetId}/data': + get: + tags: + - subset-endpoint + summary: Retrieved subset data + operationId: getData_4 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: subsetId + in: path + required: true + schema: + type: integer + format: int64 + - name: page + in: query + required: false + schema: + type: integer + format: int64 + - name: size + in: query + required: false + schema: + type: integer + format: int64 + responses: + '200': + description: Retrieved subset data content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Obtained user token + $ref: '#/components/schemas/QueryResultDto' + '400': + description: Malformed select query content: application/json: schema: - $ref: '#/components/schemas/TokenDto' - "403": - description: Not allowed to get token + $ref: '#/components/schemas/ApiErrorDto' + '403': + description: Not allowed to retrieve subset data content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "428": - description: Account is not fully setup in auth service (requires password change?) + '404': + description: >- + Failed to find database in metadata database or query in query store + of the data database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "502": - description: Connection to auth service failed + '503': + description: Failed to communicate with database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - /api/ontology/{ontologyId}: - get: + security: + - bearerAuth: [] + - basicAuth: [] + head: tags: - - ontology-endpoint - summary: Find one ontology - operationId: find_3 + - subset-endpoint + summary: Retrieved subset data + operationId: getData_5 parameters: - - name: ontologyId + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: subsetId in: path required: true schema: type: integer format: int64 + - name: page + in: query + required: false + schema: + type: integer + format: int64 + - name: size + in: query + required: false + schema: + type: integer + format: int64 responses: - "404": - description: Could not find ontology + '200': + description: Retrieved subset data + content: + application/json: + schema: + $ref: '#/components/schemas/QueryResultDto' + '400': + description: Malformed select query content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Find one ontology + '403': + description: Not allowed to retrieve subset data content: application/json: schema: - $ref: '#/components/schemas/OntologyDto' + $ref: '#/components/schemas/ApiErrorDto' + '404': + description: >- + Failed to find database in metadata database or query in query store + of the data database + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '503': + description: Failed to communicate with database + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + security: + - bearerAuth: [] + - basicAuth: [] + '/api/database/{databaseId}/subset/{queryId}': put: tags: - - ontology-endpoint - summary: Update an ontology - operationId: update + - subset-endpoint + summary: Persist subset + operationId: persist parameters: - - name: ontologyId + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: queryId in: path required: true schema: @@ -509,58 +747,67 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/OntologyModifyDto' + $ref: '#/components/schemas/QueryPersistDto' required: true responses: - "404": - description: Could not find ontology + '202': + description: Persisted subset + content: + application/json: + schema: + $ref: '#/components/schemas/QueryDto' + '400': + description: Malformed select query + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '403': + description: Not allowed to persist subset + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '404': + description: >- + Failed to find database in metadata database or query in query store + of the data database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Updated ontology successfully + '417': + description: Failed to persist subset content: application/json: schema: - $ref: '#/components/schemas/OntologyDto' + $ref: '#/components/schemas/ApiErrorDto' + '503': + description: Failed to communicate with database + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] - basicAuth: [] - delete: + '/api/database/{databaseId}/table/{tableId}/data/import': + post: tags: - - ontology-endpoint - summary: Delete an ontology - operationId: delete + - table-endpoint + summary: Import data from a dataset + description: >- + Deletes a raw data tuple in a table with at least WRITE_OWN access. Then + update the table statistics. + operationId: importDataset parameters: - - name: ontologyId + - name: databaseId in: path required: true schema: type: integer format: int64 - responses: - "404": - description: Could not find ontology - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Deleted ontology successfully - content: - application/json: {} - security: - - bearerAuth: [] - - basicAuth: [] - /api/message/{messageId}: - put: - tags: - - message-endpoint - summary: Update maintenance message - operationId: update_1 - parameters: - - name: messageId + - name: tableId in: path required: true schema: @@ -570,377 +817,476 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/BannerMessageUpdateDto' + $ref: '#/components/schemas/ImportCsvDto' required: true responses: - "202": - description: Updated message + '202': + description: Imported dataset successfully + '400': + description: Dataset query is malformed content: application/json: schema: - $ref: '#/components/schemas/BannerMessageBriefDto' - "404": - description: Could not find message + $ref: '#/components/schemas/ApiErrorDto' + '403': + description: Import table dataset not allowed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - security: - - bearerAuth: [] - - basicAuth: [] - delete: - tags: - - message-endpoint - summary: Delete maintenance message - operationId: delete_1 - parameters: - - name: messageId - in: path - required: true - schema: - type: integer - format: int64 - responses: - "202": - description: Deleted message + '404': + description: Failed to find table in metadata database content: - application/json: {} - "404": - description: Could not find message + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '503': + description: Failed to establish connection with the metadata service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - - bearerAuth: [] - basicAuth: [] - /api/image/{imageId}: + - bearerAuth: [] + '/api/database/{databaseId}/subset': get: tags: - - image-endpoint - summary: Find some image - operationId: findById + - subset-endpoint + summary: Find subsets + operationId: list parameters: - - name: imageId + - name: databaseId in: path required: true schema: type: integer format: int64 + - name: persisted + in: query + required: false + schema: + type: boolean responses: - "404": - description: Image could not be found + '200': + description: Found subsets + content: + application/json: + schema: + type: string + '403': + description: Not allowed to find subsets content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Found image + '404': + description: >- + Failed to find database in metadata database or query in query store + of the data database content: application/json: schema: - $ref: '#/components/schemas/ImageDto' - put: + $ref: '#/components/schemas/ApiErrorDto' + '503': + description: Failed to communicate with database + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + security: + - basicAuth: [] + - bearerAuth: [] + post: tags: - - image-endpoint - summary: Update some image - operationId: update_2 + - subset-endpoint + summary: Create subset + operationId: create parameters: - - name: imageId + - name: databaseId in: path required: true schema: type: integer format: int64 + - name: page + in: query + required: false + schema: + type: integer + format: int64 + - name: size + in: query + required: false + schema: + type: integer + format: int64 + - name: timestamp + in: query + required: false + schema: + type: string + format: date-time requestBody: content: application/json: schema: - $ref: '#/components/schemas/ImageChangeDto' + $ref: '#/components/schemas/ExecuteStatementDto' required: true responses: - "404": - description: Image could not be found + '201': + description: Created subset + content: + application/json: + schema: + $ref: '#/components/schemas/QueryResultDto' + '400': + description: Malformed select query content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Updated image successfully + '403': + description: Not allowed to find subset content: application/json: schema: - $ref: '#/components/schemas/ImageDto' - security: - - bearerAuth: [] - - basicAuth: [] - delete: - tags: - - image-endpoint - summary: Delete some image - operationId: delete_2 - parameters: - - name: imageId - in: path - required: true - schema: - type: integer - format: int64 - responses: - "202": - description: Deleted image successfully - "404": - description: Image could not be found + $ref: '#/components/schemas/ApiErrorDto' + '404': + description: >- + Failed to find database in metadata database or query in query store + of the data database + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '417': + description: Failed to insert query into query store of data database + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '501': + description: Failed to execute query as it contains non-supported keywords + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '503': + description: Failed to communicate with database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - - bearerAuth: [] - basicAuth: [] - /api/identifier/{identifierId}: + - bearerAuth: [] + '/api/database/{databaseId}/table/{tableId}/statistic': get: tags: - - identifier-endpoint - summary: Find some identifier - operationId: find_6 + - table-endpoint + summary: Generate table statistic + operationId: statistic parameters: - - name: identifierId + - name: databaseId in: path required: true schema: type: integer format: int64 - - name: Accept - in: header + - name: tableId + in: path required: true schema: - type: string + type: integer + format: int64 responses: - "406": - description: Failed to find acceptable representation + '200': + description: Generated table statistic content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "422": - description: Failed to retrieve from database sidecar + $ref: '#/components/schemas/TableStatisticDto' + '400': + description: Failed to obtain column statistic content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to find in data service + '404': + description: Failed to find table in metadata database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Found identifier successfully + '503': + description: Failed to establish connection with the metadata service content: application/json: schema: - $ref: '#/components/schemas/IdentifierDto' - application/ld+json: - schema: - $ref: '#/components/schemas/LdDatasetDto' - text/csv: {} - text/xml: {} - text/bibliography: {} - text/bibliography; style=apa: {} - text/bibliography; style=ieee: {} - text/bibliography; style=bibtex: {} - "404": - description: Identifier could not be found + $ref: '#/components/schemas/ApiErrorDto' + '/api/database/{databaseId}/table/{tableId}/history': + get: + tags: + - table-endpoint + summary: Find table history + description: >- + Lists the insert/delete operations performed. Authentication is only + required for tables in private databases + operationId: getHistory + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + - name: size + in: query + required: false + schema: + type: integer + format: int64 + responses: + '200': + description: Found table history content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "502": - description: Connection to data service failed + type: string + '400': + description: Invalid pagination request content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: "Identifier could not be exported, the requested style is not known" + '403': + description: Find table history not allowed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "410": - description: Failed to retrieve from S3 endpoint + '404': + description: Failed to find table history in data database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "409": - description: Exported resource was not found + '503': + description: Failed to establish connection with the metadata service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - put: + security: + - basicAuth: [] + - bearerAuth: [] + '/api/database/{databaseId}/table/{tableId}/export': + get: tags: - - identifier-endpoint - summary: Save identifier - operationId: save + - table-endpoint + summary: Export table data + operationId: exportData parameters: - - name: identifierId + - name: databaseId in: path required: true schema: type: integer format: int64 - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/IdentifierSaveDto' - required: true + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + - name: timestamp + in: query + required: false + schema: + type: string + format: date-time responses: - "403": - description: Insufficient access rights or authorities - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' - "502": - description: Connection to search service failed + '200': + description: Exported table data content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "405": - description: Creating identifier not permitted + type: string + format: binary + '400': + description: Request pagination or table data select query is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Identifier form contains invalid request data + '403': + description: Export table data not allowed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: "Failed to find database, table or view" + '404': + description: Failed to find table in metadata database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Saved identifier - content: - application/json: - schema: - $ref: '#/components/schemas/IdentifierDto' - "503": - description: Failed to save in search service + '503': + description: Failed to establish connection with the metadata service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - - bearerAuth: [] - basicAuth: [] - delete: + - bearerAuth: [] + '/api/database/{databaseId}/subset/{subsetId}': + get: tags: - - identifier-endpoint - summary: Delete some identifier - operationId: delete_3 + - subset-endpoint + summary: Find subset + operationId: findById parameters: - - name: identifierId + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: subsetId in: path required: true schema: type: integer format: int64 + - name: timestamp + in: query + required: false + schema: + type: string + format: date-time responses: - "502": - description: Connection to search service failed + '200': + description: Found subset + content: + application/json: + schema: + $ref: '#/components/schemas/QueryDto' + text/csv: {} + '400': + description: Malformed select query content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Deleting identifier not permitted + '403': + description: Not allowed to find subset content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to delete in search service + '404': + description: >- + Failed to find database in metadata database or query in query store + of the data database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Deleted identifier + '406': + description: Failed to find acceptable representation content: - '*/*': + application/json: schema: - type: object - "404": - description: Identifier or database could not be found + $ref: '#/components/schemas/ApiErrorDto' + '503': + description: Failed to communicate with database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - - bearerAuth: [] - basicAuth: [] - /api/identifier/{identifierId}/publish: - put: + - bearerAuth: [] + /api/database: + get: tags: - - identifier-endpoint - summary: Publish identifier - operationId: publish + - database-endpoint + summary: List databases + operationId: list1 parameters: - - name: identifierId - in: path - required: true + - name: internal_name + in: query + required: false schema: - type: integer - format: int64 + type: string responses: - "403": - description: Insufficient access rights or authorities + '200': + description: List of databases content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "502": - description: Connection to search service failed + type: array + items: + $ref: '#/components/schemas/DatabaseDto' + post: + tags: + - database-endpoint + summary: Create database + operationId: create_5 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/DatabaseCreateDto' + required: true + responses: + '201': + description: Created a new database + content: + application/json: + schema: + $ref: '#/components/schemas/DatabaseDto' + '400': + description: Database create query is malformed or image is not supported content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "405": - description: Creating identifier not permitted + '403': + description: >- + Database create permission is missing or grant permissions at broker + service failed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Identifier form contains invalid request data + '404': + description: Failed to fin container/user/database in metadata database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: "Failed to find database, table or view" + '409': + description: Query store could not be created content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Published identifier + '502': + description: Connection to search service failed content: application/json: schema: - $ref: '#/components/schemas/IdentifierDto' - "503": + $ref: '#/components/schemas/ApiErrorDto' + '503': description: Failed to save in search service content: application/json: @@ -949,12 +1295,32 @@ paths: security: - bearerAuth: [] - basicAuth: [] - /api/database/{databaseId}/visibility: - put: + head: tags: - database-endpoint - summary: Update database visibility - operationId: visibility + summary: List databases + operationId: list_1 + parameters: + - name: internal_name + in: query + required: false + schema: + type: string + responses: + '200': + description: List of databases + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/DatabaseDto' + '/api/database/{databaseId}/access/{userId}': + get: + tags: + - access-endpoint + summary: Check access to some database + operationId: find parameters: - name: databaseId in: path @@ -962,39 +1328,27 @@ paths: schema: type: integer format: int64 - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/DatabaseModifyVisibilityDto' - required: true + - name: userId + in: path + required: true + schema: + type: string + format: uuid responses: - "202": - description: Visibility modified successfully - content: - application/json: - schema: - $ref: '#/components/schemas/DatabaseDto' - "403": - description: Visibility modification is not permitted - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' - "502": - description: Connection to search service failed + '200': + description: Found database access content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find database in metadata database + $ref: '#/components/schemas/DatabaseAccessDto' + '403': + description: No access to this database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to save in search service + '404': + description: Database not found content: application/json: schema: @@ -1002,12 +1356,11 @@ paths: security: - bearerAuth: [] - basicAuth: [] - /api/database/{databaseId}/table/{tableId}: - delete: + put: tags: - - table-endpoint - summary: Delete table - operationId: delete_1 + - access-endpoint + summary: Modify access to some database + operationId: update_4 parameters: - name: databaseId in: path @@ -1015,45 +1368,63 @@ paths: schema: type: integer format: int64 - - name: tableId + - name: userId in: path required: true schema: - type: integer - format: int64 + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateDatabaseAccessDto' + required: true responses: - "404": - description: Failed to find table in metadata database + '202': + description: Modify access succeeded + '400': + description: Modify access query or database connection is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Deleted table + '403': + description: >- + Modify access not permitted when no access is granted in the first + place content: application/json: schema: - $ref: '#/components/schemas/DatabaseDto' - "503": - description: Failed to establish connection with the metadata service + $ref: '#/components/schemas/ApiErrorDto' + '404': + description: Database or user not found + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '502': + description: >- + Access could not be updated due to connection error in the data + service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Deletion query is malformed + '503': + description: Access could not be updated in the data service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: + - bearerAuth: [] - basicAuth: [] - /api/database/{databaseId}/table/{tableId}/column/{columnId}: - put: + post: tags: - - table-endpoint - summary: Update a table column semantic mapping - operationId: update_3 + - access-endpoint + summary: Give access to some database + operationId: create_8 parameters: - name: databaseId in: path @@ -1061,57 +1432,53 @@ paths: schema: type: integer format: int64 - - name: tableId - in: path - required: true - schema: - type: integer - format: int64 - - name: columnId + - name: userId in: path required: true schema: - type: integer - format: int64 + type: string + format: uuid requestBody: content: application/json: schema: - $ref: '#/components/schemas/ColumnSemanticsUpdateDto' + $ref: '#/components/schemas/UpdateDatabaseAccessDto' required: true responses: - "400": - description: Update semantic concept query is malformed or update unit of measurement query is malformed + '202': + description: Granting access succeeded + '400': + description: Granting access query or database connection is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "502": - description: Connection to search service failed + '403': + description: Failed giving access content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Access to the database is forbidden + '404': + description: Database or user not found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Updated column semantics successfully + '405': + description: Granting access not permitted content: application/json: schema: - $ref: '#/components/schemas/ColumnDto' - "404": - description: Failed to find user/table/database/ontology in metadata database + $ref: '#/components/schemas/ApiErrorDto' + '502': + description: Access could not be created due to connection error content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to save in search service + '503': + description: Access could not be created in the data service content: application/json: schema: @@ -1119,12 +1486,11 @@ paths: security: - bearerAuth: [] - basicAuth: [] - /api/database/{databaseId}/owner: - put: + delete: tags: - - database-endpoint - summary: Update database owner - operationId: transfer + - access-endpoint + summary: Revoke access to some database + operationId: revoke parameters: - name: databaseId in: path @@ -1132,39 +1498,41 @@ paths: schema: type: integer format: int64 - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/DatabaseTransferDto' - required: true + - name: userId + in: path + required: true + schema: + type: string + format: uuid responses: - "403": - description: Transfer of ownership is not permitted + '202': + description: Revoked access successfully + '400': + description: Modify access query or database connection is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Transfer of ownership was successful + '403': + description: Revoke of access not permitted as no access was found content: application/json: schema: - $ref: '#/components/schemas/DatabaseDto' - "404": - description: Database or user could not be found + $ref: '#/components/schemas/ApiErrorDto' + '404': + description: 'User, database with access was not found' content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "502": - description: Connection to search service failed + '502': + description: Access could not be created due to connection error content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to save in search service + '503': + description: Access could not be revoked in the data service content: application/json: schema: @@ -1172,12 +1540,11 @@ paths: security: - bearerAuth: [] - basicAuth: [] - /api/database/{databaseId}/metadata/view: - put: + head: tags: - - database-endpoint - summary: Refresh database views metadata - operationId: refreshViewMetadata + - access-endpoint + summary: Check access to some database + operationId: find_1 parameters: - name: databaseId in: path @@ -1185,33 +1552,62 @@ paths: schema: type: integer format: int64 + - name: userId + in: path + required: true + schema: + type: string + format: uuid responses: - "403": - description: Refresh view metadata is not permitted + '200': + description: Found database access + content: + application/json: + schema: + $ref: '#/components/schemas/DatabaseAccessDto' + '403': + description: No access to this database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "502": - description: Connection to search service failed + '404': + description: Database not found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Refreshed database views metadata + security: + - bearerAuth: [] + - basicAuth: [] + '/api/user/{userId}': + get: + tags: + - user-endpoint + summary: Get a user info + operationId: find_2 + parameters: + - name: userId + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: Found user content: application/json: schema: - $ref: '#/components/schemas/DatabaseDto' - "404": - description: Failed to find database in metadata database + $ref: '#/components/schemas/UserDto' + '403': + description: Find user is not permitted content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to save in search service + '404': + description: User was not found content: application/json: schema: @@ -1219,52 +1615,45 @@ paths: security: - bearerAuth: [] - basicAuth: [] - /api/database/{databaseId}/metadata/table: put: tags: - - database-endpoint - summary: Refresh database tables metadata - operationId: refreshTableMetadata + - user-endpoint + summary: Modify user information + operationId: modify parameters: - - name: databaseId + - name: userId in: path required: true schema: - type: integer - format: int64 + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UserUpdateDto' + required: true responses: - "200": - description: Refreshed database tables metadata - content: - application/json: - schema: - $ref: '#/components/schemas/DatabaseDto' - "400": - description: Failed to parse payload at search service - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Not allowed to refresh table metadata + '202': + description: Modified user information content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "502": - description: Connection to search service failed + $ref: '#/components/schemas/UserDto' + '400': + description: Modify user query is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to fin user/database in metadata database + '403': + description: Not allowed to modify user metadata content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to save in search service + '404': + description: Failed to find database/user in metadata database content: application/json: schema: @@ -1272,58 +1661,52 @@ paths: security: - bearerAuth: [] - basicAuth: [] - /api/database/{databaseId}/image: + '/api/user/{userId}/password': put: tags: - - database-endpoint - summary: Update database image - operationId: modifyImage + - user-endpoint + summary: Modify user password + operationId: password parameters: - - name: databaseId + - name: userId in: path required: true schema: - type: integer - format: int64 + type: string + format: uuid requestBody: content: application/json: schema: - $ref: '#/components/schemas/DatabaseModifyImageDto' + $ref: '#/components/schemas/UserPasswordDto' required: true responses: - "404": - description: Database or user could not be found + '202': + description: Modified user password content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "502": - description: Connection to search service failed + $ref: '#/components/schemas/UserDto' + '403': + description: Not allowed to change foreign user password content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Modify of image was successful - content: - application/json: - schema: - $ref: '#/components/schemas/DatabaseDto' - "410": - description: File was not found in the Storage Service + '404': + description: Failed to find database/user in metadata database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Modify of image is not permitted + '502': + description: Connection to auth service failed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to save in search service + '503': + description: Failed to get user in auth service content: application/json: schema: @@ -1331,192 +1714,311 @@ paths: security: - bearerAuth: [] - basicAuth: [] - /api/user: - get: + /api/user/token: + put: tags: - user-endpoint - summary: Find all users - operationId: findAll + summary: Refresh user token + operationId: refreshToken + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RefreshTokenRequestDto' + required: true responses: - "200": - description: List users + '202': + description: Refreshed user token content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/UserBriefDto' + $ref: '#/components/schemas/TokenDto' + '403': + description: Invalid refresh token + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '502': + description: Connection to auth service failed + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' post: tags: - user-endpoint - summary: Create user - operationId: create + summary: Obtain user token + operationId: getToken requestBody: content: application/json: schema: - $ref: '#/components/schemas/SignupRequestDto' + $ref: '#/components/schemas/LoginRequestDto' required: true responses: - "503": - description: Failed to create in auth service + '202': + description: Obtained user token content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "417": - description: User with e-mail already exists + $ref: '#/components/schemas/TokenDto' + '403': + description: Not allowed to get token content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "502": - description: Failed to create in auth service + '404': + description: Failed to find user in auth database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: default role not found + '428': + description: >- + Account is not fully setup in auth service (requires password + change?) content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Parameters are not well-formed (likely email) - content: - application/json: {} - "201": - description: Created user + '502': + description: Connection to auth service failed content: application/json: schema: - $ref: '#/components/schemas/UserBriefDto' - "409": - description: User with username already exists + $ref: '#/components/schemas/ApiErrorDto' + '503': + description: Failed to get user in auth service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - /api/ontology: + '/api/ontology/{ontologyId}': get: tags: - ontology-endpoint - summary: List all ontologies - operationId: findAll_2 + summary: Find one ontology + operationId: find_3 + parameters: + - name: ontologyId + in: path + required: true + schema: + type: integer + format: int64 responses: - "200": - description: List all ontologies + '200': + description: Find one ontology content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/OntologyDto' - post: + $ref: '#/components/schemas/OntologyDto' + '404': + description: Could not find ontology + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + put: tags: - ontology-endpoint - summary: Register a new ontology - operationId: create_1 + summary: Update an ontology + operationId: update + parameters: + - name: ontologyId + in: path + required: true + schema: + type: integer + format: int64 requestBody: content: application/json: schema: - $ref: '#/components/schemas/OntologyCreateDto' + $ref: '#/components/schemas/OntologyModifyDto' required: true responses: - "201": - description: Registered ontology successfully + '202': + description: Updated ontology successfully content: application/json: schema: $ref: '#/components/schemas/OntologyDto' + '404': + description: Could not find ontology + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] - basicAuth: [] - /api/message: - get: + delete: tags: - - message-endpoint - summary: Find maintenance messages - operationId: list_2 + - ontology-endpoint + summary: Delete an ontology + operationId: delete parameters: - - name: filter - in: query - required: false + - name: ontologyId + in: path + required: true schema: - type: string + type: integer + format: int64 responses: - "200": - description: List messages + '202': + description: Deleted ontology successfully + content: + application/json: {} + '404': + description: Could not find ontology content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/BannerMessageDto' - post: + $ref: '#/components/schemas/ApiErrorDto' + security: + - bearerAuth: [] + - basicAuth: [] + '/api/message/{messageId}': + put: tags: - message-endpoint - summary: Create maintenance message - operationId: create_2 + summary: Update maintenance message + operationId: update_1 + parameters: + - name: messageId + in: path + required: true + schema: + type: integer + format: int64 requestBody: content: application/json: schema: - $ref: '#/components/schemas/BannerMessageCreateDto' + $ref: '#/components/schemas/BannerMessageUpdateDto' required: true responses: - "201": - description: Created message + '202': + description: Updated message content: application/json: schema: $ref: '#/components/schemas/BannerMessageBriefDto' + '404': + description: Could not find message + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] - basicAuth: [] - /api/image: + delete: + tags: + - message-endpoint + summary: Delete maintenance message + operationId: delete_1 + parameters: + - name: messageId + in: path + required: true + schema: + type: integer + format: int64 + responses: + '202': + description: Deleted message + content: + application/json: {} + '404': + description: Could not find message + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + security: + - bearerAuth: [] + - basicAuth: [] + '/api/image/{imageId}': get: tags: - image-endpoint - summary: Find all images - operationId: findAll_3 + summary: Find some image + operationId: findById1 + parameters: + - name: imageId + in: path + required: true + schema: + type: integer + format: int64 responses: - "200": - description: List images + '200': + description: Found image content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/ContainerImage' - post: + $ref: '#/components/schemas/ImageDto' + '404': + description: Image could not be found + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + put: tags: - image-endpoint - summary: Create image - operationId: create_3 + summary: Update some image + operationId: update_2 + parameters: + - name: imageId + in: path + required: true + schema: + type: integer + format: int64 requestBody: content: application/json: schema: - $ref: '#/components/schemas/ImageCreateDto' + $ref: '#/components/schemas/ImageChangeDto' required: true responses: - "201": - description: Created image + '202': + description: Updated image successfully content: application/json: schema: $ref: '#/components/schemas/ImageDto' - "400": - description: Image specification is invalid + '404': + description: Image could not be found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "409": - description: Image already exists + security: + - bearerAuth: [] + - basicAuth: [] + delete: + tags: + - image-endpoint + summary: Delete some image + operationId: delete_2 + parameters: + - name: imageId + in: path + required: true + schema: + type: integer + format: int64 + responses: + '202': + description: Deleted image successfully + '404': + description: Image could not be found content: application/json: schema: @@ -1524,34 +2026,16 @@ paths: security: - bearerAuth: [] - basicAuth: [] - /api/identifier: + '/api/identifier/{identifierId}': get: tags: - identifier-endpoint - summary: Find all identifiers - operationId: findAll_4 + summary: Find some identifier + operationId: find_6 parameters: - - name: dbid - in: query - required: false - schema: - type: integer - format: int64 - - name: qid - in: query - required: false - schema: - type: integer - format: int64 - - name: vid - in: query - required: false - schema: - type: integer - format: int64 - - name: tid - in: query - required: false + - name: identifierId + in: path + required: true schema: type: integer format: int64 @@ -1561,71 +2045,172 @@ paths: schema: type: string responses: - "200": - description: Found identifiers successfully + '200': + description: Found identifier successfully content: application/json: schema: - type: string + $ref: '#/components/schemas/IdentifierDto' application/ld+json: schema: - type: string - "406": - description: "Identifier could not be exported, the requested style is not known" + $ref: '#/components/schemas/LdDatasetDto' + text/csv: {} + text/xml: {} + text/bibliography: {} + text/bibliography; style=apa: {} + text/bibliography; style=ieee: {} + text/bibliography; style=bibtex: {} + '400': + description: 'Identifier could not be exported, the requested style is not known' content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - post: + '404': + description: Identifier could not be found + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '406': + description: Failed to find acceptable representation + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '409': + description: Exported resource was not found + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '410': + description: Failed to retrieve from S3 endpoint + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '422': + description: Failed to retrieve from database sidecar + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '502': + description: Connection to data service failed + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '503': + description: Failed to find in data service + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + put: tags: - identifier-endpoint - summary: Draft identifier - operationId: create_4 + summary: Save identifier + operationId: save + parameters: + - name: identifierId + in: path + required: true + schema: + type: integer + format: int64 requestBody: content: application/json: schema: - $ref: '#/components/schemas/IdentifierCreateDto' + $ref: '#/components/schemas/IdentifierSaveDto' required: true responses: - "403": + '202': + description: Saved identifier + content: + application/json: + schema: + $ref: '#/components/schemas/IdentifierDto' + '400': + description: Identifier form contains invalid request data + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '403': description: Insufficient access rights or authorities content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "502": - description: Connection to search service failed + '404': + description: 'Failed to find database, table or view' content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "405": + '405': description: Creating identifier not permitted content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Identifier form contains invalid request data + '502': + description: Connection to search service failed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: "Failed to find database, table or view" + '503': + description: Failed to save in search service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "201": - description: Drafted identifier + security: + - bearerAuth: [] + - basicAuth: [] + delete: + tags: + - identifier-endpoint + summary: Delete some identifier + operationId: delete_3 + parameters: + - name: identifierId + in: path + required: true + schema: + type: integer + format: int64 + responses: + '202': + description: Deleted identifier + content: + '*/*': + schema: + type: object + '403': + description: Deleting identifier not permitted content: application/json: schema: - $ref: '#/components/schemas/IdentifierDto' - "503": - description: Failed to save in search service + $ref: '#/components/schemas/ApiErrorDto' + '404': + description: Identifier or database could not be found + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '502': + description: Connection to search service failed + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '503': + description: Failed to delete in search service content: application/json: schema: @@ -1633,61 +2218,71 @@ paths: security: - bearerAuth: [] - basicAuth: [] - /api/database/{databaseId}/view: - get: + '/api/identifier/{identifierId}/publish': + put: tags: - - view-endpoint - summary: Find view schemas - operationId: getSchema + - identifier-endpoint + summary: Publish identifier + operationId: publish parameters: - - name: databaseId + - name: identifierId in: path required: true schema: type: integer format: int64 responses: - "417": - description: View schema could not be retrieved + '202': + description: Published identifier + content: + application/json: + schema: + $ref: '#/components/schemas/IdentifierDto' + '400': + description: Identifier form contains invalid request data content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to establish connection with the metadata service + '403': + description: Insufficient access rights or authorities content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "409": - description: View schema could not be mapped to known columns + '404': + description: 'Failed to find database, table or view' content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find database/view in metadata database + '405': + description: Creating identifier not permitted content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Database schema is malformed + '502': + description: Connection to search service failed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Found view schemas + '503': + description: Failed to save in search service content: application/json: schema: - type: string - post: + $ref: '#/components/schemas/ApiErrorDto' + security: + - bearerAuth: [] + - basicAuth: [] + '/api/database/{databaseId}/visibility': + put: tags: - - view-endpoint - summary: Create view - operationId: create_1 + - database-endpoint + summary: Update database visibility + operationId: visibility parameters: - name: databaseId in: path @@ -1699,48 +2294,48 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ViewCreateDto' + $ref: '#/components/schemas/DatabaseModifyVisibilityDto' required: true responses: - "400": - description: View schema is malformed + '202': + description: Visibility modified successfully content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find database in metadata database + $ref: '#/components/schemas/DatabaseDto' + '403': + description: Visibility modification is not permitted content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "409": - description: View schema could not be mapped + '404': + description: Failed to find database in metadata database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to establish connection with the metadata service + '502': + description: Connection to search service failed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Created view + '503': + description: Failed to save in search service content: application/json: schema: - $ref: '#/components/schemas/ViewDto' + $ref: '#/components/schemas/ApiErrorDto' security: - - basicAuth: [] - bearerAuth: [] - /api/database/{databaseId}/table: + - basicAuth: [] + '/api/database/{databaseId}/table/{tableId}': get: tags: - table-endpoint - summary: Find table schemas - operationId: getSchema_1 + summary: Get information about table + operationId: findById_2 parameters: - name: databaseId in: path @@ -1748,48 +2343,51 @@ paths: schema: type: integer format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 responses: - "403": - description: Find table schema not allowed + '200': + description: Find table successfully content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find database in metadata database + $ref: '#/components/schemas/TableDto' + '403': + description: Access to the database is forbidden content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "417": - description: Failed to parse table schema + '404': + description: 'Table, database or container could not be found' content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Got table schemas - content: - application/json: - schema: - type: string - "503": - description: Failed to establish connection with the metadata service + '502': + description: Connection to search service failed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Schema data malformed + '503': + description: Failed to save in search service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - post: + security: + - bearerAuth: [] + - basicAuth: [] + put: tags: - table-endpoint - summary: Create table - operationId: create_2 + summary: Update table statistics + operationId: updateStatistic parameters: - name: databaseId in: path @@ -1797,167 +2395,162 @@ paths: schema: type: integer format: int64 - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/TableCreateDto' - required: true + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 responses: - "400": - description: Table schema or query is malformed + '202': + description: Updated table statistics successfully + '400': + description: Failed to map column statistic to known columns content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "409": - description: Table name already exists in database + '404': + description: Failed to find database/table in metadata database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find database in metadata database or table in data database + '502': + description: Connection to search service failed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to establish connection with the metadata service + '503': + description: Failed to save in search service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "201": - description: Created table - content: - application/json: - schema: - $ref: '#/components/schemas/TableDto' security: + - bearerAuth: [] - basicAuth: [] - /api/container: - get: + delete: tags: - - container-endpoint - summary: Find all containers - operationId: findAll_6 + - table-endpoint + summary: Delete a table + operationId: delete_5 parameters: - - name: limit - in: query - required: false + - name: databaseId + in: path + required: true schema: type: integer - format: int32 + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 responses: - "200": - description: List containers + '202': + description: Delete table successfully + '400': + description: Delete table query resulted in an invalid query statement content: application/json: schema: - type: array - items: - type: string - post: - tags: - - container-endpoint - summary: Create container - operationId: create_9 - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/ContainerCreateDto' - required: true - responses: - "404": - description: Container image or user could not be found + $ref: '#/components/schemas/ApiErrorDto' + '403': + description: Access to the database is forbidden content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "409": - description: Container name already exists + '404': + description: 'Table, database or container could not be found' content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "201": - description: Created a new container + '502': + description: Connection to search service failed content: application/json: schema: - $ref: '#/components/schemas/ContainerBriefDto' - security: - - bearerAuth: [] - - basicAuth: [] - /api/unit: - get: - tags: - - unit-endpoint - summary: List semantic units - operationId: findAll_1 - responses: - "200": - description: Find all semantic units + $ref: '#/components/schemas/ApiErrorDto' + '503': + description: Failed to save in search service content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/UnitDto' - /api/ontology/{ontologyId}/entity: - get: + $ref: '#/components/schemas/ApiErrorDto' + security: + - bearerAuth: [] + - basicAuth: [] + '/api/database/{databaseId}/table/{tableId}/column/{columnId}': + put: tags: - - ontology-endpoint - summary: Find entities - operationId: find_4 + - table-endpoint + summary: Update a table column semantic mapping + operationId: update_3 parameters: - - name: ontologyId + - name: databaseId in: path required: true schema: type: integer format: int64 - - name: label - in: query - required: false + - name: tableId + in: path + required: true schema: - type: string - - name: uri - in: query - required: false + type: integer + format: int64 + - name: columnId + in: path + required: true schema: - type: string + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ColumnSemanticsUpdateDto' + required: true responses: - "404": - description: Could not find ontology + '202': + description: Updated column semantics successfully + content: + application/json: + schema: + $ref: '#/components/schemas/ColumnDto' + '400': + description: >- + Update semantic concept query is malformed or update unit of + measurement query is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "422": - description: Ontology does not have rdf or sparql endpoint + '403': + description: Access to the database is forbidden content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Found entities + '404': + description: Failed to find user/table/database/ontology in metadata database content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/EntityDto' - "400": - description: Filter params are invalid + $ref: '#/components/schemas/ApiErrorDto' + '502': + description: Connection to search service failed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "417": - description: Generated query or uri is malformed + '503': + description: Failed to save in search service content: application/json: schema: @@ -1965,97 +2558,65 @@ paths: security: - bearerAuth: [] - basicAuth: [] - /api/oai: - get: - tags: - - metadata-endpoint - summary: Get the record - operationId: identify_1_1_1_1 - parameters: - - name: verb - in: query - - name: parameters - in: query - required: true - schema: - $ref: '#/components/schemas/OaiListIdentifiersParameters' - responses: - "200": - description: List containers - content: - text/xml: {} - /api/message/message/{messageId}: - get: + '/api/database/{databaseId}/owner': + put: tags: - - message-endpoint - summary: Find one maintenance message - operationId: find_5 + - database-endpoint + summary: Update database owner + operationId: transfer parameters: - - name: messageId + - name: databaseId in: path required: true schema: type: integer format: int64 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/DatabaseTransferDto' + required: true responses: - "200": - description: Get messages + '202': + description: Transfer of ownership was successful content: application/json: schema: - $ref: '#/components/schemas/BannerMessageDto' - "404": - description: Could not find message + $ref: '#/components/schemas/DatabaseDto' + '403': + description: Transfer of ownership is not permitted content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - /api/license: - get: - tags: - - license-endpoint - summary: Get all licenses - operationId: list_3 - responses: - "200": - description: List of licenses + '404': + description: Database or user could not be found content: application/json: schema: - type: array - items: - type: string - /api/identifier/retrieve: - get: - tags: - - identifier-endpoint - summary: Retrieve metadata from identifier - operationId: retrieve - parameters: - - name: url - in: query - required: true - schema: - type: string - responses: - "200": - description: Retrieved metadata from identifier + $ref: '#/components/schemas/ApiErrorDto' + '502': + description: Connection to search service failed content: application/json: schema: - $ref: '#/components/schemas/IdentifierDto' - "404": - description: Failed to find metadata for identifier + $ref: '#/components/schemas/ApiErrorDto' + '503': + description: Failed to save in search service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - /api/database/{databaseId}: + security: + - bearerAuth: [] + - basicAuth: [] + '/api/database/{databaseId}/metadata/view': put: tags: - database-endpoint - summary: Update user password in database - operationId: update + summary: Refresh database views metadata + operationId: refreshViewMetadata parameters: - name: databaseId in: path @@ -2063,41 +2624,46 @@ paths: schema: type: integer format: int64 - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/UpdateUserPasswordDto' - required: true responses: - "404": + '200': + description: Refreshed database views metadata + content: + application/json: + schema: + $ref: '#/components/schemas/DatabaseDto' + '403': + description: Refresh view metadata is not permitted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '404': description: Failed to find database in metadata database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Updated user password in database - "503": - description: Failed to communicate with database + '502': + description: Connection to search service failed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "417": - description: Failed to update user password in database + '503': + description: Failed to save in search service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: + - bearerAuth: [] - basicAuth: [] - /api/database/{databaseId}/view/{viewId}: - delete: + '/api/database/{databaseId}/metadata/table': + put: tags: - - view-endpoint - summary: Delete view - operationId: delete + - database-endpoint + summary: Refresh database tables metadata + operationId: refreshTableMetadata parameters: - name: databaseId in: path @@ -2105,48 +2671,52 @@ paths: schema: type: integer format: int64 - - name: viewId - in: path - required: true - schema: - type: integer - format: int64 responses: - "202": - description: Deleted view - "409": - description: View schema could not be mapped + '200': + description: Refreshed database tables metadata + content: + application/json: + schema: + $ref: '#/components/schemas/DatabaseDto' + '400': + description: Failed to parse payload at search service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to establish connection with the metadata service + '403': + description: Not allowed to refresh table metadata content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find view in metadata database + '404': + description: Failed to fin user/database in metadata database + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '502': + description: Connection to search service failed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Database schema is malformed + '503': + description: Failed to save in search service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - - basicAuth: [] - bearerAuth: [] - /api/database/{databaseId}/table/{tableId}/suggest: - get: + - basicAuth: [] + '/api/database/{databaseId}/image': + put: tags: - - table-endpoint - summary: Suggest table semantics - operationId: analyseTable + - database-endpoint + summary: Update database image + operationId: modifyImage parameters: - name: databaseId in: path @@ -2154,41 +2724,45 @@ paths: schema: type: integer format: int64 - - name: tableId - in: path - required: true - schema: - type: integer - format: int64 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/DatabaseModifyImageDto' + required: true responses: - "200": - description: Suggested table semantics successfully + '202': + description: Modify of image was successful content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/TableColumnEntityDto' - "400": - description: Failed to parse statistic in search service + $ref: '#/components/schemas/DatabaseDto' + '403': + description: Modify of image is not permitted content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "422": - description: Ontology does not have rdf or sparql endpoint + '404': + description: Database or user could not be found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find database/table in metadata database + '410': + description: File was not found in the Storage Service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "417": - description: Generated query is malformed + '502': + description: Connection to search service failed + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '503': + description: Failed to save in search service content: application/json: schema: @@ -2196,289 +2770,314 @@ paths: security: - bearerAuth: [] - basicAuth: [] - /api/database/{databaseId}/table/{tableId}/column/{columnId}/suggest: + /api/user: get: tags: - - table-endpoint - summary: Suggest table column semantics - operationId: analyseTableColumn - parameters: - - name: databaseId - in: path - required: true - schema: - type: integer - format: int64 - - name: tableId - in: path - required: true - schema: - type: integer - format: int64 - - name: columnId - in: path - required: true - schema: - type: integer - format: int64 + - user-endpoint + summary: Find all users + operationId: findAll responses: - "200": - description: Suggested table column semantics successfully + '200': + description: List users content: application/json: schema: type: array items: - $ref: '#/components/schemas/TableColumnEntityDto' - "422": - description: Ontology does not have rdf or sparql endpoint + $ref: '#/components/schemas/UserBriefDto' + post: + tags: + - user-endpoint + summary: Create user + operationId: create1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SignupRequestDto' + required: true + responses: + '201': + description: Created user content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find database/table in metadata database + $ref: '#/components/schemas/UserBriefDto' + '400': + description: Parameters are not well-formed (likely email) + content: + application/json: {} + '404': + description: default role not found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Generated query is malformed + '409': + description: User with username already exists content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - security: - - bearerAuth: [] - - basicAuth: [] - /api/container/{containerId}: - get: - tags: - - container-endpoint - summary: Find some container - operationId: findById_3 - parameters: - - name: containerId - in: path - required: true - schema: - type: integer - format: int64 - responses: - "200": - description: Found container + '417': + description: User with e-mail already exists content: application/json: schema: - $ref: '#/components/schemas/ContainerDto' - "404": - description: Container image could not be found + $ref: '#/components/schemas/ApiErrorDto' + '502': + description: Failed to create in auth service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - delete: - tags: - - container-endpoint - summary: Delete some container - operationId: delete_6 - parameters: - - name: containerId - in: path - required: true - schema: - type: integer - format: int64 - responses: - "404": - description: Container not found + '503': + description: Failed to create in auth service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Deleted container successfully - content: - '*/*': - schema: - type: object - security: - - bearerAuth: [] - - basicAuth: [] - /api/concept: + /api/ontology: get: tags: - - concept-endpoint - summary: List semantic concepts - operationId: findAll_7 + - ontology-endpoint + summary: List all ontologies + operationId: findAll_2 responses: - "200": - description: Find all semantic concepts + '200': + description: List all ontologies content: application/json: schema: type: array items: - $ref: '#/components/schemas/ConceptDto' - /api/database/{databaseId}/view/{viewId}/data: - get: + $ref: '#/components/schemas/OntologyDto' + post: tags: - - view-endpoint - summary: Retrieve view data - operationId: getData - parameters: - - name: databaseId - in: path - required: true - schema: - type: integer - format: int64 - - name: viewId - in: path - required: true - schema: - type: integer - format: int64 - - name: page - in: query - required: false - schema: - type: integer - format: int64 - - name: size - in: query - required: false - schema: - type: integer - format: int64 - - name: timestamp + - ontology-endpoint + summary: Register a new ontology + operationId: create_1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/OntologyCreateDto' + required: true + responses: + '201': + description: Registered ontology successfully + content: + application/json: + schema: + $ref: '#/components/schemas/OntologyDto' + security: + - bearerAuth: [] + - basicAuth: [] + /api/message: + get: + tags: + - message-endpoint + summary: Find maintenance messages + operationId: list_2 + parameters: + - name: filter in: query required: false schema: type: string - format: date-time responses: - "403": - description: Not allowed to retrieve view data + '200': + description: List messages content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "409": - description: View schema could not be mapped + type: array + items: + $ref: '#/components/schemas/BannerMessageDto' + post: + tags: + - message-endpoint + summary: Create maintenance message + operationId: create_2 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/BannerMessageCreateDto' + required: true + responses: + '201': + description: Created message content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to establish connection with the metadata service + $ref: '#/components/schemas/BannerMessageBriefDto' + security: + - bearerAuth: [] + - basicAuth: [] + /api/image: + get: + tags: + - image-endpoint + summary: Find all images + operationId: findAll_3 + responses: + '200': + description: List images content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find view in metadata database + type: array + items: + $ref: '#/components/schemas/ContainerImage' + post: + tags: + - image-endpoint + summary: Create image + operationId: create_3 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ImageCreateDto' + required: true + responses: + '201': + description: Created image content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Request pagination is malformed + $ref: '#/components/schemas/ImageDto' + '400': + description: Image specification is invalid content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Retrieved view data + '409': + description: Image already exists content: application/json: schema: - $ref: '#/components/schemas/QueryResultDto' + $ref: '#/components/schemas/ApiErrorDto' security: - - basicAuth: [] - bearerAuth: [] - head: + - basicAuth: [] + /api/identifier: + get: tags: - - view-endpoint - summary: Retrieve view data - operationId: getData_1 + - identifier-endpoint + summary: Find all identifiers + operationId: findAll_4 parameters: - - name: databaseId - in: path - required: true + - name: dbid + in: query + required: false schema: type: integer format: int64 - - name: viewId - in: path - required: true + - name: qid + in: query + required: false schema: type: integer format: int64 - - name: page + - name: vid in: query required: false schema: type: integer format: int64 - - name: size + - name: tid in: query required: false schema: type: integer format: int64 - - name: timestamp - in: query - required: false + - name: Accept + in: header + required: true schema: type: string - format: date-time responses: - "403": - description: Not allowed to retrieve view data + '200': + description: Found identifiers successfully + content: + application/json: + schema: + type: string + application/ld+json: + schema: + type: string + '406': + description: 'Identifier could not be exported, the requested style is not known' content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "409": - description: View schema could not be mapped + post: + tags: + - identifier-endpoint + summary: Draft identifier + operationId: create_4 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/IdentifierCreateDto' + required: true + responses: + '201': + description: Drafted identifier + content: + application/json: + schema: + $ref: '#/components/schemas/IdentifierDto' + '400': + description: Identifier form contains invalid request data content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to establish connection with the metadata service + '403': + description: Insufficient access rights or authorities content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find view in metadata database + '404': + description: 'Failed to find database, table or view' content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Request pagination is malformed + '405': + description: Creating identifier not permitted content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Retrieved view data + '502': + description: Connection to search service failed content: application/json: schema: - $ref: '#/components/schemas/QueryResultDto' + $ref: '#/components/schemas/ApiErrorDto' + '503': + description: Failed to save in search service + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' security: - - basicAuth: [] - bearerAuth: [] - /api/database/{databaseId}/table/{tableId}/data: + - basicAuth: [] + '/api/database/{databaseId}/view': get: tags: - - table-endpoint - summary: Retrieve table data - operationId: getData_2 + - view-endpoint + summary: Find all views + operationId: findAll_5 parameters: - name: databaseId in: path @@ -2486,63 +3085,29 @@ paths: schema: type: integer format: int64 - - name: tableId - in: path - required: true - schema: - type: integer - format: int64 - - name: timestamp - in: query - required: false - schema: - type: string - format: date-time - - name: page - in: query - required: false - schema: - type: integer - format: int64 - - name: size - in: query - required: false - schema: - type: integer - format: int64 responses: - "200": - description: Retrieved table data - content: - application/json: - schema: - $ref: '#/components/schemas/QueryResultDto' - "404": - description: Failed to find table in metadata database - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Request pagination or table data select query is malformed + '200': + description: Find views successfully content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to establish connection with the metadata service + type: array + items: + $ref: '#/components/schemas/ViewBriefDto' + '404': + description: Database or user could not be found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - - basicAuth: [] - bearerAuth: [] - put: + - basicAuth: [] + post: tags: - - table-endpoint - summary: Update table data - operationId: updateTuple + - view-endpoint + summary: Create a view + operationId: create_6 parameters: - name: databaseId in: path @@ -2550,53 +3115,76 @@ paths: schema: type: integer format: int64 - - name: tableId - in: path - required: true - schema: - type: integer - format: int64 requestBody: content: application/json: schema: - $ref: '#/components/schemas/TupleUpdateDto' + $ref: '#/components/schemas/ViewCreateDto' required: true responses: - "403": - description: Update table data not allowed + '201': + description: Create view successfully + content: + application/json: + schema: + $ref: '#/components/schemas/ViewBriefDto' + '400': + description: Create view query is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find table in metadata database + '401': + description: Credentials missing content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Updated table data - "400": - description: Request pagination or table data select query is malformed + '403': + description: Credentials missing content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to establish connection with the metadata service + '404': + description: Failed to find database/user in metadata database. + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '405': + description: Create view is not permitted + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '423': + description: Create view resulted in an invalid query statement + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '502': + description: Connection to search service failed + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' + '503': + description: Failed to save in search service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - - basicAuth: [] - bearerAuth: [] - post: + - basicAuth: [] + '/api/database/{databaseId}/table': + get: tags: - table-endpoint - summary: Create table data - operationId: createTuple + summary: List all tables + operationId: list_4 parameters: - name: databaseId in: path @@ -2604,53 +3192,35 @@ paths: schema: type: integer format: int64 - - name: tableId - in: path - required: true - schema: - type: integer - format: int64 - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/TupleDto' - required: true responses: - "403": - description: Create table data not allowed - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find table in metadata database + '200': + description: List tables content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "201": - description: Created table data - "400": - description: Request pagination or table data select query is malformed + type: array + items: + $ref: '#/components/schemas/TableBriefDto' + '403': + description: List tables not permitted content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to establish connection with the metadata service + '404': + description: Database could not be found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - - basicAuth: [] - bearerAuth: [] - delete: + - basicAuth: [] + post: tags: - table-endpoint - summary: Delete table data - operationId: deleteTuple + summary: Create a table + operationId: create_7 parameters: - name: databaseId in: path @@ -2658,312 +3228,278 @@ paths: schema: type: integer format: int64 - - name: tableId - in: path - required: true - schema: - type: integer - format: int64 requestBody: content: application/json: schema: - $ref: '#/components/schemas/TupleDeleteDto' + $ref: '#/components/schemas/TableCreateDto' required: true responses: - "403": - description: Delete table data not allowed + '201': + description: Created a new table content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find table in metadata database + $ref: '#/components/schemas/TableBriefDto' + '400': + description: Create table query is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Deleted table data - "400": - description: Request pagination or table data select query is malformed + '403': + description: Create table not permitted content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to establish connection with the metadata service + '404': + description: 'Database, container or user could not be found' content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - security: - - basicAuth: [] - - bearerAuth: [] - head: - tags: - - table-endpoint - summary: Retrieve table data - operationId: getData_3 - parameters: - - name: databaseId - in: path - required: true - schema: - type: integer - format: int64 - - name: tableId - in: path - required: true - schema: - type: integer - format: int64 - - name: timestamp - in: query - required: false - schema: - type: string - format: date-time - - name: page - in: query - required: false - schema: - type: integer - format: int64 - - name: size - in: query - required: false - schema: - type: integer - format: int64 - responses: - "200": - description: Retrieved table data - content: - application/json: - schema: - $ref: '#/components/schemas/QueryResultDto' - "404": - description: Failed to find table in metadata database + '409': + description: Create table conflicts with existing table name content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Request pagination or table data select query is malformed + '502': + description: Connection to search service failed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to establish connection with the metadata service + '503': + description: Failed to save in search service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - - basicAuth: [] - bearerAuth: [] - /api/database/{databaseId}/subset/{subsetId}/data: + - basicAuth: [] + /api/container: get: tags: - - subset-endpoint - summary: Retrieved subset data - operationId: getData_4 + - container-endpoint + summary: Find all containers + operationId: findAll_6 parameters: - - name: databaseId - in: path - required: true - schema: - type: integer - format: int64 - - name: subsetId - in: path - required: true - schema: - type: integer - format: int64 - - name: page - in: query - required: false - schema: - type: integer - format: int64 - - name: size + - name: limit in: query required: false schema: type: integer - format: int64 + format: int32 responses: - "400": - description: Malformed select query + '200': + description: List containers content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Not allowed to retrieve subset data + type: array + items: + type: string + post: + tags: + - container-endpoint + summary: Create container + operationId: create_9 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ContainerCreateDto' + required: true + responses: + '201': + description: Created a new container content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find database in metadata database or query in query store of the data database + $ref: '#/components/schemas/ContainerBriefDto' + '404': + description: Container image or user could not be found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to communicate with database + '409': + description: Container name already exists content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Retrieved subset data - content: - application/json: - schema: - $ref: '#/components/schemas/QueryResultDto' security: - bearerAuth: [] - basicAuth: [] - head: + /api/unit: + get: tags: - - subset-endpoint - summary: Retrieved subset data - operationId: getData_5 + - unit-endpoint + summary: List semantic units + operationId: findAll_1 + responses: + '200': + description: Find all semantic units + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/UnitDto' + '/api/ontology/{ontologyId}/entity': + get: + tags: + - ontology-endpoint + summary: Find entities + operationId: find_4 parameters: - - name: databaseId - in: path - required: true - schema: - type: integer - format: int64 - - name: subsetId + - name: ontologyId in: path required: true schema: type: integer format: int64 - - name: page + - name: label in: query required: false schema: - type: integer - format: int64 - - name: size + type: string + - name: uri in: query required: false schema: - type: integer - format: int64 + type: string responses: - "400": - description: Malformed select query + '200': + description: Found entities content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Not allowed to retrieve subset data + type: array + items: + $ref: '#/components/schemas/EntityDto' + '400': + description: Filter params are invalid content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find database in metadata database or query in query store of the data database + '404': + description: Could not find ontology content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to communicate with database + '417': + description: Generated query or uri is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Retrieved subset data + '422': + description: Ontology does not have rdf or sparql endpoint content: application/json: schema: - $ref: '#/components/schemas/QueryResultDto' + $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] - basicAuth: [] - /api/database/{databaseId}/subset/{queryId}: - put: + /api/oai: + get: tags: - - subset-endpoint - summary: Persist subset - operationId: persist + - metadata-endpoint + summary: Get the record + operationId: identify_1_1_1_1 parameters: - - name: databaseId - in: path + - name: verb + in: query + - name: parameters + in: query required: true schema: - type: integer - format: int64 - - name: queryId + $ref: '#/components/schemas/OaiListIdentifiersParameters' + responses: + '200': + description: List containers + content: + text/xml: {} + '/api/message/message/{messageId}': + get: + tags: + - message-endpoint + summary: Find one maintenance message + operationId: find_5 + parameters: + - name: messageId in: path required: true schema: type: integer format: int64 - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/QueryPersistDto' - required: true responses: - "202": - description: Persisted subset - content: - application/json: - schema: - $ref: '#/components/schemas/QueryDto' - "400": - description: Malformed select query + '200': + description: Get messages content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find database in metadata database or query in query store of the data database + $ref: '#/components/schemas/BannerMessageDto' + '404': + description: Could not find message content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to communicate with database + /api/license: + get: + tags: + - license-endpoint + summary: Get all licenses + operationId: list_3 + responses: + '200': + description: List of licenses content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Not allowed to persist subset + type: array + items: + type: string + /api/identifier/retrieve: + get: + tags: + - identifier-endpoint + summary: Retrieve metadata from identifier + operationId: retrieve + parameters: + - name: url + in: query + required: true + schema: + type: string + responses: + '200': + description: Retrieved metadata from identifier content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "417": - description: Failed to persist subset + $ref: '#/components/schemas/IdentifierDto' + '404': + description: Failed to find metadata for identifier content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - security: - - bearerAuth: [] - - basicAuth: [] - /api/database/{databaseId}/table/{tableId}/data/import: - post: + '/api/database/{databaseId}': + get: tags: - - table-endpoint - summary: Import dataset - operationId: importData + - database-endpoint + summary: Find some database + operationId: findById_1 parameters: - name: databaseId in: path @@ -2971,54 +3507,40 @@ paths: schema: type: integer format: int64 - - name: tableId - in: path - required: true - schema: - type: integer - format: int64 - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/ImportCsvDto' - required: true responses: - "403": - description: Import table dataset not allowed + '200': + description: Database found successfully content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find table in metadata database + $ref: '#/components/schemas/DatabaseDto' + '404': + description: Database or exchange could not be found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to establish connection with the metadata service + '502': + description: Connection to the broker service could not be established content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "400": - description: Import dataset query is malformed + '503': + description: Failed to find queue information in broker service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "202": - description: Import dataset successfully security: - - basicAuth: [] - bearerAuth: [] - /api/database/{databaseId}/subset: + - basicAuth: [] + '/api/database/{databaseId}/view/{viewId}': get: tags: - - subset-endpoint - summary: Find subsets - operationId: list + - view-endpoint + summary: Find one view + operationId: find_7 parameters: - name: databaseId in: path @@ -3026,44 +3548,39 @@ paths: schema: type: integer format: int64 - - name: persisted - in: query - required: false + - name: viewId + in: path + required: true schema: - type: boolean + type: integer + format: int64 responses: - "404": - description: Failed to find database in metadata database or query in query store of the data database + '200': + description: Find view successfully content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to communicate with database + $ref: '#/components/schemas/ViewDto' + '403': + description: Find view is not permitted content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Not allowed to find subsets + '404': + description: 'Database, view or user could not be found' content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Found subsets - content: - application/json: - schema: - type: string security: - - basicAuth: [] - bearerAuth: [] - post: + - basicAuth: [] + delete: tags: - - subset-endpoint - summary: Create subset - operationId: create_3 + - view-endpoint + summary: Delete one view + operationId: delete_4 parameters: - name: databaseId in: path @@ -3071,82 +3588,66 @@ paths: schema: type: integer format: int64 - - name: page - in: query - required: false - schema: - type: integer - format: int64 - - name: size - in: query - required: false + - name: viewId + in: path + required: true schema: type: integer format: int64 - - name: timestamp - in: query - required: false - schema: - type: string - format: date-time - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/ExecuteStatementDto' - required: true responses: - "400": - description: Malformed select query + '202': + description: Delete view successfully + '400': + description: Delete view query is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find database in metadata database or query in query store of the data database + '403': + description: Deletion not allowed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to communicate with database + '404': + description: 'Database, view or user could not be found' content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Not allowed to find subset + '405': + description: Delete view is not permitted content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "201": - description: Created subset + '423': + description: Delete view resulted in an invalid query statement content: application/json: schema: - $ref: '#/components/schemas/QueryResultDto' - "417": - description: Failed to insert query into query store of data database + $ref: '#/components/schemas/ApiErrorDto' + '502': + description: Connection to search service failed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "501": - description: Failed to execute query as it contains non-supported keywords + '503': + description: Failed to save in search service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - - basicAuth: [] - bearerAuth: [] - /api/database/{databaseId}/table/{tableId}/history: + - basicAuth: [] + '/api/database/{databaseId}/table/{tableId}/suggest': get: tags: - table-endpoint - summary: Find table history - operationId: getHistory + summary: Suggest table semantics + operationId: analyseTable parameters: - name: databaseId in: path @@ -3161,39 +3662,47 @@ paths: type: integer format: int64 responses: - "404": - description: Failed to find table history in data database + '200': + description: Suggested table semantics successfully + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/TableColumnEntityDto' + '400': + description: Failed to parse statistic in search service content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Found table history + '404': + description: Failed to find database/table in metadata database content: application/json: schema: - type: string - "403": - description: Find table history not allowed + $ref: '#/components/schemas/ApiErrorDto' + '417': + description: Generated query is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to establish connection with the metadata service + '422': + description: Ontology does not have rdf or sparql endpoint content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - - basicAuth: [] - bearerAuth: [] - /api/database/{databaseId}/table/{tableId}/export: + - basicAuth: [] + '/api/database/{databaseId}/table/{tableId}/column/{columnId}/suggest': get: tags: - table-endpoint - summary: Export table data - operationId: exportData + summary: Suggest table column semantics + operationId: analyseTableColumn parameters: - name: databaseId in: path @@ -3207,264 +3716,138 @@ paths: schema: type: integer format: int64 - - name: timestamp - in: query - required: false + - name: columnId + in: path + required: true schema: - type: string - format: date-time + type: integer + format: int64 responses: - "404": - description: Failed to find table in metadata database - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Exported table data + '200': + description: Suggested table column semantics successfully content: application/json: schema: - type: string - format: binary - "400": - description: Request pagination or table data select query is malformed + type: array + items: + $ref: '#/components/schemas/TableColumnEntityDto' + '400': + description: Generated query is malformed content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to establish connection with the metadata service + '404': + description: Failed to find database/table in metadata database content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Export table data not allowed + '422': + description: Ontology does not have rdf or sparql endpoint content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' security: - - basicAuth: [] - bearerAuth: [] - /api/database/{databaseId}/subset/{subsetId}: + - basicAuth: [] + '/api/container/{containerId}': get: tags: - - subset-endpoint - summary: Find subset - operationId: findById + - container-endpoint + summary: Find some container + operationId: findById_3 parameters: - - name: databaseId - in: path - required: true - schema: - type: integer - format: int64 - - name: subsetId + - name: containerId in: path required: true schema: type: integer format: int64 - - name: timestamp - in: query - required: false - schema: - type: string - format: date-time responses: - "400": - description: Malformed select query - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' - "404": - description: Failed to find database in metadata database or query in query store of the data database - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' - "503": - description: Failed to communicate with database - content: - application/json: - schema: - $ref: '#/components/schemas/ApiErrorDto' - "403": - description: Not allowed to find subset + '200': + description: Found container content: application/json: schema: - $ref: '#/components/schemas/ApiErrorDto' - "406": - description: Failed to find acceptable representation + $ref: '#/components/schemas/ContainerDto' + '404': + description: Container image could not be found content: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' - "200": - description: Found subset - content: - application/json: - schema: - $ref: '#/components/schemas/QueryDto' - text/csv: {} - security: - - basicAuth: [] - - bearerAuth: [] - /api/search: - get: - consumes: - - application/json - description: Performs a fuzzy search - operationId: post_fuzzy_search + delete: + tags: + - container-endpoint + summary: Delete some container + operationId: delete_6 parameters: - - in: query + - name: containerId + in: path required: true schema: - properties: - q: - example: air quality - type: string - type: string - produces: - - application/json - responses: - "200": - content: - application/json: - schema: - properties: - results: - items: - type: object - type: array - type: object - description: OK, contains the elements formatted as an array of JSON arrays - "415": - description: Wrong accept type - summary: Performs a fuzzy search - tags: - - search-endpoint - /api/search/database/{database_id}: - delete: - consumes: - - application/json - description: Deletes a database - operationId: delete_database - produces: - - application/json + type: integer + format: int64 responses: - "202": + '202': + description: Deleted container successfully content: - application/json: + '*/*': schema: - properties: - id: - example: 1 - implementation: int64 - type: integer - required: - - id type: object - description: Deleted database successfully - "404": + '404': + description: Container not found content: application/json: schema: - properties: - message: - example: Message - type: string - success: - example: false - type: boolean - required: - - success - - message - type: object - description: Database not found + $ref: '#/components/schemas/ApiErrorDto' security: - bearerAuth: [] - basicAuth: [] - summary: Deletes a database + /api/concept: + get: tags: - - database-endpoint - put: + - concept-endpoint + summary: List semantic concepts + operationId: findAll_7 + responses: + '200': + description: Find all semantic concepts + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/ConceptDto' + /api/search: + get: consumes: - application/json - description: Updates a database - operationId: update_database + description: Performs a fuzzy search + operationId: post_fuzzy_search parameters: - - in: body - name: body + - in: query + name: q required: true schema: - properties: - internal_name: - example: air_quality_abcd - type: string - name: - example: Air Quality - type: string - type: object + type: string produces: - application/json responses: - "202": - content: - application/json: - schema: - properties: - id: - example: 1 - implementation: int64 - type: integer - required: - - id - type: object - description: Updated database successfully - "400": - content: - application/json: - schema: - properties: - message: - example: Message - type: string - success: - example: false - type: boolean - required: - - success - - message - type: object - description: Invalid schema - "404": + '200': content: application/json: schema: - properties: - message: - example: Message - type: string - success: - example: false - type: boolean - required: - - success - - message - type: object - description: Database not found - security: - - bearerAuth: [] - - basicAuth: [] - summary: Updates a database + $ref: '#/components/schemas/SearchResultDto' + description: 'OK, contains the elements formatted as an array of JSON arrays' + '415': + description: Wrong accept type + summary: Performs a fuzzy search tags: - - database-endpoint - /api/search/{index}: + - search-endpoint + '/api/search/{index}': get: consumes: - application/json @@ -3506,33 +3889,16 @@ paths: produces: - application/json responses: - "200": + '200': content: application/json: schema: - properties: - results: - items: - type: object - type: array - type: - description: Same as the requested type - enum: - - database - - table - - view - - column - - user - - identifier - - concept - - unit - type: string - type: object - description: OK, contains the elements formatted as an array of JSON arrays + $ref: '#/components/schemas/IndexDto' + description: 'OK, contains the elements formatted as an array of JSON arrays' summary: Gets the index tags: - search-endpoint - /api/search/{type}: + '/api/search/{type}': post: consumes: - application/json @@ -3566,17 +3932,11 @@ paths: name: body required: true schema: - properties: - field_value_pairs: - type: object - search_term: - example: air quality - type: string - type: object + $ref: '#/components/schemas/SearchRequestDto' produces: - application/json responses: - "200": + '200': content: application/json: schema: @@ -3598,11 +3958,11 @@ paths: - unit type: string type: object - description: OK, contains the elements formatted as an array of JSON arrays + description: 'OK, contains the elements formatted as an array of JSON arrays' summary: Performs a general search tags: - search-endpoint - /api/search/{type}/fields: + '/api/search/{type}/fields': get: operationId: get_fields parameters: @@ -3622,207 +3982,18 @@ paths: - unit type: string responses: - "200": + '200': content: application/json: schema: - properties: - results: - items: - properties: - attr_friendly_name: - example: Name - type: string - attr_name: - example: name - type: string - type: - description: OpenSearch data types. - example: string - type: string - type: object - type: array - type: object + $ref: '#/components/schemas/IndexFieldsDto' description: List of fields - "404": + '404': description: Invalid type. summary: Get searchable fields tags: - search-endpoint - /health: - get: - consumes: - - application/json - description: | - Return UP if the instance is ready to serve connections. - produces: - - application/json - responses: - "200": - content: - application/json: - schema: - $ref: '#/components/schemas/Health' - description: OK, service is up and running - "404": - description: Service is not yet ready - summary: Return a healthcheck - tags: - - actuator - /api/analyse/database/{database_id}/table/{table_id}/statistics: - get: - operationId: analyse_table_stat - parameters: - - example: 1 - in: path - name: database_id - required: true - schema: - format: int64 - type: integer - - example: 1 - in: path - name: table_id - required: true - schema: - format: int64 - type: integer - responses: - "202": - content: - application/json: - schema: - $ref: '#/components/schemas/TableStats' - description: Determined statistics - "400": - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorDto' - description: Missing parameters - "404": - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorDto' - description: Table not found - security: - - bearerAuth: [] - - basicAuth: [] - summary: Determine table statistics - tags: - - analyse-endpoint - /api/analyse/datatypes: - get: - consumes: - - application/json - description: This is a simple API which returns the datatypes of a (path) csv file - operationId: analyse_datatypes - parameters: - - example: filename_s3_key - in: query - name: filename - required: true - schema: - type: string - - example: ',' - in: query - name: separator - required: true - schema: - type: string - - example: "false" - in: query - name: enum - required: false - schema: - type: boolean - - example: "2.5" - in: query - name: enum_tol - required: false - schema: - type: float - produces: - - application/json - responses: - "202": - content: - application/json: - schema: - $ref: '#/components/schemas/DataTypesDto' - description: Determined data types successfully - "400": - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorDto' - description: Failed to determine data types - "404": - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorDto' - description: Failed to find file in Storage Service - "500": - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorDto' - description: Unexpected system error - summary: Determine datatypes - tags: - - analyse-endpoint - /api/analyse/keys: - get: - consumes: - - application/json - description: This is a simple API which returns the primary keys + ranking of a (path) csv file - operationId: analyse_keys - parameters: - - example: filename_s3_key - in: query - name: filename - required: true - schema: - type: string - - example: ',' - in: query - name: separator - required: true - schema: - type: string - produces: - - application/json - responses: - "202": - content: - application/json: - schema: - $ref: '#/components/schemas/KeysDto' - description: Determined keys successfully - "400": - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorDto' - description: Failed to determine keys - "404": - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorDto' - description: Failed to find file in Storage Service or is empty - "500": - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorDto' - description: Unexpected system error - summary: Determine primary keys - tags: - - analyse-endpoint - /sidecar/export/{filename}: + '/sidecar/export/{filename}': post: consumes: - application/json @@ -3836,10 +4007,10 @@ paths: produces: - application/json responses: - "202": + '202': content: {} description: Exported the .csv - "400": + '400': description: The Storage Service could not be contacted or .csv was not found. security: - bearerAuth: [] @@ -3847,7 +4018,7 @@ paths: summary: Exports a .csv to the Storage Service tags: - sidecar - /sidecar/import/{filename}: + '/sidecar/import/{filename}': post: consumes: - application/json @@ -3861,10 +4032,10 @@ paths: produces: - application/json responses: - "202": + '202': content: {} description: Imported the .csv - "400": + '400': description: The Storage Service could not be contacted or .csv was not found. security: - bearerAuth: [] @@ -3872,3 +4043,5627 @@ paths: summary: Imports a .csv from the Storage Service tags: - sidecar +components: + securitySchemes: + basicAuth: + in: header + scheme: basic + type: http + bearerAuth: + bearerFormat: JWT + in: header + scheme: bearer + type: http + schemas: + DataTypesDto: + properties: + columns: + $ref: '#/components/schemas/SuggestedColumnDto' + line_termination: + example: "\r\n" + type: string + separator: + example: ',' + type: string + type: object + ErrorDto: + properties: + message: + example: Message + type: string + success: + example: false + type: boolean + type: object + KeysDto: + properties: + keys: + items: + properties: + column_name: + format: int64 + type: integer + type: array + required: + - keys + type: object + SuggestedColumnDto: + properties: + column_name: + type: string + type: object + QueryResultDto: + required: + - headers + - id + - result + type: object + properties: + result: + type: array + items: + type: object + additionalProperties: + type: object + headers: + type: array + items: + type: object + additionalProperties: + type: integer + format: int32 + id: + type: integer + format: int64 + ApiErrorDto: + required: + - code + - message + - status + type: object + properties: + status: + type: string + example: NOT_FOUND + enum: + - 100 CONTINUE + - 101 SWITCHING_PROTOCOLS + - 102 PROCESSING + - 103 EARLY_HINTS + - 103 CHECKPOINT + - 200 OK + - 201 CREATED + - 202 ACCEPTED + - 203 NON_AUTHORITATIVE_INFORMATION + - 204 NO_CONTENT + - 205 RESET_CONTENT + - 206 PARTIAL_CONTENT + - 207 MULTI_STATUS + - 208 ALREADY_REPORTED + - 226 IM_USED + - 300 MULTIPLE_CHOICES + - 301 MOVED_PERMANENTLY + - 302 FOUND + - 302 MOVED_TEMPORARILY + - 303 SEE_OTHER + - 304 NOT_MODIFIED + - 305 USE_PROXY + - 307 TEMPORARY_REDIRECT + - 308 PERMANENT_REDIRECT + - 400 BAD_REQUEST + - 401 UNAUTHORIZED + - 402 PAYMENT_REQUIRED + - 403 FORBIDDEN + - 404 NOT_FOUND + - 405 METHOD_NOT_ALLOWED + - 406 NOT_ACCEPTABLE + - 407 PROXY_AUTHENTICATION_REQUIRED + - 408 REQUEST_TIMEOUT + - 409 CONFLICT + - 410 GONE + - 411 LENGTH_REQUIRED + - 412 PRECONDITION_FAILED + - 413 PAYLOAD_TOO_LARGE + - 413 REQUEST_ENTITY_TOO_LARGE + - 414 URI_TOO_LONG + - 414 REQUEST_URI_TOO_LONG + - 415 UNSUPPORTED_MEDIA_TYPE + - 416 REQUESTED_RANGE_NOT_SATISFIABLE + - 417 EXPECTATION_FAILED + - 418 I_AM_A_TEAPOT + - 419 INSUFFICIENT_SPACE_ON_RESOURCE + - 420 METHOD_FAILURE + - 421 DESTINATION_LOCKED + - 422 UNPROCESSABLE_ENTITY + - 423 LOCKED + - 424 FAILED_DEPENDENCY + - 425 TOO_EARLY + - 426 UPGRADE_REQUIRED + - 428 PRECONDITION_REQUIRED + - 429 TOO_MANY_REQUESTS + - 431 REQUEST_HEADER_FIELDS_TOO_LARGE + - 451 UNAVAILABLE_FOR_LEGAL_REASONS + - 500 INTERNAL_SERVER_ERROR + - 501 NOT_IMPLEMENTED + - 502 BAD_GATEWAY + - 503 SERVICE_UNAVAILABLE + - 504 GATEWAY_TIMEOUT + - 505 HTTP_VERSION_NOT_SUPPORTED + - 506 VARIANT_ALSO_NEGOTIATES + - 507 INSUFFICIENT_STORAGE + - 508 LOOP_DETECTED + - 509 BANDWIDTH_LIMIT_EXCEEDED + - 510 NOT_EXTENDED + - 511 NETWORK_AUTHENTICATION_REQUIRED + message: + type: string + example: Error message + code: + type: string + example: error.service.code + TupleUpdateDto: + required: + - data + - keys + type: object + properties: + data: + type: object + additionalProperties: + type: object + keys: + type: object + additionalProperties: + type: object + QueryPersistDto: + required: + - persist + type: object + properties: + persist: + type: boolean + example: true + CreatorDto: + required: + - creator_name + - id + type: object + properties: + id: + type: integer + format: int64 + firstname: + type: string + example: Josiah + lastname: + type: string + example: Carberry + affiliation: + type: string + example: Brown University + creator_name: + type: string + example: 'Carberry, Josiah' + name_type: + type: string + example: Personal + enum: + - Personal + - Organizational + name_identifier: + type: string + example: 0000-0002-1825-0097 + name_identifier_scheme: + type: string + example: ORCID + enum: + - ORCID + - ROR + - ISNI + - GRID + name_identifier_scheme_uri: + type: string + example: 'https://orcid.org/' + affiliation_identifier: + type: string + example: 'https://ror.org/05gq02987' + affiliation_identifier_scheme: + type: string + example: ROR + enum: + - ROR + - GRID + - ISNI + affiliation_identifier_scheme_uri: + type: string + example: 'https://ror.org/' + IdentifierDescriptionDto: + required: + - id + type: object + properties: + id: + type: integer + format: int64 + description: + type: string + example: 'Air quality reports at Stephansplatz, Vienna' + language: + type: string + example: en + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - 'no' + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + type: + type: string + example: Abstract + enum: + - Abstract + - Methods + - SeriesInformation + - TableOfContents + - TechnicalInfo + - Other + IdentifierDto: + required: + - created + - created_by + - creator + - creators + - database_id + - execution + - id + - last_modified + - publication_year + - publisher + - query + - query_hash + - query_normalized + - titles + - type + type: object + properties: + id: + type: integer + format: int64 + type: + type: string + enum: + - database + - subset + - table + - view + titles: + type: array + items: + $ref: '#/components/schemas/IdentifierTitleDto' + descriptions: + type: array + items: + $ref: '#/components/schemas/IdentifierDescriptionDto' + funders: + type: array + items: + $ref: '#/components/schemas/IdentifierFunderDto' + query: + type: string + example: >- + SELECT `id`, `value`, `location` FROM `air_quality` WHERE `location` + = "09:STEF" + execution: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + doi: + type: string + example: 10.1038/nphys1170 + publisher: + type: string + example: TU Wien + creator: + $ref: '#/components/schemas/UserDto' + language: + type: string + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - 'no' + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + licenses: + type: array + items: + $ref: '#/components/schemas/LicenseDto' + creators: + type: array + items: + $ref: '#/components/schemas/CreatorDto' + status: + type: string + enum: + - draft + - published + created: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + database_id: + type: integer + format: int64 + example: 1 + query_id: + type: integer + format: int64 + example: 1 + table_id: + type: integer + format: int64 + example: 1 + view_id: + type: integer + format: int64 + example: 1 + query_normalized: + type: string + example: >- + SELECT `id`, `value`, `location` FROM `air_quality` WHERE `location` + = "09:STEF" + related_identifiers: + type: array + items: + $ref: '#/components/schemas/RelatedIdentifierDto' + query_hash: + type: string + description: query hash in sha512 + result_hash: + type: string + example: 34fe82cda2c53f13f8d90cfd7a3469e3a939ff311add50dce30d9136397bf8e5 + result_number: + type: integer + format: int64 + example: 1 + publication_day: + type: integer + format: int32 + example: 15 + publication_month: + type: integer + format: int32 + example: 12 + publication_year: + type: integer + format: int32 + example: 2022 + created_by: + type: string + format: uuid + last_modified: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + IdentifierFunderDto: + required: + - funder_name + - id + type: object + properties: + id: + type: integer + format: int64 + funder_name: + type: string + example: European Commission + funder_identifier: + type: string + example: 'http://doi.org/10.13039/501100000780' + funder_identifier_type: + type: string + example: Crossref Funder ID + enum: + - Crossref Funder ID + - ROR + - GND + - ISNI + - Other + scheme_uri: + type: string + example: 'http://doi.org/' + award_number: + type: string + example: '824087' + award_title: + type: string + example: EOSC-Life + IdentifierTitleDto: + required: + - id + type: object + properties: + id: + type: integer + format: int64 + title: + type: string + example: Airquality Demonstrator + language: + type: string + example: en + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - 'no' + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + type: + type: string + enum: + - AlternativeTitle + - Subtitle + - TranslatedTitle + - Other + LicenseDto: + required: + - identifier + - uri + type: object + properties: + identifier: + type: string + example: MIT + uri: + type: string + example: 'https://opensource.org/licenses/MIT' + description: + type: string + example: >- + A short and simple permissive license with conditions only requiring + preservation of copyright and license notices. Licensed works, + modifications, and larger works may be distributed under different + terms and without source code. + QueryDto: + required: + - created + - creator + - database_id + - execution + - id + - identifiers + - is_persisted + - last_modified + - query + - query_hash + - query_normalized + type: object + properties: + id: + type: integer + format: int64 + creator: + $ref: '#/components/schemas/UserDto' + execution: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + query: + type: string + example: SELECT `id` FROM `air_quality` + type: + type: string + example: query + enum: + - query + - view + identifiers: + type: array + items: + $ref: '#/components/schemas/IdentifierDto' + created: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + database_id: + type: integer + format: int64 + query_normalized: + type: string + example: SELECT `id` FROM `air_quality` + query_hash: + type: string + example: 17e682f060b5f8e47ea04c5c4855908b0a5ad612022260fe50e11ecb0cc0ab76 + is_persisted: + type: boolean + example: true + result_hash: + type: string + example: 17e682f060b5f8e47ea04c5c4855908b0a5ad612022260fe50e11ecb0cc0ab76 + result_number: + type: integer + format: int64 + example: 1 + last_modified: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + RelatedIdentifierDto: + required: + - id + - relation + - type + - value + type: object + properties: + id: + type: integer + format: int64 + value: + type: string + example: 10.70124/dc4zh-9ce78 + type: + type: string + example: DOI + enum: + - DOI + - URL + - URN + - ARK + - arXiv + - bibcode + - EAN13 + - EISSN + - Handle + - IGSN + - ISBN + - ISTC + - LISSN + - LSID + - PMID + - PURL + - UPC + - w3id + relation: + type: string + example: Cites + enum: + - IsCitedBy + - Cites + - IsSupplementTo + - IsSupplementedBy + - IsContinuedBy + - Continues + - IsDescribedBy + - Describes + - HasMetadata + - IsMetadataFor + - HasVersion + - IsVersionOf + - IsNewVersionOf + - IsPreviousVersionOf + - IsPartOf + - HasPart + - IsPublishedIn + - IsReferencedBy + - References + - IsDocumentedBy + - Documents + - IsCompiledBy + - Compiles + - IsVariantFormOf + - IsOriginalFormOf + - IsIdenticalTo + - IsReviewedBy + - Reviews + - IsDerivedFrom + - IsSourceOf + - IsRequiredBy + - Requires + - IsObsoletedBy + - Obsoletes + UserAttributesDto: + required: + - language + - theme + type: object + properties: + theme: + type: string + example: light + orcid: + type: string + example: 'https://orcid.org/0000-0002-1825-0097' + affiliation: + type: string + example: Brown University + language: + type: string + example: en + UserDto: + required: + - attributes + - id + - username + type: object + properties: + id: + type: string + format: uuid + example: 1ffc7b0e-9aeb-4e8b-b8f1-68f3936155b4 + username: + type: string + description: Only contains lowercase characters + example: jcarberry + name: + type: string + example: Josiah Carberry + attributes: + $ref: '#/components/schemas/UserAttributesDto' + qualified_name: + type: string + example: Josiah Carberry — @jcarberry + given_name: + type: string + example: Josiah + family_name: + type: string + example: Carberry + TupleDto: + required: + - data + type: object + properties: + data: + type: object + additionalProperties: + type: object + ImportCsvDto: + required: + - location + - separator + type: object + properties: + location: + type: string + example: file.csv + separator: + type: string + example: ',' + quote: + type: string + example: '"' + skip_lines: + minimum: 0 + type: integer + format: int64 + false_element: + type: string + true_element: + type: string + null_element: + type: string + example: NA + line_termination: + type: string + example: \r\n + ExecuteStatementDto: + required: + - statement + type: object + properties: + statement: + type: string + example: SELECT `id` FROM `air_quality` + ColumnStatisticDto: + required: + - mean + - median + - std_dev + - val_max + - val_min + type: object + properties: + mean: + type: number + median: + type: number + std_dev: + type: number + val_min: + type: number + val_max: + type: number + TableStatisticDto: + required: + - columns + - rows + type: object + properties: + columns: + type: object + additionalProperties: + $ref: '#/components/schemas/ColumnStatisticDto' + rows: + type: integer + format: int64 + TupleDeleteDto: + required: + - keys + type: object + properties: + keys: + type: object + additionalProperties: + type: object + ColumnBriefDto: + required: + - column_type + - database_id + - id + - internal_name + - name + - table_id + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + example: date + alias: + type: string + database_id: + type: integer + format: int64 + table_id: + type: integer + format: int64 + internal_name: + type: string + example: mdb_date + column_type: + type: string + example: date + enum: + - char + - varchar + - binary + - varbinary + - tinyblob + - tinytext + - text + - blob + - mediumtext + - mediumblob + - longtext + - longblob + - enum + - set + - bit + - tinyint + - bool + - smallint + - mediumint + - int + - bigint + - float + - double + - decimal + - date + - datetime + - timestamp + - time + - year + ColumnDto: + required: + - auto_generated + - column_type + - database_id + - id + - internal_name + - is_null_allowed + - is_public + - name + - ordinal_position + - table_id + type: object + properties: + id: + type: integer + format: int64 + name: + maxLength: 64 + minLength: 0 + type: string + example: Date + alias: + type: string + size: + type: integer + format: int64 + example: 255 + d: + type: integer + format: int64 + example: 0 + mean: + type: number + example: 45.4 + median: + type: number + example: 51 + concept: + $ref: '#/components/schemas/ConceptDto' + unit: + $ref: '#/components/schemas/UnitDto' + description: + maxLength: 2048 + minLength: 0 + type: string + example: Column comment + enums: + type: array + items: + type: string + sets: + type: array + items: + type: string + database_id: + type: integer + format: int64 + table_id: + type: integer + format: int64 + ordinal_position: + type: integer + format: int32 + example: 0 + internal_name: + maxLength: 64 + minLength: 0 + type: string + example: mdb_date + date_format: + $ref: '#/components/schemas/ImageDateDto' + auto_generated: + type: boolean + example: false + index_length: + type: integer + format: int64 + length: + type: integer + format: int64 + column_type: + type: string + example: string + enum: + - char + - varchar + - binary + - varbinary + - tinyblob + - tinytext + - text + - blob + - mediumtext + - mediumblob + - longtext + - longblob + - enum + - set + - bit + - tinyint + - bool + - smallint + - mediumint + - int + - bigint + - float + - double + - decimal + - date + - datetime + - timestamp + - time + - year + data_length: + type: integer + format: int64 + example: 34300 + max_data_length: + type: integer + format: int64 + example: 34300 + num_rows: + type: integer + format: int64 + example: 32 + val_min: + type: number + example: 0 + val_max: + type: number + example: 100 + std_dev: + type: number + example: 5.32 + is_public: + type: boolean + example: true + is_null_allowed: + type: boolean + example: false + ConceptDto: + required: + - columns + - created + - id + - uri + type: object + properties: + id: + type: integer + format: int64 + uri: + type: string + name: + type: string + description: + type: string + created: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + columns: + type: array + items: + $ref: '#/components/schemas/ColumnBriefDto' + ConstraintsDto: + type: object + properties: + uniques: + type: array + items: + $ref: '#/components/schemas/UniqueDto' + checks: + uniqueItems: true + type: array + items: + type: string + foreign_keys: + type: array + items: + $ref: '#/components/schemas/ForeignKeyDto' + primary_key: + uniqueItems: true + type: array + items: + $ref: '#/components/schemas/PrimaryKeyDto' + ContainerDto: + required: + - created + - host + - id + - image + - internal_name + - name + - sidecar_host + - sidecar_port + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + example: Air Quality + host: + type: string + port: + type: integer + format: int32 + image: + $ref: '#/components/schemas/ImageDto' + created: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + internal_name: + type: string + example: data-db + sidecar_host: + type: string + sidecar_port: + type: integer + format: int32 + ui_host: + type: string + ui_port: + type: integer + format: int32 + DatabaseAccessDto: + required: + - created + - type + - user + type: object + properties: + user: + $ref: '#/components/schemas/UserDto' + type: + type: string + enum: + - read + - write_own + - write_all + created: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + DatabaseDto: + required: + - contact + - container + - created + - creator + - exchange_name + - id + - internal_name + - is_public + - name + - owner + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + example: Air Quality + description: + type: string + example: Air Quality + tables: + type: array + items: + $ref: '#/components/schemas/TableDto' + views: + type: array + items: + $ref: '#/components/schemas/ViewDto' + container: + $ref: '#/components/schemas/ContainerDto' + accesses: + type: array + items: + $ref: '#/components/schemas/DatabaseAccessDto' + identifiers: + type: array + items: + $ref: '#/components/schemas/IdentifierDto' + subsets: + type: array + items: + $ref: '#/components/schemas/IdentifierDto' + creator: + $ref: '#/components/schemas/UserDto' + contact: + $ref: '#/components/schemas/UserDto' + owner: + $ref: '#/components/schemas/UserDto' + image: + type: array + items: + type: string + format: byte + created: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + exchange_name: + type: string + example: dbrepo + exchange_type: + type: string + example: topic + internal_name: + type: string + example: air_quality + is_public: + type: boolean + example: true + ForeignKeyBriefDto: + type: object + properties: + id: + type: integer + format: int64 + ForeignKeyDto: + required: + - name + - referenced_table + - references + - table + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + references: + type: array + items: + $ref: '#/components/schemas/ForeignKeyReferenceDto' + table: + $ref: '#/components/schemas/TableBriefDto' + referenced_table: + $ref: '#/components/schemas/TableBriefDto' + on_update: + type: string + enum: + - restrict + - cascade + - set_null + - no_action + - set_default + on_delete: + type: string + enum: + - restrict + - cascade + - set_null + - no_action + - set_default + ForeignKeyReferenceDto: + required: + - column + - foreign_key + - referenced_column + type: object + properties: + id: + type: integer + format: int64 + column: + $ref: '#/components/schemas/ColumnBriefDto' + foreign_key: + $ref: '#/components/schemas/ForeignKeyBriefDto' + referenced_column: + $ref: '#/components/schemas/ColumnBriefDto' + ImageDateDto: + required: + - created_at + - database_format + - has_time + - id + - unix_format + type: object + properties: + id: + type: integer + format: int64 + database_format: + type: string + example: '%d.%c.%Y' + unix_format: + type: string + example: dd.MM.YYYY + has_time: + type: boolean + example: false + created_at: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + ImageDto: + required: + - default_port + - dialect + - driver_class + - id + - jdbc_method + - name + - registry + - version + type: object + properties: + id: + type: integer + format: int64 + registry: + type: string + example: docker.io/library + name: + type: string + example: mariadb + version: + type: string + example: '10.5' + dialect: + type: string + example: org.hibernate.dialect.MariaDBDialect + driver_class: + type: string + example: org.mariadb.jdbc.Driver + date_formats: + type: array + items: + $ref: '#/components/schemas/ImageDateDto' + jdbc_method: + type: string + example: mariadb + default_port: + type: integer + format: int32 + example: 3306 + PrimaryKeyDto: + required: + - column + - table + type: object + properties: + id: + type: integer + format: int64 + table: + $ref: '#/components/schemas/TableBriefDto' + column: + $ref: '#/components/schemas/ColumnBriefDto' + TableBriefDto: + required: + - database_id + - id + - internal_name + - is_versioned + - name + - owner + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + example: Air Quality + description: + type: string + example: Air Quality in Austria + owner: + $ref: '#/components/schemas/UserBriefDto' + database_id: + type: integer + format: int64 + internal_name: + type: string + example: air_quality + is_versioned: + type: boolean + example: true + TableDto: + required: + - columns + - constraints + - created + - created_by + - creator + - database_id + - id + - internal_name + - is_public + - is_versioned + - name + - owner + - queue_name + - routing_key + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + example: Air Quality + alias: + type: string + identifiers: + type: array + items: + $ref: '#/components/schemas/IdentifierDto' + creator: + $ref: '#/components/schemas/UserDto' + owner: + $ref: '#/components/schemas/UserDto' + description: + maxLength: 2048 + minLength: 0 + type: string + example: Air Quality in Austria + created: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + columns: + type: array + items: + $ref: '#/components/schemas/ColumnDto' + constraints: + $ref: '#/components/schemas/ConstraintsDto' + database_id: + type: integer + format: int64 + internal_name: + type: string + example: air_quality + is_versioned: + type: boolean + example: true + created_by: + type: string + format: uuid + queue_name: + type: string + example: air_quality + queue_type: + type: string + example: quorum + routing_key: + type: string + example: dbrepo.1.2 + is_public: + type: boolean + example: true + num_rows: + type: integer + format: int64 + example: 5 + data_length: + type: integer + description: in bytes + format: int64 + example: 16384 + max_data_length: + type: integer + description: in bytes + format: int64 + example: 0 + avg_row_length: + type: integer + description: in bytes + format: int64 + example: 3276 + UniqueDto: + required: + - columns + - id + - name + - table + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + table: + $ref: '#/components/schemas/TableBriefDto' + columns: + type: array + items: + $ref: '#/components/schemas/ColumnDto' + UnitDto: + required: + - columns + - created + - id + - uri + type: object + properties: + id: + type: integer + format: int64 + uri: + type: string + name: + type: string + description: + type: string + created: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + columns: + type: array + items: + $ref: '#/components/schemas/ColumnBriefDto' + UserBriefDto: + required: + - id + - username + type: object + properties: + id: + type: string + format: uuid + example: 1ffc7b0e-9aeb-4e8b-b8f1-68f3936155b4 + username: + type: string + description: Only contains lowercase characters + example: jcarberry + name: + type: string + example: Josiah Carberry + orcid: + type: string + example: 0000-0002-1825-0097 + qualified_name: + type: string + example: Josiah Carberry — @jcarberry + given_name: + type: string + example: Josiah + family_name: + type: string + example: Carberry + ViewColumnDto: + required: + - auto_generated + - column_type + - database_id + - id + - internal_name + - is_null_allowed + - is_public + - name + - ordinal_position + type: object + properties: + id: + type: integer + format: int64 + name: + maxLength: 64 + minLength: 0 + type: string + example: Date + alias: + type: string + size: + type: integer + format: int64 + example: 255 + d: + type: integer + format: int64 + example: 0 + concept: + $ref: '#/components/schemas/ConceptDto' + unit: + $ref: '#/components/schemas/UnitDto' + description: + maxLength: 2048 + minLength: 0 + type: string + example: Column comment + database_id: + type: integer + format: int64 + ordinal_position: + type: integer + format: int32 + example: 0 + internal_name: + maxLength: 64 + minLength: 0 + type: string + example: mdb_date + date_format: + $ref: '#/components/schemas/ImageDateDto' + auto_generated: + type: boolean + example: false + index_length: + type: integer + format: int64 + length: + type: integer + format: int64 + column_type: + type: string + example: string + enum: + - char + - varchar + - binary + - varbinary + - tinyblob + - tinytext + - text + - blob + - mediumtext + - mediumblob + - longtext + - longblob + - enum + - set + - bit + - tinyint + - bool + - smallint + - mediumint + - int + - bigint + - float + - double + - decimal + - date + - datetime + - timestamp + - time + - year + is_public: + type: boolean + example: true + is_null_allowed: + type: boolean + example: false + ViewDto: + required: + - columns + - created + - creator + - database + - database_id + - id + - internal_name + - name + - query + - query_hash + type: object + properties: + id: + type: integer + format: int64 + database: + $ref: '#/components/schemas/DatabaseDto' + name: + type: string + example: Air Quality + identifiers: + type: array + items: + $ref: '#/components/schemas/IdentifierDto' + query: + type: string + example: SELECT `id` FROM `air_quality` ORDER BY `value` DESC + created: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + creator: + $ref: '#/components/schemas/UserDto' + columns: + type: array + items: + $ref: '#/components/schemas/ViewColumnDto' + database_id: + type: integer + format: int64 + internal_name: + type: string + example: air_quality + is_public: + type: boolean + example: true + initial_view: + type: boolean + description: True if it is the default view for the database + example: true + query_hash: + type: string + example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916 + last_modified: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + UserUpdateDto: + required: + - language + - theme + type: object + properties: + firstname: + type: string + example: Josiah + lastname: + type: string + example: Carberry + affiliation: + type: string + example: Brown University + orcid: + type: string + example: 0000-0002-1825-0097 + theme: + type: string + example: dark + language: + type: string + example: en + UserPasswordDto: + required: + - password + type: object + properties: + password: + type: string + RefreshTokenRequestDto: + required: + - refresh_token + type: object + properties: + refresh_token: + type: string + example: refresh_token + TokenDto: + required: + - access_token + - expires_in + - id_token + - not-before-policy + - refresh_expires_in + - refresh_token + - scope + - session_state + - token_type + type: object + properties: + scope: + type: string + access_token: + type: string + expires_in: + type: integer + format: int64 + refresh_token: + type: string + refresh_expires_in: + type: integer + format: int64 + id_token: + type: string + session_state: + type: string + token_type: + type: string + not-before-policy: + type: integer + format: int64 + OntologyModifyDto: + required: + - prefix + - uri + type: object + properties: + uri: + type: string + example: Ontology URI + prefix: + type: string + example: Ontology prefix + sparql_endpoint: + type: string + example: Ontology SPARQL endpoint + rdf_path: + type: string + example: rdf/om-2.0.rdf + OntologyDto: + required: + - created + - id + - prefix + - rdf + - sparql + - uri + type: object + properties: + id: + type: integer + format: int64 + uri: + type: string + example: 'http://www.wikidata.org/' + prefix: + type: string + example: wd + sparql: + type: boolean + example: true + rdf: + type: boolean + example: false + creator: + $ref: '#/components/schemas/UserBriefDto' + created: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + uri_pattern: + type: string + example: 'http://www.wikidata.org/entity/.*' + sparql_endpoint: + type: string + example: 'https://query.wikidata.org/sparql' + rdf_path: + type: string + example: rdf/om-2.0.rdf + BannerMessageUpdateDto: + required: + - message + - type + type: object + properties: + type: + type: string + enum: + - error + - warning + - info + message: + type: string + example: Maintenance starts on 8am on Monday + link: + type: string + example: 'https://example.com' + link_text: + type: string + example: More + display_start: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + display_end: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + BannerMessageBriefDto: + required: + - message + - type + type: object + properties: + type: + type: string + enum: + - error + - warning + - info + message: + type: string + example: Maintenance starts on 8am on Monday + link: + type: string + example: 'https://example.com' + link_text: + type: string + example: More + ImageChangeDto: + required: + - dialect + - driver_class + - jdbc_method + - registry + type: object + properties: + registry: + type: string + example: docker.io/library + defaultPort: + maximum: 65535 + minimum: 1024 + type: integer + format: int32 + example: 5432 + dialect: + type: string + example: Postgres + driver_class: + type: string + example: org.postgresql.Driver + jdbc_method: + type: string + example: postgresql + CreatorSaveDto: + required: + - creator_name + - id + type: object + properties: + id: + type: integer + format: int64 + example: 1 + firstname: + type: string + example: Josiah + lastname: + type: string + example: Carberry + affiliation: + type: string + example: Wesleyan University + creator_name: + type: string + example: 'Carberry, Josiah' + name_type: + type: string + example: Personal + enum: + - Personal + - Organizational + name_identifier: + type: string + example: 0000-0002-1825-0097 + name_identifier_scheme: + type: string + example: ORCID + enum: + - ORCID + - ROR + - ISNI + - GRID + affiliation_identifier: + type: string + example: 'https://ror.org/04d836q62' + affiliation_identifier_scheme: + type: string + example: ROR + enum: + - ROR + - GRID + - ISNI + IdentifierFunderSaveDto: + required: + - funder_name + - id + type: object + properties: + id: + type: integer + format: int64 + example: 1 + funder_name: + type: string + example: European Commission + funder_identifier: + type: string + example: 'http://doi.org/10.13039/501100000780' + funder_identifier_type: + type: string + example: Crossref Funder ID + enum: + - Crossref Funder ID + - ROR + - GND + - ISNI + - Other + scheme_uri: + type: string + example: 'http://doi.org/' + award_number: + type: string + example: '824087' + award_title: + type: string + example: EOSC-Life + IdentifierSaveDescriptionDto: + required: + - description + - id + type: object + properties: + id: + type: integer + format: int64 + example: 1 + description: + type: string + example: 'Air quality reports at Stephansplatz, Vienna' + language: + type: string + example: en + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - 'no' + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + type: + type: string + example: Abstract + enum: + - Abstract + - Methods + - SeriesInformation + - TableOfContents + - TechnicalInfo + - Other + IdentifierSaveDto: + required: + - creators + - database_id + - id + - publication_year + - publisher + - titles + - type + type: object + properties: + id: + type: integer + format: int64 + example: 1 + type: + type: string + example: database + enum: + - database + - subset + - table + - view + doi: + type: string + example: 10.1111/11111111 + titles: + type: array + items: + $ref: '#/components/schemas/IdentifierSaveTitleDto' + descriptions: + type: array + items: + $ref: '#/components/schemas/IdentifierSaveDescriptionDto' + funders: + type: array + items: + $ref: '#/components/schemas/IdentifierFunderSaveDto' + licenses: + type: array + items: + $ref: '#/components/schemas/LicenseDto' + publisher: + type: string + example: TU Wien + language: + type: string + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - 'no' + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + creators: + type: array + items: + $ref: '#/components/schemas/CreatorSaveDto' + database_id: + type: integer + format: int64 + example: 1 + query_id: + type: integer + format: int64 + view_id: + type: integer + format: int64 + table_id: + type: integer + format: int64 + publication_day: + type: integer + format: int32 + example: 15 + publication_month: + type: integer + format: int32 + example: 12 + publication_year: + type: integer + format: int32 + example: 2022 + related_identifiers: + type: array + items: + $ref: '#/components/schemas/RelatedIdentifierSaveDto' + IdentifierSaveTitleDto: + required: + - id + - title + type: object + properties: + id: + type: integer + format: int64 + example: 1 + title: + type: string + example: Airquality Demonstrator + language: + type: string + example: en + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - 'no' + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + type: + type: string + example: Subtitle + enum: + - AlternativeTitle + - Subtitle + - TranslatedTitle + - Other + RelatedIdentifierSaveDto: + required: + - id + - relation + - type + - value + type: object + properties: + id: + type: integer + format: int64 + example: 1 + value: + type: string + example: 10.70124/dc4zh-9ce78 + type: + type: string + example: DOI + enum: + - DOI + - URL + - URN + - ARK + - arXiv + - bibcode + - EAN13 + - EISSN + - Handle + - IGSN + - ISBN + - ISTC + - LISSN + - LSID + - PMID + - PURL + - UPC + - w3id + relation: + type: string + example: Cites + enum: + - IsCitedBy + - Cites + - IsSupplementTo + - IsSupplementedBy + - IsContinuedBy + - Continues + - IsDescribedBy + - Describes + - HasMetadata + - IsMetadataFor + - HasVersion + - IsVersionOf + - IsNewVersionOf + - IsPreviousVersionOf + - IsPartOf + - HasPart + - IsPublishedIn + - IsReferencedBy + - References + - IsDocumentedBy + - Documents + - IsCompiledBy + - Compiles + - IsVariantFormOf + - IsOriginalFormOf + - IsIdenticalTo + - IsReviewedBy + - Reviews + - IsDerivedFrom + - IsSourceOf + - IsRequiredBy + - Requires + - IsObsoletedBy + - Obsoletes + DatabaseModifyVisibilityDto: + required: + - is_public + type: object + properties: + is_public: + type: boolean + example: true + ColumnSemanticsUpdateDto: + type: object + properties: + concept_uri: + type: string + unit_uri: + type: string + DatabaseTransferDto: + required: + - id + type: object + properties: + id: + type: string + format: uuid + DatabaseModifyImageDto: + type: object + properties: + key: + type: string + UpdateDatabaseAccessDto: + required: + - type + type: object + properties: + type: + type: string + enum: + - read + - write_own + - write_all + SignupRequestDto: + required: + - email + - password + - username + type: object + properties: + username: + pattern: '^[a-z0-9]{3,}$' + type: string + example: user + email: + type: string + example: user@example.com + password: + type: string + LoginRequestDto: + required: + - password + - username + type: object + properties: + username: + type: string + example: user + password: + type: string + OntologyCreateDto: + required: + - prefix + - uri + type: object + properties: + uri: + type: string + example: Ontology URI + prefix: + type: string + example: Ontology prefix + sparql_endpoint: + type: string + example: Ontology SPARQL endpoint + BannerMessageCreateDto: + required: + - message + - type + type: object + properties: + type: + type: string + enum: + - error + - warning + - info + message: + type: string + example: Maintenance starts on 8am on Monday + link: + type: string + example: 'https://example.com' + link_text: + type: string + example: More + display_start: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + display_end: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + ImageCreateDto: + required: + - default_port + - dialect + - driver_class + - jdbc_method + - name + - registry + - version + type: object + properties: + registry: + type: string + example: docker.io/library + name: + type: string + example: mariadb + version: + type: string + dialect: + type: string + driver_class: + type: string + jdbc_method: + type: string + default_port: + maximum: 65535 + minimum: 1024 + type: integer + format: int32 + IdentifierCreateDto: + required: + - creators + - database_id + - publication_year + - publisher + - titles + - type + type: object + properties: + type: + type: string + example: database + enum: + - database + - subset + - table + - view + doi: + type: string + example: 10.1111/11111111 + titles: + type: array + items: + $ref: '#/components/schemas/IdentifierSaveTitleDto' + descriptions: + type: array + items: + $ref: '#/components/schemas/IdentifierSaveDescriptionDto' + funders: + type: array + items: + $ref: '#/components/schemas/IdentifierFunderSaveDto' + licenses: + type: array + items: + $ref: '#/components/schemas/LicenseDto' + publisher: + type: string + example: TU Wien + language: + type: string + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - 'no' + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + creators: + type: array + items: + $ref: '#/components/schemas/CreatorSaveDto' + database_id: + type: integer + format: int64 + example: 1 + query_id: + type: integer + format: int64 + view_id: + type: integer + format: int64 + table_id: + type: integer + format: int64 + publication_day: + type: integer + format: int32 + example: 15 + publication_month: + type: integer + format: int32 + example: 12 + publication_year: + type: integer + format: int32 + example: 2022 + related_identifiers: + type: array + items: + $ref: '#/components/schemas/RelatedIdentifierSaveDto' + DatabaseCreateDto: + required: + - container_id + - is_public + - name + type: object + properties: + name: + type: string + example: Air Quality + container_id: + type: integer + format: int64 + example: 1 + is_public: + type: boolean + example: true + ViewCreateDto: + required: + - is_public + - name + - query + type: object + properties: + name: + maxLength: 64 + minLength: 1 + type: string + example: Air Quality + query: + type: string + example: SELECT `id` FROM `air_quality` + is_public: + type: boolean + example: true + ViewBriefDto: + required: + - created + - creator + - database_id + - id + - internal_name + - name + - query + - query_hash + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + example: Air Quality + identifier: + $ref: '#/components/schemas/IdentifierDto' + query: + type: string + example: SELECT `id` FROM `air_quality` ORDER BY `value` DESC + created: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + creator: + $ref: '#/components/schemas/UserDto' + database_id: + type: integer + format: int64 + internal_name: + type: string + example: air_quality + is_public: + type: boolean + example: true + initial_view: + type: boolean + description: True if it is the default view for the database + example: true + query_hash: + type: string + example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916 + last_modified: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + ColumnCreateDto: + required: + - name + - null_allowed + - type + type: object + properties: + name: + type: string + example: Date + type: + type: string + example: string + enum: + - char + - varchar + - binary + - varbinary + - tinyblob + - tinytext + - text + - blob + - mediumtext + - mediumblob + - longtext + - longblob + - enum + - set + - bit + - tinyint + - bool + - smallint + - mediumint + - int + - bigint + - float + - double + - decimal + - date + - datetime + - timestamp + - time + - year + size: + type: integer + format: int64 + example: 255 + d: + type: integer + format: int64 + example: 0 + description: + maxLength: 2048 + minLength: 0 + type: string + example: Formatted as YYYY-MM-dd + dfid: + type: integer + description: date format id + format: int64 + enums: + type: array + description: 'enum values, only considered when type = ENUM' + items: + type: string + description: 'enum values, only considered when type = ENUM' + sets: + type: array + description: 'set values, only considered when type = SET' + items: + type: string + description: 'set values, only considered when type = SET' + index_length: + type: integer + format: int64 + null_allowed: + type: boolean + example: true + concept_uri: + type: string + unit_uri: + type: string + ConstraintsCreateDto: + required: + - checks + - foreign_keys + - primary_key + - uniques + type: object + properties: + uniques: + type: array + items: + type: array + items: + type: string + checks: + uniqueItems: true + type: array + items: + type: string + foreign_keys: + type: array + items: + $ref: '#/components/schemas/ForeignKeyCreateDto' + primary_key: + uniqueItems: true + type: array + items: + type: string + ForeignKeyCreateDto: + required: + - columns + - referenced_columns + - referenced_table + type: object + properties: + columns: + type: array + items: + type: string + referenced_table: + type: string + referenced_columns: + type: array + items: + type: string + on_update: + type: string + enum: + - restrict + - cascade + - set_null + - no_action + - set_default + on_delete: + type: string + enum: + - restrict + - cascade + - set_null + - no_action + - set_default + TableCreateDto: + required: + - columns + - constraints + - name + type: object + properties: + name: + maxLength: 64 + minLength: 1 + type: string + example: Air Quality + description: + maxLength: 180 + minLength: 0 + type: string + example: Air Quality in Austria + columns: + type: array + items: + $ref: '#/components/schemas/ColumnCreateDto' + constraints: + $ref: '#/components/schemas/ConstraintsCreateDto' + need_sequence: + type: boolean + ContainerCreateDto: + required: + - host + - image_id + - name + - privileged_password + - privileged_username + - sidecar_host + - sidecar_port + type: object + properties: + name: + type: string + example: Air Quality + host: + type: string + description: Hostname of container + port: + type: integer + description: Port of container + format: int32 + image_id: + type: integer + description: Image ID + format: int64 + sidecar_host: + type: string + sidecar_port: + type: integer + format: int32 + ui_host: + type: string + ui_port: + type: integer + format: int32 + privileged_username: + type: string + description: Username of privileged user + example: root + privileged_password: + type: string + description: Password of privileged user + ContainerBriefDto: + required: + - created + - hash + - id + - image + - internal_name + - name + - running + type: object + properties: + id: + type: integer + format: int64 + hash: + type: string + example: f829dd8a884182d0da846f365dee1221fd16610a14c81b8f9f295ff162749e50 + name: + type: string + example: Air Quality + image: + $ref: '#/components/schemas/ImageBriefDto' + running: + type: boolean + example: true + created: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + internal_name: + type: string + example: air-quality + ImageBriefDto: + required: + - id + - jdbc_method + - name + - version + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + example: mariadb + version: + type: string + example: '10.5' + jdbc_method: + type: string + example: mariadb + EntityDto: + required: + - label + - uri + type: object + properties: + uri: + type: string + example: 'https://www.wikidata.org/entity/Q1686799' + label: + type: string + example: Apache Jena + description: + type: string + example: open source semantic web framework for Java + OaiListIdentifiersParameters: + type: object + properties: + metadataPrefix: + type: string + from: + type: string + until: + type: string + set: + type: string + resumptionToken: + type: string + fromDate: + type: string + format: date-time + untilDate: + type: string + format: date-time + parametersString: + type: string + BannerMessageDto: + required: + - id + - message + - type + type: object + properties: + id: + type: integer + format: int64 + type: + type: string + enum: + - error + - warning + - info + message: + type: string + example: Maintenance starts on 8am on Monday + link: + type: string + example: 'https://example.com' + link_text: + type: string + example: More + display_start: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + display_end: + type: string + format: date-time + example: '2021-03-12T15:26:21.000Z' + Constraints: + type: object + properties: + uniques: + type: array + items: + $ref: '#/components/schemas/Unique' + foreignKeys: + type: array + items: + $ref: '#/components/schemas/ForeignKey' + checks: + uniqueItems: true + type: array + items: + type: string + primaryKey: + type: array + items: + $ref: '#/components/schemas/PrimaryKey' + Container: + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + internalName: + type: string + host: + type: string + port: + type: integer + format: int32 + sidecarHost: + type: string + sidecarPort: + type: integer + format: int32 + uiHost: + type: string + uiPort: + type: integer + format: int32 + uiAdditionalFlags: + type: string + databases: + type: array + items: + $ref: '#/components/schemas/Database' + image: + $ref: '#/components/schemas/ContainerImage' + created: + type: string + format: date-time + lastModified: + type: string + format: date-time + privilegedUsername: + type: string + privilegedPassword: + type: string + ContainerImage: + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + registry: + type: string + version: + type: string + driverClass: + type: string + dialect: + type: string + jdbcMethod: + type: string + defaultPort: + type: integer + format: int32 + dateFormats: + type: array + items: + $ref: '#/components/schemas/ContainerImageDate' + containers: + type: array + items: + $ref: '#/components/schemas/Container' + created: + type: string + format: date-time + lastModified: + type: string + format: date-time + ContainerImageDate: + type: object + properties: + id: + type: integer + format: int64 + iid: + type: integer + format: int64 + image: + $ref: '#/components/schemas/ContainerImage' + example: + type: string + hasTime: + type: boolean + databaseFormat: + type: string + unixFormat: + type: string + createdAt: + type: string + format: date-time + Creator: + type: object + properties: + id: + type: integer + format: int64 + firstname: + type: string + lastname: + type: string + creatorName: + type: string + nameType: + type: string + enum: + - PERSONAL + - ORGANIZATIONAL + nameIdentifier: + type: string + nameIdentifierScheme: + type: string + enum: + - ORCID + - ROR + - ISNI + - GRID + nameIdentifierSchemeUri: + type: string + affiliation: + type: string + affiliationIdentifier: + type: string + affiliationIdentifierScheme: + type: string + enum: + - ROR + - GRID + - ISNI + affiliationIdentifierSchemeUri: + type: string + identifier: + $ref: '#/components/schemas/Identifier' + apaName: + type: string + bibtexName: + type: string + ieeeName: + type: string + Database: + type: object + properties: + id: + type: integer + format: int64 + createdBy: + type: string + format: uuid + creator: + $ref: '#/components/schemas/User' + ownedBy: + type: string + format: uuid + owner: + $ref: '#/components/schemas/User' + cid: + type: integer + format: int64 + container: + $ref: '#/components/schemas/Container' + name: + type: string + internalName: + type: string + exchangeName: + type: string + description: + type: string + contactPerson: + type: string + format: uuid + contact: + $ref: '#/components/schemas/User' + identifiers: + type: array + items: + $ref: '#/components/schemas/Identifier' + subsets: + type: array + items: + $ref: '#/components/schemas/Identifier' + tables: + type: array + items: + $ref: '#/components/schemas/Table' + views: + type: array + items: + $ref: '#/components/schemas/View' + accesses: + type: array + items: + $ref: '#/components/schemas/DatabaseAccess' + isPublic: + type: boolean + image: + type: array + items: + type: string + format: byte + created: + type: string + format: date-time + lastModified: + type: string + format: date-time + DatabaseAccess: + type: object + properties: + huserid: + type: string + format: uuid + user: + $ref: '#/components/schemas/User' + hdbid: + type: integer + format: int64 + database: + $ref: '#/components/schemas/Database' + type: + type: string + enum: + - AccessType.READ + - AccessType.WRITE_OWN + - AccessType.WRITE_ALL + created: + type: string + format: date-time + ForeignKey: + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + table: + $ref: '#/components/schemas/Table' + referencedTable: + $ref: '#/components/schemas/Table' + references: + type: array + items: + $ref: '#/components/schemas/ForeignKeyReference' + onUpdate: + type: string + enum: + - ReferenceType.RESTRICT + - ReferenceType.CASCADE + - ReferenceType.SET_NULL + - ReferenceType.NO_ACTION + - ReferenceType.SET_DEFAULT + onDelete: + type: string + enum: + - ReferenceType.RESTRICT + - ReferenceType.CASCADE + - ReferenceType.SET_NULL + - ReferenceType.NO_ACTION + - ReferenceType.SET_DEFAULT + ForeignKeyReference: + type: object + properties: + id: + type: integer + format: int64 + foreignKey: + $ref: '#/components/schemas/ForeignKey' + column: + $ref: '#/components/schemas/TableColumn' + referencedColumn: + $ref: '#/components/schemas/TableColumn' + Identifier: + type: object + properties: + id: + type: integer + format: int64 + queryId: + type: integer + format: int64 + tableId: + type: integer + format: int64 + viewId: + type: integer + format: int64 + creators: + type: array + items: + $ref: '#/components/schemas/Creator' + publisher: + type: string + status: + type: string + enum: + - DRAFT + - PUBLISHED + language: + type: string + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - 'no' + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + titles: + type: array + items: + $ref: '#/components/schemas/IdentifierTitle' + descriptions: + type: array + items: + $ref: '#/components/schemas/IdentifierDescription' + funders: + type: array + items: + $ref: '#/components/schemas/IdentifierFunder' + licenses: + type: array + items: + $ref: '#/components/schemas/License' + type: + type: string + enum: + - DATABASE + - SUBSET + - TABLE + - VIEW + query: + type: string + queryNormalized: + type: string + queryHash: + type: string + resultHash: + type: string + execution: + type: string + format: date-time + resultNumber: + type: integer + format: int64 + publicationYear: + type: integer + format: int32 + publicationMonth: + type: integer + format: int32 + publicationDay: + type: integer + format: int32 + database: + $ref: '#/components/schemas/Database' + relatedIdentifiers: + type: array + items: + $ref: '#/components/schemas/RelatedIdentifier' + doi: + type: string + createdBy: + type: string + format: uuid + creator: + $ref: '#/components/schemas/User' + created: + type: string + format: date-time + lastModified: + type: string + format: date-time + IdentifierDescription: + type: object + properties: + id: + type: integer + format: int64 + description: + type: string + descriptionType: + type: string + enum: + - Abstract + - Methods + - SeriesInformation + - TableOfContents + - TechnicalInfo + - Other + language: + type: string + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - 'no' + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + identifier: + $ref: '#/components/schemas/Identifier' + IdentifierFunder: + type: object + properties: + id: + type: integer + format: int64 + funderName: + type: string + funderIdentifier: + type: string + funderIdentifierType: + type: string + enum: + - CROSSREF_FUNDER_ID + - ROR + - GND + - ISNI + - OTHER + schemeUri: + type: string + awardNumber: + type: string + awardTitle: + type: string + identifier: + $ref: '#/components/schemas/Identifier' + IdentifierTitle: + type: object + properties: + id: + type: integer + format: int64 + title: + type: string + titleType: + type: string + enum: + - AlternativeTitle + - Subtitle + - TranslatedTitle + - Other + language: + type: string + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - 'no' + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + identifier: + $ref: '#/components/schemas/Identifier' + License: + type: object + properties: + identifier: + type: string + uri: + type: string + description: + type: string + PrimaryKey: + type: object + properties: + id: + type: integer + format: int64 + table: + $ref: '#/components/schemas/Table' + column: + $ref: '#/components/schemas/TableColumn' + RelatedIdentifier: + type: object + properties: + id: + type: integer + format: int64 + value: + type: string + type: + type: string + enum: + - DOI + - URL + - URN + - ARK + - arXiv + - bibcode + - EAN13 + - EISSN + - Handle + - IGSN + - ISBN + - ISTC + - LISSN + - LSID + - PMID + - PURL + - UPC + - w3id + relation: + type: string + enum: + - IsCitedBy + - Cites + - IsSupplementTo + - IsSupplementedBy + - IsContinuedBy + - Continues + - IsDescribedBy + - Describes + - HasMetadata + - IsMetadataFor + - HasVersion + - IsVersionOf + - IsNewVersionOf + - IsPreviousVersionOf + - IsPartOf + - HasPart + - IsPublishedIn + - IsReferencedBy + - References + - IsDocumentedBy + - Documents + - IsCompiledBy + - Compiles + - IsVariantFormOf + - IsOriginalFormOf + - IsIdenticalTo + - IsReviewedBy + - Reviews + - IsDerivedFrom + - IsSourceOf + - IsRequiredBy + - Requires + - IsObsoletedBy + - Obsoletes + identifier: + $ref: '#/components/schemas/Identifier' + Table: + type: object + properties: + id: + type: integer + format: int64 + tdbid: + type: integer + format: int64 + createdBy: + type: string + format: uuid + creator: + $ref: '#/components/schemas/User' + ownedBy: + type: string + format: uuid + owner: + $ref: '#/components/schemas/User' + name: + type: string + internalName: + type: string + queueName: + type: string + description: + type: string + database: + $ref: '#/components/schemas/Database' + columns: + type: array + items: + $ref: '#/components/schemas/TableColumn' + identifiers: + type: array + items: + $ref: '#/components/schemas/Identifier' + constraints: + $ref: '#/components/schemas/Constraints' + isVersioned: + type: boolean + numRows: + type: integer + format: int64 + dataLength: + type: integer + format: int64 + maxDataLength: + type: integer + format: int64 + avgRowLength: + type: integer + format: int64 + created: + type: string + format: date-time + lastModified: + type: string + format: date-time + TableColumn: + type: object + properties: + id: + type: integer + format: int64 + dateFormat: + $ref: '#/components/schemas/ContainerImageDate' + table: + $ref: '#/components/schemas/Table' + name: + type: string + autoGenerated: + type: boolean + internalName: + type: string + description: + type: string + indexLength: + type: integer + format: int64 + alias: + type: string + columnType: + type: string + enum: + - TableColumnType.CHAR + - TableColumnType.VARCHAR + - TableColumnType.BINARY + - TableColumnType.VARBINARY + - TableColumnType.TINYBLOB + - TableColumnType.TINYTEXT + - TableColumnType.TEXT + - TableColumnType.BLOB + - TableColumnType.MEDIUMTEXT + - TableColumnType.MEDIUMBLOB + - TableColumnType.LONGTEXT + - TableColumnType.LONGBLOB + - TableColumnType.ENUM + - TableColumnType.SET + - TableColumnType.BIT + - TableColumnType.TINYINT + - TableColumnType.BOOL + - TableColumnType.SMALLINT + - TableColumnType.MEDIUMINT + - TableColumnType.INT + - TableColumnType.BIGINT + - TableColumnType.FLOAT + - TableColumnType.DOUBLE + - TableColumnType.DECIMAL + - TableColumnType.DATE + - TableColumnType.DATETIME + - TableColumnType.TIMESTAMP + - TableColumnType.TIME + - TableColumnType.YEAR + length: + type: integer + format: int64 + isNullAllowed: + type: boolean + ordinalPosition: + type: integer + format: int32 + created: + type: string + format: date-time + concept: + $ref: '#/components/schemas/TableColumnConcept' + unit: + $ref: '#/components/schemas/TableColumnUnit' + enums: + type: array + items: + type: string + sets: + type: array + items: + type: string + size: + type: integer + format: int64 + d: + type: integer + format: int64 + min: + type: number + max: + type: number + mean: + type: number + median: + type: number + stdDev: + type: number + lastModified: + type: string + format: date-time + TableColumnConcept: + type: object + properties: + id: + type: integer + format: int64 + uri: + type: string + name: + type: string + description: + type: string + created: + type: string + format: date-time + columns: + type: array + items: + $ref: '#/components/schemas/TableColumn' + TableColumnUnit: + type: object + properties: + id: + type: integer + format: int64 + uri: + type: string + name: + type: string + description: + type: string + created: + type: string + format: date-time + columns: + type: array + items: + $ref: '#/components/schemas/TableColumn' + Unique: + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + table: + $ref: '#/components/schemas/Table' + columns: + type: array + items: + $ref: '#/components/schemas/TableColumn' + User: + type: object + properties: + id: + type: string + format: uuid + username: + type: string + firstname: + type: string + lastname: + type: string + email: + type: string + orcid: + type: string + affiliation: + type: string + language: + type: string + accesses: + type: array + items: + $ref: '#/components/schemas/DatabaseAccess' + theme: + type: string + mariadbPassword: + type: string + View: + type: object + properties: + id: + type: integer + format: int64 + vdbid: + type: integer + format: int64 + createdBy: + type: string + format: uuid + creator: + $ref: '#/components/schemas/User' + name: + type: string + internalName: + type: string + isPublic: + type: boolean + isInitialView: + type: boolean + query: + type: string + queryHash: + type: string + identifiers: + type: array + items: + $ref: '#/components/schemas/Identifier' + database: + $ref: '#/components/schemas/Database' + columns: + type: array + items: + $ref: '#/components/schemas/ViewColumn' + created: + type: string + format: date-time + lastModified: + type: string + format: date-time + ViewColumn: + type: object + properties: + id: + type: integer + format: int64 + dateFormat: + $ref: '#/components/schemas/ContainerImageDate' + view: + $ref: '#/components/schemas/View' + name: + type: string + autoGenerated: + type: boolean + internalName: + type: string + columnType: + type: string + enum: + - TableColumnType.CHAR + - TableColumnType.VARCHAR + - TableColumnType.BINARY + - TableColumnType.VARBINARY + - TableColumnType.TINYBLOB + - TableColumnType.TINYTEXT + - TableColumnType.TEXT + - TableColumnType.BLOB + - TableColumnType.MEDIUMTEXT + - TableColumnType.MEDIUMBLOB + - TableColumnType.LONGTEXT + - TableColumnType.LONGBLOB + - TableColumnType.ENUM + - TableColumnType.SET + - TableColumnType.BIT + - TableColumnType.TINYINT + - TableColumnType.BOOL + - TableColumnType.SMALLINT + - TableColumnType.MEDIUMINT + - TableColumnType.INT + - TableColumnType.BIGINT + - TableColumnType.FLOAT + - TableColumnType.DOUBLE + - TableColumnType.DECIMAL + - TableColumnType.DATE + - TableColumnType.DATETIME + - TableColumnType.TIMESTAMP + - TableColumnType.TIME + - TableColumnType.YEAR + isNullAllowed: + type: boolean + ordinalPosition: + type: integer + format: int32 + size: + type: integer + format: int64 + d: + type: integer + format: int64 + LdCreatorDto: + required: + - '@type' + - name + type: object + properties: + name: + type: string + sameAs: + type: string + givenName: + type: string + familyName: + type: string + '@type': + type: string + LdDatasetDto: + required: + - '@context' + - '@type' + - citation + - creator + - description + - hasPart + - identifier + - name + - temporalCoverage + - url + - version + type: object + properties: + name: + type: string + description: + type: string + url: + type: string + identifier: + type: array + items: + type: string + license: + type: string + creator: + type: array + items: + $ref: '#/components/schemas/LdCreatorDto' + citation: + type: string + hasPart: + type: array + items: + $ref: '#/components/schemas/LdDatasetDto' + temporalCoverage: + type: string + version: + type: string + format: date-time + '@context': + type: string + '@type': + type: string + TableColumnEntityDto: + required: + - column_id + - database_id + - table_id + - uri + type: object + properties: + uri: + type: string + example: 'https://www.wikidata.org/entity/Q1686799' + label: + type: string + example: Apache Jena + description: + type: string + example: open source semantic web framework for Java + database_id: + type: integer + format: int64 + example: 1 + table_id: + type: integer + format: int64 + example: 1 + column_id: + type: integer + format: int64 + example: 1 + IndexDto: + properties: + results: + items: + type: object + type: array + type: + description: Same as the requested type + enum: + - database + - table + - view + - column + - user + - identifier + - concept + - unit + type: string + required: + - results + - type + IndexFieldDto: + properties: + attr_friendly_name: + example: Name + type: string + attr_name: + example: name + type: string + type: + description: OpenSearch data types. + example: string + type: string + required: + - attr_name + - attr_friendly_name + - type + type: object + IndexFieldsDto: + properties: + results: + items: + $ref: '#/components/schemas/IndexFieldDto' + type: array + required: + - results + type: object + SearchRequestDto: + properties: + field_value_pairs: + type: object + search_term: + type: string + required: + - search_term + - field_value_pairs + type: object + SearchResultDto: + properties: + results: + items: + type: object + type: array + required: + - results + type: object diff --git a/.docs/.swagger/openapi-merge.json b/.docs/.swagger/openapi-merge.json new file mode 100644 index 0000000000000000000000000000000000000000..af25a7582fc3673595a82f6b143a3e7b823a0aa9 --- /dev/null +++ b/.docs/.swagger/openapi-merge.json @@ -0,0 +1,23 @@ +{ + "inputs": [ + { + "inputFile": "./api.base.yaml" + }, + { + "inputFile": "./api-analyse.yaml" + }, + { + "inputFile": "./api-data.yaml" + }, + { + "inputFile": "./api-metadata.yaml" + }, + { + "inputFile": "./api-search.yaml" + }, + { + "inputFile": "./api-sidecar.yaml" + } + ], + "output": "./api.yaml" +} diff --git a/.docs/.swagger/swagger-ui.html b/.docs/.swagger/swagger-ui.html index 98f7cb441fb441c5b4f559e7f7820d112aed7982..0bb08a1c07c1bfca6cc820474190dada3580df48 100644 --- a/.docs/.swagger/swagger-ui.html +++ b/.docs/.swagger/swagger-ui.html @@ -7,7 +7,7 @@ <title>DBRepo REST API</title> <link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5.17.12/swagger-ui.css"/> <link rel="stylesheet" href="./custom.css"/> - <link rel="icon" href="https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/master/.docs/images/signet_white.png" /> + <link rel="icon" href="https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/master/.docs/images/logos/favicon.png" /> </head> <body> <div class="swagger-ui"> diff --git a/.docs/api/analyse-service.md b/.docs/api/analyse-service.md index be5efdbf5c8c58dd0c0825e7c1328188d01b1aba..484271bbfe75062897c6a7a2a4497e084337f3e1 100644 --- a/.docs/api/analyse-service.md +++ b/.docs/api/analyse-service.md @@ -11,19 +11,19 @@ author: Martin Weise * Ports: 5000/tcp * Prometheus: `http://<hostname>:5000/metrics` * Health: `http://<hostname>:5000/health` - * Swagger UI: `http://<hostname>:5000/swagger-ui/` <a href="../swagger/analyse" target="_blank">:fontawesome-solid-square-up-right: view online</a> + * Swagger UI: `http://<hostname>:5000/swagger-ui/` <a href="./swagger/analyse" target="_blank">:fontawesome-solid-square-up-right: view online</a> ## Overview -It suggests data types for the [User Interface](../system-other-ui) when creating a table from a +It suggests data types for the [User Interface](./system-other-ui) when creating a table from a *comma separated values* (CSV) -file. It recommends enumerations for columns and returns e.g. a list of potential primary key candidates. The researcher is able to confirm these suggestions manually. Moreover, the Analyse Service determines basic statistical properties of numerical columns. ### Analysis -After [uploading](../system-services-storage/#buckets) the CSV-file into the `dbrepo-upload` bucket of -the [Storage Service](../system-services-storage), analysis for data types and primary keys follows the flow: +After [uploading](./system-services-storage/#buckets) the CSV-file into the `dbrepo-upload` bucket of +the [Storage Service](./system-services-storage), analysis for data types and primary keys follows the flow: 1. Retrieve the CSV-file from the `dbrepo-upload` bucket of the Storage Service as data stream (=nothing is stored in the service) with the [`boto3`](https://boto3.amazonaws.com/v1/documentation/api/latest/index.html) client. @@ -36,16 +36,16 @@ the [Storage Service](../system-services-storage), analysis for data types and p ### Examples -See the [usage page](../usage-analyse/) for examples. +See the [usage page](./usage-analyse/) for examples. ## Limitations !!! question "Do you miss functionality? Do these limitations affect you?" We strongly encourage you to help us implement it as we are welcoming contributors to open-source software and get - in [contact](../contact) with us, we happily answer requests for collaboration with attached CV and your programming + in [contact](./contact) with us, we happily answer requests for collaboration with attached CV and your programming experience! ## Security -1. Credentials for the [Storage Service](../system-services-storage) are stored in plaintext environment variables. +1. Credentials for the [Storage Service](./system-services-storage) are stored in plaintext environment variables. diff --git a/.docs/api/data-service.md b/.docs/api/data-service.md index df6b87e2f06bd59e90ce6116a240d538cd8185c4..41efb2151420a4507d6d0e15e6df5e8be7486984 100644 --- a/.docs/api/data-service.md +++ b/.docs/api/data-service.md @@ -14,7 +14,7 @@ author: Martin Weise - Readiness: `http://<hostname>:9093/actuator/health/readiness` - Liveness: `http://<hostname>:9093/actuator/health/liveness` * Prometheus: `http://<hostname>:9093/actuator/prometheus` - * Swagger UI: `http://<hostname>:9093/swagger-ui/index.html` <a href="../swagger/data" target="_blank">:fontawesome-solid-square-up-right: view online</a> + * Swagger UI: `http://<hostname>:9093/swagger-ui/index.html` <a href="./swagger/data" target="_blank">:fontawesome-solid-square-up-right: view online</a> ## Overview @@ -27,7 +27,7 @@ Data Service up. !!! question "Do you miss functionality? Do these limitations affect you?" We strongly encourage you to help us implement it as we are welcoming contributors to open-source software and get - in [contact](../contact) with us, we happily answer requests for collaboration with attached CV and your programming + in [contact](./contact) with us, we happily answer requests for collaboration with attached CV and your programming experience! ## Security diff --git a/.docs/api/gateway-service.md b/.docs/api/gateway-service.md index 172892e3bdb13411c658093cbc7adf76fbdd6de7..cd3be4f73dd8f4891513615f7b901c055f71fed5 100644 --- a/.docs/api/gateway-service.md +++ b/.docs/api/gateway-service.md @@ -41,7 +41,7 @@ If your TLS private key as a password, you need to specify it in the `dbrepo.con ### User Interface -To serve the [User Interface](../system-other-ui/) under different port than `80`, change the port mapping in +To serve the [User Interface](./system-other-ui/) under different port than `80`, change the port mapping in the `docker-compose.yml` to e.g. port `8000`: ```yaml title="docker-compose.yml" @@ -61,7 +61,7 @@ services: !!! question "Do you miss functionality? Do these limitations affect you?" We strongly encourage you to help us implement it as we are welcoming contributors to open-source software and get - in [contact](../contact) with us, we happily answer requests for collaboration with attached CV and your programming + in [contact](./contact) with us, we happily answer requests for collaboration with attached CV and your programming experience! diff --git a/.docs/api/index.md b/.docs/api/index.md index 8b8d7218b5fe26e2b477aef4a7139b221a061731..1468c2b20fd0786b0f2a7e80f697adf6ae211b26 100644 --- a/.docs/api/index.md +++ b/.docs/api/index.md @@ -5,7 +5,7 @@ author: Martin Weise # Overview We developed a Python Library for communicating with DBRepo from e.g. Jupyter Notebooks. See -the [Python Library](../usage-python) page for more details. +the [Python Library](./usage-python) page for more details. We give usage examples of the most important use-cases we identified. @@ -30,7 +30,7 @@ A user wants to create an account in DBRepo. button and provide a valid work e-mail address :material-numeric-1-circle-outline: and a username (in lowercase alphanumeric characters) :material-numeric-2-circle-outline:. Choose a secure password in field :material-numeric-3-circle-outline: and repeat it in field :material-numeric-4-circle-outline:. Click "SUBMIT" and - the system creates a user account in Figure 1 with the [default roles](../system-services-authentication/#roles) + the system creates a user account in Figure 1 with the [default roles](./system-services-authentication/#roles) that your administrator has assigned. <figure markdown> @@ -425,7 +425,7 @@ A user wants to import a database dump in `.sql` (or in `.sql.gz`) format into D Setup a new connection in the MySQL Workbench (c.f. Figure 14) by clicking the small ":material-plus-circle-outline:" button :material-numeric-1-circle-outline: to open the dialog. In the opened dialog fill out the connection parameters (for local deployments the hostname is `127.0.0.1` and port `3307` for the - [Data Database](../system-databases-data/) :material-numeric-2-circle-outline:. + [Data Database](./system-databases-data/) :material-numeric-2-circle-outline:. The default credentials are username `root` and password `dbrepo`, type the password in :material-numeric-3-circle-outline: and click the "OK" button. Then finish the setup of the new connection by @@ -470,8 +470,8 @@ A user wants to import a database dump in `.sql` (or in `.sql.gz`) format into D gunzip < dump.sql.gz | mysql -H127.0.0.1 -p3307 -uUSERNAME -pYOURPASSWORD db_name ``` - The [Metadata Service](../system-services-metadata) periodically (by default configuration every 60 seconds) checks - and adds missing tables and views to the [Metadata Database](../system-databases-metadata), the database dump + The [Metadata Service](./system-services-metadata) periodically (by default configuration every 60 seconds) checks + and adds missing tables and views to the [Metadata Database](./system-databases-metadata), the database dump will be visible afterwards. Currently, date formats for columns with time types (e.g. `DATE`, `TIMESTAMP`) are assumed to match the first date format found for the database image. This may need to be manually specified by the administrator. @@ -479,7 +479,7 @@ A user wants to import a database dump in `.sql` (or in `.sql.gz`) format into D !!! example "Specifying a custom date format" In case the pre-defined date formats are not matching the found date format in the database dump, the system - administrator needs to add it manually in the [Metadata Database](../system-databases-metadata). + administrator needs to add it manually in the [Metadata Database](./system-databases-metadata). ```sql INSERT INTO `mdb_images_date` (`iid`, `database_format`, `unix_format`, `example`, `has_time`) @@ -658,7 +658,7 @@ A user wants to create a subset and export it as csv file. ``` Afterwards, you can see the subset in the UI with subset id `@subsetId` and persist it there. Only the administrator - can persist the subset in the [Data Database](../system-databases-data) through JDBC by setting the `persisted` + can persist the subset in the [Data Database](./system-databases-data) through JDBC by setting the `persisted` column to `true` in the `qs_queries` table. === "Python" @@ -732,7 +732,7 @@ A user wants to assign a persistent identifier to a database owned by them. <figcaption>Figure 21: Open the get persisent identifier form.</figcaption> </figure> - First, provide information on the dataset creator(s). Since the [Metadata Service](../system-services-metadata) + First, provide information on the dataset creator(s). Since the [Metadata Service](./system-services-metadata) automatically resolves external PIDs, the easiest way is to provide the correct mandatory data is by filling the name identifier :material-numeric-1-circle-outline:. The creator type :material-numeric-2-circle-outline: denotes either a natural person or organization. Optionally fill out the given @@ -779,7 +779,7 @@ A user wants to assign a persistent identifier to a database owned by them. <figcaption>Figure 25: Related identifiers, license and language of the identifier.</figcaption> </figure> - Optionally add funding information, again the [Metadata Service](../system-services-metadata) + Optionally add funding information, again the [Metadata Service](./system-services-metadata) automatically resolves external PIDs, the easiest way is to provide the correct mandatory data is by filling the funder identifier :material-numeric-1-circle-outline: that attempts to get the funder name :material-numeric-2-circle-outline:. If you provide an award number :material-numeric-3-circle-outline: and/or @@ -817,11 +817,11 @@ A user wants to assign a persistent identifier to a database owned by them. !!! warning - Creating a PID directly in the [Metadata Database](../system-databases-metadata) is not recommended! It bypasses + Creating a PID directly in the [Metadata Database](./system-databases-metadata) is not recommended! It bypasses validation and creation of external PIDs (e.g. DOI) and may lead to inconstistent data locally compared to external systems (e.g. DataCite Fabrica). - Create a local PID directly in the [Metadata Database](../system-databases-metadata) by filling the tables in this + Create a local PID directly in the [Metadata Database](./system-databases-metadata) by filling the tables in this order (they have foreign key dependencies). 1. `mdb_identifiers` ... identifier core information @@ -928,7 +928,7 @@ A user wants a public database to be private and only give specific users access === "JDBC" To change the visibility of a database as administrator with direct JDBC access to - the [Metadata Database](../system-databases-metadata), change the visibility directly by executing the SQL-query + the [Metadata Database](./system-databases-metadata), change the visibility directly by executing the SQL-query in the `fda` schema: ```sql diff --git a/.docs/api/metadata-service.md b/.docs/api/metadata-service.md index 33f3db3bfe5be3d473420599ff90b6582a9e4443..362a9c36bcf6a32ba8262d002716e108d998b2be 100644 --- a/.docs/api/metadata-service.md +++ b/.docs/api/metadata-service.md @@ -14,7 +14,7 @@ author: Martin Weise - Readiness: `http://<hostname>:9099/actuator/health/readiness` - Liveness: `http://<hostname>:9099/actuator/health/liveness` * Prometheus: `http://<hostname>:9099/actuator/prometheus` - * Swagger UI: `http://<hostname>:9099/swagger-ui/index.html` <a href="../swagger/metadata" target="_blank">:fontawesome-solid-square-up-right: view online</a> + * Swagger UI: `http://<hostname>:9099/swagger-ui/index.html` <a href="./swagger/metadata" target="_blank">:fontawesome-solid-square-up-right: view online</a> ## Overview @@ -75,23 +75,23 @@ Executing SQL queries through the Query Endpoint must fulfill some restrictions: ### Semantics -The service provides metadata to the table columns in the [Metadata Database](../system-databases-metadata) from +The service provides metadata to the table columns in the [Metadata Database](./system-databases-metadata) from registered ontologies like Wikidata [`wd:`](https://wikidata.org), Ontology of Units of Measurement [`om2:`](https://www.ontology-of-units-of-measure.org/resource/om-2), Friend of a Friend [`foaf:`](http://xmlns.com/foaf/0.1/), the [`prov:`](http://www.w3.org/ns/prov#) namespace, etc. ### Tables -The service manages tables in the [Data Database](../system-databases-data) and manages the metadata of these tables -in the [Metadata Database](../system-databases-metadata). Any tables that are created outside of DBRepo (e.g. directly via the JDBC API) are +The service manages tables in the [Data Database](./system-databases-data) and manages the metadata of these tables +in the [Metadata Database](./system-databases-metadata). Any tables that are created outside of DBRepo (e.g. directly via the JDBC API) are periodically fetched by this service (based on the `OBTAIN_METADATA_RATE` environment variable, default interval is 60 seconds). ### Users -The service manages users in the [Data Database](../system-databases-data) -and [Metadata Database](../system-databases-metadata), as well as in the [Broker Service](../system-services-broker) -and the [Authentication Service](../system-services-authentication). +The service manages users in the [Data Database](./system-databases-data) +and [Metadata Database](./system-databases-metadata), as well as in the [Broker Service](./system-services-broker) +and the [Authentication Service](./system-services-authentication). The default configuration grants the users only very basic permissions on the databases: @@ -123,8 +123,8 @@ A list of all grants is available in the MariaDB documentation for [`GRANT`](htt ### Views -The service manages views in the [Data Database](../system-databases-data) -and [Metadata Database](../system-databases-metadata). Any views that are created outside of DBRepo (e.g. directly via +The service manages views in the [Data Database](./system-databases-data) +and [Metadata Database](./system-databases-metadata). Any views that are created outside of DBRepo (e.g. directly via the JDBC API) are periodically fetched by this service (based on the `OBTAIN_METADATA_RATE` environment variable, default interval is 60 seconds). @@ -136,7 +136,7 @@ default interval is 60 seconds). !!! question "Do you miss functionality? Do these limitations affect you?" We strongly encourage you to help us implement it as we are welcoming contributors to open-source software and get - in [contact](../contact) with us, we happily answer requests for collaboration with attached CV and your programming + in [contact](./contact) with us, we happily answer requests for collaboration with attached CV and your programming experience! ## Security diff --git a/.docs/api/open-api.md b/.docs/api/open-api.md index f06ec67a0daec31d77ddd0b62716276183c4b728..72395271dea13288dd0065b2a385095faad2955b 100644 --- a/.docs/api/open-api.md +++ b/.docs/api/open-api.md @@ -2,6 +2,12 @@ author: Martin Weise --- -All services are documented using the -[](https://www.openapis.org/){ tabindex=-1 } -documentation standard. + + +## tl;dr + +[:simple-swagger: View Swagger-UI](../../swagger/){ .md-button .md-button--primary tabindex=-1 } + +## Overview + +All services are documented using the [OpenAPI 3.1](https://www.openapis.org/) documentation standard. \ No newline at end of file diff --git a/.docs/api/storage-service.md b/.docs/api/storage-service.md index 2219c5fa5759dce36cbb0276594b1f0c5d32ee64..bf40ca83c8cfde0951a3796df0fbb06e0e486478 100644 --- a/.docs/api/storage-service.md +++ b/.docs/api/storage-service.md @@ -36,7 +36,7 @@ The default configuration creates two buckets `dbrepo-upload`, `dbrepo-download` !!! question "Do you miss functionality? Do these limitations affect you?" We strongly encourage you to help us implement it as we are welcoming contributors to open-source software and get - in [contact](../contact) with us, we happily answer requests for collaboration with attached CV and your programming + in [contact](./contact) with us, we happily answer requests for collaboration with attached CV and your programming experience! ## Security diff --git a/.docs/deployment-docker-compose.md b/.docs/deployment-docker-compose.md index 0d541cd174207c544bd7d9ed007ffefd734b9f9a..7b6d9922561ddeafee790da540e301b65e09f74c 100644 --- a/.docs/deployment-docker-compose.md +++ b/.docs/deployment-docker-compose.md @@ -53,7 +53,7 @@ technologies. The conceptualized microservices operate the basic database operat ### Notes -Please note that we only save the state of the databases as well as the [Broker Service](../system-services-broker) +Please note that we only save the state of the databases as well as the [Broker Service](./system-services-broker) since RabbitMQ maintains state inside the container. ## Deployment @@ -147,8 +147,8 @@ Please be warned that the default configuration is not intended for public deplo running system within minutes to play around within the system and explore features. It is strongly advised to change the default `.env` environment variables. -Next, create a [user account](../usage-overview/#create-user-account) and -then [create a database](../usage-overview/#create-database) to [import a dataset](../usage-overview/#import-dataset). +Next, create a [user account](./usage-overview/#create-user-account) and +then [create a database](./usage-overview/#create-database) to [import a dataset](./usage-overview/#import-dataset). ## Security @@ -193,4 +193,4 @@ then [create a database](../usage-overview/#create-database) to [import a datase !!! info "Alternative Deployments" - Alternatively, you can also deploy DBRepo with [Helm](../deployment-helm/) in your virtual machine instead. + Alternatively, you can also deploy DBRepo with [Helm](./deployment-helm/) in your virtual machine instead. diff --git a/.docs/deployment-helm.md b/.docs/deployment-helm.md index 745ad87b944da4afde11fff736e984ecc860f90c..5b0be43553584e6c6be4f582615bc9afcffd918a 100644 --- a/.docs/deployment-helm.md +++ b/.docs/deployment-helm.md @@ -32,12 +32,12 @@ about values, etc. ## Limitations 1. MariaDB Galera does not (yet) support XA-transactions required by the authentication service (=Keycloak). Therefore - only a single MariaDB pod can be deployed at once for the [auth database](../system-databases-authentication). + only a single MariaDB pod can be deployed at once for the [auth database](./system-databases-authentication). 2. The entire Helm deployment is rootless (=`runAsNonRoot=true`) except for - the [Storage Service](../system-services-storage/) which still requires a root user. + the [Storage Service](./system-services-storage/) which still requires a root user. !!! question "Do you miss functionality? Do these limitations affect you?" We strongly encourage you to help us implement it as we are welcoming contributors to open-source software and get - in [contact](../contact) with us, we happily answer requests for collaboration with attached CV and your programming + in [contact](./contact) with us, we happily answer requests for collaboration with attached CV and your programming experience! diff --git a/.docs/docker/_header.md b/.docs/docker/_header.md index 081bf9697cbe996cb43d86787fc36319c617be1e..3a5b13338af17c5e1f3a146aaba6c3aa35b5a3d4 100644 --- a/.docs/docker/_header.md +++ b/.docs/docker/_header.md @@ -10,7 +10,7 @@ # Supported tags -* [`1.4.x`](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/blob/release-__APP_VERSION__/dbrepo-DIR/Dockerfile/) +* [`1.4.3`](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/blob/release-1.4.3/dbrepo-DIR/Dockerfile/) * [`latest`](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/blob/release-latest/dbrepo-DIR/Dockerfile/) # Non-supported tags @@ -29,8 +29,8 @@ * **Source of this description:** - [docs repo's `.docs/docker` directory](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/tree/release-__APP_VERSION__/.docs/docker) - ([history](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/commits/release-__APP_VERSION__/.docs/docker)) + [docs repo's `.docs/docker` directory](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/tree/release-1.4.3/.docs/docker) + ([history](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/commits/release-1.4.3/.docs/docker)) # What is DBRepo? diff --git a/.docs/examples/hazard.md b/.docs/examples/hazard.md new file mode 100644 index 0000000000000000000000000000000000000000..9f434d8eae0f42b1703658980ac0e393036a0a2a --- /dev/null +++ b/.docs/examples/hazard.md @@ -0,0 +1,23 @@ +--- +author: Martin Weise +--- + +## tl;dr + +[:fontawesome-solid-database: Dataset](https://dbrepo1.ec.tuwien.ac.at/pid/51){ .md-button .md-button--primary target="_blank" } +[:material-file-document: Archive](https://doi.org/10.48436/yaecs-dgr27){ .md-button .md-button--secondary target="_blank" } + +## Description + +TBD + +## Solution + +TBD + +## DBRepo Features + +- [x] Complex database schema +- [x] Complex views +- [x] System versioning +- [x] Subset exploration \ No newline at end of file diff --git a/.docs/publications.md b/.docs/publications.md index cbaac17564c183597abda9cbf3fccbf61ebfc873..4b64d9a5746b2bf9db2c0804e174df08a6e70321 100644 --- a/.docs/publications.md +++ b/.docs/publications.md @@ -14,14 +14,14 @@ hide: Semantic Digital Repository for Relational Databases. *International Journal of Digital Curation*, 17(1), 11. DOI: [10.2218/ijdc.v17i1.825](https://doi.org/10.2218/ijdc.v17i1.825)<br /> - [[BibTeX](../papers/weise2022dbrepo.bib)] [[RIS](../papers/weise2022dbrepo.ris)] [[RDF](../papers/weise2022dbrepo.rdf)] [[EndNote](../papers/weise2022dbrepo.xml)] + [[BibTeX](./papers/weise2022dbrepo.bib)] [[RIS](./papers/weise2022dbrepo.ris)] [[RDF](./papers/weise2022dbrepo.rdf)] [[EndNote](./papers/weise2022dbrepo.xml)] ## Logos DBRepo logo in various formats: -* PNG: [bigger](../images/logo/logo.png) ([smaller](../images/logo/favicon.png)) -* SVG: [bigger](../images/logo/logo.svg) ([smaller](../images/logo/favicon.svg)) +* PNG: [bigger](./images/logo/logo.png) ([smaller](./images/logo/favicon.png)) +* SVG: [bigger](./images/logo/logo.svg) ([smaller](./images/logo/favicon.svg)) ## Refereed diff --git a/.docs/usage-storage.md b/.docs/usage-storage.md index 253fe8e960814e2a91d723dd44c620726df6b7e9..fb409571f79d3c4459fc29c61ab242f83956d125 100644 --- a/.docs/usage-storage.md +++ b/.docs/usage-storage.md @@ -53,7 +53,7 @@ $ aws --endpoint-url http://localhost:9000 \ ## Other -Alternatively, you can use the middleware of the [User Interface](../system-other-ui/) to upload files. +Alternatively, you can use the middleware of the [User Interface](./system-other-ui/) to upload files. Alternatively, you can use a S3-compatible client: diff --git a/.docs/usage-upload.md b/.docs/usage-upload.md index f84f853eb617e10c6f0583975670fb788dd0e878..1735e6cced219dced24296bdd42ec0693c6f75a8 100644 --- a/.docs/usage-upload.md +++ b/.docs/usage-upload.md @@ -11,7 +11,7 @@ We recommend using a TUS-compatible client: * [tus-js-client](https://github.com/tus/tus-js-client) (JavaScript/Node.js) * [tusd](https://github.com/tus/tusd) (Go) -Upload a file to the `dbrepo-upload` bucket in the [Storage Service](../system-services-storage/) using the Node.js +Upload a file to the `dbrepo-upload` bucket in the [Storage Service](./system-services-storage/) using the Node.js middleware. === "Terminal" diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1556f266d6ff8f1cb571dcce6975185dc346a843..1c0328375d3a5b32e209dedf0540f3c16c1b8110 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -247,7 +247,7 @@ test-lib: script: - "pip install pipenv" - "pipenv install gunicorn && pipenv install --dev --system --deploy" - - cd ./lib/python/ && coverage run -m pytest tests/test_database.py --junitxml=report.xml && coverage html --omit="test/*" && coverage report --omit="test/*" > ./coverage.txt + - cd ./lib/python/ && coverage run -m pytest tests/test_unit_analyse.py tests/test_unit_container.py tests/test_unit_database.py tests/test_unit_identifier.py tests/test_unit_license.py tests/test_unit_query.py tests/test_unit_rest_client.py tests/test_unit_table.py tests/test_unit_user.py tests/test_unit_view.py --junitxml=report.xml && coverage html --omit="test/*" && coverage report --omit="test/*" > ./coverage.txt - "cat ./coverage.txt | grep -o 'TOTAL[^%]*%'" artifacts: when: always @@ -569,7 +569,6 @@ docs-registry: - "apt-get update && apt-get install -y sed" script: - pip install -r ./requirements.txt - - find .docs -type f -exec sed -i -e "s/__APP_VERSION__/${APP_VERSION}/g" {} \; - python3 .docs/docker/release.py release-images: @@ -618,16 +617,16 @@ release-docs: before_script: - "wget https://github.com/mikefarah/yq/releases/download/v4.2.0/yq_linux_amd64 -O /usr/bin/yq" - "chmod +x /usr/bin/yq" - - "apt-get update && apt-get install -y git make sed wget ssh" + - "apk add --update alpine-sdk bash sed wget openssh" - "pip install -r ./requirements.txt" - "mkdir -p ./final/${VERSION}/swagger" script: - - "make gen-swagger-doc gen-lib-doc gen-docs-doc" + - "make gen-lib-doc gen-docs-doc" - "cp -r ./lib/python/docs/build/html ./final/${VERSION}/sphinx" # sphinx - "cp .docs/.swagger/api.yaml ./final/${VERSION}/swagger/api.yaml" # swagger - "cp .docs/.swagger/swagger-ui.html ./final/${VERSION}/swagger/index.html" # swagger - "cp .docs/.swagger/custom.css ./final/${VERSION}/swagger/custom.css" # swagger - - "cp -r ./site ./final/${VERSION}" # mkdocs + - "cp -r ./site/* ./final/${VERSION}" # mkdocs - eval $(ssh-agent -s) - "mkdir -p /root/.ssh" - echo "$CI_KEY_PRIVATE" > /root/.ssh/id_rsa && chmod 0600 /root/.ssh/id_rsa @@ -635,7 +634,7 @@ release-docs: - echo "$CI_DOC_ID" > ~/.ssh/known_hosts - tar czf ./final.tar.gz ./final - "scp -oHostKeyAlgorithms=+ssh-rsa -oPubkeyAcceptedAlgorithms=+ssh-rsa final.tar.gz $CI_DOC_USER@$CI_DOC_IP:final.tar.gz" - - "ssh -oHostKeyAlgorithms=+ssh-rsa -oPubkeyAcceptedAlgorithms=+ssh-rsa $CI_DOC_USER@$CI_DOC_IP 'rm -rf /system/user/ifs/infrastructures/public_html/dbrepo/*; tar xzf ./final.tar.gz; rm -f ./final.tar.gz; cp -r ./final/* /system/user/ifs/infrastructures/public_html/dbrepo; rm -rf ./final'" + - "ssh -oHostKeyAlgorithms=+ssh-rsa -oPubkeyAcceptedAlgorithms=+ssh-rsa $CI_DOC_USER@$CI_DOC_IP 'rm -rf /system/user/ifs/infrastructures/public_html/dbrepo/*; tar xzf ./final.tar.gz; rm -f ./final.tar.gz; cp -r ./final/* /system/user/ifs/infrastructures/public_html/dbrepo/${VERSION}; rm -rf ./final'" release-libs: stage: release diff --git a/Makefile b/Makefile index 3c178cfa9eaae9a6a54464d1d12288ad7a186e93..84d1f85e5d329478a5a0de2c61ec69c2ab494c53 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,7 @@ APP_VERSION ?= 1.4.3 CHART_VERSION ?= 1.4.3 -REPOSITORY_1_URL ?= docker.io/dbrepo -REPOSITORY_2_URL ?= s210.dl.hpc.tuwien.ac.at/dbrepo +REPOSITORY_URL ?= docker.io/dbrepo .PHONY: all all: help diff --git a/dbrepo-analyse-service/Pipfile.lock b/dbrepo-analyse-service/Pipfile.lock index d1f47348f8d5aa0a9d78d9c8b28ebf7006197766..adf893c96069e0238f9cede9ae366e0094edf68b 100644 --- a/dbrepo-analyse-service/Pipfile.lock +++ b/dbrepo-analyse-service/Pipfile.lock @@ -167,27 +167,28 @@ }, "boto3": { "hashes": [ - "sha256:009cd143509f2ff4c37582c3f45d50f28c95eed68e8a5c36641206bdb597a9ea", - "sha256:7e59f0a848be477a4c98a90e7a18a0e284adfb643f7879d2b303c5f493661b7a" + "sha256:8f9c43c54b3dfaa36c4a0d7b42c417227a515bc7a2e163e62802780000a5a3e2", + "sha256:cea2365a25b2b83a97e77f24ac6f922ef62e20636b42f9f6ee9f97188f9c1c03" ], "index": "pypi", - "version": "==1.34.113" + "markers": "python_version >= '3.8'", + "version": "==1.34.119" }, "botocore": { "hashes": [ - "sha256:449912ba3c4ded64f21d09d428146dd9c05337b2a112e15511bf2c4888faae79", - "sha256:8ca87776450ef41dd25c327eb6e504294230a5756940d68bcfdedc4a7cdeca97" + "sha256:4bdf7926a1290b2650d62899ceba65073dd2693e61c35f5cdeb3a286a0aaa27b", + "sha256:b253f15b24b87b070e176af48e8ef146516090429d30a7d8b136a4c079b28008" ], "markers": "python_version >= '3.8'", - "version": "==1.34.113" + "version": "==1.34.119" }, "certifi": { "hashes": [ - "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", - "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" + "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", + "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" ], "markers": "python_version >= '3.6'", - "version": "==2024.2.2" + "version": "==2024.6.2" }, "cffi": { "hashes": [ @@ -353,48 +354,53 @@ }, "cryptography": { "hashes": [ - "sha256:02c0eee2d7133bdbbc5e24441258d5d2244beb31da5ed19fbb80315f4bbbff55", - "sha256:0d563795db98b4cd57742a78a288cdbdc9daedac29f2239793071fe114f13785", - "sha256:16268d46086bb8ad5bf0a2b5544d8a9ed87a0e33f5e77dd3c3301e63d941a83b", - "sha256:1a58839984d9cb34c855197043eaae2c187d930ca6d644612843b4fe8513c886", - "sha256:2954fccea107026512b15afb4aa664a5640cd0af630e2ee3962f2602693f0c82", - "sha256:2e47577f9b18723fa294b0ea9a17d5e53a227867a0a4904a1a076d1646d45ca1", - "sha256:31adb7d06fe4383226c3e963471f6837742889b3c4caa55aac20ad951bc8ffda", - "sha256:3577d029bc3f4827dd5bf8bf7710cac13527b470bbf1820a3f394adb38ed7d5f", - "sha256:36017400817987670037fbb0324d71489b6ead6231c9604f8fc1f7d008087c68", - "sha256:362e7197754c231797ec45ee081f3088a27a47c6c01eff2ac83f60f85a50fe60", - "sha256:3de9a45d3b2b7d8088c3fbf1ed4395dfeff79d07842217b38df14ef09ce1d8d7", - "sha256:4f698edacf9c9e0371112792558d2f705b5645076cc0aaae02f816a0171770fd", - "sha256:5482e789294854c28237bba77c4c83be698be740e31a3ae5e879ee5444166582", - "sha256:5e44507bf8d14b36b8389b226665d597bc0f18ea035d75b4e53c7b1ea84583cc", - "sha256:779245e13b9a6638df14641d029add5dc17edbef6ec915688f3acb9e720a5858", - "sha256:789caea816c6704f63f6241a519bfa347f72fbd67ba28d04636b7c6b7da94b0b", - "sha256:7f8b25fa616d8b846aef64b15c606bb0828dbc35faf90566eb139aa9cff67af2", - "sha256:8cb8ce7c3347fcf9446f201dc30e2d5a3c898d009126010cbd1f443f28b52678", - "sha256:93a3209f6bb2b33e725ed08ee0991b92976dfdcf4e8b38646540674fc7508e13", - "sha256:a3a5ac8b56fe37f3125e5b72b61dcde43283e5370827f5233893d461b7360cd4", - "sha256:a47787a5e3649008a1102d3df55424e86606c9bae6fb77ac59afe06d234605f8", - "sha256:a79165431551042cc9d1d90e6145d5d0d3ab0f2d66326c201d9b0e7f5bf43604", - "sha256:a987f840718078212fdf4504d0fd4c6effe34a7e4740378e59d47696e8dfb477", - "sha256:a9bc127cdc4ecf87a5ea22a2556cab6c7eda2923f84e4f3cc588e8470ce4e42e", - "sha256:bd13b5e9b543532453de08bcdc3cc7cebec6f9883e886fd20a92f26940fd3e7a", - "sha256:c65f96dad14f8528a447414125e1fc8feb2ad5a272b8f68477abbcc1ea7d94b9", - "sha256:d8e3098721b84392ee45af2dd554c947c32cc52f862b6a3ae982dbb90f577f14", - "sha256:e6b79d0adb01aae87e8a44c2b64bc3f3fe59515280e00fb6d57a7267a2583cda", - "sha256:e6b8f1881dac458c34778d0a424ae5769de30544fc678eac51c1c8bb2183e9da", - "sha256:e9b2a6309f14c0497f348d08a065d52f3020656f675819fc405fb63bbcd26562", - "sha256:ecbfbc00bf55888edda9868a4cf927205de8499e7fabe6c050322298382953f2", - "sha256:efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9" + "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad", + "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583", + "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b", + "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c", + "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1", + "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648", + "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949", + "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba", + "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c", + "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9", + "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d", + "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c", + "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e", + "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2", + "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d", + "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7", + "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70", + "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2", + "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7", + "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14", + "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe", + "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e", + "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71", + "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961", + "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7", + "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c", + "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28", + "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842", + "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902", + "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801", + "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a", + "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e" ], "markers": "python_version >= '3.7'", - "version": "==42.0.7" + "version": "==42.0.8" }, "dbrepo": { "hashes": [ - "sha256:ceab260cf76c050e118ce0f0589fec66059396751e03f2ec41fa489cfacc4e7b" + "sha256:2bdb48c70b4c99b5044fbfc12aa653c1e9281ca8913a433cc08a1e14cb4bd2ef" + ], + "path": "./lib/dbrepo-1.4.4.tar.gz" + }, + "events": { + "hashes": [ + "sha256:a7286af378ba3e46640ac9825156c93bdba7502174dd696090fdfcd4d80a1abd" ], - "path": "./lib/dbrepo-1.4.4.tar.gz", - "version": "==1.4.4" + "version": "==0.5" }, "exceptiongroup": { "hashes": [ @@ -402,6 +408,7 @@ "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==1.2.1" }, "flasgger": { @@ -417,6 +424,7 @@ "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==3.0.3" }, "flask-cors": { @@ -441,6 +449,7 @@ "sha256:9215d05a9413d3855764bcd67035e75819d23af2fafb6b55197eb5a3313fdfb2" ], "index": "pypi", + "markers": "python_version >= '3.7' and python_version < '4'", "version": "==4.6.0" }, "frozenlist": { @@ -571,6 +580,7 @@ "sha256:fbfdce91239fe306772faab57597186710d5699213f4df099d1612da7320d682" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==24.2.1" }, "greenlet": { @@ -635,6 +645,7 @@ "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==3.0.3" }, "gunicorn": { @@ -643,6 +654,7 @@ "sha256:4a0b436239ff76fb33f11c07a16482c521a7e09c1ce3cc293c2330afe01bec63" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==22.0.0" }, "idna": { @@ -698,6 +710,7 @@ "sha256:61c9170f92e736b530655e75374681d4fcca9cfa8763ab42be57353b2b203494" ], "index": "pypi", + "markers": "python_version >= '3.6'", "version": "==1.3.1" }, "markupsafe": { @@ -918,15 +931,17 @@ "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f" ], "index": "pypi", + "markers": "python_version >= '3.9'", "version": "==1.26.4" }, "opensearch-py": { "hashes": [ - "sha256:0dde4ac7158a717d92a8cd81964cb99705a4b80bcf9258ba195b9a9f23f5226d", - "sha256:cf093a40e272b60663f20417fc1264ac724dcf1e03c1a4542a6b44835b1e6c49" + "sha256:0b7c27e8ed84c03c99558406927b6161f186a72502ca6d0325413d8e5523ba96", + "sha256:b6e78b685dd4e9c016d7a4299cf1de69e299c88322e3f81c716e6e23fe5683c1" ], "index": "pypi", - "version": "==2.5.0" + "markers": "python_version >= '3.8' and python_version < '4'", + "version": "==2.6.0" }, "packaging": { "hashes": [ @@ -969,6 +984,7 @@ "sha256:eee3a87076c0756de40b05c5e9a6069c035ba43e8dd71c379e68cab2c20f16ad" ], "index": "pypi", + "markers": "python_version >= '3.9'", "version": "==2.2.2" }, "pika": { @@ -1043,96 +1059,97 @@ }, "pydantic": { "hashes": [ - "sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5", - "sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc" + "sha256:c46c76a40bb1296728d7a8b99aa73dd70a48c3510111ff290034f860c99c419e", + "sha256:ea91b002777bf643bb20dd717c028ec43216b24a6001a280f83877fd2655d0b4" ], "index": "pypi", - "version": "==2.7.1" + "markers": "python_version >= '3.8'", + "version": "==2.7.3" }, "pydantic-core": { "hashes": [ - "sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b", - "sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a", - "sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90", - "sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d", - "sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e", - "sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d", - "sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027", - "sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804", - "sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347", - "sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400", - "sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3", - "sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399", - "sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349", - "sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd", - "sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c", - "sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e", - "sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413", - "sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3", - "sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e", - "sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3", - "sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91", - "sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce", - "sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c", - "sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb", - "sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664", - "sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6", - "sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd", - "sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3", - "sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af", - "sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043", - "sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350", - "sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7", - "sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0", - "sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563", - "sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761", - "sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72", - "sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3", - "sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb", - "sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788", - "sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b", - "sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c", - "sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038", - "sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250", - "sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec", - "sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c", - "sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74", - "sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81", - "sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439", - "sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75", - "sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0", - "sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8", - "sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150", - "sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438", - "sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae", - "sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857", - "sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038", - "sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374", - "sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f", - "sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241", - "sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592", - "sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4", - "sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d", - "sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b", - "sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b", - "sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182", - "sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e", - "sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641", - "sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70", - "sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9", - "sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a", - "sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543", - "sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b", - "sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f", - "sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38", - "sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845", - "sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2", - "sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0", - "sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4", - "sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242" + "sha256:01dd777215e2aa86dfd664daed5957704b769e726626393438f9c87690ce78c3", + "sha256:0eb2a4f660fcd8e2b1c90ad566db2b98d7f3f4717c64fe0a83e0adb39766d5b8", + "sha256:0fbbdc827fe5e42e4d196c746b890b3d72876bdbf160b0eafe9f0334525119c8", + "sha256:123c3cec203e3f5ac7b000bd82235f1a3eced8665b63d18be751f115588fea30", + "sha256:14601cdb733d741b8958224030e2bfe21a4a881fb3dd6fbb21f071cabd48fa0a", + "sha256:18f469a3d2a2fdafe99296a87e8a4c37748b5080a26b806a707f25a902c040a8", + "sha256:19894b95aacfa98e7cb093cd7881a0c76f55731efad31073db4521e2b6ff5b7d", + "sha256:1b4de2e51bbcb61fdebd0ab86ef28062704f62c82bbf4addc4e37fa4b00b7cbc", + "sha256:1d886dc848e60cb7666f771e406acae54ab279b9f1e4143babc9c2258213daa2", + "sha256:1f4d26ceb5eb9eed4af91bebeae4b06c3fb28966ca3a8fb765208cf6b51102ab", + "sha256:21a5e440dbe315ab9825fcd459b8814bb92b27c974cbc23c3e8baa2b76890077", + "sha256:293afe532740370aba8c060882f7d26cfd00c94cae32fd2e212a3a6e3b7bc15e", + "sha256:2f5966897e5461f818e136b8451d0551a2e77259eb0f73a837027b47dc95dab9", + "sha256:2fd41f6eff4c20778d717af1cc50eca52f5afe7805ee530a4fbd0bae284f16e9", + "sha256:2fdf2156aa3d017fddf8aea5adfba9f777db1d6022d392b682d2a8329e087cef", + "sha256:3c40d4eaad41f78e3bbda31b89edc46a3f3dc6e171bf0ecf097ff7a0ffff7cb1", + "sha256:43d447dd2ae072a0065389092a231283f62d960030ecd27565672bd40746c507", + "sha256:44a688331d4a4e2129140a8118479443bd6f1905231138971372fcde37e43528", + "sha256:44c7486a4228413c317952e9d89598bcdfb06399735e49e0f8df643e1ccd0558", + "sha256:44cd83ab6a51da80fb5adbd9560e26018e2ac7826f9626bc06ca3dc074cd198b", + "sha256:46387e38bd641b3ee5ce247563b60c5ca098da9c56c75c157a05eaa0933ed154", + "sha256:4701b19f7e3a06ea655513f7938de6f108123bf7c86bbebb1196eb9bd35cf724", + "sha256:4748321b5078216070b151d5271ef3e7cc905ab170bbfd27d5c83ee3ec436695", + "sha256:4b06beb3b3f1479d32befd1f3079cc47b34fa2da62457cdf6c963393340b56e9", + "sha256:4d0dcc59664fcb8974b356fe0a18a672d6d7cf9f54746c05f43275fc48636851", + "sha256:4e99bc050fe65c450344421017f98298a97cefc18c53bb2f7b3531eb39bc7805", + "sha256:509daade3b8649f80d4e5ff21aa5673e4ebe58590b25fe42fac5f0f52c6f034a", + "sha256:51991a89639a912c17bef4b45c87bd83593aee0437d8102556af4885811d59f5", + "sha256:53db086f9f6ab2b4061958d9c276d1dbe3690e8dd727d6abf2321d6cce37fa94", + "sha256:564d7922e4b13a16b98772441879fcdcbe82ff50daa622d681dd682175ea918c", + "sha256:574d92eac874f7f4db0ca653514d823a0d22e2354359d0759e3f6a406db5d55d", + "sha256:578e24f761f3b425834f297b9935e1ce2e30f51400964ce4801002435a1b41ef", + "sha256:59ff3e89f4eaf14050c8022011862df275b552caef8082e37b542b066ce1ff26", + "sha256:5f09baa656c904807e832cf9cce799c6460c450c4ad80803517032da0cd062e2", + "sha256:6891a2ae0e8692679c07728819b6e2b822fb30ca7445f67bbf6509b25a96332c", + "sha256:6a750aec7bf431517a9fd78cb93c97b9b0c496090fee84a47a0d23668976b4b0", + "sha256:6f5c4d41b2771c730ea1c34e458e781b18cc668d194958e0112455fff4e402b2", + "sha256:77450e6d20016ec41f43ca4a6c63e9fdde03f0ae3fe90e7c27bdbeaece8b1ed4", + "sha256:81b5efb2f126454586d0f40c4d834010979cb80785173d1586df845a632e4e6d", + "sha256:823be1deb01793da05ecb0484d6c9e20baebb39bd42b5d72636ae9cf8350dbd2", + "sha256:834b5230b5dfc0c1ec37b2fda433b271cbbc0e507560b5d1588e2cc1148cf1ce", + "sha256:847a35c4d58721c5dc3dba599878ebbdfd96784f3fb8bb2c356e123bdcd73f34", + "sha256:86110d7e1907ab36691f80b33eb2da87d780f4739ae773e5fc83fb272f88825f", + "sha256:8951eee36c57cd128f779e641e21eb40bc5073eb28b2d23f33eb0ef14ffb3f5d", + "sha256:8a7164fe2005d03c64fd3b85649891cd4953a8de53107940bf272500ba8a788b", + "sha256:8b8bab4c97248095ae0c4455b5a1cd1cdd96e4e4769306ab19dda135ea4cdb07", + "sha256:90afc12421df2b1b4dcc975f814e21bc1754640d502a2fbcc6d41e77af5ec312", + "sha256:938cb21650855054dc54dfd9120a851c974f95450f00683399006aa6e8abb057", + "sha256:942ba11e7dfb66dc70f9ae66b33452f51ac7bb90676da39a7345e99ffb55402d", + "sha256:972658f4a72d02b8abfa2581d92d59f59897d2e9f7e708fdabe922f9087773af", + "sha256:97736815b9cc893b2b7f663628e63f436018b75f44854c8027040e05230eeddb", + "sha256:98906207f29bc2c459ff64fa007afd10a8c8ac080f7e4d5beff4c97086a3dabd", + "sha256:99457f184ad90235cfe8461c4d70ab7dd2680e28821c29eca00252ba90308c78", + "sha256:a0d829524aaefdebccb869eed855e2d04c21d2d7479b6cada7ace5448416597b", + "sha256:a2fdd81edd64342c85ac7cf2753ccae0b79bf2dfa063785503cb85a7d3593223", + "sha256:a55b5b16c839df1070bc113c1f7f94a0af4433fcfa1b41799ce7606e5c79ce0a", + "sha256:a642295cd0c8df1b86fc3dced1d067874c353a188dc8e0f744626d49e9aa51c4", + "sha256:ab86ce7c8f9bea87b9d12c7f0af71102acbf5ecbc66c17796cff45dae54ef9a5", + "sha256:abc267fa9837245cc28ea6929f19fa335f3dc330a35d2e45509b6566dc18be23", + "sha256:ae1d6df168efb88d7d522664693607b80b4080be6750c913eefb77e34c12c71a", + "sha256:b2ebef0e0b4454320274f5e83a41844c63438fdc874ea40a8b5b4ecb7693f1c4", + "sha256:b48ece5bde2e768197a2d0f6e925f9d7e3e826f0ad2271120f8144a9db18d5c8", + "sha256:b7cdf28938ac6b8b49ae5e92f2735056a7ba99c9b110a474473fd71185c1af5d", + "sha256:bb4462bd43c2460774914b8525f79b00f8f407c945d50881568f294c1d9b4443", + "sha256:bc4ff9805858bd54d1a20efff925ccd89c9d2e7cf4986144b30802bf78091c3e", + "sha256:c1322d7dd74713dcc157a2b7898a564ab091ca6c58302d5c7b4c07296e3fd00f", + "sha256:c67598100338d5d985db1b3d21f3619ef392e185e71b8d52bceacc4a7771ea7e", + "sha256:ca26a1e73c48cfc54c4a76ff78df3727b9d9f4ccc8dbee4ae3f73306a591676d", + "sha256:d323a01da91851a4f17bf592faf46149c9169d68430b3146dcba2bb5e5719abc", + "sha256:dc1803ac5c32ec324c5261c7209e8f8ce88e83254c4e1aebdc8b0a39f9ddb443", + "sha256:e00a3f196329e08e43d99b79b286d60ce46bed10f2280d25a1718399457e06be", + "sha256:e85637bc8fe81ddb73fda9e56bab24560bdddfa98aa64f87aaa4e4b6730c23d2", + "sha256:e858ac0a25074ba4bce653f9b5d0a85b7456eaddadc0ce82d3878c22489fa4ee", + "sha256:eae237477a873ab46e8dd748e515c72c0c804fb380fbe6c85533c7de51f23a8f", + "sha256:ebef0dd9bf9b812bf75bda96743f2a6c5734a02092ae7f721c048d156d5fabae", + "sha256:ec3beeada09ff865c344ff3bc2f427f5e6c26401cc6113d77e372c3fdac73864", + "sha256:f76d0ad001edd426b92233d45c746fd08f467d56100fd8f30e9ace4b005266e4", + "sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951", + "sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc" ], "markers": "python_version >= '3.8'", - "version": "==2.18.2" + "version": "==2.18.4" }, "pyjwt": { "hashes": [ @@ -1224,11 +1241,12 @@ }, "requests": { "hashes": [ - "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289", - "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c" + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" ], "index": "pypi", - "version": "==2.32.2" + "markers": "python_version >= '3.8'", + "version": "==2.32.3" }, "rpds-py": { "hashes": [ @@ -1377,11 +1395,11 @@ }, "typing-extensions": { "hashes": [ - "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8", - "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594" + "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a", + "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1" ], "markers": "python_version >= '3.8'", - "version": "==4.12.0" + "version": "==4.12.1" }, "tzdata": { "hashes": [ @@ -1393,11 +1411,11 @@ }, "urllib3": { "hashes": [ - "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07", - "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0" + "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", + "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.26.18" + "markers": "python_version >= '3.10'", + "version": "==2.2.1" }, "werkzeug": { "hashes": [ @@ -1592,11 +1610,11 @@ }, "certifi": { "hashes": [ - "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", - "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" + "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", + "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" ], "markers": "python_version >= '3.6'", - "version": "==2024.2.2" + "version": "==2024.6.2" }, "cffi": { "hashes": [ @@ -1754,61 +1772,62 @@ }, "coverage": { "hashes": [ - "sha256:06d96b9b19bbe7f049c2be3c4f9e06737ec6d8ef8933c7c3a4c557ef07936e46", - "sha256:13017a63b0e499c59b5ba94a8542fb62864ba3016127d1e4ef30d354fc2b00e9", - "sha256:1acc2e2ef098a1d4bf535758085f508097316d738101a97c3f996bccba963ea5", - "sha256:1aef719b6559b521ae913ddeb38f5048c6d1a3d366865e8b320270b7bc4693c2", - "sha256:1e4225990a87df898e40ca31c9e830c15c2c53b1d33df592bc8ef314d71f0281", - "sha256:1f11f98753800eb1ec872562a398081f6695f91cd01ce39819e36621003ec52a", - "sha256:1f29bf497d51a5077994b265e976d78b09d9d0dff6ca5763dbb4804534a5d380", - "sha256:1f96aa94739593ae0707eda9813ce363a0a0374a810ae0eced383340fc4a1f73", - "sha256:20e611fc36e1a0fc7bbf957ef9c635c8807d71fbe5643e51b2769b3cc0fb0b51", - "sha256:23f2f16958b16152b43a39a5ecf4705757ddd284b3b17a77da3a62aef9c057ef", - "sha256:24bb4c7859a3f757a116521d4d3a8a82befad56ea1bdacd17d6aafd113b0071e", - "sha256:26716a1118c6ce2188283b4b60a898c3be29b480acbd0a91446ced4fe4e780d8", - "sha256:29da75ce20cb0a26d60e22658dd3230713c6c05a3465dd8ad040ffc991aea318", - "sha256:2b144d142ec9987276aeff1326edbc0df8ba4afbd7232f0ca10ad57a115e95b6", - "sha256:2c79f058e7bec26b5295d53b8c39ecb623448c74ccc8378631f5cb5c16a7e02c", - "sha256:3bb5b92a0ab3d22dfdbfe845e2fef92717b067bdf41a5b68c7e3e857c0cff1a4", - "sha256:3d3f7744b8a8079d69af69d512e5abed4fb473057625588ce126088e50d05493", - "sha256:3d9c62cff2ffb4c2a95328488fd7aa96a7a4b34873150650fe76b19c08c9c792", - "sha256:3e12536446ad4527ac8ed91d8a607813085683bcce27af69e3b31cd72b3c5960", - "sha256:40dbb8e7727560fe8ab65efcddfec1ae25f30ef02e2f2e5d78cfb52a66781ec5", - "sha256:431a3917e32223fcdb90b79fe60185864a9109631ebc05f6c5aa03781a00b513", - "sha256:448ec61ea9ea7916d5579939362509145caaecf03161f6f13e366aebb692a631", - "sha256:482df956b055d3009d10fce81af6ffab28215d7ed6ad4a15e5c8e67cb7c5251c", - "sha256:4a00bd5ba8f1a4114720bef283cf31583d6cb1c510ce890a6da6c4268f0070b7", - "sha256:51b6cee539168a912b4b3b040e4042b9e2c9a7ad9c8546c09e4eaeff3eacba6b", - "sha256:554c7327bf0fd688050348e22db7c8e163fb7219f3ecdd4732d7ed606b417263", - "sha256:5662bf0f6fb6757f5c2d6279c541a5af55a39772c2362ed0920b27e3ce0e21f7", - "sha256:5997d418c219dcd4dcba64e50671cca849aaf0dac3d7a2eeeb7d651a5bd735b8", - "sha256:59a75e6aa5c25b50b5a1499f9718f2edff54257f545718c4fb100f48d570ead4", - "sha256:60b66b0363c5a2a79fba3d1cd7430c25bbd92c923d031cae906bdcb6e054d9a2", - "sha256:6e34680049eecb30b6498784c9637c1c74277dcb1db75649a152f8004fbd6646", - "sha256:74eeaa13e8200ad72fca9c5f37395fb310915cec6f1682b21375e84fd9770e84", - "sha256:7c5c5b7ae2763533152880d5b5b451acbc1089ade2336b710a24b2b0f5239d20", - "sha256:829fb55ad437d757c70d5b1c51cfda9377f31506a0a3f3ac282bc6a387d6a5f1", - "sha256:878243e1206828908a6b4a9ca7b1aa8bee9eb129bf7186fc381d2646f4524ce9", - "sha256:8809c0ea0e8454f756e3bd5c36d04dddf222989216788a25bfd6724bfcee342c", - "sha256:8941e35a0e991a7a20a1fa3e3182f82abe357211f2c335a9e6007067c3392fcf", - "sha256:894b1acded706f1407a662d08e026bfd0ff1e59e9bd32062fea9d862564cfb65", - "sha256:900532713115ac58bc3491b9d2b52704a05ed408ba0918d57fd72c94bc47fba1", - "sha256:976cd92d9420e6e2aa6ce6a9d61f2b490e07cb468968adf371546b33b829284b", - "sha256:97de509043d3f0f2b2cd171bdccf408f175c7f7a99d36d566b1ae4dd84107985", - "sha256:9a42970ce74c88bdf144df11c52c5cf4ad610d860de87c0883385a1c9d9fa4ab", - "sha256:9e41c94035e5cdb362beed681b58a707e8dc29ea446ea1713d92afeded9d1ddd", - "sha256:9f805481d5eff2a96bac4da1570ef662bf970f9a16580dc2c169c8c3183fa02b", - "sha256:a35c97af60a5492e9e89f8b7153fe24eadfd61cb3a2fb600df1a25b5dab34b7e", - "sha256:a7c6574225f34ce45466f04751d957b5c5e6b69fca9351db017c9249786172ce", - "sha256:c7ebf2a37e4f5fea3c1a11e1f47cea7d75d0f2d8ef69635ddbd5c927083211fc", - "sha256:d0305e02e40c7cfea5d08d6368576537a74c0eea62b77633179748d3519d6705", - "sha256:e1046aab24c48c694f0793f669ac49ea68acde6a0798ac5388abe0a5615b5ec8", - "sha256:e5d22eba19273b2069e4efeff88c897a26bdc64633cbe0357a198f92dca94268", - "sha256:ec27e93bbf5976f0465e8936f02eb5add99bbe4e4e7b233607e4d7622912d68d", - "sha256:fe76d6dee5e4febefa83998b17926df3a04e5089e3d2b1688c74a9157798d7a2" + "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523", + "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f", + "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d", + "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb", + "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0", + "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c", + "sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98", + "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83", + "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8", + "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7", + "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac", + "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84", + "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb", + "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3", + "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884", + "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614", + "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd", + "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807", + "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd", + "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8", + "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc", + "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db", + "sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0", + "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08", + "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232", + "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d", + "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a", + "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1", + "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286", + "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303", + "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341", + "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84", + "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45", + "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc", + "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec", + "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd", + "sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155", + "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52", + "sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d", + "sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485", + "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31", + "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d", + "sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d", + "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d", + "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85", + "sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce", + "sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb", + "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974", + "sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24", + "sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56", + "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9", + "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35" ], "index": "pypi", - "version": "==7.5.2" + "markers": "python_version >= '3.8'", + "version": "==7.5.3" }, "docker": { "hashes": [ @@ -1818,6 +1837,12 @@ "markers": "python_version >= '3.8'", "version": "==7.1.0" }, + "events": { + "hashes": [ + "sha256:a7286af378ba3e46640ac9825156c93bdba7502174dd696090fdfcd4d80a1abd" + ], + "version": "==0.5" + }, "idna": { "hashes": [ "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", @@ -1844,11 +1869,12 @@ }, "opensearch-py": { "hashes": [ - "sha256:0dde4ac7158a717d92a8cd81964cb99705a4b80bcf9258ba195b9a9f23f5226d", - "sha256:cf093a40e272b60663f20417fc1264ac724dcf1e03c1a4542a6b44835b1e6c49" + "sha256:0b7c27e8ed84c03c99558406927b6161f186a72502ca6d0325413d8e5523ba96", + "sha256:b6e78b685dd4e9c016d7a4299cf1de69e299c88322e3f81c716e6e23fe5683c1" ], "index": "pypi", - "version": "==2.5.0" + "markers": "python_version >= '3.8' and python_version < '4'", + "version": "==2.6.0" }, "packaging": { "hashes": [ @@ -1914,11 +1940,12 @@ }, "pytest": { "hashes": [ - "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd", - "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1" + "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343", + "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977" ], "index": "pypi", - "version": "==8.2.1" + "markers": "python_version >= '3.8'", + "version": "==8.2.2" }, "python-dateutil": { "hashes": [ @@ -1930,11 +1957,12 @@ }, "requests": { "hashes": [ - "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289", - "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c" + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" ], "index": "pypi", - "version": "==2.32.2" + "markers": "python_version >= '3.8'", + "version": "==2.32.3" }, "requests-mock": { "hashes": [ @@ -1942,6 +1970,7 @@ "sha256:e9e12e333b525156e82a3c852f22016b9158220d2f47454de9cae8a77d371401" ], "index": "pypi", + "markers": "python_version >= '3.5'", "version": "==1.12.1" }, "six": { @@ -1964,6 +1993,7 @@ "sha256:54d330d085c0a11fc5da0b001af87aec4dd3e814104376bf7513e8646c77442a" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==0.0.1rc1" }, "testcontainers-opensearch": { @@ -1971,23 +2001,24 @@ "sha256:0bdf270b5b7f53915832f7c31dd2bd3ffdc20b534ea6b32231cc7003049bd0e1" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==0.0.1rc1" }, "typing-extensions": { "hashes": [ - "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8", - "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594" + "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a", + "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1" ], "markers": "python_version >= '3.8'", - "version": "==4.12.0" + "version": "==4.12.1" }, "urllib3": { "hashes": [ - "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07", - "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0" + "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", + "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.26.18" + "markers": "python_version >= '3.10'", + "version": "==2.2.1" }, "wrapt": { "hashes": [ diff --git a/dbrepo-analyse-service/app.py b/dbrepo-analyse-service/app.py index de1ca37a4d5ac444ddb527a86e041d5868bf1e4b..0e8a10bf1dccdad1917e85407c53913529b741ba 100644 --- a/dbrepo-analyse-service/app.py +++ b/dbrepo-analyse-service/app.py @@ -19,7 +19,6 @@ from botocore.exceptions import ClientError from clients.keycloak_client import KeycloakClient, User from determine_dt import determine_datatypes from determine_pk import determine_pk -from determine_stats import determine_stats logging.addLevelName(level=logging.NOTSET, levelName='TRACE') logging.basicConfig(level=logging.DEBUG) @@ -58,7 +57,7 @@ basic_auth = HTTPBasicAuth() auth = MultiAuth(token_auth, basic_auth) metrics = PrometheusMetrics(app) -metrics.info("app_info", "Application info", version="__APPVERSION__") +metrics.info("app_info", "Application info", version="1.4.4") app.config["SWAGGER"] = {"openapi": "3.0.1", "title": "Swagger UI", "uiversion": 3} swagger_config = { @@ -79,6 +78,64 @@ swagger_config = { template = { "openapi": "3.0.0", "components": { + "schemas": { + "DataTypesDto": { + "properties": { + "columns": { + "$ref": "#/components/schemas/SuggestedColumnDto" + }, + "line_termination": { + "example": "\r\n", + "type": "string" + }, + "separator": { + "example": ",", + "type": "string" + } + }, + "type": "object" + }, + "ErrorDto": { + "properties": { + "message": { + "example": "Message", + "type": "string" + }, + "success": { + "example": False, + "type": "boolean" + } + }, + "type": "object" + }, + "KeysDto": { + "properties": { + "keys": { + "items": { + "properties": { + "column_name": { + "format": "int64", + "type": "integer" + } + } + }, + "type": "array" + } + }, + "required": [ + "keys" + ], + "type": "object" + }, + "SuggestedColumnDto": { + "properties": { + "column_name": { + "type": "string" + } + }, + "type": "object" + } + }, "securitySchemes": { "bearerAuth": { "type": "http", @@ -96,7 +153,7 @@ template = { "info": { "title": "Database Repository Analyse Service API", "description": "Service that analyses data structures", - "version": "__APPVERSION__", + "version": "1.4.4", "contact": { "name": "Prof. Andreas Rauber", "email": "andreas.rauber@tuwien.ac.at" @@ -180,7 +237,6 @@ def get_user_roles(user: User) -> List[str]: @app.route("/health", methods=["GET"], endpoint="analyse_health") -@swag_from("as-yml/health.yml") def get_health(): res = dumps({"status": "UP", "message": "Application is up and running"}) return Response(res, mimetype="application/json"), 200 @@ -231,25 +287,3 @@ def analyse_keys(): except OSError as e: logging.error(f"Failed to determine primary key: {e}") return ApiError(status='BAD_REQUEST', message=str(e), code='analyse.database.invalid'), 400 - - -@app.route("/api/analyse/database/<database_id>/table/<table_id>/statistics", methods=["GET"], - endpoint="analyse_analyse_table_stat") -@auth.login_required(role=['admin', 'export-query-data', 'export-table-data']) -@metrics.gauge(name='dbrepo_analyse_table_stat', description='Time needed to analyse table statistics') -@swag_from("as-yml/analyse_table_stat.yml") -def analyse_table_stat(database_id: int = None, table_id: int = None): - if database_id is None: - return ApiError(status='BAD_REQUEST', message="Missing path variable 'database_id'", - code='analyse.database.invalid'), 400 - if table_id is None: - return ApiError(status='BAD_REQUEST', message="Missing path variable 'table_id'", - code='analyse.table.invalid'), 400 - - try: - table_stats = determine_stats(database_id=database_id, table_id=table_id) - logging.info(f"Analysed table statistics") - return table_stats.model_dump(), 202 - except OSError: - return ApiError(status='NOT_FOUND', message='Database or table does not exist', - code='analyse.database.missing'), 404 diff --git a/dbrepo-analyse-service/as-yml/analyse_datatypes.yml b/dbrepo-analyse-service/as-yml/analyse_datatypes.yml index 5d30665da832f594a49ecf234205ccd54c1aa32d..ae52198766a9e7842f8320d338791a4f099f26a5 100644 --- a/dbrepo-analyse-service/as-yml/analyse_datatypes.yml +++ b/dbrepo-analyse-service/as-yml/analyse_datatypes.yml @@ -57,48 +57,6 @@ responses: application/json: schema: $ref: '#/components/schemas/ErrorDto' -components: - schemas: - DetermineDataTypesDto: - required: - - filename - - separator - type: object - properties: - enum: - type: boolean - example: false - enum_tol: - type: double - example: 0.01 - filename: - type: string - example: s3-key-from-seaweedfs - separator: - type: string - example: "," - DataTypesDto: - type: object - properties: - columns: - $ref: '#/components/schemas/SuggestedColumnDto' - line_termination: - type: string - example: "\r\n" - separator: - type: string - example: "," - SuggestedColumnDto: - type: object - properties: - column_name: - type: string - ErrorDto: - type: object - properties: - success: - type: boolean - example: false - message: - type: string - example: Message \ No newline at end of file +security: + - bearerAuth: [ ] + - basicAuth: [ ] diff --git a/dbrepo-analyse-service/as-yml/analyse_keys.yml b/dbrepo-analyse-service/as-yml/analyse_keys.yml index a01b396cec7f49fb0960f8025a064ca5fbb74c72..da4f0bbca04b65b8f4131a6d8ab1a4d43270ad60 100644 --- a/dbrepo-analyse-service/as-yml/analyse_keys.yml +++ b/dbrepo-analyse-service/as-yml/analyse_keys.yml @@ -45,42 +45,6 @@ responses: application/json: schema: $ref: '#/components/schemas/ErrorDto' -components: - schemas: - KeysDto: - required: - - keys - type: object - properties: - keys: - type: array - items: - properties: - column_name: - type: integer - format: int64 - DataTypesDto: - type: object - properties: - columns: - $ref: '#/components/schemas/SuggestedColumnDto' - line_termination: - type: string - example: "\r\n" - separator: - type: string - example: "," - SuggestedColumnDto: - type: object - properties: - column_name: - type: string - ErrorDto: - type: object - properties: - success: - type: boolean - example: false - message: - type: string - example: Message \ No newline at end of file +security: + - bearerAuth: [ ] + - basicAuth: [ ] \ No newline at end of file diff --git a/dbrepo-analyse-service/as-yml/analyse_table_stat.yml b/dbrepo-analyse-service/as-yml/analyse_table_stat.yml index 6978daf22904d3449c621f8e253a08908df6a8c8..8639d4dd9278ddf118f552249021fc60498dd47c 100644 --- a/dbrepo-analyse-service/as-yml/analyse_table_stat.yml +++ b/dbrepo-analyse-service/as-yml/analyse_table_stat.yml @@ -39,50 +39,3 @@ responses: application/json: schema: $ref: '#/components/schemas/ErrorDto' -components: - schemas: - TableStats: - required: - - columns - type: object - properties: - columns: - type: object - properties: - column_name: - $ref: '#/components/schemas/Stats' - Stats: - type: object - properties: - val_min: - type: float - example: "0.0" - val_max: - type: float - example: "1.0" - mean: - type: float - example: "0.3" - median: - type: float - example: "0.45" - std_dev: - type: float - example: "0.12" - ErrorDto: - type: object - properties: - success: - type: boolean - example: false - message: - type: string - example: Message - securitySchemes: - basicAuth: - type: http - scheme: basic - bearerAuth: - type: http - scheme: bearer - bearerFormat: JWT \ No newline at end of file diff --git a/dbrepo-analyse-service/as-yml/health.yml b/dbrepo-analyse-service/as-yml/health.yml deleted file mode 100644 index a0f7ebcbacbd06a4dcaf262298456cf5b713cce8..0000000000000000000000000000000000000000 --- a/dbrepo-analyse-service/as-yml/health.yml +++ /dev/null @@ -1,18 +0,0 @@ -tags: - - health-endpoint -summary: "Check if application is running" -description: "This is a simple API which checks if the application is healthy" -consumes: - - "application/json" -produces: - - "application/json" -responses: - 200: - description: "OK" - schema: - type: "object" - properties: - status: - type: "string" - example: "UP" - \ No newline at end of file diff --git a/dbrepo-analyse-service/determine_dt.py b/dbrepo-analyse-service/determine_dt.py index 5aa34240e4fa32be83e2e9626bf04931479b3d98..7c5401a20c3c37c12405c424161a5fb89e585bcd 100644 --- a/dbrepo-analyse-service/determine_dt.py +++ b/dbrepo-analyse-service/determine_dt.py @@ -9,7 +9,6 @@ import pandas from numpy import dtype, max, min from flask import current_app -from pandas._libs.tslibs.parsing import DateParseError from clients.s3_client import S3Client @@ -65,7 +64,7 @@ def determine_datatypes(filename, enum=False, enum_tol=0.0001, separator=None) - pandas.to_datetime(df[name], format='mixed') r[name] = 'timestamp' continue - except DateParseError: + except ValueError: pass max_size = max(df[name].astype(str).map(len)) if max_size <= 1: diff --git a/dbrepo-analyse-service/determine_stats.py b/dbrepo-analyse-service/determine_stats.py deleted file mode 100644 index d529ab8c28a5231f658a0081d1aec51c50a015bb..0000000000000000000000000000000000000000 --- a/dbrepo-analyse-service/determine_stats.py +++ /dev/null @@ -1,28 +0,0 @@ -import logging - -from flask import current_app - -from pandas import DataFrame, isna -from dbrepo.RestClient import RestClient - -from api.dto import TableStat, ColumnStat - - -def determine_stats(database_id: int, table_id: int) -> TableStat: - client = RestClient(endpoint=current_app.config['GATEWAY_SERVICE_ENDPOINT'], - username=current_app.config['ADMIN_USERNAME'], password=current_app.config['ADMIN_PASSWORD']) - df: DataFrame = client.get_table_data(database_id=database_id, table_id=table_id, page=0, size=1000, df=True) - stats = TableStat(columns=dict()) - for name, dtype in df.dtypes.items(): - # Check if the column has a numeric data type - if dtype.kind in "fi": - val_min = None if isna(df[name].min()) else df[name].min() - val_max = None if isna(df[name].max()) else df[name].max() - mean = None if isna(df[name].mean()) else df[name].mean() - median = None if isna(df[name].median()) else df[name].median() - std_dev = None if isna(df[name].std()) else df[name].std() - stats.columns[str(name)] = ColumnStat(val_min=val_min, val_max=val_max, mean=mean, median=median, - std_dev=std_dev) - logging.debug(f"statistical props of the first 1000 rows: <min={val_min}, max={val_max}, mean={mean}, " - f"median={median}, std_dev={std_dev}>") - return stats diff --git a/dbrepo-analyse-service/lib/dbrepo-1.4.3-py3-none-any.whl b/dbrepo-analyse-service/lib/dbrepo-1.4.3-py3-none-any.whl deleted file mode 100644 index 2e19eddac149ac401c67a52ba56577132e32869a..0000000000000000000000000000000000000000 Binary files a/dbrepo-analyse-service/lib/dbrepo-1.4.3-py3-none-any.whl and /dev/null differ diff --git a/dbrepo-analyse-service/lib/dbrepo-1.4.3.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.4.3.tar.gz deleted file mode 100644 index ffb89654bab83c6f72a9381825e41f0dbe7d37c9..0000000000000000000000000000000000000000 Binary files a/dbrepo-analyse-service/lib/dbrepo-1.4.3.tar.gz and /dev/null differ diff --git a/dbrepo-analyse-service/lib/dbrepo-1.4.4-py3-none-any.whl b/dbrepo-analyse-service/lib/dbrepo-1.4.4-py3-none-any.whl index 11873004972bb08703994ba1fb0ddf18f96f6a2c..694a6fc02560b3b5d858df0e5a0bd9acf45c8f20 100644 Binary files a/dbrepo-analyse-service/lib/dbrepo-1.4.4-py3-none-any.whl and b/dbrepo-analyse-service/lib/dbrepo-1.4.4-py3-none-any.whl differ diff --git a/dbrepo-analyse-service/lib/dbrepo-1.4.4.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.4.4.tar.gz index f7452a0e12c9a2d44f663bc1f338204b7579144b..f344d01026b92476d80703cbfb7d884cb7822e05 100644 Binary files a/dbrepo-analyse-service/lib/dbrepo-1.4.4.tar.gz and b/dbrepo-analyse-service/lib/dbrepo-1.4.4.tar.gz differ diff --git a/dbrepo-auth-service/dbrepo-realm.json b/dbrepo-auth-service/dbrepo-realm.json index f5ced37ff24b995b58f2cbb16686269b9ad46056..bd5a5464e7aeadd4c4012e7c0fa7e74efa2b6d04 100644 --- a/dbrepo-auth-service/dbrepo-realm.json +++ b/dbrepo-auth-service/dbrepo-realm.json @@ -126,7 +126,7 @@ "description" : "${default-table-handling}", "composite" : true, "composites" : { - "realm" : [ "modify-table-column-semantics", "list-tables", "find-table", "create-table", "delete-table" ] + "realm" : [ "modify-table-column-semantics", "list-tables", "update-table-statistic", "find-table", "create-table", "delete-table" ] }, "clientRole" : false, "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", @@ -166,6 +166,14 @@ "clientRole" : false, "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", "attributes" : { } + }, { + "id" : "0e12eedf-545d-4d32-ac4d-2821dcb118b8", + "name" : "update-table-statistic", + "description" : "${update-table-statistic}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } }, { "id" : "e63e61a2-d852-4ad3-bfb5-92d9ceafef6a", "name" : "escalated-user-handling", @@ -2110,7 +2118,7 @@ "subType" : "authenticated", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "saml-user-property-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper", "oidc-address-mapper" ] + "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-address-mapper" ] } }, { "id" : "3ab11d74-5e76-408a-b85a-26bf8950f979", @@ -2119,7 +2127,7 @@ "subType" : "anonymous", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "oidc-address-mapper", "saml-user-property-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper" ] + "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper", "saml-role-list-mapper", "saml-user-attribute-mapper" ] } } ], "org.keycloak.keys.KeyProvider" : [ { @@ -2171,7 +2179,7 @@ "internationalizationEnabled" : false, "supportedLocales" : [ ], "authenticationFlows" : [ { - "id" : "fbce9485-c780-438c-bbe9-135352504aa7", + "id" : "8b55b559-905f-4f73-b050-0cd68f676a42", "alias" : "Account verification options", "description" : "Method with which to verity the existing account", "providerId" : "basic-flow", @@ -2193,7 +2201,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "dce6a1a5-7099-4366-a644-79b08fd399fd", + "id" : "293efab0-aa10-44e6-8f5a-dd63d6908d9e", "alias" : "Authentication Options", "description" : "Authentication options.", "providerId" : "basic-flow", @@ -2222,7 +2230,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "ac79c3e5-8aa3-499c-ae23-1656ab67972c", + "id" : "f3c7659d-9c24-43e7-b94c-8bfb4811084f", "alias" : "Browser - Conditional OTP", "description" : "Flow to determine if the OTP is required for the authentication", "providerId" : "basic-flow", @@ -2244,7 +2252,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "ecafaa7c-4a1f-4842-b8cd-6661fea1da33", + "id" : "1d83f267-0342-41c1-9a64-11cc9b8e62fc", "alias" : "Direct Grant - Conditional OTP", "description" : "Flow to determine if the OTP is required for the authentication", "providerId" : "basic-flow", @@ -2266,7 +2274,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "55d29fb3-07a8-47b7-a051-9176e404ab55", + "id" : "bb881bf0-e8f5-418e-91ec-09624683ec66", "alias" : "First broker login - Conditional OTP", "description" : "Flow to determine if the OTP is required for the authentication", "providerId" : "basic-flow", @@ -2288,7 +2296,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "23a6b3f9-d7dc-41f0-b9b0-917e64aa62ed", + "id" : "aea83d83-6c28-4df6-9543-2bf74cc4b78a", "alias" : "Handle Existing Account", "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider", "providerId" : "basic-flow", @@ -2310,7 +2318,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "ea03fe83-9a6c-47e0-85e9-94fb006bc504", + "id" : "78283326-7419-4cca-a5dd-cf510db7041c", "alias" : "Reset - Conditional OTP", "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", "providerId" : "basic-flow", @@ -2332,7 +2340,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "c2f4bb71-24a7-42a2-a870-d0485b6430f7", + "id" : "c88bb673-7092-4996-8c46-e9b08c94eb8c", "alias" : "User creation or linking", "description" : "Flow for the existing/non-existing user alternatives", "providerId" : "basic-flow", @@ -2355,7 +2363,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "08a0c43e-434c-4f9d-97d8-efcc697c0bdb", + "id" : "6632c7a3-8a7f-4f94-a15d-bdce1563f419", "alias" : "Verify Existing Account by Re-authentication", "description" : "Reauthentication of existing account", "providerId" : "basic-flow", @@ -2377,7 +2385,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "9df5a633-532d-4da0-99ad-b60bac9a984b", + "id" : "3a383f61-8ad4-4815-93a8-d04eefc48791", "alias" : "browser", "description" : "browser based authentication", "providerId" : "basic-flow", @@ -2413,7 +2421,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "cac0d15d-bba8-4731-a184-5711bfdc38d8", + "id" : "fc65865d-d3a4-4769-a665-fd49b34d2687", "alias" : "clients", "description" : "Base authentication for clients", "providerId" : "client-flow", @@ -2449,7 +2457,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "5cb539c9-6124-4883-b058-e4b0062c8ed0", + "id" : "40077362-bb0b-41c7-a297-1d4c3625b17d", "alias" : "direct grant", "description" : "OpenID Connect Resource Owner Grant", "providerId" : "basic-flow", @@ -2478,7 +2486,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "610d7baf-f915-44e0-8617-8ae6309b1098", + "id" : "5b2f7f25-f5dd-4013-800d-6030b79e257e", "alias" : "docker auth", "description" : "Used by Docker clients to authenticate against the IDP", "providerId" : "basic-flow", @@ -2493,7 +2501,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "d613df19-1185-4796-b1e9-9716f4b241c9", + "id" : "e9da2536-e792-461d-aceb-085f18ca533c", "alias" : "first broker login", "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", "providerId" : "basic-flow", @@ -2516,7 +2524,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "7a475371-0966-4dff-9296-28790d5aa227", + "id" : "4c17ae53-d99e-4f47-92ef-47accae912fd", "alias" : "forms", "description" : "Username, password, otp and other auth forms.", "providerId" : "basic-flow", @@ -2538,7 +2546,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "7d71011c-9828-495a-8fc6-82e88e308d26", + "id" : "da0ed32c-3259-4571-877b-914fa2aa30b3", "alias" : "http challenge", "description" : "An authentication flow based on challenge-response HTTP Authentication Schemes", "providerId" : "basic-flow", @@ -2560,7 +2568,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "0eb1b344-0a43-4ffa-8bf2-98560bd7471f", + "id" : "476d469b-5c54-42af-a41c-5dbe08412395", "alias" : "registration", "description" : "registration flow", "providerId" : "basic-flow", @@ -2576,7 +2584,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "fd2328ca-38ca-4dc9-b9e5-09790a3512c5", + "id" : "714c4dc0-d7b3-4e12-93bd-59a7c4fbeef2", "alias" : "registration form", "description" : "registration form", "providerId" : "form-flow", @@ -2612,7 +2620,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "770cf19b-4bc2-4161-b156-161dc23eebaa", + "id" : "316122ff-d003-49f7-9a0d-a570489bec9d", "alias" : "reset credentials", "description" : "Reset credentials for a user if they forgot their password or something", "providerId" : "basic-flow", @@ -2648,7 +2656,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "ab251c63-6c1b-4d93-9f26-2f5d18c81832", + "id" : "5c90488c-9d5c-460d-9deb-9740740c3a9e", "alias" : "saml ecp", "description" : "SAML ECP Profile Authentication Flow", "providerId" : "basic-flow", @@ -2664,13 +2672,13 @@ } ] } ], "authenticatorConfig" : [ { - "id" : "709dcd0e-a60b-4ae5-ac66-d15374b1562c", + "id" : "874c7063-05d5-45fb-b919-840798663176", "alias" : "create unique user config", "config" : { "require.password.update.after.registration" : "false" } }, { - "id" : "f80268b2-6944-4acd-b622-426369f8c44d", + "id" : "93cf220e-2830-4ccb-9054-b3b87ef75fd4", "alias" : "review profile config", "config" : { "update.profile.on.first.login" : "missing" diff --git a/dbrepo-data-db/sidecar/app.py b/dbrepo-data-db/sidecar/app.py index f4342301dfed6a16dc21a60db21c1d0272b07061..c88966bb00e789e8b102985a5abbdf4ec7034c90 100644 --- a/dbrepo-data-db/sidecar/app.py +++ b/dbrepo-data-db/sidecar/app.py @@ -170,7 +170,6 @@ def get_user_roles(user: User) -> List[str]: @app.route("/health", methods=["GET"], endpoint="actuator_health") -@swag_from("ds-yml/health.yml") def health(): logging.debug("endpoint health, body=%s", request) res = dumps({"status": "UP", "message": "Application is up and running"}) diff --git a/dbrepo-data-db/sidecar/ds-yml/import.yml b/dbrepo-data-db/sidecar/ds-yml/import.yml index a129e86fa1aa0a0768b718f9115934b8ca7113b1..87c6777127ffaf36caf42a567140148f09b7ee64 100644 --- a/dbrepo-data-db/sidecar/ds-yml/import.yml +++ b/dbrepo-data-db/sidecar/ds-yml/import.yml @@ -11,8 +11,8 @@ parameters: description: Name of the object file to import from the Storage Service required: true security: -- bearerAuth: [] -- basicAuth: [] + - bearerAuth: [ ] + - basicAuth: [ ] responses: 202: description: Imported the .csv diff --git a/dbrepo-data-service/Dockerfile b/dbrepo-data-service/Dockerfile index 0d278d8a016734b9daf3740d54f8d5273b6fe3c7..d4016836d91bf88f09ad60279689d9b16b5d9bb8 100644 --- a/dbrepo-data-service/Dockerfile +++ b/dbrepo-data-service/Dockerfile @@ -21,9 +21,11 @@ COPY ./services ./services RUN mvn clean package -DskipTests ###### THIRD STAGE ###### -FROM eclipse-temurin:17-jdk as runtime +FROM amazoncorretto:17-alpine3.19 as runtime MAINTAINER Martin Weise <martin.weise@tuwien.ac.at> +RUN apk add --no-cache curl bash jq + WORKDIR /app USER 65534 diff --git a/dbrepo-data-service/metrics.md b/dbrepo-data-service/metrics.md index 5e0773ad8c40200051ba25a814268208c57e2e26..425b58ad17e24683a606cf0a4cb9d3123412e4cf 100644 --- a/dbrepo-data-service/metrics.md +++ b/dbrepo-data-service/metrics.md @@ -6,12 +6,14 @@ | `dbrepo_subset_find` | Find subset | | `dbrepo_subset_list` | Find subsets | | `dbrepo_subset_persist` | Persist subset | -| `dbrepo_table_data_create` | Create table data | +| `dbrepo_table_data_create` | Insert a raw data tuple | | `dbrepo_table_data_delete` | Delete table data | | `dbrepo_table_data_export` | Export table data | | `dbrepo_table_data_history` | Find table history | -| `dbrepo_table_data_import` | Import dataset | +| `dbrepo_table_data_import` | Import data from a dataset | | `dbrepo_table_data_list` | Retrieve table data | -| `dbrepo_table_data_update` | Update table data | +| `dbrepo_table_data_update` | Update a raw data tuple | +| `dbrepo_table_schema_list` | Find table schemas | +| `dbrepo_table_statistic` | Generate table statistic | | `dbrepo_view_data` | Retrieve view data | | `dbrepo_view_schema_list` | Find view schemas | diff --git a/dbrepo-data-service/pom.xml b/dbrepo-data-service/pom.xml index 98ad4d797ce44b3e92a2644562e56118e9c7932b..3df58f676f876a8729e6485eef9291717404a242 100644 --- a/dbrepo-data-service/pom.xml +++ b/dbrepo-data-service/pom.xml @@ -60,7 +60,7 @@ <jackson-datatype.version>2.15.0</jackson-datatype.version> <commons-io.version>2.15.0</commons-io.version> <commons-validator.version>1.8.0</commons-validator.version> - <jacoco.version>0.8.11</jacoco.version> + <jacoco.version>0.8.12</jacoco.version> <jwt.version>4.3.0</jwt.version> <opencsv.version>5.7.1</opencsv.version> <super-csv.version>2.4.0</super-csv.version> @@ -266,16 +266,6 @@ <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>${jacoco.version}</version> - <configuration> - <excludes> - <exclude>at/tuwien/mapper/**/*</exclude> - <exclude>at/tuwien/exception/**/*</exclude> - <exclude>at/tuwien/config/**/*</exclude> - <exclude>at/tuwien/auth/**/*</exclude> - <exclude>at/tuwien/handlers/**/*</exclude> - <exclude>**/DbrepoDataServiceApplication.class</exclude> - </excludes> - </configuration> <executions> <execution> <id>default-prepare-agent</id> diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java index ea7b1b3677cea807fc3892b6835db60f58233b41..4b58c5de3363606e17358de63e35fc8125c555b0 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java @@ -4,6 +4,7 @@ import at.tuwien.api.database.UpdateDatabaseAccessDto; import at.tuwien.api.database.internal.PrivilegedDatabaseDto; import at.tuwien.api.error.ApiErrorDto; import at.tuwien.api.user.PrivilegedUserDto; +import at.tuwien.api.user.UserDto; import at.tuwien.exception.*; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.service.AccessService; @@ -42,7 +43,8 @@ public class AccessEndpoint { @PostMapping("/{userId}") @PreAuthorize("hasAuthority('admin')") - @Operation(summary = "Give access to some database", security = {@SecurityRequirement(name = "basicAuth")}) + @Operation(summary = "Give access to some database", security = {@SecurityRequirement(name = "basicAuth")}, + hidden = true) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Granting access succeeded"), @@ -76,10 +78,10 @@ public class AccessEndpoint { @NotBlank @PathVariable("userId") UUID userId, @Valid @RequestBody UpdateDatabaseAccessDto data) throws NotAllowedException, QueryMalformedException, DatabaseNotFoundException, RemoteUnavailableException, - UserNotFoundException, DatabaseMalformedException { + UserNotFoundException, DatabaseMalformedException, ServiceException { log.debug("endpoint give access to database, databaseId={}, userId={}", databaseId, userId); final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId); - final PrivilegedUserDto user = metadataServiceGateway.getUserById(userId); + final PrivilegedUserDto user = metadataServiceGateway.getPrivilegedUserById(userId); if (database.getAccesses().stream().anyMatch(a -> a.getUser().getId().equals(userId))) { log.error("Failed to create access to user with id {}: already has access", userId); throw new NotAllowedException("Failed to create access to user with id " + userId + ": already has access"); @@ -95,7 +97,8 @@ public class AccessEndpoint { @PutMapping("/{userId}") @PreAuthorize("hasAuthority('admin')") - @Operation(summary = "Update access to some database", security = {@SecurityRequirement(name = "basicAuth")}) + @Operation(summary = "Update access to some database", security = {@SecurityRequirement(name = "basicAuth")}, + hidden = true) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Update access succeeded", @@ -130,11 +133,11 @@ public class AccessEndpoint { @NotBlank @PathVariable("userId") UUID userId, @Valid @RequestBody UpdateDatabaseAccessDto access) throws NotAllowedException, QueryMalformedException, DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, - DatabaseMalformedException { + DatabaseMalformedException, ServiceException { log.debug("endpoint modify access to database, databaseId={}, userId={}, access.type={}", databaseId, userId, access.getType()); final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId); - final PrivilegedUserDto user = metadataServiceGateway.getUserById(userId); + final UserDto user = metadataServiceGateway.getUserById(userId); if (database.getAccesses().stream().noneMatch(a -> a.getUser().getId().equals(userId))) { log.error("Failed to update access to user with id {}: no access", userId); throw new NotAllowedException("Failed to update access to user with id " + userId + ": no access"); @@ -150,7 +153,8 @@ public class AccessEndpoint { @DeleteMapping("/{userId}") @PreAuthorize("hasAuthority('admin')") - @Operation(summary = "Revoke access to some database", security = {@SecurityRequirement(name = "basicAuth")}) + @Operation(summary = "Revoke access to some database", security = {@SecurityRequirement(name = "basicAuth")}, + hidden = true) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Revoked access successfully"), @@ -183,10 +187,10 @@ public class AccessEndpoint { public ResponseEntity<?> revoke(@NotBlank @PathVariable("databaseId") Long databaseId, @NotBlank @PathVariable("userId") UUID userId) throws NotAllowedException, QueryMalformedException, DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, - DatabaseMalformedException { + DatabaseMalformedException, ServiceException { log.debug("endpoint revoke access to database, databaseId={}, userId={}", databaseId, userId); final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId); - final PrivilegedUserDto user = metadataServiceGateway.getUserById(userId); + final UserDto user = metadataServiceGateway.getUserById(userId); if (database.getAccesses().stream().noneMatch(a -> a.getUser().getId().equals(userId))) { log.error("Failed to delete access to user with id {}: no access", userId); throw new NotAllowedException("Failed to delete access to user with id " + userId + ": no access"); diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java index f69019e7178dd8631723d929747d8654d94881e4..bd32093068efc009a835975c9622f7bbe83eb1a5 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java @@ -54,7 +54,8 @@ public class DatabaseEndpoint { @PostMapping @PreAuthorize("hasAuthority('admin')") - @Operation(summary = "Create database", security = {@SecurityRequirement(name = "basicAuth")}) + @Operation(summary = "Create database", security = {@SecurityRequirement(name = "basicAuth")}, + hidden = true) @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Created a database", @@ -84,7 +85,7 @@ public class DatabaseEndpoint { }) public ResponseEntity<DatabaseDto> create(@Valid @RequestBody CreateDatabaseDto data) throws DatabaseUnavailableException, RemoteUnavailableException, ContainerNotFoundException, - DatabaseMalformedException, QueryStoreCreateException { + DatabaseMalformedException, QueryStoreCreateException, ServiceException { log.debug("endpoint create database, data.containerId={}, data.internalName={}, data.username={}", data.getContainerId(), data.getInternalName(), data.getUsername()); final PrivilegedContainerDto container = metadataServiceGateway.getContainerById(data.getContainerId()); @@ -107,7 +108,8 @@ public class DatabaseEndpoint { @PutMapping("/{databaseId}") @PreAuthorize("hasAuthority('admin')") - @Operation(summary = "Update user password in database", security = {@SecurityRequirement(name = "basicAuth")}) + @Operation(summary = "Update user password in database", security = {@SecurityRequirement(name = "basicAuth")}, + hidden = true) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Updated user password in database"), @@ -130,7 +132,7 @@ public class DatabaseEndpoint { public ResponseEntity<Void> update(@NotBlank @PathVariable("databaseId") Long databaseId, @Valid @RequestBody UpdateUserPasswordDto data) throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, - DatabaseMalformedException { + DatabaseMalformedException, ServiceException { log.debug("endpoint update user password in database, databaseId={}, data.username={}", databaseId, data.getUsername()); final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId); diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/SubsetEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/SubsetEndpoint.java index b9a9ae442d8a34340237a9098e79b3a08baa95f8..0d4b53b92c9cb32ee588abc917a81b3d222fa8d8 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/SubsetEndpoint.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/SubsetEndpoint.java @@ -84,7 +84,7 @@ public class SubsetEndpoint { @RequestParam(name = "persisted", required = false) Boolean filterPersisted, Principal principal) throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, - QueryNotFoundException, NotAllowedException { + QueryNotFoundException, NotAllowedException, ServiceException { log.debug("endpoint find subsets in database, databaseId={}, filterPersisted={}, principal.name={}", databaseId, filterPersisted, principal != null ? principal.getName() : null); final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId); @@ -149,7 +149,8 @@ public class SubsetEndpoint { Principal principal) throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, QueryNotFoundException, FormatNotAvailableException, StorageUnavailableException, QueryMalformedException, - SidecarExportException, StorageNotFoundException, NotAllowedException, UserNotFoundException { + SidecarExportException, StorageNotFoundException, NotAllowedException, UserNotFoundException, + ServiceException { String accept = httpServletRequest.getHeader("Accept"); log.debug("endpoint find subset in database, databaseId={}, subsetId={}, accept={}, timestamp={}", databaseId, subsetId, accept, timestamp); @@ -251,7 +252,7 @@ public class SubsetEndpoint { throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, QueryNotFoundException, StorageUnavailableException, QueryMalformedException, SidecarExportException, StorageNotFoundException, QueryStoreInsertException, TableMalformedException, PaginationException, - QueryNotSupportedException, NotAllowedException, UserNotFoundException { + QueryNotSupportedException, NotAllowedException, UserNotFoundException, ServiceException { log.debug("endpoint create subset in database, databaseId={}, data.statement={}, principal.name={}, page={}, size={}, timestamp={}", databaseId, data.getStatement(), principal.getName(), page, size, timestamp); /* check */ @@ -323,7 +324,8 @@ public class SubsetEndpoint { @RequestParam(required = false) Long page, @RequestParam(required = false) Long size) throws PaginationException, DatabaseNotFoundException, RemoteUnavailableException, NotAllowedException, QueryNotFoundException, - DatabaseUnavailableException, TableMalformedException, QueryMalformedException, UserNotFoundException { + DatabaseUnavailableException, TableMalformedException, QueryMalformedException, UserNotFoundException, + ServiceException { log.debug("endpoint re-execute query, databaseId={}, subsetId={}, principal.name={} page={}, size={}", databaseId, subsetId, principal != null ? principal.getName() : null, page, size); endpointValidator.validateDataParams(page, size); @@ -408,7 +410,7 @@ public class SubsetEndpoint { @NotNull @Valid @RequestBody QueryPersistDto data, @NotNull Principal principal) throws NotAllowedException, RemoteUnavailableException, DatabaseNotFoundException, QueryStorePersistException, - DatabaseUnavailableException, QueryNotFoundException, UserNotFoundException { + DatabaseUnavailableException, QueryNotFoundException, UserNotFoundException, ServiceException { log.debug("endpoint persist query, databaseId={}, queryId={}, data.persist={}, principal.name={}", databaseId, queryId, data.getPersist(), principal.getName()); metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal)); diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java index d00089687032e3ae0ccfd84309620b264438c0be..6856e634ab6776f6db497428cfaaad5aa64394a7 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java @@ -12,7 +12,6 @@ import at.tuwien.api.database.table.internal.TableCreateDto; import at.tuwien.api.error.ApiErrorDto; import at.tuwien.exception.*; import at.tuwien.gateway.MetadataServiceGateway; -import at.tuwien.service.AnalyseService; import at.tuwien.service.TableService; import at.tuwien.utils.UserUtil; import at.tuwien.validation.EndpointValidator; @@ -47,22 +46,21 @@ import java.util.List; public class TableEndpoint { private final TableService tableService; - private final AnalyseService analyseService; private final EndpointValidator endpointValidator; private final MetadataServiceGateway metadataServiceGateway; @Autowired - public TableEndpoint(TableService tableService, AnalyseService analyseService, EndpointValidator endpointValidator, + public TableEndpoint(TableService tableService, EndpointValidator endpointValidator, MetadataServiceGateway metadataServiceGateway) { this.tableService = tableService; - this.analyseService = analyseService; this.endpointValidator = endpointValidator; this.metadataServiceGateway = metadataServiceGateway; } @PostMapping @PreAuthorize("hasAuthority('admin')") - @Operation(summary = "Create table", security = {@SecurityRequirement(name = "basicAuth")}) + @Operation(summary = "Create table", security = {@SecurityRequirement(name = "basicAuth")}, + hidden = true) @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Created table", @@ -93,7 +91,7 @@ public class TableEndpoint { public ResponseEntity<TableDto> create(@NotNull @PathVariable("databaseId") Long databaseId, @Valid @RequestBody TableCreateDto data) throws DatabaseNotFoundException, RemoteUnavailableException, TableMalformedException, DatabaseUnavailableException, TableExistsException, - TableNotFoundException, QueryMalformedException { + TableNotFoundException, QueryMalformedException, ServiceException { log.debug("endpoint create table, databaseId={}, data.name={}", databaseId, data.getName()); final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId); try { @@ -107,7 +105,8 @@ public class TableEndpoint { @DeleteMapping("/{tableId}") @PreAuthorize("hasAuthority('admin')") - @Operation(summary = "Delete table", security = {@SecurityRequirement(name = "basicAuth")}) + @Operation(summary = "Delete table", security = {@SecurityRequirement(name = "basicAuth")}, + hidden = true) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Deleted table", @@ -133,7 +132,7 @@ public class TableEndpoint { public ResponseEntity<Void> delete(@NotBlank @PathVariable("databaseId") Long databaseId, @NotBlank @PathVariable("tableId") Long tableId) throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, - QueryMalformedException { + QueryMalformedException, ServiceException { log.debug("endpoint delete table, databaseId={}, tableId={}", databaseId, tableId); final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId); try { @@ -177,7 +176,7 @@ public class TableEndpoint { @RequestParam(required = false) Long page, @RequestParam(required = false) Long size) throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, - TableMalformedException, PaginationException, QueryMalformedException { + TableMalformedException, PaginationException, QueryMalformedException, ServiceException { log.debug("endpoint find table data, databaseId={}, tableId={}, timestamp={}, page={}, size={}", databaseId, tableId, timestamp, page, size); endpointValidator.validateDataParams(page, size); @@ -212,7 +211,9 @@ public class TableEndpoint { @PostMapping("/{tableId}/data") @PreAuthorize("hasAuthority('insert-table-data')") @Observed(name = "dbrepo_table_data_create") - @Operation(summary = "Create table data", security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")}) + @Operation(summary = "Insert a raw data tuple", + description = "Inserts a raw data tuple into a table with at least WRITE_OWN access. Then update the table statistics.", + security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Created table data"), @@ -227,30 +228,30 @@ public class TableEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), @ApiResponse(responseCode = "404", - description = "Failed to find table in metadata database", + description = "Failed to find table in metadata database or blob in storage service", content = {@Content( mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), @ApiResponse(responseCode = "503", - description = "Failed to establish connection with the metadata service", + description = "Failed to establish connection with the metadata service or storage service", content = {@Content( mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<Void> createTuple(@NotBlank @PathVariable("databaseId") Long databaseId, - @NotBlank @PathVariable("tableId") Long tableId, - @Valid @RequestBody TupleDto data, - @NotNull Principal principal) + public ResponseEntity<Void> insertRawTuple(@NotBlank @PathVariable("databaseId") Long databaseId, + @NotBlank @PathVariable("tableId") Long tableId, + @Valid @RequestBody TupleDto data, + @NotNull Principal principal) throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, - TableMalformedException, QueryMalformedException, NotAllowedException { - log.debug("endpoint create table data, databaseId={}, tableId={}", databaseId, tableId); + TableMalformedException, QueryMalformedException, NotAllowedException, StorageUnavailableException, + StorageNotFoundException, ServiceException { + log.debug("endpoint insert raw table data, databaseId={}, tableId={}", databaseId, tableId); final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId); final DatabaseAccessDto access = metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal)); endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), UserUtil.getId(principal)); try { tableService.createTuple(table, data); - final TableStatisticDto statistics = analyseService.analyseTable(databaseId, tableId); - metadataServiceGateway.updateTableStatistics(databaseId, tableId, statistics); + metadataServiceGateway.updateTableStatistics(databaseId, tableId); return ResponseEntity.status(HttpStatus.CREATED) .build(); } catch (SQLException e) { @@ -262,7 +263,9 @@ public class TableEndpoint { @PutMapping("/{tableId}/data") @PreAuthorize("hasAuthority('insert-table-data')") @Observed(name = "dbrepo_table_data_update") - @Operation(summary = "Update table data", security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")}) + @Operation(summary = "Update a raw data tuple", + description = "Updates a raw data tuple in a table with at least WRITE_OWN access. Then update the table statistics.", + security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Updated table data"), @@ -287,21 +290,20 @@ public class TableEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<Void> updateTuple(@NotBlank @PathVariable("databaseId") Long databaseId, - @NotBlank @PathVariable("tableId") Long tableId, - @Valid @RequestBody TupleUpdateDto data, - @NotNull Principal principal) + public ResponseEntity<Void> updateRawTuple(@NotBlank @PathVariable("databaseId") Long databaseId, + @NotBlank @PathVariable("tableId") Long tableId, + @Valid @RequestBody TupleUpdateDto data, + @NotNull Principal principal) throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, - TableMalformedException, QueryMalformedException, NotAllowedException { - log.debug("endpoint update table data, databaseId={}, tableId={}, data.keys={}", databaseId, tableId, + TableMalformedException, QueryMalformedException, NotAllowedException, ServiceException { + log.debug("endpoint update raw table data, databaseId={}, tableId={}, data.keys={}", databaseId, tableId, data.getKeys()); final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId); final DatabaseAccessDto access = metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal)); endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), UserUtil.getId(principal)); try { tableService.updateTuple(table, data); - final TableStatisticDto statistics = analyseService.analyseTable(databaseId, tableId); - metadataServiceGateway.updateTableStatistics(databaseId, tableId, statistics); + metadataServiceGateway.updateTableStatistics(databaseId, tableId); return ResponseEntity.status(HttpStatus.ACCEPTED) .build(); } catch (SQLException e) { @@ -313,7 +315,9 @@ public class TableEndpoint { @DeleteMapping("/{tableId}/data") @PreAuthorize("hasAuthority('delete-table-data')") @Observed(name = "dbrepo_table_data_delete") - @Operation(summary = "Delete table data", security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")}) + @Operation(summary = "Delete table data", + description = "Deletes a raw data tuple in a table with at least WRITE_OWN access. Then update the table statistics.", + security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Deleted table data"), @@ -338,21 +342,20 @@ public class TableEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<Void> deleteTuple(@NotBlank @PathVariable("databaseId") Long databaseId, - @NotBlank @PathVariable("tableId") Long tableId, - @Valid @RequestBody TupleDeleteDto data, - @NotNull Principal principal) + public ResponseEntity<Void> deleteRawTuple(@NotBlank @PathVariable("databaseId") Long databaseId, + @NotBlank @PathVariable("tableId") Long tableId, + @Valid @RequestBody TupleDeleteDto data, + @NotNull Principal principal) throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, - TableMalformedException, QueryMalformedException, NotAllowedException { - log.debug("endpoint update table data, databaseId={}, tableId={}, data.keys={}", databaseId, tableId, + TableMalformedException, QueryMalformedException, NotAllowedException, ServiceException { + log.debug("endpoint delete raw table data, databaseId={}, tableId={}, data.keys={}", databaseId, tableId, data.getKeys()); final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId); final DatabaseAccessDto access = metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal)); endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), UserUtil.getId(principal)); try { tableService.deleteTuple(table, data); - final TableStatisticDto statistics = analyseService.analyseTable(databaseId, tableId); - metadataServiceGateway.updateTableStatistics(databaseId, tableId, statistics); + metadataServiceGateway.updateTableStatistics(databaseId, tableId); return ResponseEntity.status(HttpStatus.ACCEPTED) .build(); } catch (SQLException e) { @@ -363,13 +366,20 @@ public class TableEndpoint { @GetMapping("/{tableId}/history") @Observed(name = "dbrepo_table_data_history") - @Operation(summary = "Find table history", security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")}) + @Operation(summary = "Find table history", + description = "Lists the insert/delete operations performed. Authentication is only required for tables in private databases", + security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Found table history", content = {@Content( mediaType = "application/json", schema = @Schema(implementation = TableHistoryDto[].class))}), + @ApiResponse(responseCode = "400", + description = "Invalid pagination request", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), @ApiResponse(responseCode = "403", description = "Find table history not allowed", content = {@Content( @@ -386,19 +396,30 @@ public class TableEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<List<TableHistoryDto>> getHistory(@NotBlank @PathVariable("databaseId") Long databaseId, - @NotBlank @PathVariable("tableId") Long tableId, + public ResponseEntity<List<TableHistoryDto>> getHistory(@NotNull @PathVariable("databaseId") Long databaseId, + @NotNull @PathVariable("tableId") Long tableId, + @RequestParam(value = "size", required = false) Long size, Principal principal) throws DatabaseUnavailableException, - RemoteUnavailableException, TableNotFoundException, NotAllowedException { + RemoteUnavailableException, TableNotFoundException, NotAllowedException, ServiceException, + PaginationException { log.debug("endpoint find table history, databaseId={}, tableId={}", databaseId, tableId); + if (size != null && size <= 0) { + log.error("Invalid size: must be > 0"); + throw new PaginationException("Invalid size: must be bigger than zero"); + } else if (size == null) { + log.debug("size not set: default to 100L"); + size = 100L; + } final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId); - if (!table.getIsPublic() && principal == null) { - log.error("Failed to find table history: no authentication found"); - throw new NotAllowedException("Failed to find table history: no authentication found"); + if (!table.getIsPublic()) { + if (principal == null) { + log.error("Failed to find table history: no authentication found"); + throw new NotAllowedException("Failed to find table history: no authentication found"); + } + metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal)); } - metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal)); try { - final List<TableHistoryDto> dto = tableService.history(table); + final List<TableHistoryDto> dto = tableService.history(table, size); return ResponseEntity.status(HttpStatus.OK) .body(dto); } catch (SQLException e) { @@ -408,8 +429,9 @@ public class TableEndpoint { } @GetMapping - @PreAuthorize("isAuthenticated()") - @Operation(summary = "Find table schemas") + @PreAuthorize("hasAuthority('admin')") + @Observed(name = "dbrepo_table_schema_list") + @Operation(summary = "Find table schemas", hidden = true) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Got table schemas", @@ -444,7 +466,7 @@ public class TableEndpoint { }) public ResponseEntity<List<TableDto>> getSchema(@NotBlank @PathVariable("databaseId") Long databaseId) throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, - DatabaseMalformedException, TableNotFoundException, QueryMalformedException { + DatabaseMalformedException, TableNotFoundException, QueryMalformedException, ServiceException { log.debug("endpoint inspect table schemas, databaseId={}", databaseId); final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId); try { @@ -491,7 +513,7 @@ public class TableEndpoint { Principal principal) throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, NotAllowedException, StorageUnavailableException, QueryMalformedException, SidecarExportException, - StorageNotFoundException { + StorageNotFoundException, ServiceException { log.debug("endpoint find table history, databaseId={}, tableId={}, timestamp={}", databaseId, tableId, timestamp); final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId); if (!table.getIsPublic()) { @@ -524,12 +546,14 @@ public class TableEndpoint { @PostMapping("/{tableId}/data/import") @Observed(name = "dbrepo_table_data_import") @PreAuthorize("hasAuthority('insert-table-data')") - @Operation(summary = "Import dataset", security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")}) + @Operation(summary = "Import data from a dataset", + description = "Deletes a raw data tuple in a table with at least WRITE_OWN access. Then update the table statistics.", + security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", - description = "Import dataset successfully"), + description = "Imported dataset successfully"), @ApiResponse(responseCode = "400", - description = "Import dataset query is malformed", + description = "Dataset query is malformed", content = {@Content( mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), @@ -549,12 +573,13 @@ public class TableEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<Void> importData(@NotBlank @PathVariable("databaseId") Long databaseId, - @NotBlank @PathVariable("tableId") Long tableId, - @Valid @RequestBody ImportCsvDto data, - @NotNull Principal principal) + public ResponseEntity<Void> importDataset(@NotBlank @PathVariable("databaseId") Long databaseId, + @NotBlank @PathVariable("tableId") Long tableId, + @Valid @RequestBody ImportCsvDto data, + @NotNull Principal principal) throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, - QueryMalformedException, StorageNotFoundException, SidecarImportException, NotAllowedException { + QueryMalformedException, StorageNotFoundException, SidecarImportException, NotAllowedException, + ServiceException { log.debug("endpoint insert table data, databaseId={}, tableId={}, data.location={}", databaseId, tableId, data.getLocation()); final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId); final DatabaseAccessDto access = metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal)); @@ -569,11 +594,49 @@ public class TableEndpoint { } try { tableService.importDataset(table, data); - final TableStatisticDto statistics = analyseService.analyseTable(databaseId, tableId); - metadataServiceGateway.updateTableStatistics(databaseId, tableId, statistics); + metadataServiceGateway.updateTableStatistics(databaseId, tableId); return ResponseEntity.accepted() .build(); + } catch (SQLException e) { + log.error("Failed to establish connection to database: {}", e.getMessage()); + throw new DatabaseUnavailableException("Failed to establish connection to database", e); + } + } + @GetMapping("/{tableId}/statistic") + @Observed(name = "dbrepo_table_statistic") + @Operation(summary = "Generate table statistic") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Generated table statistic", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = TableStatisticDto.class))}), + @ApiResponse(responseCode = "400", + description = "Failed to obtain column statistic", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), + @ApiResponse(responseCode = "404", + description = "Failed to find table in metadata database", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), + @ApiResponse(responseCode = "503", + description = "Failed to establish connection with the metadata service", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), + }) + public ResponseEntity<TableStatisticDto> statistic(@NotBlank @PathVariable("databaseId") Long databaseId, + @NotBlank @PathVariable("tableId") Long tableId) + throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, + ServiceException, TableMalformedException, QueryMalformedException { + log.debug("endpoint generate table statistic, databaseId={}, tableId={}", databaseId, tableId); + final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId); + try { + final TableStatisticDto dto = tableService.getStatistics(table); + return ResponseEntity.ok(dto); } catch (SQLException e) { log.error("Failed to establish connection to database: {}", e.getMessage()); throw new DatabaseUnavailableException("Failed to establish connection to database", e); diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java index 91e5f7390dbe542e39bfa826981dae18574eb647..64eea4ebd0ba058691faad70cafd5d9d7df1fec0 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java @@ -4,7 +4,6 @@ import at.tuwien.api.database.*; import at.tuwien.api.database.internal.PrivilegedDatabaseDto; import at.tuwien.api.database.internal.PrivilegedViewDto; import at.tuwien.api.database.query.QueryResultDto; -import at.tuwien.api.database.table.TableDto; import at.tuwien.api.error.ApiErrorDto; import at.tuwien.exception.*; import at.tuwien.gateway.MetadataServiceGateway; @@ -54,9 +53,9 @@ public class ViewEndpoint { } @GetMapping - @PreAuthorize("isAuthenticated()") + @PreAuthorize("hasAuthority('admin')") @Observed(name = "dbrepo_view_schema_list") - @Operation(summary = "Find view schemas") + @Operation(summary = "Find view schemas", hidden = true) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Found view schemas", @@ -91,7 +90,8 @@ public class ViewEndpoint { }) public ResponseEntity<List<ViewDto>> getSchema(@NotBlank @PathVariable("databaseId") Long databaseId) throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, - ViewMalformedException, ViewNotFoundException, DatabaseMalformedException, ViewSchemaException { + ViewMalformedException, ViewNotFoundException, DatabaseMalformedException, ViewSchemaException, + ServiceException { log.debug("endpoint inspect view schemas, databaseId={}", databaseId); final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId); try { @@ -104,7 +104,8 @@ public class ViewEndpoint { @PostMapping @PreAuthorize("hasAuthority('admin')") - @Operation(summary = "Create view", security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")}) + @Operation(summary = "Create view", security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")}, + hidden = true) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Created view", @@ -134,7 +135,7 @@ public class ViewEndpoint { }) public ResponseEntity<ViewDto> create(@NotNull @PathVariable("databaseId") Long databaseId, @Valid @RequestBody ViewCreateDto data) throws DatabaseUnavailableException, - DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException { + DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException, ServiceException { log.debug("endpoint create view, databaseId={}, data.name={}", databaseId, data.getName()); final PrivilegedDatabaseDto database = metadataServiceGateway.getDatabaseById(databaseId); try { @@ -148,7 +149,8 @@ public class ViewEndpoint { @DeleteMapping("/{viewId}") @PreAuthorize("hasAuthority('admin')") - @Operation(summary = "Delete view", security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")}) + @Operation(summary = "Delete view", security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")}, + hidden = true) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Deleted view"), @@ -176,7 +178,7 @@ public class ViewEndpoint { public ResponseEntity<Void> delete(@NotBlank @PathVariable("databaseId") Long databaseId, @NotBlank @PathVariable("viewId") Long viewId) throws DatabaseUnavailableException, RemoteUnavailableException, ViewNotFoundException, - ViewMalformedException { + ViewMalformedException, ServiceException { log.debug("endpoint delete view, databaseId={}, viewId={}", databaseId, viewId); final PrivilegedViewDto view = metadataServiceGateway.getViewById(databaseId, viewId); try { @@ -232,7 +234,8 @@ public class ViewEndpoint { @NotNull HttpServletRequest request, Principal principal) throws DatabaseUnavailableException, RemoteUnavailableException, ViewNotFoundException, - QueryMalformedException, ViewMalformedException, PaginationException, NotAllowedException { + QueryMalformedException, ViewMalformedException, PaginationException, NotAllowedException, + ServiceException { log.debug("endpoint get view data, databaseId={}, viewId={}, page={}, size={}, timestamp={}", databaseId, viewId, page, size, timestamp); endpointValidator.validateDataParams(page, size); diff --git a/dbrepo-data-service/rest-service/src/main/resources/application-local.yml b/dbrepo-data-service/rest-service/src/main/resources/application-local.yml index fda4447d0b66d22e95cdb1bd1c2525a9eb5f9a15..c36b248b7ea2a72bf60d27eeaef910679035e01b 100644 --- a/dbrepo-data-service/rest-service/src/main/resources/application-local.yml +++ b/dbrepo-data-service/rest-service/src/main/resources/application-local.yml @@ -49,9 +49,9 @@ logging: org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver: debug dbrepo: endpoints: - gatewayService: http://localhost - storageService: http://localhost:9000 - authService: http://localhost:8080 + metadataService: http://localhost + storageService: http://localhost/api/storage + authService: http://localhost/api/auth s3: accessKeyId: seaweedfsadmin secretAccessKey: seaweedfsadmin diff --git a/dbrepo-data-service/rest-service/src/main/resources/application.yml b/dbrepo-data-service/rest-service/src/main/resources/application.yml index 44daf91e46c603ae27ee7780e4ecc62de90b5339..771f95d8d75fe38cc4832bedeeb6a74132d0440e 100644 --- a/dbrepo-data-service/rest-service/src/main/resources/application.yml +++ b/dbrepo-data-service/rest-service/src/main/resources/application.yml @@ -50,9 +50,9 @@ logging: org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver: debug dbrepo: endpoints: - gatewayService: "${GATEWAY_SERVICE_ENDPOINT:http://gateway-service}" - storageService: "${S3_ENDPOINT:http://storage-service:9000}" - authService: "${AUTH_SERVICE_HOST:http://auth-service:8080}" + metadataService: "${METADATA_SERVICE_ENDPOINT:http://gateway-service}" + storageService: "${S3_ENDPOINT:http://gateway-service/api/storage}" + authService: "${AUTH_SERVICE_HOST:http://gateway-service/api/auth}" s3: accessKeyId: "${S3_ACCESS_KEY_ID:seaweedfsadmin}" secretAccessKey: "${S3_SECRET_ACCESS_KEY:seaweedfsadmin}" diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java index 43d3b515073e947fcbf474b5d041115a3eb2b3aa..54af799db3fd021475222be7fac444ad83ed4535 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java @@ -12,6 +12,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; +import java.io.IOException; import java.sql.*; import java.time.Instant; import java.util.*; @@ -77,6 +78,34 @@ public class MariaDbConfig { log.debug("created init database {}", database.getInternalName()); } + public static void grantReadAccess(PrivilegedDatabaseDto database, String username) { + final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName(); + log.trace("connect to database {}", jdbc); + try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) { + connection.prepareStatement("GRANT SELECT ON *.* TO `" + username + "`@`%`;") + .executeUpdate(); + connection.prepareStatement("FLUSH PRIVILEGES;") + .executeUpdate(); + } catch (SQLException e) { + log.error("could not grant read access", e); + } + log.debug("granted read access to user {} in database {}", username, database.getInternalName()); + } + + public static void grantWriteAccess(PrivilegedDatabaseDto database, String username) { + final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName(); + log.trace("connect to database {}", jdbc); + try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) { + connection.prepareStatement("GRANT SELECT, CREATE, CREATE VIEW, CREATE ROUTINE, CREATE TEMPORARY TABLES, LOCK TABLES, INDEX, TRIGGER, INSERT, UPDATE, DELETE ON *.* TO `" + username + "`@`%`;") + .executeUpdate(); + connection.prepareStatement("FLUSH PRIVILEGES;") + .executeUpdate(); + } catch (SQLException e) { + log.error("could not grant read access", e); + } + log.debug("granted read access to user {} in database {}", username, database.getInternalName()); + } + public static void dropAllDatabases(PrivilegedContainerDto container) { final String jdbc = "jdbc:mariadb://" + container.getHost() + ":" + container.getPort(); log.trace("connect to database {}", jdbc); @@ -136,31 +165,43 @@ public class MariaDbConfig { } } - public static String getPrivileges(String hostname, Integer port, String username, String password) - throws Exception { - return getPrivileges(hostname, port, null, username, password); - } - - public static String getPrivileges(String hostname, Integer port, String database, String username, String password) - throws Exception { - final String jdbc = "jdbc:mariadb://" + hostname + ":" + port + (database != null ? "/" + database : ""); + public static List<String> getPrivileges(PrivilegedDatabaseDto database, String username) throws SQLException { + final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName(); log.trace("connect to database {}", jdbc); - try (Connection connection = DriverManager.getConnection(jdbc, username, password)) { + try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) { final String query = "SHOW GRANTS FOR `" + username + "`;"; log.trace("prepare statement '{}'", query); final PreparedStatement statement = connection.prepareStatement(query); final ResultSet set = statement.executeQuery(); statement.close(); if (set.next()) { - return set.getString(1); + final Matcher matcher = Pattern.compile("GRANT (.*) ON.*").matcher(set.getString(1)); + if (matcher.find()) { + final List<String> privileges = Arrays.asList(matcher.group(1).split(","));; + log.trace("found privileges: {}", privileges); + return privileges; + } } } - throw new Exception("Failed to get privileges"); + throw new SQLException("Failed to get privileges"); + } + + public static void dropTable(PrivilegedDatabaseDto database, String table) throws SQLException { + final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName(); + log.trace("connect to database {}", jdbc); + try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) { + final String query = "DROP TABLE `" + table + "`;"; + log.trace("prepare statement '{}'", query); + final PreparedStatement statement = connection.prepareStatement(query); + statement.executeUpdate(); + statement.close(); + } + log.debug("dropped table {}", table); } - public static void mockQuery(String hostname, String query, String username, String password) + public static void mockQuery(String hostname, Integer port, String database, String query, String username, String password) throws SQLException { - final String jdbc = "jdbc:mariadb://" + hostname; + final String jdbc = "jdbc:mariadb://" + hostname + ":" + port + "/" + database; log.trace("connect to database {}", jdbc); try (Connection connection = DriverManager.getConnection(jdbc, username, password)) { final PreparedStatement statement = connection.prepareStatement(query); diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/AccessEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/AccessEndpointUnitTest.java index 4598a94b94095d4cf463f286bf10977ee72516ad..544f3f0d17d95c6fbb807743a58698f090ee8b37 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/AccessEndpointUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/AccessEndpointUnitTest.java @@ -41,12 +41,12 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) public void create_succeeds() throws UserNotFoundException, NotAllowedException, QueryMalformedException, - DatabaseNotFoundException, RemoteUnavailableException, DatabaseMalformedException { + DatabaseNotFoundException, RemoteUnavailableException, DatabaseMalformedException, ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); - when(metadataServiceGateway.getUserById(USER_4_ID)) + when(metadataServiceGateway.getPrivilegedUserById(USER_4_ID)) .thenReturn(USER_4_PRIVILEGED_DTO); /* test */ @@ -56,12 +56,12 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) public void create_alreadyAccess_fails() throws UserNotFoundException, DatabaseNotFoundException, - RemoteUnavailableException { + RemoteUnavailableException, ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); - when(metadataServiceGateway.getUserById(USER_1_ID)) + when(metadataServiceGateway.getPrivilegedUserById(USER_1_ID)) .thenReturn(USER_1_PRIVILEGED_DTO); /* test */ @@ -72,7 +72,8 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) - public void create_databaseNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException { + public void create_databaseNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException, + ServiceException { /* mock */ doThrow(DatabaseNotFoundException.class) @@ -88,18 +89,18 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) public void create_userNotFound_fails() throws UserNotFoundException, DatabaseNotFoundException, - RemoteUnavailableException { + RemoteUnavailableException, ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); doThrow(UserNotFoundException.class) .when(metadataServiceGateway) - .getUserById(USER_1_ID); + .getPrivilegedUserById(USER_4_ID); /* test */ assertThrows(UserNotFoundException.class, () -> { - accessEndpoint.create(DATABASE_1_ID, USER_1_ID, UPDATE_DATABASE_ACCESS_READ_DTO); + accessEndpoint.create(DATABASE_1_ID, USER_4_ID, UPDATE_DATABASE_ACCESS_READ_DTO); }); } @@ -116,12 +117,12 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) public void update_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, - NotAllowedException, QueryMalformedException, DatabaseMalformedException { + NotAllowedException, QueryMalformedException, DatabaseMalformedException, ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); - when(metadataServiceGateway.getUserById(USER_1_ID)) + when(metadataServiceGateway.getPrivilegedUserById(USER_1_ID)) .thenReturn(USER_1_PRIVILEGED_DTO); /* test */ @@ -140,7 +141,8 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) - public void update_databaseNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException { + public void update_databaseNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException, + ServiceException { /* mock */ doThrow(DatabaseNotFoundException.class) @@ -156,7 +158,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) public void update_userNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException, - UserNotFoundException { + UserNotFoundException, ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) @@ -174,12 +176,12 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) public void revoke_succeeds() throws UserNotFoundException, NotAllowedException, QueryMalformedException, - DatabaseNotFoundException, RemoteUnavailableException, DatabaseMalformedException { + DatabaseNotFoundException, RemoteUnavailableException, DatabaseMalformedException, ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); - when(metadataServiceGateway.getUserById(USER_1_ID)) + when(metadataServiceGateway.getPrivilegedUserById(USER_1_ID)) .thenReturn(USER_1_PRIVILEGED_DTO); /* test */ @@ -198,7 +200,8 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) - public void revoke_databaseNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException { + public void revoke_databaseNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException, + ServiceException { /* mock */ doThrow(DatabaseNotFoundException.class) @@ -214,7 +217,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) public void revoke_userNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException, - UserNotFoundException { + UserNotFoundException, ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java index 8ab4d444f1970240e393c4fd0607e83692bed880..21769ff5eb39d5448a0dd05036a6efc7444eb0d2 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java @@ -58,7 +58,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) public void create_succeeds() throws DatabaseUnavailableException, RemoteUnavailableException, - QueryStoreCreateException, ContainerNotFoundException, DatabaseMalformedException { + QueryStoreCreateException, ContainerNotFoundException, DatabaseMalformedException, ServiceException { /* test */ databaseEndpoint.create(DATABASE_1_CREATE_INTERNAL); @@ -67,7 +67,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME) public void create_noRole_fails() throws RemoteUnavailableException, ContainerNotFoundException, - SQLException, QueryStoreCreateException, DatabaseMalformedException { + SQLException, QueryStoreCreateException, DatabaseMalformedException, ServiceException { /* mock */ when(metadataServiceGateway.getContainerById(CONTAINER_1_ID)) @@ -89,7 +89,8 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) - public void create_containerNotFound_fails() throws RemoteUnavailableException, ContainerNotFoundException { + public void create_containerNotFound_fails() throws RemoteUnavailableException, ContainerNotFoundException, + ServiceException { /* mock */ doThrow(ContainerNotFoundException.class) @@ -105,7 +106,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) public void create_queryStore_fails() throws RemoteUnavailableException, ContainerNotFoundException, SQLException, - DatabaseMalformedException, QueryStoreCreateException { + DatabaseMalformedException, QueryStoreCreateException, ServiceException { /* mock */ doThrow(ContainerNotFoundException.class) @@ -126,7 +127,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) public void update_succeeds() throws DatabaseUnavailableException, RemoteUnavailableException, - DatabaseMalformedException, DatabaseNotFoundException { + DatabaseMalformedException, DatabaseNotFoundException, ServiceException { /* test */ databaseEndpoint.update(DATABASE_1_ID, USER_1_UPDATE_PASSWORD_DTO); @@ -134,7 +135,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME) - public void update_noRole_fails() throws RemoteUnavailableException, DatabaseNotFoundException { + public void update_noRole_fails() throws RemoteUnavailableException, DatabaseNotFoundException, ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) @@ -148,7 +149,8 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) - public void update_databaseNotFound_fails() throws RemoteUnavailableException, DatabaseNotFoundException { + public void update_databaseNotFound_fails() throws RemoteUnavailableException, DatabaseNotFoundException, + ServiceException { /* mock */ doThrow(DatabaseNotFoundException.class) @@ -164,7 +166,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) public void update_password_fails() throws RemoteUnavailableException, DatabaseNotFoundException, SQLException, - DatabaseMalformedException { + DatabaseMalformedException, ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/SubsetEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/SubsetEndpointUnitTest.java index d212bb3064252f2ab2317028224914e96bb85c5f..6cdb0c6753488d84be16798636d46d42c139392f 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/SubsetEndpointUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/SubsetEndpointUnitTest.java @@ -66,7 +66,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser public void findAllById_succeeds() throws DatabaseUnavailableException, NotAllowedException, QueryNotFoundException, - DatabaseNotFoundException, RemoteUnavailableException, SQLException { + DatabaseNotFoundException, RemoteUnavailableException, SQLException, ServiceException { /* test */ final List<QueryDto> response = generic_findAllById(DATABASE_3_ID, DATABASE_3_PRIVILEGED_DTO, null); @@ -98,7 +98,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { public void findById_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, DatabaseUnavailableException, StorageUnavailableException, NotAllowedException, QueryMalformedException, QueryNotFoundException, SidecarExportException, FormatNotAvailableException, StorageNotFoundException, - SQLException { + SQLException, ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) @@ -113,7 +113,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { public void findById_acceptCsv_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, DatabaseUnavailableException, StorageUnavailableException, NotAllowedException, QueryMalformedException, QueryNotFoundException, SidecarExportException, FormatNotAvailableException, - StorageNotFoundException, SQLException { + StorageNotFoundException, SQLException, ServiceException { final ExportResourceDto mock = ExportResourceDto.builder() .filename("deadbeef") .resource(new InputStreamResource(InputStream.nullInputStream())) @@ -134,7 +134,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { public void findById_timestamp_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, DatabaseUnavailableException, StorageUnavailableException, NotAllowedException, QueryMalformedException, QueryNotFoundException, SidecarExportException, FormatNotAvailableException, - StorageNotFoundException, SQLException { + StorageNotFoundException, SQLException, ServiceException { final ExportResourceDto mock = ExportResourceDto.builder() .filename("deadbeef") .resource(new InputStreamResource(InputStream.nullInputStream())) @@ -152,7 +152,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser - public void findById_fails() throws DatabaseNotFoundException, RemoteUnavailableException { + public void findById_fails() throws DatabaseNotFoundException, RemoteUnavailableException, ServiceException { /* mock */ doThrow(DatabaseNotFoundException.class) @@ -171,7 +171,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { NotAllowedException, SidecarExportException, QueryNotSupportedException, PaginationException, StorageNotFoundException, DatabaseUnavailableException, StorageUnavailableException, QueryMalformedException, QueryNotFoundException, DatabaseNotFoundException, RemoteUnavailableException, - FormatNotAvailableException, SQLException { + SQLException, ServiceException { final ExecuteStatementDto request = ExecuteStatementDto.builder() .statement(QUERY_5_STATEMENT) .build(); @@ -207,7 +207,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { TableMalformedException, NotAllowedException, SidecarExportException, QueryNotSupportedException, PaginationException, StorageNotFoundException, DatabaseUnavailableException, StorageUnavailableException, QueryMalformedException, QueryNotFoundException, DatabaseNotFoundException, RemoteUnavailableException, - FormatNotAvailableException, SQLException { + SQLException, ServiceException { final ExecuteStatementDto request = ExecuteStatementDto.builder() .statement(QUERY_5_STATEMENT) .build(); @@ -227,7 +227,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"execute-query"}) public void create_databaseNotFound_fails() throws NotAllowedException, RemoteUnavailableException, - DatabaseNotFoundException { + DatabaseNotFoundException, ServiceException { final ExecuteStatementDto request = ExecuteStatementDto.builder() .statement(QUERY_5_STATEMENT) .build(); @@ -260,7 +260,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_4_USERNAME, authorities = {"execute-query"}) - public void create_noAccess_fails() throws NotAllowedException, RemoteUnavailableException { + public void create_noAccess_fails() throws NotAllowedException, RemoteUnavailableException, ServiceException { final ExecuteStatementDto request = ExecuteStatementDto.builder() .statement(QUERY_5_STATEMENT) .build(); @@ -279,7 +279,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @Test public void getData_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, NotAllowedException, SQLException, QueryNotFoundException, TableMalformedException, QueryMalformedException, - DatabaseUnavailableException, PaginationException { + DatabaseUnavailableException, PaginationException, ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) @@ -308,7 +308,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @Test public void getData_onlyHead_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, NotAllowedException, SQLException, QueryNotFoundException, TableMalformedException, QueryMalformedException, - DatabaseUnavailableException, PaginationException { + DatabaseUnavailableException, PaginationException, ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_3_ID)) @@ -332,7 +332,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_1_USERNAME) public void getData_private_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, DatabaseUnavailableException, NotAllowedException, TableMalformedException, - QueryMalformedException, QueryNotFoundException, PaginationException, SQLException { + QueryMalformedException, QueryNotFoundException, PaginationException, SQLException, ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) @@ -357,7 +357,8 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser - public void getData_privateAnonymous_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException { + public void getData_privateAnonymous_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, + ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) @@ -372,7 +373,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_1_USERNAME) public void getData_privateNoAccess_fails() throws DatabaseNotFoundException, RemoteUnavailableException, - NotAllowedException { + NotAllowedException, ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) @@ -391,7 +392,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_1_USERNAME) public void getData_privateOnlyHead_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, DatabaseUnavailableException, NotAllowedException, TableMalformedException, - QueryMalformedException, QueryNotFoundException, PaginationException, SQLException { + QueryMalformedException, QueryNotFoundException, PaginationException, SQLException, ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) @@ -415,7 +416,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_3_USERNAME, authorities = {"persist-query"}) public void persist_succeeds() throws NotAllowedException, RemoteUnavailableException, DatabaseNotFoundException, QueryStorePersistException, SQLException, UserNotFoundException, QueryNotFoundException, - DatabaseUnavailableException { + DatabaseUnavailableException, ServiceException { final QueryPersistDto request = QueryPersistDto.builder() .persist(true) .build(); @@ -450,7 +451,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"persist-query"}) - public void persist_noAccess_fails() throws NotAllowedException, RemoteUnavailableException { + public void persist_noAccess_fails() throws NotAllowedException, RemoteUnavailableException, ServiceException { final QueryPersistDto request = QueryPersistDto.builder() .persist(true) .build(); @@ -469,7 +470,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"persist-query"}) public void persist_databaseNotFound_fails() throws NotAllowedException, RemoteUnavailableException, - DatabaseNotFoundException { + DatabaseNotFoundException, ServiceException { final QueryPersistDto request = QueryPersistDto.builder() .persist(true) .build(); @@ -489,7 +490,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { protected List<QueryDto> generic_findAllById(Long databaseId, PrivilegedDatabaseDto database, Principal principal) throws DatabaseUnavailableException, NotAllowedException, QueryNotFoundException, DatabaseNotFoundException, - RemoteUnavailableException, SQLException { + RemoteUnavailableException, SQLException, ServiceException { /* mock */ if (database != null) { @@ -513,7 +514,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { Principal principal) throws UserNotFoundException, DatabaseUnavailableException, StorageUnavailableException, NotAllowedException, QueryMalformedException, QueryNotFoundException, DatabaseNotFoundException, SidecarExportException, RemoteUnavailableException, FormatNotAvailableException, - StorageNotFoundException, SQLException { + StorageNotFoundException, SQLException, ServiceException { /* mock */ when(queryService.findById(DATABASE_3_PRIVILEGED_DTO, subsetId)) diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java index fd93a3ae967be7290776b8d4d910c25a93f12c9a..62375e2ab4e397924ce1f6d3a8428111be633478 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java @@ -7,7 +7,6 @@ import at.tuwien.api.database.table.*; import at.tuwien.endpoints.TableEndpoint; import at.tuwien.exception.*; import at.tuwien.gateway.MetadataServiceGateway; -import at.tuwien.service.AnalyseService; import at.tuwien.service.TableService; import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; @@ -44,9 +43,6 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @MockBean private TableService tableService; - @MockBean - private AnalyseService analyseService; - @MockBean private MetadataServiceGateway metadataServiceGateway; @@ -59,7 +55,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) public void create_succeeds() throws DatabaseUnavailableException, TableMalformedException, DatabaseNotFoundException, TableExistsException, RemoteUnavailableException, SQLException, - TableNotFoundException, QueryMalformedException { + TableNotFoundException, QueryMalformedException, ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) @@ -84,7 +80,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) - public void create_databaseNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException { + public void create_databaseNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException, + ServiceException { /* mock */ doThrow(DatabaseNotFoundException.class) @@ -100,7 +97,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) public void delete_succeeds() throws RemoteUnavailableException, DatabaseUnavailableException, - TableNotFoundException, QueryMalformedException, SQLException { + TableNotFoundException, QueryMalformedException, SQLException, ServiceException { /* mock */ when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) @@ -126,7 +123,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) - public void delete_tableNotFound_fails() throws RemoteUnavailableException, TableNotFoundException { + public void delete_tableNotFound_fails() throws RemoteUnavailableException, TableNotFoundException, + ServiceException { /* mock */ doThrow(TableNotFoundException.class) @@ -142,7 +140,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser public void getData_succeeds() throws DatabaseUnavailableException, TableNotFoundException, TableMalformedException, - SQLException, QueryMalformedException, RemoteUnavailableException, PaginationException { + SQLException, QueryMalformedException, RemoteUnavailableException, PaginationException, ServiceException { /* mock */ when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID)) @@ -166,7 +164,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser - public void getData_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException { + public void getData_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException, + ServiceException { /* mock */ doThrow(TableNotFoundException.class) @@ -182,7 +181,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"}) public void createTuple_succeeds() throws DatabaseUnavailableException, TableNotFoundException, - TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException, SQLException { + TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException, + SQLException, StorageUnavailableException, StorageNotFoundException, ServiceException { final TupleDto request = TupleDto.builder() .data(new HashMap<>() {{ put(COLUMN_8_1_INTERNAL_NAME, 7L); @@ -198,14 +198,12 @@ public class TableEndpointUnitTest extends AbstractUnitTest { doNothing() .when(tableService) .createTuple(TABLE_8_PRIVILEGED_DTO, request); - when(analyseService.analyseTable(DATABASE_3_ID, TABLE_8_ID)) - .thenReturn(TABLE_8_STATISTIC_DTO); doNothing() .when(metadataServiceGateway) - .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TABLE_8_STATISTIC_DTO); + .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID); /* test */ - final ResponseEntity<Void> response = tableEndpoint.createTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); + final ResponseEntity<Void> response = tableEndpoint.insertRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); assertEquals(HttpStatus.CREATED, response.getStatusCode()); } @@ -221,13 +219,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { - tableEndpoint.createTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + tableEndpoint.insertRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); }); } @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) - public void createTuple_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException { + public void createTuple_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException, + ServiceException { final TupleDto request = TupleDto.builder() .data(new HashMap<>() {{ put(COLUMN_8_1_INTERNAL_NAME, 7L); @@ -242,14 +241,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(TableNotFoundException.class, () -> { - tableEndpoint.createTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + tableEndpoint.insertRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); }); } @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) public void createTuple_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException, - NotAllowedException { + NotAllowedException, ServiceException { final TupleDto request = TupleDto.builder() .data(new HashMap<>() {{ put(COLUMN_8_1_INTERNAL_NAME, 7L); @@ -265,14 +264,15 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - tableEndpoint.createTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + tableEndpoint.insertRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); }); } @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"}) public void createTuple_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException, - NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException { + NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException, + StorageUnavailableException, StorageNotFoundException, ServiceException { final TupleDto request = TupleDto.builder() .data(new HashMap<>() {{ put(COLUMN_8_1_INTERNAL_NAME, 7L); @@ -287,13 +287,13 @@ public class TableEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO); /* test */ - tableEndpoint.createTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); + tableEndpoint.insertRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); } @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) public void createTuple_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException, - NotAllowedException { + NotAllowedException, ServiceException { final TupleDto request = TupleDto.builder() .data(new HashMap<>() {{ put(COLUMN_8_1_INTERNAL_NAME, 7L); @@ -309,14 +309,15 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - tableEndpoint.createTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + tableEndpoint.insertRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); }); } @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) public void createTuple_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException, - NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException { + NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException, + StorageUnavailableException, StorageNotFoundException, ServiceException { final TupleDto request = TupleDto.builder() .data(new HashMap<>() {{ put(COLUMN_8_1_INTERNAL_NAME, 7L); @@ -331,13 +332,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO); /* test */ - tableEndpoint.createTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + tableEndpoint.insertRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); } @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"}) public void updateTuple_succeeds() throws DatabaseUnavailableException, TableNotFoundException, - TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException, SQLException { + TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException, + SQLException, ServiceException { final TupleUpdateDto request = TupleUpdateDto.builder() .keys(new HashMap<>() {{ put(COLUMN_8_1_INTERNAL_NAME, 6L); @@ -356,14 +358,12 @@ public class TableEndpointUnitTest extends AbstractUnitTest { doNothing() .when(tableService) .updateTuple(TABLE_8_PRIVILEGED_DTO, request); - when(analyseService.analyseTable(DATABASE_3_ID, TABLE_8_ID)) - .thenReturn(TABLE_8_STATISTIC_DTO); doNothing() .when(metadataServiceGateway) - .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TABLE_8_STATISTIC_DTO); + .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID); /* test */ - final ResponseEntity<Void> response = tableEndpoint.updateTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); + final ResponseEntity<Void> response = tableEndpoint.updateRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); } @@ -382,13 +382,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { - tableEndpoint.updateTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + tableEndpoint.updateRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); }); } @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) - public void updateTuple_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException { + public void updateTuple_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException, + ServiceException { final TupleUpdateDto request = TupleUpdateDto.builder() .keys(new HashMap<>() {{ put(COLUMN_8_1_INTERNAL_NAME, 6L); @@ -406,14 +407,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(TableNotFoundException.class, () -> { - tableEndpoint.updateTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + tableEndpoint.updateRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); }); } @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) public void updateTuple_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException, - NotAllowedException { + NotAllowedException, ServiceException { final TupleUpdateDto request = TupleUpdateDto.builder() .keys(new HashMap<>() {{ put(COLUMN_8_1_INTERNAL_NAME, 6L); @@ -432,7 +433,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - tableEndpoint.updateTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + tableEndpoint.updateRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); }); } @@ -440,7 +441,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"}) public void updateTuple_writeOwnAccess_succeeds() throws DatabaseUnavailableException, TableNotFoundException, TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException, - SQLException { + SQLException, ServiceException { final TupleUpdateDto request = TupleUpdateDto.builder() .keys(new HashMap<>() {{ put(COLUMN_8_1_INTERNAL_NAME, 6L); @@ -459,21 +460,19 @@ public class TableEndpointUnitTest extends AbstractUnitTest { doNothing() .when(tableService) .updateTuple(TABLE_8_PRIVILEGED_DTO, request); - when(analyseService.analyseTable(DATABASE_3_ID, TABLE_8_ID)) - .thenReturn(TABLE_8_STATISTIC_DTO); doNothing() .when(metadataServiceGateway) - .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TABLE_8_STATISTIC_DTO); + .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID); /* test */ - final ResponseEntity<Void> response = tableEndpoint.updateTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); + final ResponseEntity<Void> response = tableEndpoint.updateRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); } @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) public void updateTuple_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException, - NotAllowedException { + NotAllowedException, ServiceException { final TupleUpdateDto request = TupleUpdateDto.builder() .keys(new HashMap<>() {{ put(COLUMN_8_1_INTERNAL_NAME, 6L); @@ -492,7 +491,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - tableEndpoint.updateTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + tableEndpoint.updateRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); }); } @@ -500,7 +499,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) public void updateTuple_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException, NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException, - SQLException { + SQLException, ServiceException { final TupleUpdateDto request = TupleUpdateDto.builder() .keys(new HashMap<>() {{ put(COLUMN_8_1_INTERNAL_NAME, 6L); @@ -519,21 +518,20 @@ public class TableEndpointUnitTest extends AbstractUnitTest { doNothing() .when(tableService) .updateTuple(TABLE_8_PRIVILEGED_DTO, request); - when(analyseService.analyseTable(DATABASE_3_ID, TABLE_8_ID)) - .thenReturn(TABLE_8_STATISTIC_DTO); doNothing() .when(metadataServiceGateway) - .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TABLE_8_STATISTIC_DTO); + .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID); /* test */ - final ResponseEntity<Void> response = tableEndpoint.updateTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + final ResponseEntity<Void> response = tableEndpoint.updateRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); } @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-table-data"}) public void deleteTuple_succeeds() throws DatabaseUnavailableException, TableNotFoundException, - TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException, SQLException { + TableMalformedException, NotAllowedException, QueryMalformedException, RemoteUnavailableException, + SQLException, ServiceException { final TupleDeleteDto request = TupleDeleteDto.builder() .keys(new HashMap<>() {{ put(COLUMN_8_1_INTERNAL_NAME, 6L); @@ -548,14 +546,12 @@ public class TableEndpointUnitTest extends AbstractUnitTest { doNothing() .when(tableService) .deleteTuple(TABLE_8_PRIVILEGED_DTO, request); - when(analyseService.analyseTable(DATABASE_3_ID, TABLE_8_ID)) - .thenReturn(TABLE_8_STATISTIC_DTO); doNothing() .when(metadataServiceGateway) - .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TABLE_8_STATISTIC_DTO); + .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID); /* test */ - final ResponseEntity<Void> response = tableEndpoint.deleteTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); + final ResponseEntity<Void> response = tableEndpoint.deleteRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); } @@ -570,13 +566,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { - tableEndpoint.deleteTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + tableEndpoint.deleteRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); }); } @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"delete-table-data"}) - public void deleteTuple_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException { + public void deleteTuple_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException, + ServiceException { final TupleDeleteDto request = TupleDeleteDto.builder() .keys(new HashMap<>() {{ put(COLUMN_8_1_INTERNAL_NAME, 6L); @@ -590,14 +587,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(TableNotFoundException.class, () -> { - tableEndpoint.deleteTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + tableEndpoint.deleteRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); }); } @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-table-data"}) public void deleteTuple_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException, - NotAllowedException { + NotAllowedException, ServiceException { final TupleDeleteDto request = TupleDeleteDto.builder() .keys(new HashMap<>() {{ put(COLUMN_8_1_INTERNAL_NAME, 6L); @@ -612,7 +609,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - tableEndpoint.deleteTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + tableEndpoint.deleteRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); }); } @@ -620,7 +617,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-table-data"}) public void deleteTuple_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException, NotAllowedException, TableMalformedException, SQLException, QueryMalformedException, - DatabaseUnavailableException { + DatabaseUnavailableException, ServiceException { final TupleDeleteDto request = TupleDeleteDto.builder() .keys(new HashMap<>() {{ put(COLUMN_8_1_INTERNAL_NAME, 6L); @@ -635,21 +632,19 @@ public class TableEndpointUnitTest extends AbstractUnitTest { doNothing() .when(tableService) .deleteTuple(TABLE_8_PRIVILEGED_DTO, request); - when(analyseService.analyseTable(DATABASE_3_ID, TABLE_8_ID)) - .thenReturn(TABLE_8_STATISTIC_DTO); doNothing() .when(metadataServiceGateway) - .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TABLE_8_STATISTIC_DTO); + .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID); /* test */ - final ResponseEntity<Void> response = tableEndpoint.deleteTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); + final ResponseEntity<Void> response = tableEndpoint.deleteRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); } @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"delete-table-data"}) public void deleteTuple_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException, - NotAllowedException { + NotAllowedException, ServiceException { final TupleDeleteDto request = TupleDeleteDto.builder() .keys(new HashMap<>() {{ put(COLUMN_8_1_INTERNAL_NAME, 6L); @@ -664,7 +659,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - tableEndpoint.deleteTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + tableEndpoint.deleteRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); }); } @@ -672,7 +667,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_3_USERNAME, authorities = {"delete-table-data"}) public void deleteTuple_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException, NotAllowedException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException, - SQLException { + SQLException, ServiceException { final TupleDeleteDto request = TupleDeleteDto.builder() .keys(new HashMap<>() {{ put(COLUMN_8_1_INTERNAL_NAME, 6L); @@ -687,36 +682,35 @@ public class TableEndpointUnitTest extends AbstractUnitTest { doNothing() .when(tableService) .deleteTuple(TABLE_8_PRIVILEGED_DTO, request); - when(analyseService.analyseTable(DATABASE_3_ID, TABLE_8_ID)) - .thenReturn(TABLE_8_STATISTIC_DTO); doNothing() .when(metadataServiceGateway) - .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TABLE_8_STATISTIC_DTO); + .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID); /* test */ - final ResponseEntity<Void> response = tableEndpoint.deleteTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + final ResponseEntity<Void> response = tableEndpoint.deleteRawTuple(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); } @Test @WithAnonymousUser public void getHistory_succeeds() throws DatabaseUnavailableException, TableNotFoundException, - RemoteUnavailableException, SQLException, NotAllowedException { + RemoteUnavailableException, SQLException, NotAllowedException, ServiceException, PaginationException { /* mock */ when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID)) .thenReturn(TABLE_8_PRIVILEGED_DTO); - when(tableService.history(TABLE_8_PRIVILEGED_DTO)) + when(tableService.history(TABLE_8_PRIVILEGED_DTO, null)) .thenReturn(List.of()); /* test */ - final ResponseEntity<List<TableHistoryDto>> response = tableEndpoint.getHistory(DATABASE_3_ID, TABLE_8_ID, null); + final ResponseEntity<List<TableHistoryDto>> response = tableEndpoint.getHistory(DATABASE_3_ID, TABLE_8_ID, null, null); assertEquals(HttpStatus.OK, response.getStatusCode()); } @Test @WithAnonymousUser - public void getHistory_privateNoRole_fails() throws TableNotFoundException, RemoteUnavailableException { + public void getHistory_privateNoRole_fails() throws TableNotFoundException, RemoteUnavailableException, + ServiceException { /* mock */ when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) @@ -724,14 +718,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - tableEndpoint.getHistory(DATABASE_1_ID, TABLE_1_ID, null); + tableEndpoint.getHistory(DATABASE_1_ID, TABLE_1_ID, null, null); }); } @Test @WithMockUser(username = USER_4_USERNAME) public void getHistory_privateNoAccess_fails() throws NotAllowedException, RemoteUnavailableException, - TableNotFoundException { + TableNotFoundException, ServiceException { /* mock */ when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) @@ -742,13 +736,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - tableEndpoint.getHistory(DATABASE_1_ID, TABLE_1_ID, USER_4_PRINCIPAL); + tableEndpoint.getHistory(DATABASE_1_ID, TABLE_1_ID, null, USER_4_PRINCIPAL); }); } @Test @WithAnonymousUser - public void getHistory_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException { + public void getHistory_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException, + ServiceException { /* mock */ doThrow(TableNotFoundException.class) @@ -757,7 +752,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(TableNotFoundException.class, () -> { - tableEndpoint.getHistory(DATABASE_3_ID, TABLE_8_ID, null); + tableEndpoint.getHistory(DATABASE_3_ID, TABLE_8_ID, null, null); }); } @@ -765,7 +760,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void exportData_succeeds() throws DatabaseUnavailableException, TableNotFoundException, NotAllowedException, StorageUnavailableException, QueryMalformedException, SidecarExportException, RemoteUnavailableException, - StorageNotFoundException, SQLException { + StorageNotFoundException, SQLException, ServiceException { final ExportResourceDto mock = ExportResourceDto.builder() .filename("deadbeef") .resource(new InputStreamResource(InputStream.nullInputStream())) @@ -786,7 +781,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_4_USERNAME) public void exportData_privateNoAccess_fails() throws TableNotFoundException, NotAllowedException, - RemoteUnavailableException { + RemoteUnavailableException, ServiceException { /* mock */ when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) @@ -806,7 +801,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"}) public void importData_succeeds() throws DatabaseUnavailableException, TableNotFoundException, SidecarImportException, NotAllowedException, QueryMalformedException, RemoteUnavailableException, - StorageNotFoundException, SQLException { + StorageNotFoundException, SQLException, ServiceException { final ImportCsvDto request = ImportCsvDto.builder() .skipLines(1L) .lineTermination("\\n") @@ -821,14 +816,12 @@ public class TableEndpointUnitTest extends AbstractUnitTest { doNothing() .when(tableService) .importDataset(TABLE_8_PRIVILEGED_DTO, request); - when(analyseService.analyseTable(DATABASE_3_ID, TABLE_8_ID)) - .thenReturn(TABLE_8_STATISTIC_DTO); doNothing() .when(metadataServiceGateway) - .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID, TABLE_8_STATISTIC_DTO); + .updateTableStatistics(DATABASE_3_ID, TABLE_8_ID); /* test */ - final ResponseEntity<Void> response = tableEndpoint.importData(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); + final ResponseEntity<Void> response = tableEndpoint.importDataset(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); } @@ -843,13 +836,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { - tableEndpoint.importData(DATABASE_3_ID, TABLE_8_ID, request, USER_4_PRINCIPAL); + tableEndpoint.importDataset(DATABASE_3_ID, TABLE_8_ID, request, USER_4_PRINCIPAL); }); } @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) - public void importData_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException { + public void importData_tableNotFound_fails() throws TableNotFoundException, RemoteUnavailableException, + ServiceException { final ImportCsvDto request = ImportCsvDto.builder() .skipLines(1L) .lineTermination("\\n") @@ -863,14 +857,14 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(TableNotFoundException.class, () -> { - tableEndpoint.importData(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + tableEndpoint.importDataset(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); }); } @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) public void importData_readAccess_fails() throws TableNotFoundException, RemoteUnavailableException, - NotAllowedException { + NotAllowedException, ServiceException { final ImportCsvDto request = ImportCsvDto.builder() .skipLines(1L) .lineTermination("\\n") @@ -885,7 +879,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - tableEndpoint.importData(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + tableEndpoint.importDataset(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); }); } @@ -893,7 +887,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_1_USERNAME, authorities = {"insert-table-data"}) public void importData_writeOwnAccess_succeeds() throws TableNotFoundException, RemoteUnavailableException, NotAllowedException, DatabaseUnavailableException, SidecarImportException, QueryMalformedException, - StorageNotFoundException { + StorageNotFoundException, ServiceException { final ImportCsvDto request = ImportCsvDto.builder() .skipLines(1L) .lineTermination("\\n") @@ -907,13 +901,13 @@ public class TableEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_3_USER_1_WRITE_OWN_ACCESS_DTO); /* test */ - tableEndpoint.importData(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); + tableEndpoint.importDataset(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); } @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) public void importData_writeOwnAccessForeign_fails() throws TableNotFoundException, RemoteUnavailableException, - NotAllowedException { + NotAllowedException, ServiceException { final ImportCsvDto request = ImportCsvDto.builder() .skipLines(1L) .lineTermination("\\n") @@ -928,7 +922,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - tableEndpoint.importData(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); + tableEndpoint.importDataset(DATABASE_3_ID, TABLE_8_ID, request, USER_3_PRINCIPAL); }); } @@ -936,7 +930,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_3_USERNAME, authorities = {"insert-table-data"}) public void importData_writeAllAccessForeign_succeeds() throws TableNotFoundException, RemoteUnavailableException, NotAllowedException, DatabaseUnavailableException, SidecarImportException, QueryMalformedException, - StorageNotFoundException { + StorageNotFoundException, ServiceException { final ImportCsvDto request = ImportCsvDto.builder() .skipLines(1L) .lineTermination("\\n") @@ -950,7 +944,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO); /* test */ - tableEndpoint.importData(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); + tableEndpoint.importDataset(DATABASE_3_ID, TABLE_8_ID, request, USER_1_PRINCIPAL); } } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java index de98f501d095dc637b1b21cd667459f65eb08ee8..af4767b0490d69c2d704e8a5243cfced6a61cbe9 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java @@ -52,7 +52,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) public void create_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException, - SQLException, DatabaseUnavailableException { + SQLException, DatabaseUnavailableException, ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) @@ -68,7 +68,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME) public void create_noRole_fails() throws DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException, - SQLException { + SQLException, ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) @@ -84,7 +84,8 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) - public void create_databaseNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException { + public void create_databaseNotFound_fails() throws DatabaseNotFoundException, RemoteUnavailableException, + ServiceException { /* mock */ doThrow(DatabaseNotFoundException.class) @@ -100,7 +101,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) public void delete_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException, - SQLException, DatabaseUnavailableException, ViewNotFoundException { + SQLException, DatabaseUnavailableException, ViewNotFoundException, ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) @@ -117,7 +118,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME) public void delete_noRole_fails() throws DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException, - SQLException { + SQLException, ServiceException { /* mock */ when(metadataServiceGateway.getDatabaseById(DATABASE_1_ID)) @@ -134,7 +135,8 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"admin"}) - public void delete_databaseNotFound_fails() throws RemoteUnavailableException, ViewNotFoundException { + public void delete_databaseNotFound_fails() throws RemoteUnavailableException, ViewNotFoundException, + ServiceException { /* mock */ doThrow(ViewNotFoundException.class) @@ -151,7 +153,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"}) public void getData_succeeds() throws RemoteUnavailableException, ViewNotFoundException, ViewMalformedException, SQLException, DatabaseUnavailableException, QueryMalformedException, PaginationException, - NotAllowedException { + NotAllowedException, ServiceException { /* mock */ when(metadataServiceGateway.getViewById(DATABASE_1_ID, VIEW_1_ID)) @@ -181,7 +183,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"}) public void getData_onlyHead_succeeds() throws RemoteUnavailableException, ViewNotFoundException, ViewMalformedException, SQLException, DatabaseUnavailableException, QueryMalformedException, - PaginationException, NotAllowedException { + PaginationException, NotAllowedException, ServiceException { /* mock */ when(metadataServiceGateway.getViewById(DATABASE_1_ID, VIEW_1_ID)) @@ -207,7 +209,8 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"}) - public void getData_viewNotFound_fails() throws RemoteUnavailableException, ViewNotFoundException { + public void getData_viewNotFound_fails() throws RemoteUnavailableException, ViewNotFoundException, + ServiceException { /* mock */ doThrow(ViewNotFoundException.class) @@ -223,7 +226,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"view-database-view-data"}) public void getData_privateNoAccess_fails() throws RemoteUnavailableException, ViewNotFoundException, - NotAllowedException { + NotAllowedException, ServiceException { /* mock */ when(metadataServiceGateway.getViewById(DATABASE_1_ID, VIEW_3_ID)) diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/DataDatabaseGatewayUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/DataDatabaseGatewayUnitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..30a4d31cfbb288b58817bc52d803d913fa353421 --- /dev/null +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/DataDatabaseGatewayUnitTest.java @@ -0,0 +1,151 @@ +package at.tuwien.gateway; + +import at.tuwien.exception.*; +import at.tuwien.test.AbstractUnitTest; +import lombok.extern.log4j.Log4j2; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.*; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.RestTemplate; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; + +@Log4j2 +@SpringBootTest +@ExtendWith(SpringExtension.class) +public class DataDatabaseGatewayUnitTest extends AbstractUnitTest { + + @MockBean + @Qualifier("restTemplate") + private RestTemplate restTemplate; + + @Autowired + private DataDatabaseSidecarGateway dataDatabaseSidecarGateway; + + @BeforeEach + public void beforeEach() { + genesis(); + } + + @Test + public void importFile_succeeds() throws RemoteUnavailableException, StorageNotFoundException, ServiceException { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), eq(HttpEntity.EMPTY), eq(Void.class))) + .thenReturn(ResponseEntity.accepted() + .build()); + + /* test */ + dataDatabaseSidecarGateway.importFile(CONTAINER_1_HOST, CONTAINER_1_PORT, "filename"); + } + + @Test + public void importFile_unavailable_fails() { + + /* mock */ + doThrow(HttpServerErrorException.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.POST), eq(HttpEntity.EMPTY), eq(Void.class)); + + /* test */ + assertThrows(RemoteUnavailableException.class, () -> { + dataDatabaseSidecarGateway.importFile(CONTAINER_1_HOST, CONTAINER_1_PORT, "filename"); + }); + } + + @Test + public void importFile_statusCode_fails() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), eq(HttpEntity.EMPTY), eq(Void.class))) + .thenReturn(ResponseEntity.status(HttpStatus.OK) + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + dataDatabaseSidecarGateway.importFile(CONTAINER_1_HOST, CONTAINER_1_PORT, "filename"); + }); + } + + @Test + public void importFile_s3_fails() { + + /* mock */ + doThrow(HttpClientErrorException.BadRequest.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.POST), eq(HttpEntity.EMPTY), eq(Void.class)); + + /* test */ + assertThrows(StorageNotFoundException.class, () -> { + dataDatabaseSidecarGateway.importFile(CONTAINER_1_HOST, CONTAINER_1_PORT, "filename"); + }); + } + + @Test + public void exportFile_succeeds() throws RemoteUnavailableException, StorageNotFoundException, ServiceException { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), eq(HttpEntity.EMPTY), eq(Void.class))) + .thenReturn(ResponseEntity.accepted() + .build()); + + /* test */ + dataDatabaseSidecarGateway.exportFile(CONTAINER_1_HOST, CONTAINER_1_PORT, "filename"); + } + + @Test + public void exportFile_unavailable_fails() { + + /* mock */ + doThrow(HttpServerErrorException.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.POST), eq(HttpEntity.EMPTY), eq(Void.class)); + + /* test */ + assertThrows(RemoteUnavailableException.class, () -> { + dataDatabaseSidecarGateway.exportFile(CONTAINER_1_HOST, CONTAINER_1_PORT, "filename"); + }); + } + + @Test + public void exportFile_statusCode_fails() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), eq(HttpEntity.EMPTY), eq(Void.class))) + .thenReturn(ResponseEntity.status(HttpStatus.OK) + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + dataDatabaseSidecarGateway.exportFile(CONTAINER_1_HOST, CONTAINER_1_PORT, "filename"); + }); + } + + @Test + public void exportFile_s3_fails() { + + /* mock */ + doThrow(HttpClientErrorException.BadRequest.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.POST), eq(HttpEntity.EMPTY), eq(Void.class)); + + /* test */ + assertThrows(StorageNotFoundException.class, () -> { + dataDatabaseSidecarGateway.exportFile(CONTAINER_1_HOST, CONTAINER_1_PORT, "filename"); + }); + } + +} diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/InterceptorUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/InterceptorUnitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0fd20a8025bc209df9c645f4d2b01329660dbf03 --- /dev/null +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/InterceptorUnitTest.java @@ -0,0 +1,61 @@ +package at.tuwien.gateway; + +import at.tuwien.api.keycloak.TokenDto; +import at.tuwien.exception.RemoteUnavailableException; +import at.tuwien.exception.ServiceException; +import at.tuwien.exception.StorageNotFoundException; +import at.tuwien.test.AbstractUnitTest; +import lombok.extern.log4j.Log4j2; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.RestTemplate; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; + +@Log4j2 +@SpringBootTest +@ExtendWith(SpringExtension.class) +public class InterceptorUnitTest extends AbstractUnitTest { + + @MockBean + @Qualifier("keycloakRestTemplate") + private RestTemplate restTemplate; + + @Autowired + private DataDatabaseSidecarGateway dataDatabaseSidecarGateway; + + @BeforeEach + public void beforeEach() { + genesis(); + } + + @Test + public void intercept_succeeds() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) + .thenReturn(ResponseEntity.ok() + .build()); + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(Void.class))) + .thenReturn(ResponseEntity.ok() + .build()); + + /* test */ + restTemplate.exchange("https://example.com", HttpMethod.GET, HttpEntity.EMPTY, Void.class); + } +} diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakSidecarGatewayUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakSidecarGatewayUnitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2a02e03466d57116c3c529d5750229e80b015b26 --- /dev/null +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakSidecarGatewayUnitTest.java @@ -0,0 +1,101 @@ +package at.tuwien.gateway; + +import at.tuwien.api.keycloak.TokenDto; +import at.tuwien.exception.RemoteUnavailableException; +import at.tuwien.exception.ServiceConnectionException; +import at.tuwien.exception.ServiceException; +import at.tuwien.test.AbstractUnitTest; +import lombok.extern.log4j.Log4j2; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.RestTemplate; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; + +@Log4j2 +@SpringBootTest +@ExtendWith(SpringExtension.class) +public class KeycloakSidecarGatewayUnitTest extends AbstractUnitTest { + + @MockBean + @Qualifier("restTemplate") + private RestTemplate restTemplate; + + @Autowired + private KeycloakGateway keycloakGateway; + + @BeforeEach + public void beforeEach() { + genesis(); + } + + @Test + public void obtainUserToken_succeeds() throws ServiceException, RemoteUnavailableException { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) + .thenReturn(ResponseEntity.ok() + .build()); + + /* test */ + final TokenDto response = keycloakGateway.obtainUserToken(USER_1_USERNAME, USER_1_PASSWORD); + } + + @Test + public void obtainUserToken_unavailable_fails() { + + /* mock */ + doThrow(HttpServerErrorException.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)); + + /* test */ + assertThrows(RemoteUnavailableException.class, () -> { + keycloakGateway.obtainUserToken(USER_1_USERNAME, USER_1_PASSWORD); + }); + } + + @Test + public void obtainUserToken_badRequest_fails() { + + /* mock */ + doThrow(HttpClientErrorException.BadRequest.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)); + + /* test */ + assertThrows(ServiceException.class, () -> { + keycloakGateway.obtainUserToken(USER_1_USERNAME, USER_1_PASSWORD); + }); + } + + @Test + public void obtainUserToken_statusCode_fails() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) + .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT) + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + keycloakGateway.obtainUserToken(USER_1_USERNAME, USER_1_PASSWORD); + }); + } + +} diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/MetadataServiceGatewayUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/MetadataServiceGatewayUnitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1ba4978788d7ee5d05d881d397a453086eaed41c --- /dev/null +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/MetadataServiceGatewayUnitTest.java @@ -0,0 +1,933 @@ +package at.tuwien.gateway; + +import at.tuwien.api.container.ContainerDto; +import at.tuwien.api.container.internal.PrivilegedContainerDto; +import at.tuwien.api.database.DatabaseAccessDto; +import at.tuwien.api.database.ViewDto; +import at.tuwien.api.database.internal.PrivilegedDatabaseDto; +import at.tuwien.api.database.internal.PrivilegedViewDto; +import at.tuwien.api.database.table.TableDto; +import at.tuwien.api.database.table.internal.PrivilegedTableDto; +import at.tuwien.api.identifier.IdentifierDto; +import at.tuwien.api.user.PrivilegedUserDto; +import at.tuwien.api.user.UserDto; +import at.tuwien.exception.*; +import at.tuwien.test.AbstractUnitTest; +import lombok.extern.log4j.Log4j2; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.*; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.RestTemplate; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; + +@Log4j2 +@SpringBootTest +@ExtendWith(SpringExtension.class) +public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { + + @MockBean + @Qualifier("restTemplate") + private RestTemplate restTemplate; + + @Autowired + private MetadataServiceGateway metadataServiceGateway; + + @BeforeEach + public void beforeEach() { + genesis(); + } + + @Test + public void getTableById_succeeds() throws TableNotFoundException, RemoteUnavailableException, ServiceException { + final HttpHeaders headers = new HttpHeaders(); + headers.set("X-Type", IMAGE_1_JDBC); + headers.set("X-Host", CONTAINER_1_HOST); + headers.set("X-Port", "" + CONTAINER_1_PORT); + headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME); + headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD); + headers.set("X-Database", DATABASE_1_INTERNALNAME); + headers.set("X-Sidecar-Host", CONTAINER_1_SIDECAR_HOST); + headers.set("X-Sidecar-Port", "" + CONTAINER_1_SIDECAR_PORT); + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableDto.class))) + .thenReturn(ResponseEntity.status(HttpStatus.OK) + .headers(headers) + .body(TABLE_1_DTO)); + + /* test */ + final PrivilegedTableDto response = metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID); + assertEquals(IMAGE_1_JDBC, response.getDatabase().getContainer().getImage().getJdbcMethod()); + assertEquals(CONTAINER_1_HOST, response.getDatabase().getContainer().getHost()); + assertEquals(CONTAINER_1_PORT, response.getDatabase().getContainer().getPort()); + assertEquals(CONTAINER_1_PRIVILEGED_USERNAME, response.getDatabase().getContainer().getUsername()); + assertEquals(CONTAINER_1_PRIVILEGED_PASSWORD, response.getDatabase().getContainer().getPassword()); + assertEquals(DATABASE_1_INTERNALNAME, response.getDatabase().getInternalName()); + assertEquals(CONTAINER_1_SIDECAR_HOST, response.getDatabase().getContainer().getSidecarHost()); + assertEquals(CONTAINER_1_SIDECAR_PORT, response.getDatabase().getContainer().getSidecarPort()); + } + + @Test + public void getTableById_notFound_fails() { + + /* mock */ + doThrow(HttpClientErrorException.NotFound.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableDto.class)); + + /* test */ + assertThrows(TableNotFoundException.class, () -> { + metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID); + }); + } + + @Test + public void getTableById_unavailable_fails() { + + /* mock */ + doThrow(HttpServerErrorException.ServiceUnavailable.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableDto.class)); + + /* test */ + assertThrows(RemoteUnavailableException.class, () -> { + metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID); + }); + } + + @Test + public void getTableById_statusCode_fails() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableDto.class))) + .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT) + .body(TABLE_1_DTO)); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID); + }); + } + + @Test + public void getTableById_headerMissing_fails() { + final List<String> customHeaders = List.of("X-Type", "X-Host", "X-Port", "X-Username", "X-Password", "X-Database", "X-Sidecar-Host", "X-Sidecar-Port"); + + for (int i = 0; i < customHeaders.size(); i++) { + final HttpHeaders headers = new HttpHeaders(); + for (int j = 0; j < i; j++) { + headers.add(customHeaders.get(j), ""); + } + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableDto.class))) + .thenReturn(ResponseEntity.status(HttpStatus.OK) + .headers(headers) + .body(TABLE_1_DTO)); + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID); + }); + } + } + + @Test + public void getTableById_emptyBody_fails() { + final HttpHeaders headers = new HttpHeaders(); + headers.set("X-Type", IMAGE_1_JDBC); + headers.set("X-Host", CONTAINER_1_HOST); + headers.set("X-Port", "" + CONTAINER_1_PORT); + headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME); + headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD); + headers.set("X-Database", DATABASE_1_INTERNALNAME); + headers.set("X-Sidecar-Host", CONTAINER_1_SIDECAR_HOST); + headers.set("X-Sidecar-Port", "" + CONTAINER_1_SIDECAR_PORT); + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableDto.class))) + .thenReturn(ResponseEntity.status(HttpStatus.OK) + .headers(headers) + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID); + }); + } + + @Test + public void getDatabaseByInternalName_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, + ServiceException { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto[].class))) + .thenReturn(ResponseEntity.status(HttpStatus.OK) + .body(new PrivilegedDatabaseDto[]{DATABASE_1_PRIVILEGED_DTO})); + + /* test */ + final PrivilegedDatabaseDto response = metadataServiceGateway.getDatabaseByInternalName(DATABASE_1_INTERNALNAME); + assertEquals(response.getId(), response.getId()); + } + + @Test + public void getDatabaseByInternalName_unavailable_fails() { + + /* mock */ + doThrow(HttpServerErrorException.ServiceUnavailable.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto[].class)); + + /* test */ + assertThrows(RemoteUnavailableException.class, () -> { + metadataServiceGateway.getDatabaseByInternalName(DATABASE_1_INTERNALNAME); + }); + } + + @Test + public void getDatabaseByInternalName_statusCode_fails() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto[].class))) + .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT) + .body(new PrivilegedDatabaseDto[]{DATABASE_1_PRIVILEGED_DTO})); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getDatabaseByInternalName(DATABASE_1_INTERNALNAME); + }); + } + + @Test + public void getDatabaseByInternalName_emptyBody_fails() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto[].class))) + .thenReturn(ResponseEntity.ok() + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getDatabaseByInternalName(DATABASE_1_INTERNALNAME); + }); + } + + @Test + public void getDatabaseByInternalName_notFound_fails() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto[].class))) + .thenReturn(ResponseEntity.ok() + .body(new PrivilegedDatabaseDto[]{})); + + /* test */ + assertThrows(DatabaseNotFoundException.class, () -> { + metadataServiceGateway.getDatabaseByInternalName(DATABASE_1_INTERNALNAME); + }); + } + + @Test + public void getDatabaseById_succeeds() throws RemoteUnavailableException, ServiceException, + DatabaseNotFoundException { + final HttpHeaders headers = new HttpHeaders(); + headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME); + headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD); + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto.class))) + .thenReturn(ResponseEntity.ok() + .headers(headers) + .body(DATABASE_1_PRIVILEGED_DTO)); + + /* test */ + final PrivilegedDatabaseDto response = metadataServiceGateway.getDatabaseById(DATABASE_1_ID); + assertEquals(DATABASE_1_ID, response.getId()); + } + + @Test + public void getDatabaseById_unavailable_fails() { + + /* mock */ + doThrow(HttpServerErrorException.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto.class)); + + /* test */ + assertThrows(RemoteUnavailableException.class, () -> { + metadataServiceGateway.getDatabaseById(DATABASE_1_ID); + }); + } + + @Test + public void getDatabaseById_notFound_fails() { + + /* mock */ + doThrow(HttpClientErrorException.NotFound.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto.class)); + + /* test */ + assertThrows(DatabaseNotFoundException.class, () -> { + metadataServiceGateway.getDatabaseById(DATABASE_1_ID); + }); + } + + @Test + public void getDatabaseById_statusCode_fails() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto.class))) + .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT) + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getDatabaseById(DATABASE_1_ID); + }); + } + + @Test + public void getDatabaseById_emptyBody_fails() { + final HttpHeaders headers = new HttpHeaders(); + headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME); + headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD); + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto.class))) + .thenReturn(ResponseEntity.status(HttpStatus.OK) + .headers(headers) + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getDatabaseById(DATABASE_1_ID); + }); + } + + @Test + public void getDatabaseById_headerMissing_fails() { + final List<String> customHeaders = List.of("X-Username", "X-Password"); + + for (int i = 0; i < customHeaders.size(); i++) { + final HttpHeaders headers = new HttpHeaders(); + for (int j = 0; j < i; j++) { + headers.add(customHeaders.get(j), ""); + } + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto.class))) + .thenReturn(ResponseEntity.status(HttpStatus.OK) + .headers(headers) + .build()); + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getDatabaseById(DATABASE_1_ID); + }); + } + } + + @Test + public void getContainerById_succeeds() throws RemoteUnavailableException, ContainerNotFoundException, ServiceException { + final HttpHeaders headers = new HttpHeaders(); + headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME); + headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD); + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ContainerDto.class))) + .thenReturn(ResponseEntity.ok() + .headers(headers) + .body(CONTAINER_1_DTO)); + + /* test */ + final PrivilegedContainerDto response = metadataServiceGateway.getContainerById(CONTAINER_1_ID); + assertEquals(CONTAINER_1_ID, response.getId()); + } + + @Test + public void getContainerById_unavailable_fails() { + + /* mock */ + doThrow(HttpServerErrorException.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ContainerDto.class)); + + /* test */ + assertThrows(RemoteUnavailableException.class, () -> { + metadataServiceGateway.getContainerById(CONTAINER_1_ID); + }); + } + + @Test + public void getContainerById_notFound_fails() { + + /* mock */ + doThrow(HttpClientErrorException.NotFound.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ContainerDto.class)); + + /* test */ + assertThrows(ContainerNotFoundException.class, () -> { + metadataServiceGateway.getContainerById(CONTAINER_1_ID); + }); + } + + @Test + public void getContainerById_statusCode_fails() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ContainerDto.class))) + .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT) + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getContainerById(CONTAINER_1_ID); + }); + } + + @Test + public void getContainerById_headerMissing_fails() { + final List<String> customHeaders = List.of("X-Username", "X-Password"); + + for (int i = 0; i < customHeaders.size(); i++) { + final HttpHeaders headers = new HttpHeaders(); + for (int j = 0; j < i; j++) { + headers.add(customHeaders.get(j), ""); + } + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ContainerDto.class))) + .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT) + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getContainerById(CONTAINER_1_ID); + }); + } + } + + @Test + public void getContainerById_emptyBody_fails() { + final HttpHeaders headers = new HttpHeaders(); + headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME); + headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD); + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ContainerDto.class))) + .thenReturn(ResponseEntity.status(HttpStatus.OK) + .headers(headers) + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getContainerById(CONTAINER_1_ID); + }); + } + + @Test + public void getViewById_succeeds() throws RemoteUnavailableException, ViewNotFoundException, ServiceException { + final HttpHeaders headers = new HttpHeaders(); + headers.set("X-Type", IMAGE_1_JDBC); + headers.set("X-Host", CONTAINER_1_HOST); + headers.set("X-Port", "" + CONTAINER_1_PORT); + headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME); + headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD); + headers.set("X-Database", DATABASE_1_INTERNALNAME); + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ViewDto.class))) + .thenReturn(ResponseEntity.ok() + .headers(headers) + .body(VIEW_1_DTO)); + + /* test */ + final PrivilegedViewDto response = metadataServiceGateway.getViewById(CONTAINER_1_ID, VIEW_1_ID); + assertEquals(VIEW_1_ID, response.getId()); + } + + @Test + public void getViewById_unavailable_fails() { + + /* mock */ + doThrow(HttpServerErrorException.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ViewDto.class)); + + /* test */ + assertThrows(RemoteUnavailableException.class, () -> { + metadataServiceGateway.getViewById(CONTAINER_1_ID, VIEW_1_ID); + }); + } + + @Test + public void getViewById_notFound_fails() { + + /* mock */ + doThrow(HttpClientErrorException.NotFound.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ViewDto.class)); + + /* test */ + assertThrows(ViewNotFoundException.class, () -> { + metadataServiceGateway.getViewById(CONTAINER_1_ID, VIEW_1_ID); + }); + } + + @Test + public void getViewById_statusCode_fails() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ViewDto.class))) + .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT) + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getViewById(CONTAINER_1_ID, VIEW_1_ID); + }); + } + + @Test + public void getViewById_headerMissing_fails() { + final List<String> customHeaders = List.of("X-Type", "X-Host", "X-Port", "X-Username", "X-Password", "X-Database"); + + for (int i = 0; i < customHeaders.size(); i++) { + final HttpHeaders headers = new HttpHeaders(); + for (int j = 0; j < i; j++) { + headers.add(customHeaders.get(j), ""); + } + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ViewDto.class))) + .thenReturn(ResponseEntity.status(HttpStatus.OK) + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getViewById(CONTAINER_1_ID, VIEW_1_ID); + }); + } + } + + @Test + public void getViewById_emptyBody_fails() { + final HttpHeaders headers = new HttpHeaders(); + headers.set("X-Type", IMAGE_1_JDBC); + headers.set("X-Host", CONTAINER_1_HOST); + headers.set("X-Port", "" + CONTAINER_1_PORT); + headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME); + headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD); + headers.set("X-Database", DATABASE_1_INTERNALNAME); + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ViewDto.class))) + .thenReturn(ResponseEntity.ok() + .headers(headers) + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getViewById(CONTAINER_1_ID, VIEW_1_ID); + }); + } + + @Test + public void getUserById_succeeds() throws RemoteUnavailableException, UserNotFoundException, ServiceException { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class))) + .thenReturn(ResponseEntity.ok() + .body(USER_1_DTO)); + + /* test */ + final UserDto response = metadataServiceGateway.getUserById(USER_1_ID); + assertEquals(USER_1_ID, response.getId()); + } + + @Test + public void getUserById_unavailable_fails() { + + /* mock */ + doThrow(HttpServerErrorException.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class)); + + /* test */ + assertThrows(RemoteUnavailableException.class, () -> { + metadataServiceGateway.getUserById(USER_1_ID); + }); + } + + @Test + public void getUserById_notFound_fails() { + + /* mock */ + doThrow(HttpClientErrorException.NotFound.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class)); + + /* test */ + assertThrows(UserNotFoundException.class, () -> { + metadataServiceGateway.getUserById(USER_1_ID); + }); + } + + @Test + public void getUserById_statusCode_fails() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class))) + .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT) + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getUserById(USER_1_ID); + }); + } + + @Test + public void getUserById_emptyBody_fails() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class))) + .thenReturn(ResponseEntity.ok() + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getUserById(USER_1_ID); + }); + } + + @Test + public void getPrivilegedUserById_succeeds() throws RemoteUnavailableException, UserNotFoundException, + ServiceException { + final HttpHeaders headers = new HttpHeaders(); + headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME); + headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD); + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class))) + .thenReturn(ResponseEntity.ok() + .headers(headers) + .body(USER_1_DTO)); + + /* test */ + final PrivilegedUserDto response = metadataServiceGateway.getPrivilegedUserById(USER_1_ID); + assertEquals(USER_1_ID, response.getId()); + assertEquals(CONTAINER_1_PRIVILEGED_USERNAME, response.getUsername()); + assertEquals(CONTAINER_1_PRIVILEGED_PASSWORD, response.getPassword()); + } + + @Test + public void getPrivilegedUserById_unavailable_fails() { + + /* mock */ + doThrow(HttpServerErrorException.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class)); + + /* test */ + assertThrows(RemoteUnavailableException.class, () -> { + metadataServiceGateway.getPrivilegedUserById(USER_1_ID); + }); + } + + @Test + public void getPrivilegedUserById_notFound_fails() { + + /* mock */ + doThrow(HttpClientErrorException.NotFound.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class)); + + /* test */ + assertThrows(UserNotFoundException.class, () -> { + metadataServiceGateway.getPrivilegedUserById(USER_1_ID); + }); + } + + @Test + public void getPrivilegedUserById_statusCode_fails() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class))) + .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT) + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getPrivilegedUserById(USER_1_ID); + }); + } + + @Test + public void getPrivilegedUserById_headerMissing_fails() { + final List<String> customHeaders = List.of("X-Username", "X-Password"); + + for (int i = 0; i < customHeaders.size(); i++) { + final HttpHeaders headers = new HttpHeaders(); + for (int j = 0; j < i; j++) { + headers.add(customHeaders.get(j), ""); + } + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class))) + .thenReturn(ResponseEntity.status(HttpStatus.OK) + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getPrivilegedUserById(USER_1_ID); + }); + } + } + + @Test + public void getPrivilegedUserById_emptyBody_fails() { + final HttpHeaders headers = new HttpHeaders(); + headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME); + headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD); + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class))) + .thenReturn(ResponseEntity.ok() + .headers(headers) + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getPrivilegedUserById(USER_1_ID); + }); + } + + @Test + public void getAccess_succeeds() throws RemoteUnavailableException, NotAllowedException, ServiceException { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(DatabaseAccessDto.class))) + .thenReturn(ResponseEntity.ok() + .body(DATABASE_1_USER_1_READ_ACCESS_DTO)); + + /* test */ + final DatabaseAccessDto response = metadataServiceGateway.getAccess(DATABASE_1_ID, USER_1_ID); + } + + @Test + public void getAccess_unavailable_fails() { + + /* mock */ + doThrow(HttpServerErrorException.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(DatabaseAccessDto.class)); + + /* test */ + assertThrows(RemoteUnavailableException.class, () -> { + metadataServiceGateway.getAccess(DATABASE_1_ID, USER_1_ID); + }); + } + + @Test + public void getAccess_forbidden_fails() { + + /* mock */ + doThrow(HttpClientErrorException.Forbidden.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(DatabaseAccessDto.class)); + + /* test */ + assertThrows(NotAllowedException.class, () -> { + metadataServiceGateway.getAccess(DATABASE_1_ID, USER_1_ID); + }); + } + + @Test + public void getAccess_notFound_fails() { + + /* mock */ + doThrow(HttpClientErrorException.NotFound.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(DatabaseAccessDto.class)); + + /* test */ + assertThrows(NotAllowedException.class, () -> { + metadataServiceGateway.getAccess(DATABASE_1_ID, USER_1_ID); + }); + } + + @Test + public void getAccess_statusCode_fails() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(DatabaseAccessDto.class))) + .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT) + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getAccess(DATABASE_1_ID, USER_1_ID); + }); + } + + @Test + public void getAccess_emptyBody_fails() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(DatabaseAccessDto.class))) + .thenReturn(ResponseEntity.ok() + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getAccess(DATABASE_1_ID, USER_1_ID); + }); + } + + @Test + public void getIdentifiers_witSubset_succeeds() throws RemoteUnavailableException, DatabaseNotFoundException, ServiceException { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(IdentifierDto[].class))) + .thenReturn(ResponseEntity.ok() + .body(new IdentifierDto[]{IDENTIFIER_1_DTO})); + + /* test */ + final List<IdentifierDto> response = metadataServiceGateway.getIdentifiers(DATABASE_1_ID, QUERY_1_ID); + assertEquals(1, response.size()); + } + + @Test + public void getIdentifiers_succeeds() throws RemoteUnavailableException, DatabaseNotFoundException, ServiceException { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(IdentifierDto[].class))) + .thenReturn(ResponseEntity.ok() + .body(new IdentifierDto[]{IDENTIFIER_1_DTO})); + + /* test */ + final List<IdentifierDto> response = metadataServiceGateway.getIdentifiers(DATABASE_1_ID, null); + assertEquals(1, response.size()); + } + + @Test + public void getIdentifiers_unavailable_fails() { + + /* mock */ + doThrow(HttpServerErrorException.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(IdentifierDto[].class)); + + /* test */ + assertThrows(RemoteUnavailableException.class, () -> { + metadataServiceGateway.getIdentifiers(DATABASE_1_ID, QUERY_1_ID); + }); + } + + @Test + public void getIdentifiers_notFound_fails() { + + /* mock */ + doThrow(HttpClientErrorException.NotFound.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(IdentifierDto[].class)); + + /* test */ + assertThrows(DatabaseNotFoundException.class, () -> { + metadataServiceGateway.getIdentifiers(DATABASE_1_ID, QUERY_1_ID); + }); + } + + @Test + public void getIdentifiers_statusCode_fails() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(IdentifierDto[].class))) + .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT) + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getIdentifiers(DATABASE_1_ID, QUERY_1_ID); + }); + } + + @Test + public void getIdentifiers_emptyBody_fails() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(IdentifierDto[].class))) + .thenReturn(ResponseEntity.ok() + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.getIdentifiers(DATABASE_1_ID, QUERY_1_ID); + }); + } + + @Test + public void updateTableStatistics_succeeds() throws RemoteUnavailableException, ServiceException, TableNotFoundException { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), eq(HttpEntity.EMPTY), eq(Void.class))) + .thenReturn(ResponseEntity.accepted() + .build()); + + /* test */ + metadataServiceGateway.updateTableStatistics(DATABASE_1_ID, TABLE_1_ID); + } + + @Test + public void updateTableStatistics_unavailable_fails() { + + /* mock */ + doThrow(HttpServerErrorException.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.PUT), eq(HttpEntity.EMPTY), eq(Void.class)); + + /* test */ + assertThrows(RemoteUnavailableException.class, () -> { + metadataServiceGateway.updateTableStatistics(DATABASE_1_ID, TABLE_1_ID); + }); + } + + @Test + public void updateTableStatistics_notFound_fails() { + + /* mock */ + doThrow(HttpClientErrorException.NotFound.class) + .when(restTemplate) + .exchange(anyString(), eq(HttpMethod.PUT), eq(HttpEntity.EMPTY), eq(Void.class)); + + /* test */ + assertThrows(TableNotFoundException.class, () -> { + metadataServiceGateway.updateTableStatistics(DATABASE_1_ID, TABLE_1_ID); + }); + } + + @Test + public void updateTableStatistics_statusCode_fails() { + + /* mock */ + when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), eq(HttpEntity.EMPTY), eq(Void.class))) + .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT) + .build()); + + /* test */ + assertThrows(ServiceException.class, () -> { + metadataServiceGateway.updateTableStatistics(DATABASE_1_ID, TABLE_1_ID); + }); + } + +} diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerIntegrationTest.java index 2994e7f0987edbe9e35820556fdf70d7b003b48d..dec1fcc0282993ba0a7b527dc4dda7088fc0e4a5 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerIntegrationTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerIntegrationTest.java @@ -3,6 +3,7 @@ package at.tuwien.listener; import at.tuwien.config.MariaDbConfig; import at.tuwien.config.MariaDbContainerConfig; import at.tuwien.exception.RemoteUnavailableException; +import at.tuwien.exception.ServiceException; import at.tuwien.exception.TableNotFoundException; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.test.AbstractUnitTest; @@ -61,7 +62,8 @@ public class DefaultListenerIntegrationTest extends AbstractUnitTest { } @Test - public void onMessage_succeeds(CapturedOutput output) throws TableNotFoundException, RemoteUnavailableException { + public void onMessage_succeeds(CapturedOutput output) throws TableNotFoundException, RemoteUnavailableException, + ServiceException { final Message request = buildMessage("dbrepo." + DATABASE_1_ID + "." + TABLE_1_ID, "{\"id\":4,\"date\":\"2023-10-03\",\"mintemp\":15.0,\"rainfall\":0.2}", new HashMap<>()); /* mock */ @@ -75,7 +77,8 @@ public class DefaultListenerIntegrationTest extends AbstractUnitTest { @Test @Disabled - public void onMessage_tableNotFound_fails(CapturedOutput output) throws TableNotFoundException, RemoteUnavailableException { + public void onMessage_tableNotFound_fails(CapturedOutput output) throws TableNotFoundException, + RemoteUnavailableException, ServiceException { final Message request = buildMessage("dbrepo." + DATABASE_1_ID + "." + TABLE_1_ID, "{\"id\":4,\"date\":\"2023-10-03\",\"mintemp\":15.0,\"rainfall\":0.2}", new HashMap<>()); /* mock */ diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerUnitTest.java index 5c2f61d5b7e42e0d888a15cc25e6884f7b70f353..ab4a171c8915440055934c904247832ce0cf7549 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerUnitTest.java @@ -3,6 +3,7 @@ package at.tuwien.listener; import at.tuwien.config.MariaDbConfig; import at.tuwien.config.MariaDbContainerConfig; import at.tuwien.exception.RemoteUnavailableException; +import at.tuwien.exception.ServiceException; import at.tuwien.exception.TableNotFoundException; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.test.AbstractUnitTest; @@ -75,7 +76,7 @@ public class DefaultListenerUnitTest extends AbstractUnitTest { @Test public void onMessage_messageMalformed_fails(CapturedOutput output) throws TableNotFoundException, - RemoteUnavailableException { + RemoteUnavailableException, ServiceException { final Message request = buildMessage("dbrepo.1.1", "{,}", new HashMap<>()); /* mock */ @@ -89,7 +90,7 @@ public class DefaultListenerUnitTest extends AbstractUnitTest { @Test public void onMessage_tableNotFound_fails(CapturedOutput output) throws TableNotFoundException, - RemoteUnavailableException { + RemoteUnavailableException, ServiceException { final Message request = buildMessage("dbrepo.1.1", "{\"id\":1}", new HashMap<>()); /* mock */ diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java index 1b51d3072c52398288c68725b6b020d08e66e622..803632c078717ef92de0bbedd246734276aa0f9a 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java @@ -34,7 +34,6 @@ import org.springframework.test.web.servlet.MockMvc; import java.io.File; import java.io.IOException; -import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.*; @@ -177,22 +176,22 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest { /* ignore */ } try { - tableEndpoint.createTuple(DATABASE_1_ID, TABLE_1_ID, TupleDto.builder().build(), USER_1_PRINCIPAL); + tableEndpoint.insertRawTuple(DATABASE_1_ID, TABLE_1_ID, TupleDto.builder().build(), USER_1_PRINCIPAL); } catch (Exception e) { /* ignore */ } try { - tableEndpoint.updateTuple(DATABASE_1_ID, TABLE_1_ID, TupleUpdateDto.builder().build(), USER_1_PRINCIPAL); + tableEndpoint.updateRawTuple(DATABASE_1_ID, TABLE_1_ID, TupleUpdateDto.builder().build(), USER_1_PRINCIPAL); } catch (Exception e) { /* ignore */ } try { - tableEndpoint.deleteTuple(DATABASE_1_ID, TABLE_1_ID, TupleDeleteDto.builder().build(), USER_1_PRINCIPAL); + tableEndpoint.deleteRawTuple(DATABASE_1_ID, TABLE_1_ID, TupleDeleteDto.builder().build(), USER_1_PRINCIPAL); } catch (Exception e) { /* ignore */ } try { - tableEndpoint.getHistory(DATABASE_1_ID, TABLE_1_ID, USER_1_PRINCIPAL); + tableEndpoint.getHistory(DATABASE_1_ID, TABLE_1_ID, null, USER_1_PRINCIPAL); } catch (Exception e) { /* ignore */ } @@ -207,7 +206,7 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest { /* ignore */ } try { - tableEndpoint.importData(DATABASE_1_ID, TABLE_1_ID, ImportCsvDto.builder().build(), USER_1_PRINCIPAL); + tableEndpoint.importDataset(DATABASE_1_ID, TABLE_1_ID, ImportCsvDto.builder().build(), USER_1_PRINCIPAL); } catch (Exception e) { /* ignore */ } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/AccessServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/AccessServiceIntegrationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b7b8e0e2630b32c834cc229d043160505496ed63 --- /dev/null +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/AccessServiceIntegrationTest.java @@ -0,0 +1,145 @@ +package at.tuwien.service; + +import at.tuwien.api.database.AccessTypeDto; +import at.tuwien.config.MariaDbConfig; +import at.tuwien.config.MariaDbContainerConfig; +import at.tuwien.exception.DatabaseMalformedException; +import at.tuwien.test.AbstractUnitTest; +import lombok.extern.log4j.Log4j2; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.testcontainers.containers.MariaDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.sql.SQLException; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +@Log4j2 +@SpringBootTest +@ExtendWith(SpringExtension.class) +@Testcontainers +public class AccessServiceIntegrationTest extends AbstractUnitTest { + + @Autowired + private AccessService accessService; + + @Value("${dbrepo.grant.default.read}") + private String grantDefaultRead; + + @Value("${dbrepo.grant.default.write}") + private String grantDefaultWrite; + + @Container + private static MariaDBContainer<?> mariaDBContainer = MariaDbContainerConfig.getContainer(); + + @BeforeEach + public void beforeEach() throws SQLException { + genesis(); + /* metadata database */ + MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); + MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO); + } + + @Test + public void create_read_succeeds() throws SQLException, DatabaseMalformedException { + + /* test */ + accessService.create(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO, AccessTypeDto.READ); + final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME); + for (String privilege : grantDefaultRead.split(",")) { + assertTrue(privileges.stream().anyMatch(p -> p.trim().equals(privilege.trim()))); + } + } + + @Test + public void create_writeOwn_succeeds() throws SQLException, DatabaseMalformedException { + + /* test */ + accessService.create(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO, AccessTypeDto.WRITE_OWN); + final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME); + for (String privilege : grantDefaultWrite.split(",")) { + assertTrue(privileges.stream().anyMatch(p -> p.trim().equals(privilege.trim()))); + } + } + + @Test + public void create_writeAll_succeeds() throws SQLException, DatabaseMalformedException { + + /* test */ + accessService.create(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO, AccessTypeDto.WRITE_ALL); + final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME); + for (String privilege : grantDefaultWrite.split(",")) { + assertTrue(privileges.stream().anyMatch(p -> p.trim().equals(privilege.trim()))); + } + } + + @Test + public void update_read_succeeds() throws SQLException, DatabaseMalformedException { + + /* test */ + accessService.update(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO, AccessTypeDto.READ); + final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME); + for (String privilege : grantDefaultRead.split(",")) { + assertTrue(privileges.stream().anyMatch(p -> p.trim().equals(privilege.trim()))); + } + } + + @Test + public void update_writeOwn_succeeds() throws SQLException, DatabaseMalformedException { + + /* test */ + accessService.update(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO, AccessTypeDto.WRITE_OWN); + final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME); + for (String privilege : grantDefaultWrite.split(",")) { + assertTrue(privileges.stream().anyMatch(p -> p.trim().equals(privilege.trim()))); + } + } + + @Test + public void update_writeAll_succeeds() throws SQLException, DatabaseMalformedException { + + /* test */ + accessService.update(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO, AccessTypeDto.WRITE_ALL); + final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME); + for (String privilege : grantDefaultWrite.split(",")) { + assertTrue(privileges.stream().anyMatch(p -> p.trim().equals(privilege.trim()))); + } + } + + @Test + public void update_notFound_fails() { + + /* test */ + assertThrows(DatabaseMalformedException.class, () -> { + accessService.update(DATABASE_1_PRIVILEGED_DTO, USER_5_DTO, AccessTypeDto.WRITE_ALL); + }); + } + + @Test + public void delete_succeeds() throws SQLException, DatabaseMalformedException { + + /* test */ + accessService.delete(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO); + final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME); + assertEquals(1, privileges.size()); + assertEquals("USAGE", privileges.get(0)); + } + + @Test + public void delete_notFound_fails() { + + /* test */ + assertThrows(DatabaseMalformedException.class, () -> { + accessService.delete(DATABASE_1_PRIVILEGED_DTO, USER_5_DTO); + }); + } + +} diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e53f6ad88f92095ae405d586d39a399e0a6b0304 --- /dev/null +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java @@ -0,0 +1,119 @@ +package at.tuwien.service; + +import at.tuwien.api.database.internal.PrivilegedDatabaseDto; +import at.tuwien.api.user.internal.UpdateUserPasswordDto; +import at.tuwien.config.MariaDbConfig; +import at.tuwien.config.MariaDbContainerConfig; +import at.tuwien.exception.*; +import at.tuwien.mapper.MariaDbMapper; +import at.tuwien.mapper.MariaDbMapperImpl; +import at.tuwien.test.AbstractUnitTest; +import lombok.extern.log4j.Log4j2; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.testcontainers.containers.MariaDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.sql.SQLException; + +import static org.junit.jupiter.api.Assertions.*; + +@Log4j2 +@SpringBootTest +@ExtendWith(SpringExtension.class) +@Testcontainers +public class DatabaseServiceIntegrationTest extends AbstractUnitTest { + + @Autowired + private DatabaseService databaseService; + + @Container + private static MariaDBContainer<?> mariaDBContainer = MariaDbContainerConfig.getContainer(); + + @Autowired + private MariaDbMapper mariaDbMapper; + + @BeforeEach + public void beforeEach() throws SQLException { + genesis(); + /* metadata database */ + MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); + } + + @Test + public void create_succeeds() throws SQLException, DatabaseMalformedException { + + /* test */ + final PrivilegedDatabaseDto response = databaseService.create(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL); + assertNull(response.getName()); + assertEquals(DATABASE_1_INTERNALNAME, response.getInternalName()); + assertEquals(EXCHANGE_DBREPO_NAME, response.getExchangeName()); + assertNotNull(response.getCreator()); + assertEquals(USER_1_ID, response.getCreator().getId()); + assertNotNull(response.getOwner()); + assertEquals(USER_1_ID, response.getOwner().getId()); + assertNotNull(response.getContact()); + assertEquals(USER_1_ID, response.getContact().getId()); + assertNotNull(response.getContainer()); + assertEquals(CONTAINER_1_ID, response.getContainer().getId()); + } + + @Test + public void create_exists_fails() throws SQLException { + + /* mock */ + MariaDbConfig.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); + + /* test */ + assertThrows(DatabaseMalformedException.class, () -> { + databaseService.create(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL); + }); + } + + @Test + public void update_succeeds() throws SQLException, DatabaseMalformedException { + final UpdateUserPasswordDto request = UpdateUserPasswordDto.builder() + .username(USER_1_USERNAME) + .password(USER_2_PASSWORD) + .build(); + + /* mock */ + MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO); + MariaDbConfig.grantWriteAccess(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME); + + /* pre-condition */ + MariaDbConfig.mockQuery(CONTAINER_1_HOST, CONTAINER_1_PORT, DATABASE_1_INTERNALNAME, "CREATE SEQUENCE debug NOCACHE", USER_1_USERNAME, USER_1_PASSWORD); + try { + MariaDbConfig.mockQuery(CONTAINER_1_HOST, CONTAINER_1_PORT, DATABASE_1_INTERNALNAME, "CREATE SEQUENCE debug NOCACHE", USER_1_USERNAME, USER_2_PASSWORD); + fail(); + } catch (SQLException e) { + /* ignore */ + } + + /* test */ + databaseService.update(DATABASE_1_PRIVILEGED_DTO, request); + MariaDbConfig.mockQuery(CONTAINER_1_HOST, CONTAINER_1_PORT, DATABASE_1_INTERNALNAME, "CREATE SEQUENCE debug2 NOCACHE", USER_1_USERNAME, USER_2_PASSWORD); + } + + @Test + public void update_notExists_fails() throws SQLException { + final UpdateUserPasswordDto request = UpdateUserPasswordDto.builder() + .username("i_do_not_exist") + .password(USER_1_PASSWORD) + .build(); + + /* mock */ + MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO); + + /* test */ + assertThrows(DatabaseMalformedException.class, () -> { + databaseService.update(DATABASE_1_PRIVILEGED_DTO, request); + }); + } + +} diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java index 452c88932ca431e0cbee5755f29bb6f7f4a1d889..4bfa5b443a19ed6bf7af2c55183fd94fa0366baf 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java @@ -4,6 +4,7 @@ import at.tuwien.config.MariaDbConfig; import at.tuwien.config.MariaDbContainerConfig; import at.tuwien.exception.ContainerNotFoundException; import at.tuwien.exception.RemoteUnavailableException; +import at.tuwien.exception.ServiceException; import at.tuwien.exception.TableNotFoundException; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.service.impl.QueueServiceRabbitMqImpl; @@ -50,7 +51,8 @@ public class QueueServiceIntegrationTest extends AbstractUnitTest { } @Test - public void insert_succeeds() throws InterruptedException, SQLException, RemoteUnavailableException, ContainerNotFoundException, TableNotFoundException { + public void insert_succeeds() throws InterruptedException, SQLException, RemoteUnavailableException, + ContainerNotFoundException, TableNotFoundException, ServiceException { final Map<String, Object> request = new HashMap<>() {{ put("id", 4L); put("date", "2023-10-03"); @@ -73,7 +75,8 @@ public class QueueServiceIntegrationTest extends AbstractUnitTest { } @Test - public void insert_onlyMandatoryFields_succeeds() throws InterruptedException, SQLException, RemoteUnavailableException, TableNotFoundException { + public void insert_onlyMandatoryFields_succeeds() throws InterruptedException, SQLException, + RemoteUnavailableException, TableNotFoundException, ServiceException { final Map<String, Object> request = new HashMap<>() {{ put("id", 5L); put("date", "2023-10-04"); diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java index c9efad23f02b5ef280e8d9a55605d94e79a6b2fd..25dcb0caea1e161e0c6964b5cc121495aed78130 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java @@ -1,13 +1,19 @@ package at.tuwien.service; +import at.tuwien.api.container.image.ImageDateDto; import at.tuwien.api.database.ViewColumnDto; import at.tuwien.api.database.ViewDto; +import at.tuwien.api.database.table.TableBriefDto; import at.tuwien.api.database.table.TableDto; import at.tuwien.api.database.table.columns.ColumnDto; import at.tuwien.api.database.table.columns.ColumnTypeDto; import at.tuwien.api.database.table.constraints.ConstraintsDto; +import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto; +import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto; +import at.tuwien.api.database.table.constraints.foreign.ReferenceTypeDto; import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto; import at.tuwien.api.database.table.constraints.unique.UniqueDto; +import at.tuwien.api.identifier.IdentifierDto; import at.tuwien.config.MariaDbConfig; import at.tuwien.config.MariaDbContainerConfig; import at.tuwien.exception.*; @@ -24,6 +30,7 @@ import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import java.sql.SQLException; +import java.util.LinkedList; import java.util.List; import java.util.Set; @@ -62,34 +69,11 @@ public class SchemaServiceIntegrationTest extends AbstractUnitTest { final List<ColumnDto> columns = response.getColumns(); assertNotNull(columns); assertEquals(5, columns.size()); - final ColumnDto column0 = columns.get(0); - assertEquals("id", column0.getName()); - assertEquals("id", column0.getInternalName()); - assertEquals(ColumnTypeDto.BIGINT, column0.getColumnType()); - assertFalse(column0.getIsNullAllowed()); - final ColumnDto column1 = columns.get(1); - assertEquals("given_name", column1.getName()); - assertEquals("given_name", column1.getInternalName()); - assertEquals(ColumnTypeDto.VARCHAR, column1.getColumnType()); - assertEquals(255, column1.getSize()); - assertFalse(column1.getIsNullAllowed()); - final ColumnDto column2 = columns.get(2); - assertEquals("middle_name", column2.getName()); - assertEquals("middle_name", column2.getInternalName()); - assertEquals(ColumnTypeDto.VARCHAR, column2.getColumnType()); - assertEquals(255, column2.getSize()); - assertTrue(column2.getIsNullAllowed()); - final ColumnDto column3 = columns.get(3); - assertEquals("family_name", column3.getName()); - assertEquals("family_name", column3.getInternalName()); - assertEquals(ColumnTypeDto.VARCHAR, column3.getColumnType()); - assertEquals(255, column3.getSize()); - assertFalse(column3.getIsNullAllowed()); - final ColumnDto column4 = columns.get(4); - assertEquals("age", column4.getName()); - assertEquals("age", column4.getInternalName()); - assertEquals(ColumnTypeDto.INT, column4.getColumnType()); - assertFalse(column4.getIsNullAllowed()); + assertColumn(columns.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null, null); + assertColumn(columns.get(1), null, null, DATABASE_1_ID, "given_name", "given_name", ColumnTypeDto.VARCHAR, 255L, null, false, null, null); + assertColumn(columns.get(2), null, null, DATABASE_1_ID, "middle_name", "middle_name", ColumnTypeDto.VARCHAR, 255L, null, true, null, null); + assertColumn(columns.get(3), null, null, DATABASE_1_ID, "family_name", "family_name", ColumnTypeDto.VARCHAR, 255L, null, false, null, null); + assertColumn(columns.get(4), null, null, DATABASE_1_ID, "age", "age", ColumnTypeDto.INT, 10L, 0L, false, null, null); final ConstraintsDto constraints = response.getConstraints(); assertNotNull(constraints); final Set<PrimaryKeyDto> primaryKey = constraints.getPrimaryKey(); @@ -100,9 +84,210 @@ public class SchemaServiceIntegrationTest extends AbstractUnitTest { final List<UniqueDto> uniques = constraints.getUniques(); assertEquals(1, uniques.size()); assertEquals(2, uniques.get(0).getColumns().size()); + assertEquals("not_in_metadata_db", uniques.get(0).getTable().getName()); assertEquals("not_in_metadata_db", uniques.get(0).getTable().getInternalName()); assertEquals("given_name", uniques.get(0).getColumns().get(0).getInternalName()); assertEquals("family_name", uniques.get(0).getColumns().get(1).getInternalName()); + final List<ForeignKeyDto> foreignKeys = constraints.getForeignKeys(); + assertEquals(0, foreignKeys.size()); + } + + @Test + public void inspectTableFullConstraints_succeeds() throws TableNotFoundException, SQLException, QueryMalformedException { + + /* test */ + final TableDto response = schemaService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "weather_aus"); + assertEquals("weather_aus", response.getInternalName()); + assertEquals("weather_aus", response.getName()); + assertEquals(DATABASE_1_ID, response.getTdbid()); + assertTrue(response.getIsVersioned()); + assertEquals(DATABASE_1_PUBLIC, response.getIsPublic()); + assertEquals(DATABASE_1_OWNER, response.getCreatedBy()); + assertNotNull(response.getCreator()); + assertEquals(DATABASE_1_OWNER, response.getCreator().getId()); + assertEquals(USER_1_NAME, response.getCreator().getName()); + assertEquals(USER_1_USERNAME, response.getCreator().getUsername()); + assertEquals(USER_1_FIRSTNAME, response.getCreator().getFirstname()); + assertEquals(USER_1_LASTNAME, response.getCreator().getLastname()); + assertEquals(USER_1_QUALIFIED_NAME, response.getCreator().getQualifiedName()); + assertNotNull(response.getCreator().getAttributes()); + assertEquals(USER_1_AFFILIATION, response.getCreator().getAttributes().getAffiliation()); + assertEquals(USER_1_THEME, response.getCreator().getAttributes().getTheme()); + assertEquals(USER_1_LANGUAGE, response.getCreator().getAttributes().getLanguage()); + assertEquals(USER_1_ORCID_UNCOMPRESSED, response.getCreator().getAttributes().getOrcid()); + assertNull(response.getCreator().getAttributes().getMariadbPassword()); + final List<IdentifierDto> identifiers = response.getIdentifiers(); + assertNotNull(identifiers); + assertEquals(0, identifiers.size()); + final List<ColumnDto> columns = response.getColumns(); + assertNotNull(columns); + assertEquals(5, columns.size()); + assertColumn(columns.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null, null); + assertColumn(columns.get(1), null, null, DATABASE_1_ID, "date", "date", ColumnTypeDto.DATE, null, null, false, IMAGE_DATE_1_ID, null); + assertColumn(columns.get(2), null, null, DATABASE_1_ID, "location", "location", ColumnTypeDto.VARCHAR, 255L, null, true, null, "Closest city"); + assertColumn(columns.get(3), null, null, DATABASE_1_ID, "mintemp", "mintemp", ColumnTypeDto.DOUBLE, 22L, null, true, null, null); + assertColumn(columns.get(4), null, null, DATABASE_1_ID, "rainfall", "rainfall", ColumnTypeDto.DOUBLE, 22L, null, true, null, null); + final ConstraintsDto constraints = response.getConstraints(); + final List<PrimaryKeyDto> primaryKey = new LinkedList<>(constraints.getPrimaryKey()); + assertEquals(1, primaryKey.size()); + final PrimaryKeyDto pk0 = primaryKey.get(0); + assertNull(pk0.getId()); + assertNotNull(pk0.getTable()); + assertNull(pk0.getTable().getId()); + assertEquals("weather_aus", pk0.getTable().getName()); + assertEquals("weather_aus", pk0.getTable().getInternalName()); + assertEquals("Weather in Australia", pk0.getTable().getDescription()); + assertNotNull(pk0.getColumn()); + assertNull(pk0.getColumn().getId()); + assertNull(pk0.getColumn().getTableId()); + assertEquals(DATABASE_1_ID, pk0.getColumn().getDatabaseId()); + assertNull(pk0.getColumn().getAlias()); + assertEquals("id", pk0.getColumn().getName()); + assertEquals("id", pk0.getColumn().getInternalName()); + assertEquals(ColumnTypeDto.BIGINT, pk0.getColumn().getColumnType()); + final List<UniqueDto> uniques = constraints.getUniques(); + assertEquals(1, uniques.size()); + final UniqueDto unique0 = uniques.get(0); + assertNotNull(unique0.getTable()); + assertNull(unique0.getTable().getId()); + assertEquals(TABLE_1_INTERNALNAME, unique0.getTable().getName()); + assertEquals(TABLE_1_INTERNALNAME, unique0.getTable().getInternalName()); + assertEquals(TABLE_1_DESCRIPTION, unique0.getTable().getDescription()); + assertTrue(unique0.getTable().getIsVersioned()); + assertNotNull(unique0.getColumns()); + assertEquals(1, unique0.getColumns().size()); + assertNull(unique0.getColumns().get(0).getId()); + assertNull(unique0.getColumns().get(0).getTableId()); + assertEquals("date", unique0.getColumns().get(0).getName()); + assertEquals("date", unique0.getColumns().get(0).getInternalName()); + final List<String> checks = new LinkedList<>(constraints.getChecks()); + assertEquals("`mintemp` > 0", checks.get(0)); + final List<ForeignKeyDto> foreignKeys = constraints.getForeignKeys(); + assertEquals(1, foreignKeys.size()); + final ForeignKeyDto fk0 = foreignKeys.get(0); + assertNotNull(fk0.getName()); + assertNotNull(fk0.getReferences()); + final ForeignKeyReferenceDto fk0ref0 = fk0.getReferences().get(0); + assertNull(fk0ref0.getId()); + assertNotNull(fk0ref0.getColumn()); + assertNotNull(fk0ref0.getReferencedColumn()); + assertNotNull(fk0ref0.getForeignKey()); + assertEquals(DATABASE_1_ID, fk0ref0.getColumn().getDatabaseId()); + assertNull(fk0ref0.getColumn().getId()); + assertNull(fk0ref0.getColumn().getTableId()); + assertEquals("location", fk0ref0.getColumn().getName()); + assertEquals("location", fk0ref0.getColumn().getInternalName()); + assertEquals(DATABASE_1_ID, fk0ref0.getReferencedColumn().getDatabaseId()); + assertNull(fk0ref0.getReferencedColumn().getId()); + assertNull(fk0ref0.getReferencedColumn().getTableId()); + assertEquals("location", fk0ref0.getReferencedColumn().getName()); + assertEquals("location", fk0ref0.getReferencedColumn().getInternalName()); + assertNotNull(fk0.getOnUpdate()); + assertEquals(ReferenceTypeDto.RESTRICT, fk0.getOnUpdate()); + assertNotNull(fk0.getOnDelete()); + assertEquals(ReferenceTypeDto.SET_NULL, fk0.getOnDelete()); + final TableBriefDto fk0table = fk0.getTable(); + assertNull(fk0table.getId()); + assertEquals(DATABASE_1_ID, fk0table.getDatabaseId()); + assertEquals(TABLE_1_INTERNALNAME, fk0table.getName()); + assertEquals(TABLE_1_INTERNALNAME, fk0table.getInternalName()); + assertNotNull(fk0.getOnDelete()); + assertNotNull(fk0.getOnUpdate()); + assertNotNull(fk0.getReferencedTable()); + assertEquals(TABLE_2_INTERNALNAME, fk0.getReferencedTable().getName()); + assertEquals(TABLE_2_INTERNALNAME, fk0.getReferencedTable().getInternalName()); + } + + @Test + public void inspectTable_multipleForeignKeyReferences_succeeds() throws TableNotFoundException, SQLException, QueryMalformedException { + + /* test */ + final TableDto response = schemaService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "complex_foreign_keys"); + final ConstraintsDto constraints = response.getConstraints(); + final List<ForeignKeyDto> foreignKeys = constraints.getForeignKeys(); + assertEquals(1, foreignKeys.size()); + final ForeignKeyDto fk0 = foreignKeys.get(0); + assertNotNull(fk0.getName()); + assertNotNull(fk0.getReferences()); + final ForeignKeyReferenceDto fk0ref0 = fk0.getReferences().get(0); + assertNull(fk0ref0.getId()); + assertNotNull(fk0ref0.getColumn()); + assertNotNull(fk0ref0.getReferencedColumn()); + assertNotNull(fk0ref0.getForeignKey()); + assertEquals(DATABASE_1_ID, fk0ref0.getColumn().getDatabaseId()); + assertNull(fk0ref0.getColumn().getId()); + assertNull(fk0ref0.getColumn().getTableId()); + assertEquals("weather_id", fk0ref0.getColumn().getName()); + assertEquals("weather_id", fk0ref0.getColumn().getInternalName()); + assertEquals(DATABASE_1_ID, fk0ref0.getReferencedColumn().getDatabaseId()); + assertNull(fk0ref0.getReferencedColumn().getId()); + assertNull(fk0ref0.getReferencedColumn().getTableId()); + assertEquals("id", fk0ref0.getReferencedColumn().getName()); + assertEquals("id", fk0ref0.getReferencedColumn().getInternalName()); + final ForeignKeyReferenceDto fk0ref1 = fk0.getReferences().get(1); + assertNull(fk0ref1.getId()); + assertNotNull(fk0ref1.getColumn()); + assertNotNull(fk0ref1.getReferencedColumn()); + assertNotNull(fk0ref1.getForeignKey()); + assertEquals(DATABASE_1_ID, fk0ref1.getColumn().getDatabaseId()); + assertNull(fk0ref1.getColumn().getId()); + assertNull(fk0ref1.getColumn().getTableId()); + assertEquals("other_id", fk0ref1.getColumn().getName()); + assertEquals("other_id", fk0ref1.getColumn().getInternalName()); + assertEquals(DATABASE_1_ID, fk0ref1.getReferencedColumn().getDatabaseId()); + assertNull(fk0ref1.getReferencedColumn().getId()); + assertNull(fk0ref1.getReferencedColumn().getTableId()); + assertEquals("other_id", fk0ref1.getReferencedColumn().getName()); + assertEquals("other_id", fk0ref1.getReferencedColumn().getInternalName()); + final TableBriefDto fk0refT0 = fk0.getTable(); + assertNull(fk0refT0.getId()); + assertEquals(DATABASE_1_ID, fk0refT0.getDatabaseId()); + assertEquals("complex_foreign_keys", fk0refT0.getName()); + assertEquals("complex_foreign_keys", fk0refT0.getInternalName()); + assertNotNull(fk0.getReferencedTable()); + assertEquals("complex_primary_key", fk0.getReferencedTable().getName()); + assertEquals("complex_primary_key", fk0.getReferencedTable().getInternalName()); + assertNotNull(fk0.getOnDelete()); + assertNotNull(fk0.getOnUpdate()); + } + + @Test + public void inspectTable_multiplePrimaryKey_succeeds() throws TableNotFoundException, SQLException, QueryMalformedException { + + /* test */ + final TableDto response = schemaService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "complex_primary_key"); + final ConstraintsDto constraints = response.getConstraints(); + final List<PrimaryKeyDto> primaryKey = new LinkedList<>(constraints.getPrimaryKey()); + assertEquals(2, primaryKey.size()); + final PrimaryKeyDto pk0 = primaryKey.get(0); + assertNull(pk0.getId()); + assertNotNull(pk0.getTable()); + assertNull(pk0.getTable().getId()); + assertEquals("complex_primary_key", pk0.getTable().getName()); + assertEquals("complex_primary_key", pk0.getTable().getInternalName()); + assertNotNull(pk0.getColumn()); + assertNull(pk0.getColumn().getId()); + assertNull(pk0.getColumn().getTableId()); + assertEquals(DATABASE_1_ID, pk0.getColumn().getDatabaseId()); + assertNull(pk0.getColumn().getAlias()); + assertEquals("id", pk0.getColumn().getName()); + assertEquals("id", pk0.getColumn().getInternalName()); + assertEquals(ColumnTypeDto.BIGINT, pk0.getColumn().getColumnType()); + final PrimaryKeyDto pk1 = primaryKey.get(1); + assertNull(pk1.getId()); + assertNotNull(pk1.getTable()); + assertNull(pk1.getTable().getId()); + assertEquals("complex_primary_key", pk1.getTable().getName()); + assertEquals("complex_primary_key", pk1.getTable().getInternalName()); + assertNotNull(pk1.getColumn()); + assertNull(pk1.getColumn().getId()); + assertNull(pk1.getColumn().getTableId()); + assertEquals(DATABASE_1_ID, pk1.getColumn().getDatabaseId()); + assertNull(pk1.getColumn().getAlias()); + assertEquals("other_id", pk1.getColumn().getName()); + assertEquals("other_id", pk1.getColumn().getInternalName()); + assertEquals(ColumnTypeDto.BIGINT, pk1.getColumn().getColumnType()); + } @Test @@ -140,4 +325,51 @@ public class SchemaServiceIntegrationTest extends AbstractUnitTest { assertEquals(DATABASE_1_ID, column3.getDatabaseId()); } + protected static void assertViewColumn(ViewColumnDto column, Long id, Long databaseId, String name, String internalName, + ColumnTypeDto type, Long size, Long d, Boolean nullAllowed, + ImageDateDto dateFormat, String description) { + log.trace("assert column: {}", internalName); + assertNotNull(column); + assertEquals(id, column.getId()); + assertEquals(databaseId, column.getDatabaseId()); + assertEquals(name, column.getName()); + assertEquals(internalName, column.getInternalName()); + assertEquals(type, column.getColumnType()); + assertEquals(size, column.getSize()); + assertEquals(d, column.getD()); + assertEquals(nullAllowed, column.getIsNullAllowed()); + assertEquals(description, column.getDescription()); + if (dateFormat != null) { + assertNotNull(column.getDateFormat()); + assertEquals(dateFormat.getId(), column.getDateFormat().getId()); + } else { + assertNull(column.getDateFormat()); + } + } + + protected static void assertColumn(ColumnDto column, Long id, Long tableId, Long databaseId, String name, + String internalName, ColumnTypeDto type, Long size, Long d, Boolean nullAllowed, + Long dfid, String description) { + log.trace("assert column: {}", internalName); + assertNotNull(column); + assertEquals(id, column.getId()); + assertEquals(tableId, column.getTableId()); + assertEquals(databaseId, column.getDatabaseId()); + assertNotNull(column.getTable()); + assertEquals(tableId, column.getTable().getId()); + assertEquals(name, column.getName()); + assertEquals(internalName, column.getInternalName()); + assertEquals(type, column.getColumnType()); + assertEquals(size, column.getSize()); + assertEquals(d, column.getD()); + assertEquals(nullAllowed, column.getIsNullAllowed()); + assertEquals(description, column.getDescription()); + if (dfid != null) { + assertNotNull(column.getDateFormat()); + assertEquals(dfid, column.getDateFormat().getId()); + } else { + assertNull(column.getDateFormat()); + } + } + } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/StorageServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/StorageServiceIntegrationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..336a2072c58f36762e74ad154f1737647466c7a7 --- /dev/null +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/StorageServiceIntegrationTest.java @@ -0,0 +1,171 @@ +package at.tuwien.service; + +import at.tuwien.ExportResourceDto; +import at.tuwien.api.database.AccessTypeDto; +import at.tuwien.config.MariaDbConfig; +import at.tuwien.config.MariaDbContainerConfig; +import at.tuwien.config.S3Config; +import at.tuwien.exception.DatabaseMalformedException; +import at.tuwien.exception.StorageNotFoundException; +import at.tuwien.exception.StorageUnavailableException; +import at.tuwien.test.AbstractUnitTest; +import lombok.extern.log4j.Log4j2; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.testcontainers.containers.MariaDBContainer; +import org.testcontainers.containers.MinIOContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.CreateBucketRequest; +import software.amazon.awssdk.services.s3.model.PutObjectRequest; + +import java.io.File; +import java.io.InputStream; +import java.sql.SQLException; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +@Log4j2 +@SpringBootTest +@ExtendWith(SpringExtension.class) +@Testcontainers +public class StorageServiceIntegrationTest extends AbstractUnitTest { + + @Autowired + private StorageService storageService; + + @Autowired + private S3Client s3Client; + + @Autowired + private S3Config s3Config; + + @Container + private static final MinIOContainer minIOContainer = new MinIOContainer("minio/minio:RELEASE.2024-06-06T09-36-42Z"); + + @DynamicPropertySource + static void dynamicProperties(DynamicPropertyRegistry registry) { + registry.add("dbrepo.endpoints.storageService", minIOContainer::getS3URL); + } + + @BeforeEach + public void beforeEach() throws SQLException { + genesis(); + /* s3 */ + if (s3Client.listBuckets().buckets().stream().noneMatch(b -> b.name().equals(s3Config.getS3ImportBucket()))) { + s3Client.createBucket(CreateBucketRequest.builder() + .bucket(s3Config.getS3ImportBucket()) + .build()); + } + if (s3Client.listBuckets().buckets().stream().noneMatch(b -> b.name().equals(s3Config.getS3ExportBucket()))) { + s3Client.createBucket(CreateBucketRequest.builder() + .bucket(s3Config.getS3ExportBucket()) + .build()); + } + } + + @Test + public void getObject_succeeds() throws StorageUnavailableException, StorageNotFoundException { + + /* mock */ + s3Client.putObject(PutObjectRequest.builder() + .key("s3key") + .bucket(s3Config.getS3ImportBucket()) + .build(), RequestBody.fromFile(new File("src/test/resources/csv/weather_aus.csv"))); + + /* test */ + final InputStream response = storageService.getObject(s3Config.getS3ImportBucket(), "s3key"); + assertNotNull(response); + } + + @Test + public void getObject_notFound_fails() { + + /* test */ + assertThrows(StorageNotFoundException.class, () -> { + storageService.getObject(s3Config.getS3ImportBucket(), "i_do_not_exist"); + }); + } + + @Test + public void getObject_bucket_fails() { + + /* test */ + assertThrows(StorageUnavailableException.class, () -> { + storageService.getObject("i_do_not_exist", "s3key"); + }); + } + + @Test + public void getBytes_succeeds() throws StorageUnavailableException, StorageNotFoundException { + + /* mock */ + s3Client.putObject(PutObjectRequest.builder() + .key("s3key") + .bucket(s3Config.getS3ImportBucket()) + .build(), RequestBody.fromFile(new File("src/test/resources/csv/weather_aus.csv"))); + + /* test */ + final byte[] response = storageService.getBytes(s3Config.getS3ImportBucket(), "s3key"); + assertNotNull(response); + } + + @Test + public void getBytes_simple_succeeds() throws StorageUnavailableException, StorageNotFoundException { + + /* mock */ + s3Client.putObject(PutObjectRequest.builder() + .key("s3key") + .bucket(s3Config.getS3ImportBucket()) + .build(), RequestBody.fromFile(new File("src/test/resources/csv/weather_aus.csv"))); + + /* test */ + final byte[] response = storageService.getBytes("s3key"); + assertNotNull(response); + } + + @Test + public void getBytes_notFound_fails() { + + /* test */ + assertThrows(StorageNotFoundException.class, () -> { + storageService.getBytes(s3Config.getS3ImportBucket(), "i_do_not_exist"); + }); + } + + @Test + public void getResource_succeeds() throws StorageUnavailableException, StorageNotFoundException { + + /* mock */ + s3Client.putObject(PutObjectRequest.builder() + .key("s3key") + .bucket(s3Config.getS3ImportBucket()) + .build(), RequestBody.fromFile(new File("src/test/resources/csv/weather_aus.csv"))); + + /* test */ + final ExportResourceDto response = storageService.getResource(s3Config.getS3ImportBucket(), "s3key"); + assertEquals("s3key", response.getFilename()); + assertNotNull(response.getResource()); + } + + @Test + public void getResource_notFound_fails() { + + /* test */ + assertThrows(StorageNotFoundException.class, () -> { + storageService.getBytes(s3Config.getS3ImportBucket(), "i_do_not_exist"); + }); + } + +} diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SubsetServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SubsetServiceIntegrationTest.java index f041dc0e7c231ffe22952c2e2303c5c1a1b14b35..aa30bc0580ff3b0aba950a1f1ea495b135280782 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SubsetServiceIntegrationTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SubsetServiceIntegrationTest.java @@ -57,13 +57,13 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { @Test public void execute_succeeds() throws QueryStoreInsertException, TableMalformedException, SQLException, QueryNotFoundException, InterruptedException, UserNotFoundException, NotAllowedException, - RemoteUnavailableException { + RemoteUnavailableException, ServiceException, DatabaseNotFoundException { /* pre-condition */ Thread.sleep(1000) /* wait for test container some more */; /* mock */ - when(metadataServiceGateway.getUser(QUERY_1_CREATED_BY)) + when(metadataServiceGateway.getUserById(QUERY_1_CREATED_BY)) .thenReturn(QUERY_1_CREATOR); /* test */ @@ -98,7 +98,7 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { @Test public void execute_oneResult_succeeds() throws QueryStoreInsertException, TableMalformedException, SQLException, QueryNotFoundException, InterruptedException, UserNotFoundException, NotAllowedException, - RemoteUnavailableException { + RemoteUnavailableException, ServiceException, DatabaseNotFoundException { /* pre-condition */ Thread.sleep(1000) /* wait for test container some more */; @@ -106,7 +106,7 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { /* mock */ when(metadataServiceGateway.getIdentifiers(DATABASE_1_ID, QUERY_1_ID)) .thenReturn(List.of(IDENTIFIER_2_DTO)); - when(metadataServiceGateway.getUser(QUERY_1_CREATED_BY)) + when(metadataServiceGateway.getUserById(QUERY_1_CREATED_BY)) .thenReturn(QUERY_1_CREATOR); /* test */ @@ -129,13 +129,13 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { @Test public void execute_oneResultPagination_succeeds() throws QueryStoreInsertException, TableMalformedException, SQLException, QueryNotFoundException, InterruptedException, UserNotFoundException, NotAllowedException, - RemoteUnavailableException { + RemoteUnavailableException, ServiceException, DatabaseNotFoundException { /* pre-condition */ Thread.sleep(1000) /* wait for test container some more */; /* mock */ - when(metadataServiceGateway.getUser(USER_1_ID)) + when(metadataServiceGateway.getUserById(USER_1_ID)) .thenReturn(USER_1_DTO); when(metadataServiceGateway.getIdentifiers(eq(DATABASE_1_ID), anyLong())) .thenReturn(List.of()); @@ -159,7 +159,7 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { @Test public void findAll_succeeds() throws SQLException, QueryNotFoundException, InterruptedException, - NotAllowedException, RemoteUnavailableException { + NotAllowedException, RemoteUnavailableException, ServiceException, DatabaseNotFoundException { /* test */ final List<QueryDto> response = findAll_generic(null); @@ -170,7 +170,7 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { @Test public void findAll_onlyPersisted_succeeds() throws SQLException, QueryNotFoundException, InterruptedException, - NotAllowedException, RemoteUnavailableException { + NotAllowedException, RemoteUnavailableException, ServiceException, DatabaseNotFoundException { /* test */ final List<QueryDto> response = findAll_generic(true); @@ -180,7 +180,7 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { @Test public void findAll_onlyNonPersisted_succeeds() throws SQLException, QueryNotFoundException, InterruptedException, - NotAllowedException, RemoteUnavailableException { + NotAllowedException, RemoteUnavailableException, ServiceException, DatabaseNotFoundException { /* test */ final List<QueryDto> response = findAll_generic(false); @@ -190,14 +190,15 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { @Test public void findById_succeeds() throws SQLException, QueryNotFoundException, InterruptedException, - UserNotFoundException, NotAllowedException, RemoteUnavailableException { + UserNotFoundException, NotAllowedException, RemoteUnavailableException, ServiceException, + DatabaseNotFoundException { /* test */ findById_generic(QUERY_1_ID); } @Test - public void findById_fails() { + public void findById_fails() { /* test */ assertThrows(QueryNotFoundException.class, () -> { @@ -207,10 +208,11 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { @Test public void persist_succeeds() throws SQLException, InterruptedException, QueryStorePersistException, - QueryNotFoundException, UserNotFoundException, NotAllowedException, RemoteUnavailableException { + QueryNotFoundException, UserNotFoundException, NotAllowedException, RemoteUnavailableException, + ServiceException, DatabaseNotFoundException { /* mock */ - when(metadataServiceGateway.getUser(QUERY_2_CREATED_BY)) + when(metadataServiceGateway.getUserById(QUERY_2_CREATED_BY)) .thenReturn(QUERY_2_CREATOR); /* test */ @@ -222,10 +224,11 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { @Test public void persist_unPersist_succeeds() throws SQLException, InterruptedException, QueryStorePersistException, - QueryNotFoundException, UserNotFoundException, NotAllowedException, RemoteUnavailableException { + QueryNotFoundException, UserNotFoundException, NotAllowedException, RemoteUnavailableException, + ServiceException, DatabaseNotFoundException { /* mock */ - when(metadataServiceGateway.getUser(QUERY_1_CREATED_BY)) + when(metadataServiceGateway.getUserById(QUERY_1_CREATED_BY)) .thenReturn(QUERY_1_CREATOR); /* test */ @@ -235,8 +238,9 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { assertFalse(response.getIsPersisted()); } - protected void findById_generic(Long queryId) throws InterruptedException, NotAllowedException, RemoteUnavailableException, - SQLException, UserNotFoundException, QueryNotFoundException { + protected void findById_generic(Long queryId) throws InterruptedException, NotAllowedException, + RemoteUnavailableException, SQLException, UserNotFoundException, QueryNotFoundException, ServiceException, + DatabaseNotFoundException { /* pre-condition */ Thread.sleep(1000) /* wait for test container some more */; @@ -244,7 +248,7 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { /* mock */ when(metadataServiceGateway.getIdentifiers(DATABASE_1_ID, QUERY_1_ID)) .thenReturn(List.of(IDENTIFIER_2_DTO)); - when(metadataServiceGateway.getUser(QUERY_1_CREATED_BY)) + when(metadataServiceGateway.getUserById(QUERY_1_CREATED_BY)) .thenReturn(QUERY_1_CREATOR); MariaDbConfig.insertQueryStore(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO, USER_1_ID); @@ -255,7 +259,8 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { } protected List<QueryDto> findAll_generic(Boolean filterPersisted) throws InterruptedException, SQLException, - QueryNotFoundException, NotAllowedException, RemoteUnavailableException { + QueryNotFoundException, NotAllowedException, RemoteUnavailableException, ServiceException, + DatabaseNotFoundException { /* pre-condition */ Thread.sleep(1000) /* wait for test container some more */; @@ -263,15 +268,16 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { /* mock */ MariaDbConfig.insertQueryStore(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO, USER_1_ID); MariaDbConfig.insertQueryStore(DATABASE_1_PRIVILEGED_DTO, QUERY_2_DTO, USER_1_ID); - when(metadataServiceGateway.getIdentifiers(DATABASE_1_ID)) + when(metadataServiceGateway.getIdentifiers(DATABASE_1_ID, null)) .thenReturn(List.of(IDENTIFIER_2_DTO, IDENTIFIER_5_DTO)); /* test */ return queryService.findAll(DATABASE_1_PRIVILEGED_DTO, filterPersisted); } - protected void persist_generic(Long queryId, List<IdentifierDto> identifiers, Boolean persist) throws InterruptedException, - NotAllowedException, RemoteUnavailableException, SQLException, QueryStorePersistException { + protected void persist_generic(Long queryId, List<IdentifierDto> identifiers, Boolean persist) + throws InterruptedException, RemoteUnavailableException, SQLException, QueryStorePersistException, + ServiceException, DatabaseNotFoundException { /* pre-condition */ Thread.sleep(1000) /* wait for test container some more */; diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java index 25144d827dabaaf1b88fc7ab4914ae2ccc1b3283..86a0442ef60a4dc80365c48b8567a15ad04f9e85 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java @@ -1,20 +1,29 @@ package at.tuwien.service; -import at.tuwien.api.database.table.TableDto; -import at.tuwien.api.database.table.TupleDeleteDto; -import at.tuwien.api.database.table.TupleDto; -import at.tuwien.api.database.table.TupleUpdateDto; +import at.tuwien.ExportResourceDto; +import at.tuwien.api.database.query.ImportCsvDto; +import at.tuwien.api.database.query.QueryResultDto; +import at.tuwien.api.database.table.*; +import at.tuwien.api.database.table.columns.ColumnCreateDto; import at.tuwien.api.database.table.columns.ColumnDto; +import at.tuwien.api.database.table.columns.ColumnStatisticDto; import at.tuwien.api.database.table.columns.ColumnTypeDto; +import at.tuwien.api.database.table.constraints.ConstraintsCreateDto; import at.tuwien.api.database.table.constraints.ConstraintsDto; +import at.tuwien.api.database.table.constraints.foreign.ForeignKeyCreateDto; +import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto; +import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto; import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto; import at.tuwien.api.database.table.constraints.unique.UniqueDto; +import at.tuwien.api.database.table.internal.TableCreateDto; import at.tuwien.config.MariaDbConfig; import at.tuwien.config.MariaDbContainerConfig; import at.tuwien.exception.*; +import at.tuwien.gateway.DataDatabaseSidecarGateway; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; +import org.apache.commons.io.FileUtils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -22,19 +31,26 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.core.io.InputStreamResource; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.testcontainers.containers.MariaDBContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import java.math.BigInteger; import java.sql.SQLException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.time.Instant; +import java.util.*; -import static org.junit.Assert.assertEquals; +import static at.tuwien.service.SchemaServiceIntegrationTest.assertColumn; +import static at.tuwien.service.SchemaServiceIntegrationTest.assertViewColumn; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.when; @Log4j2 @@ -49,6 +65,12 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { @MockBean private MetadataServiceGateway metadataServiceGateway; + @MockBean + private DataDatabaseSidecarGateway dataDatabaseSidecarGateway; + + @MockBean + private StorageService storageService; + @Container private static MariaDBContainer<?> mariaDBContainer = MariaDbContainerConfig.getContainer(); @@ -57,12 +79,14 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { genesis(); /* metadata database */ MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); + MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNALNAME); MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO); } @Test public void updateTuple_succeeds() throws InterruptedException, SQLException, RemoteUnavailableException, - ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException { + ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException, + ServiceException { /* modify row based on primary key */ final TupleUpdateDto request = TupleUpdateDto.builder() .data(new HashMap<>() {{ @@ -96,8 +120,9 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { } @Test - public void updateTuple_modifyPrimaryKey_succeeds() throws InterruptedException, SQLException, RemoteUnavailableException, - ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException { + public void updateTuple_modifyPrimaryKey_succeeds() throws InterruptedException, SQLException, + RemoteUnavailableException, ContainerNotFoundException, TableNotFoundException, TableMalformedException, + QueryMalformedException, ServiceException { /* modify row primary key based on primary key */ final TupleUpdateDto request = TupleUpdateDto.builder() .data(new HashMap<>() {{ @@ -132,8 +157,9 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { } @Test - public void updateTuple_missingPrimaryKey_succeeds() throws InterruptedException, SQLException, RemoteUnavailableException, - ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException { + public void updateTuple_missingPrimaryKey_succeeds() throws InterruptedException, SQLException, + RemoteUnavailableException, ContainerNotFoundException, TableNotFoundException, TableMalformedException, + QueryMalformedException, ServiceException { /* modify row based on non-primary key column */ final TupleUpdateDto request = TupleUpdateDto.builder() .data(new HashMap<>() {{ @@ -168,7 +194,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { @Test public void updateTuple_notInOrder_succeeds() throws InterruptedException, SQLException, RemoteUnavailableException, - ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException { + ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException, + ServiceException { /* modify row based on non-primary key column */ final TupleUpdateDto request = TupleUpdateDto.builder() .data(new HashMap<>() {{ @@ -203,7 +230,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { @Test public void createTuple_succeeds() throws InterruptedException, SQLException, RemoteUnavailableException, - ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException { + ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException, + StorageUnavailableException, StorageNotFoundException, ServiceException { /* add row with primary key */ final TupleDto request = TupleDto.builder() .data(new HashMap<>() {{ @@ -236,7 +264,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { @Test public void createTuple_notInOrder_succeeds() throws InterruptedException, SQLException, RemoteUnavailableException, - ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException { + ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException, + StorageUnavailableException, StorageNotFoundException, ServiceException { /* add row with primary key */ final TupleDto request = TupleDto.builder() .data(new HashMap<>() {{ @@ -269,7 +298,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { @Test public void deleteTuple_succeeds() throws InterruptedException, SQLException, RemoteUnavailableException, - ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException { + ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException, + ServiceException { /* delete row based on primary key */ final TupleDeleteDto request = TupleDeleteDto.builder() .keys(new HashMap<>() {{ @@ -293,8 +323,9 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { } @Test - public void deleteTuple_withoutPrimaryKey_succeeds() throws InterruptedException, SQLException, RemoteUnavailableException, - ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException { + public void deleteTuple_withoutPrimaryKey_succeeds() throws InterruptedException, SQLException, + RemoteUnavailableException, ContainerNotFoundException, TableNotFoundException, TableMalformedException, + QueryMalformedException, ServiceException { /* remove row based on non-primary key */ final TupleDeleteDto request = TupleDeleteDto.builder() .keys(new HashMap<>() {{ @@ -324,56 +355,392 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { /* test */ final List<TableDto> response = tableService.getSchemas(DATABASE_1_PRIVILEGED_DTO); + assertEquals(3, response.size()); final TableDto table0 = response.get(0); - Assertions.assertEquals("not_in_metadata_db", table0.getInternalName()); - Assertions.assertEquals("not_in_metadata_db", table0.getName()); + Assertions.assertEquals("complex_foreign_keys", table0.getInternalName()); + Assertions.assertEquals("complex_foreign_keys", table0.getName()); Assertions.assertEquals(DATABASE_1_ID, table0.getTdbid()); assertTrue(table0.getIsVersioned()); Assertions.assertEquals(DATABASE_1_PUBLIC, table0.getIsPublic()); - final List<ColumnDto> columns = table0.getColumns(); - assertNotNull(columns); - Assertions.assertEquals(5, columns.size()); - final ColumnDto column0 = columns.get(0); - Assertions.assertEquals("id", column0.getName()); - Assertions.assertEquals("id", column0.getInternalName()); - Assertions.assertEquals(ColumnTypeDto.BIGINT, column0.getColumnType()); - assertFalse(column0.getIsNullAllowed()); - final ColumnDto column1 = columns.get(1); - Assertions.assertEquals("given_name", column1.getName()); - Assertions.assertEquals("given_name", column1.getInternalName()); - Assertions.assertEquals(ColumnTypeDto.VARCHAR, column1.getColumnType()); - Assertions.assertEquals(255, column1.getSize()); - assertFalse(column1.getIsNullAllowed()); - final ColumnDto column2 = columns.get(2); - Assertions.assertEquals("middle_name", column2.getName()); - Assertions.assertEquals("middle_name", column2.getInternalName()); - Assertions.assertEquals(ColumnTypeDto.VARCHAR, column2.getColumnType()); - Assertions.assertEquals(255, column2.getSize()); - assertTrue(column2.getIsNullAllowed()); - final ColumnDto column3 = columns.get(3); - Assertions.assertEquals("family_name", column3.getName()); - Assertions.assertEquals("family_name", column3.getInternalName()); - Assertions.assertEquals(ColumnTypeDto.VARCHAR, column3.getColumnType()); - Assertions.assertEquals(255, column3.getSize()); - assertFalse(column3.getIsNullAllowed()); - final ColumnDto column4 = columns.get(4); - Assertions.assertEquals("age", column4.getName()); - Assertions.assertEquals("age", column4.getInternalName()); - Assertions.assertEquals(ColumnTypeDto.INT, column4.getColumnType()); - assertFalse(column4.getIsNullAllowed()); - final ConstraintsDto constraints = table0.getConstraints(); - assertNotNull(constraints); - final Set<PrimaryKeyDto> primaryKey = constraints.getPrimaryKey(); - Assertions.assertEquals(1, primaryKey.size()); - final Set<String> checks = constraints.getChecks(); - Assertions.assertEquals(1, checks.size()); - Assertions.assertEquals(Set.of("`age` > 0 and `age` < 120"), checks); - final List<UniqueDto> uniques = constraints.getUniques(); - Assertions.assertEquals(1, uniques.size()); - Assertions.assertEquals(2, uniques.get(0).getColumns().size()); - Assertions.assertEquals("not_in_metadata_db", uniques.get(0).getTable().getInternalName()); - Assertions.assertEquals("given_name", uniques.get(0).getColumns().get(0).getInternalName()); - Assertions.assertEquals("family_name", uniques.get(0).getColumns().get(1).getInternalName()); + final List<ColumnDto> columns0 = table0.getColumns(); + assertNotNull(columns0); + Assertions.assertEquals(3, columns0.size()); + assertColumn(columns0.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null, null); + assertColumn(columns0.get(1), null, null, DATABASE_1_ID, "weather_id", "weather_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null, null); + assertColumn(columns0.get(2), null, null, DATABASE_1_ID, "other_id", "other_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null, null); + final ConstraintsDto constraints0 = table0.getConstraints(); + assertNotNull(constraints0); + assertEquals(1, constraints0.getPrimaryKey().size()); + final PrimaryKeyDto pk0 = new LinkedList<>(constraints0.getPrimaryKey()).get(0); + assertNull(pk0.getId()); + assertNull(pk0.getColumn().getId()); + assertEquals("id", pk0.getColumn().getName()); + assertEquals("id", pk0.getColumn().getInternalName()); + assertEquals(1, constraints0.getForeignKeys().size()); + final ForeignKeyDto fk0 = constraints0.getForeignKeys().get(0); + assertNotNull(fk0.getName()); + assertNull(fk0.getTable().getId()); + assertEquals("complex_foreign_keys", fk0.getTable().getName()); + assertEquals("complex_foreign_keys", fk0.getTable().getInternalName()); + assertNull(fk0.getReferencedTable().getId()); + assertEquals("complex_primary_key", fk0.getReferencedTable().getName()); + assertEquals("complex_primary_key", fk0.getReferencedTable().getInternalName()); + assertEquals(2, fk0.getReferences().size()); + final ForeignKeyReferenceDto fk0r0 = fk0.getReferences().get(0); + assertEquals("weather_id", fk0r0.getColumn().getName()); + assertEquals("weather_id", fk0r0.getColumn().getInternalName()); + assertNotNull(fk0r0.getColumn().getName()); + assertNotNull(fk0r0.getForeignKey()); + assertEquals("id", fk0r0.getReferencedColumn().getName()); + assertEquals("id", fk0r0.getReferencedColumn().getInternalName()); + final ForeignKeyReferenceDto fk0r1 = fk0.getReferences().get(1); + assertEquals("other_id", fk0r1.getColumn().getName()); + assertEquals("other_id", fk0r1.getColumn().getInternalName()); + assertNotNull(fk0r1.getColumn().getName()); + assertNotNull(fk0r1.getForeignKey()); + assertEquals("other_id", fk0r1.getReferencedColumn().getName()); + assertEquals("other_id", fk0r1.getReferencedColumn().getInternalName()); + assertEquals(0, constraints0.getChecks().size()); + assertEquals(0, constraints0.getUniques().size()); + /* table 1 */ + final TableDto table1 = response.get(1); + Assertions.assertEquals("complex_primary_key", table1.getInternalName()); + Assertions.assertEquals("complex_primary_key", table1.getName()); + Assertions.assertEquals(DATABASE_1_ID, table1.getTdbid()); + assertTrue(table1.getIsVersioned()); + Assertions.assertEquals(DATABASE_1_PUBLIC, table1.getIsPublic()); + final List<ColumnDto> columns1 = table1.getColumns(); + assertNotNull(columns1); + Assertions.assertEquals(2, columns1.size()); + assertColumn(columns1.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null, null); + assertColumn(columns1.get(1), null, null, DATABASE_1_ID, "other_id", "other_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null, null); + final ConstraintsDto constraints1 = table1.getConstraints(); + assertNotNull(constraints1); + assertEquals(2, constraints1.getPrimaryKey().size()); + final PrimaryKeyDto pk10 = new LinkedList<>(constraints1.getPrimaryKey()).get(0); + assertNull(pk10.getId()); + assertNull(pk10.getColumn().getId()); + assertEquals("id", pk10.getColumn().getName()); + assertEquals("id", pk10.getColumn().getInternalName()); + final PrimaryKeyDto pk11 = new LinkedList<>(constraints1.getPrimaryKey()).get(1); + assertNull(pk11.getId()); + assertNull(pk11.getColumn().getId()); + assertEquals("other_id", pk11.getColumn().getName()); + assertEquals("other_id", pk11.getColumn().getInternalName()); + assertEquals(0, constraints1.getForeignKeys().size()); + assertEquals(0, constraints1.getChecks().size()); + assertEquals(0, constraints1.getUniques().size()); + /* table 2 */ + final TableDto table2 = response.get(2); + Assertions.assertEquals("not_in_metadata_db", table2.getInternalName()); + Assertions.assertEquals("not_in_metadata_db", table2.getName()); + Assertions.assertEquals(DATABASE_1_ID, table2.getTdbid()); + assertTrue(table2.getIsVersioned()); + Assertions.assertEquals(DATABASE_1_PUBLIC, table2.getIsPublic()); + final List<ColumnDto> columns2 = table2.getColumns(); + assertNotNull(columns2); + Assertions.assertEquals(5, columns2.size()); + assertColumn(columns2.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null, null); + assertColumn(columns2.get(1), null, null, DATABASE_1_ID, "given_name", "given_name", ColumnTypeDto.VARCHAR, 255L, null, false, null, null); + assertColumn(columns2.get(2), null, null, DATABASE_1_ID, "middle_name", "middle_name", ColumnTypeDto.VARCHAR, 255L, null, true, null, null); + assertColumn(columns2.get(3), null, null, DATABASE_1_ID, "family_name", "family_name", ColumnTypeDto.VARCHAR, 255L, null, false, null, null); + assertColumn(columns2.get(4), null, null, DATABASE_1_ID, "age", "age", ColumnTypeDto.INT, 10L, 0L, false, null, null); + final ConstraintsDto constraints2 = table2.getConstraints(); + assertNotNull(constraints2); + final Set<PrimaryKeyDto> primaryKey2 = constraints2.getPrimaryKey(); + Assertions.assertEquals(1, primaryKey2.size()); + final Set<String> checks2 = constraints2.getChecks(); + Assertions.assertEquals(1, checks2.size()); + Assertions.assertEquals(Set.of("`age` > 0 and `age` < 120"), checks2); + final List<UniqueDto> uniques2 = constraints2.getUniques(); + Assertions.assertEquals(1, uniques2.size()); + Assertions.assertEquals(2, uniques2.get(0).getColumns().size()); + Assertions.assertEquals("not_in_metadata_db", uniques2.get(0).getTable().getInternalName()); + Assertions.assertEquals("given_name", uniques2.get(0).getColumns().get(0).getInternalName()); + Assertions.assertEquals("family_name", uniques2.get(0).getColumns().get(1).getInternalName()); + } + + @Test + public void create_succeeds() throws TableNotFoundException, TableMalformedException, SQLException, + QueryMalformedException, TableExistsException { + + /* test */ + final TableDto response = tableService.createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_CREATE_INTERNAL_DTO); + assertEquals(TABLE_4_NAME, response.getName()); + assertEquals(TABLE_4_INTERNALNAME, response.getInternalName()); + assertEquals(TABLE_4_COLUMNS.size(), response.getColumns().size()); + } + + @Test + public void getStatistics_succeeds() throws TableMalformedException, SQLException, QueryMalformedException { + + /* test */ + final TableStatisticDto response = tableService.getStatistics(TABLE_1_PRIVILEGED_DTO); + assertEquals(TABLE_1_COLUMNS.size(), response.getColumns().size()); + assertEquals(3L, response.getRows()); + assertEquals(Set.of("id", "date", "location", "mintemp", "rainfall"), response.getColumns().keySet()); + final ColumnStatisticDto column0 = response.getColumns().get("id"); + assertEquals(BigDecimal.valueOf(1L), column0.getMin()); + assertEquals(BigDecimal.valueOf(3L), column0.getMax()); + assertNotNull(column0.getMean()); + assertNotNull(column0.getMedian()); + assertNotNull(column0.getStdDev()); + final ColumnStatisticDto column1 = response.getColumns().get("date"); + assertNull(column1.getMin()); + assertNull(column1.getMax()); + assertNull(column1.getMean()); + assertNull(column1.getMedian()); + assertNull(column1.getStdDev()); + final ColumnStatisticDto column2 = response.getColumns().get("location"); + assertNull(column2.getMin()); + assertNull(column2.getMax()); + assertNull(column2.getMean()); + assertNull(column2.getMedian()); + assertNull(column2.getStdDev()); + final ColumnStatisticDto column3 = response.getColumns().get("mintemp"); + assertEquals(BigDecimal.valueOf(7.4), column3.getMin()); + assertEquals(BigDecimal.valueOf(13.4), column3.getMax()); + assertNotNull(column3.getMean()); + assertNotNull(column3.getMedian()); + assertNotNull(column3.getStdDev()); + final ColumnStatisticDto column4 = response.getColumns().get("rainfall"); + assertEquals(BigDecimal.valueOf(0L), column4.getMin()); + assertEquals(BigDecimal.valueOf(0.6), column4.getMax()); + assertNotNull(column4.getMean()); + assertNotNull(column4.getMedian()); + assertNotNull(column4.getStdDev()); + } + + @Test + public void create_malformed_fails() { + final at.tuwien.api.database.table.internal.TableCreateDto request = TableCreateDto.builder() + .needSequence(false) + .name("missing_foreign_key") + .columns(List.of(ColumnCreateDto.builder() + .name("id") + .type(ColumnTypeDto.BIGINT) + .nullAllowed(false) + .build())) + .constraints(ConstraintsCreateDto.builder() + .foreignKeys(List.of(ForeignKeyCreateDto.builder() + .columns(List.of("i_do_not_exist")) + .referencedTable("neither_do_i") + .referencedColumns(List.of("behold")) + .build())) + .build()) + .build(); + + /* test */ + assertThrows(TableMalformedException.class, () -> { + tableService.createTable(DATABASE_1_PRIVILEGED_DTO, request); + }); + } + + @Test + public void create_needSequence_succeeds() throws TableNotFoundException, TableMalformedException, SQLException, + QueryMalformedException, TableExistsException { + + /* mock */ + MariaDbConfig.dropTable(DATABASE_1_PRIVILEGED_DTO, TABLE_1_INTERNALNAME); + + /* test */ + final TableDto response = tableService.createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_1_CREATE_INTERNAL_DTO); + assertEquals(TABLE_1_NAME, response.getName()); + assertEquals(TABLE_1_INTERNALNAME, response.getInternalName()); + assertEquals(TABLE_1_COLUMNS.size(), response.getColumns().size()); + } + + @Test + public void delete_succeeds() throws SQLException, QueryMalformedException { + + /* test */ + tableService.delete(TABLE_1_PRIVILEGED_DTO); + } + + @Test + public void delete_notFound_fails() throws SQLException { + + /* mock */ + MariaDbConfig.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNALNAME); + + /* test */ + assertThrows(QueryMalformedException.class, () -> { + tableService.delete(TABLE_5_PRIVILEGED_DTO); + }); + } + + @Test + public void getCount_succeeds() throws SQLException, QueryMalformedException { + + /* test */ + final Long response = tableService.getCount(TABLE_1_PRIVILEGED_DTO, null); + assertEquals(3, response); + } + + @Test + public void getCount_timestamp_succeeds() throws SQLException, QueryMalformedException { + + /* test */ + final Long response = tableService.getCount(TABLE_1_PRIVILEGED_DTO, Instant.ofEpochSecond(0)); + assertEquals(0, response); + } + + @Test + public void getCount_notFound_fails() throws SQLException { + + /* mock */ + MariaDbConfig.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNALNAME); + + /* test */ + assertThrows(QueryMalformedException.class, () -> { + tableService.getCount(TABLE_5_PRIVILEGED_DTO, null); + }); + } + + @Test + public void getData_succeeds() throws SQLException, TableMalformedException { + + /* test */ + final QueryResultDto response = tableService.getData(TABLE_1_PRIVILEGED_DTO, null, 0L, 10L); + assertEquals(TABLE_1_ID, response.getId()); + final List<Map<String, Integer>> headers = response.getHeaders(); + assertEquals(5, headers.size()); + assertEquals(0, headers.get(0).get("id")); + assertEquals(1, headers.get(1).get("date")); + assertEquals(2, headers.get(2).get("location")); + assertEquals(3, headers.get(3).get("mintemp")); + assertEquals(4, headers.get(4).get("rainfall")); + final List<Map<String, Object>> result = response.getResult(); + assertEquals(Instant.ofEpochSecond(1228089600), result.get(0).get("date")); + assertEquals(0.6, result.get(0).get("rainfall")); + assertEquals("Albury", result.get(0).get("location")); + assertEquals(BigInteger.valueOf(1L), result.get(0).get("id")); + assertEquals(13.4, result.get(0).get("mintemp")); + assertEquals(Instant.ofEpochSecond(1228176000), result.get(1).get("date")); + assertEquals(0.0, result.get(1).get("rainfall")); + assertEquals("Albury", result.get(1).get("location")); + assertEquals(BigInteger.valueOf(2L), result.get(1).get("id")); + assertEquals(7.4, result.get(1).get("mintemp")); + assertEquals(Instant.ofEpochSecond(1228262400), result.get(2).get("date")); + assertEquals(0.0, result.get(2).get("rainfall")); + assertEquals("Albury", result.get(2).get("location")); + assertEquals(BigInteger.valueOf(3L), result.get(2).get("id")); + assertEquals(12.9, result.get(2).get("mintemp")); + } + + @Test + public void getData_notFound_fails() throws SQLException { + + /* mock */ + MariaDbConfig.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNALNAME); + + /* test */ + assertThrows(TableMalformedException.class, () -> { + tableService.getData(TABLE_5_PRIVILEGED_DTO, null, 0L, 10L); + }); + } + + @Test + public void history_succeeds() throws SQLException, TableNotFoundException { + + /* test */ + final List<TableHistoryDto> response = tableService.history(TABLE_1_PRIVILEGED_DTO, 1000L); + assertEquals(1, response.size()); + final TableHistoryDto history0 = response.get(0); + assertNotNull(history0.getTimestamp()); + assertEquals("INSERT", history0.getEvent()); + assertEquals(3, history0.getTotal()); + } + + @Test + public void history_notFound_fails() throws SQLException { + + /* mock */ + MariaDbConfig.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNALNAME); + + /* test */ + assertThrows(TableNotFoundException.class, () -> { + tableService.history(TABLE_5_PRIVILEGED_DTO, null); + }); + } + + @Test + public void importDataset_withSeparatorAndQuoteAndNullElement_succeeds() throws SidecarImportException, ServiceException, SQLException, + QueryMalformedException, RemoteUnavailableException, StorageNotFoundException, IOException { + final ImportCsvDto request = ImportCsvDto.builder() + .location("weather_aus.csv") + .separator(';') + .quote('"') + .nullElement("NA") + .build(); + + /* mock */ + final File source = new File("src/test/resources/csv/weather_aus.csv"); + final File target = new File("/tmp/weather_aus.csv"); + log.trace("copy dataset from {} to {}", source.toPath().toAbsolutePath(), target.toPath().toAbsolutePath()); + FileUtils.copyFile(source, target); + doNothing() + .when(dataDatabaseSidecarGateway) + .importFile(anyString(), anyInt(), eq("weather_aus.csv")); + + /* test */ + tableService.importDataset(TABLE_1_PRIVILEGED_DTO, request); + } + + @Test + public void importDataset_malformedData_fails() throws ServiceException, RemoteUnavailableException, StorageNotFoundException, + IOException { + final ImportCsvDto request = ImportCsvDto.builder() + .location("weather_aus.csv") + .separator(';') + .quote('"') + .build(); + + /* mock */ + final File source = new File("src/test/resources/csv/weather_aus.csv"); + final File target = new File("/tmp/weather_aus.csv"); + log.trace("copy dataset from {} to {}", source.toPath().toAbsolutePath(), target.toPath().toAbsolutePath()); + FileUtils.copyFile(source, target); + doNothing() + .when(dataDatabaseSidecarGateway) + .importFile(anyString(), anyInt(), eq("weather_aus.csv")); + + /* test */ + assertThrows(QueryMalformedException.class, () -> { + tableService.importDataset(TABLE_1_PRIVILEGED_DTO, request); + }); + } + + @Test + public void exportDataset_succeeds() throws ServiceException, SQLException, + QueryMalformedException, RemoteUnavailableException, StorageNotFoundException, StorageUnavailableException, + SidecarExportException { + final ExportResourceDto mock = ExportResourceDto.builder() + .filename("weather_aus.csv") + .resource(new InputStreamResource(InputStream.nullInputStream())) + .build(); + + /* mock */ + doNothing() + .when(dataDatabaseSidecarGateway) + .exportFile(anyString(), anyInt(), eq("weather_aus.csv")); + when(storageService.getResource("weather_aus.csv")) + .thenReturn(mock); + + /* test */ + final ExportResourceDto response = tableService.exportDataset(TABLE_1_PRIVILEGED_DTO, null); + } + + @Test + public void exportDataset_malformedData_fails() throws SQLException { + + /* mock */ + MariaDbConfig.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNALNAME); + + /* test */ + assertThrows(QueryMalformedException.class, () -> { + tableService.exportDataset(TABLE_5_PRIVILEGED_DTO, null); + }); } } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java index ba846f37cc1a4dd8de4c2e1927a9c1f2493f29f3..eea4d65320ed1002ebcff6c6120e3c372a2e0027 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java @@ -24,6 +24,7 @@ import java.time.Instant; import java.util.List; import java.util.Map; +import static at.tuwien.service.SchemaServiceIntegrationTest.assertViewColumn; import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -58,7 +59,21 @@ public class ViewServiceIntegrationTest extends AbstractUnitTest { public void create_succeeds() throws SQLException, ViewMalformedException { /* test */ - viewService.create(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO); + final ViewDto response = viewService.create(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO); + assertEquals(VIEW_1_NAME, response.getName()); + assertEquals(VIEW_1_INTERNAL_NAME, response.getInternalName()); + assertEquals(VIEW_1_QUERY, response.getQuery()); + assertNotNull(response.getQueryHash()); + assertEquals(DATABASE_1_PUBLIC, response.getIsPublic()); + final List<ViewColumnDto> columns = response.getColumns(); + assertEquals(VIEW_1_COLUMNS.size(), columns.size()); + ViewColumnDto ref = VIEW_1_COLUMNS_DTO.get(0); + SchemaServiceIntegrationTest.assertViewColumn(columns.get(0), null, ref.getDatabaseId(), ref.getName(), ref.getInternalName(), ref.getColumnType(), ref.getSize(), ref.getD(), ref.getIsNullAllowed(), ref.getDateFormat(), ref.getDescription()); + ref = VIEW_1_COLUMNS_DTO.get(1); + SchemaServiceIntegrationTest.assertViewColumn(columns.get(1), null, ref.getDatabaseId(), ref.getName(), ref.getInternalName(), ref.getColumnType(), ref.getSize(), ref.getD(), ref.getIsNullAllowed(), ref.getDateFormat(), ref.getDescription()); + ref = VIEW_1_COLUMNS_DTO.get(2); + SchemaServiceIntegrationTest.assertViewColumn(columns.get(2), null, ref.getDatabaseId(), ref.getName(), ref.getInternalName(), ref.getColumnType(), ref.getSize(), ref.getD(), ref.getIsNullAllowed(), ref.getDateFormat(), ref.getDescription()); + } @Test diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/MariaDbUtilTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/MariaDbUtilTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6ed73e8a01563a6b0b7e950afe5f9bf7c86cfbcf --- /dev/null +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/utils/MariaDbUtilTest.java @@ -0,0 +1,42 @@ +package at.tuwien.utils; + +import at.tuwien.api.database.table.columns.ColumnTypeDto; +import org.junit.jupiter.api.Test; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.core.MessageProperties; + +import java.nio.charset.StandardCharsets; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class MariaDbUtilTest { + + @Test + public void needValueQuotes_succeeds() { + assertTrue(MariaDbUtil.needValueQuotes(ColumnTypeDto.TINYBLOB)); + assertTrue(MariaDbUtil.needValueQuotes(ColumnTypeDto.MEDIUMBLOB)); + assertTrue(MariaDbUtil.needValueQuotes(ColumnTypeDto.LONGBLOB)); + assertTrue(MariaDbUtil.needValueQuotes(ColumnTypeDto.BLOB)); + assertTrue(MariaDbUtil.needValueQuotes(ColumnTypeDto.CHAR)); + assertTrue(MariaDbUtil.needValueQuotes(ColumnTypeDto.VARCHAR)); + assertTrue(MariaDbUtil.needValueQuotes(ColumnTypeDto.ENUM)); + assertTrue(MariaDbUtil.needValueQuotes(ColumnTypeDto.SET)); + assertTrue(MariaDbUtil.needValueQuotes(ColumnTypeDto.TINYTEXT)); + assertTrue(MariaDbUtil.needValueQuotes(ColumnTypeDto.MEDIUMTEXT)); + assertTrue(MariaDbUtil.needValueQuotes(ColumnTypeDto.LONGTEXT)); + assertTrue(MariaDbUtil.needValueQuotes(ColumnTypeDto.TEXT)); + assertTrue(MariaDbUtil.needValueQuotes(ColumnTypeDto.BINARY)); + assertTrue(MariaDbUtil.needValueQuotes(ColumnTypeDto.VARBINARY)); + assertTrue(MariaDbUtil.needValueQuotes(ColumnTypeDto.DATETIME)); + assertTrue(MariaDbUtil.needValueQuotes(ColumnTypeDto.DATE)); + assertTrue(MariaDbUtil.needValueQuotes(ColumnTypeDto.TIMESTAMP)); + assertFalse(MariaDbUtil.needValueQuotes(ColumnTypeDto.INT)); + assertFalse(MariaDbUtil.needValueQuotes(ColumnTypeDto.TINYINT)); + assertFalse(MariaDbUtil.needValueQuotes(ColumnTypeDto.MEDIUMINT)); + assertFalse(MariaDbUtil.needValueQuotes(ColumnTypeDto.DOUBLE)); + assertFalse(MariaDbUtil.needValueQuotes(ColumnTypeDto.DECIMAL)); + assertFalse(MariaDbUtil.needValueQuotes(ColumnTypeDto.BOOL)); + } +} diff --git a/dbrepo-data-service/rest-service/src/test/resources/application.properties b/dbrepo-data-service/rest-service/src/test/resources/application.properties index ed58329c18d9c4a5bc8f60404fa2c6c99836ddf6..07eb7f642bd62128618f3d0b86d04c0ba4743644 100644 --- a/dbrepo-data-service/rest-service/src/test/resources/application.properties +++ b/dbrepo-data-service/rest-service/src/test/resources/application.properties @@ -25,4 +25,8 @@ logging.level.at.tuwien.=trace spring.rabbitmq.host=localhost spring.rabbitmq.virtual-host=dbrepo spring.rabbitmq.username=guest -spring.rabbitmq.password=guest \ No newline at end of file +spring.rabbitmq.password=guest + +# s3 +dbrepo.s3.accessKeyId=minioadmin +dbrepo.s3.secretAccessKey=minioadmin \ No newline at end of file diff --git a/dbrepo-data-service/rest-service/src/test/resources/init/weather.sql b/dbrepo-data-service/rest-service/src/test/resources/init/weather.sql index 2eef31b4752b03ed0b1ccad1cc2d93a56e44f1ae..052f23adf8f5772a996d430877c8785d24651305 100644 --- a/dbrepo-data-service/rest-service/src/test/resources/init/weather.sql +++ b/dbrepo-data-service/rest-service/src/test/resources/init/weather.sql @@ -13,12 +13,27 @@ CREATE TABLE weather_aus ( id BIGINT NOT NULL PRIMARY KEY, `date` DATE NOT NULL, - location VARCHAR(255) NULL, + location VARCHAR(255) NULL COMMENT 'Closest city', mintemp DOUBLE PRECISION NULL, rainfall DOUBLE PRECISION NULL, - FOREIGN KEY (location) REFERENCES weather_location (location), + FOREIGN KEY (location) REFERENCES weather_location (location) ON DELETE SET NULL, UNIQUE (`date`), CHECK (`mintemp` > 0) +) WITH SYSTEM VERSIONING COMMENT 'Weather in Australia'; + +CREATE TABLE complex_primary_key +( + id BIGINT NOT NULL, + other_id BIGINT NOT NULL, + PRIMARY KEY (id, other_id) +) WITH SYSTEM VERSIONING; + +CREATE TABLE complex_foreign_keys +( + id BIGINT NOT NULL PRIMARY KEY, + weather_id BIGINT NOT NULL, + other_id BIGINT NOT NULL, + FOREIGN KEY (weather_id, other_id) REFERENCES complex_primary_key (id, `other_id`) ) WITH SYSTEM VERSIONING; CREATE TABLE sensor diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java b/dbrepo-data-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java index 6cd55e9ef768e47f3d3463001ba99b5378f5351e..805035d42171ba59b997639d26f8104129628a74 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java @@ -3,6 +3,7 @@ package at.tuwien.auth; import at.tuwien.api.keycloak.TokenDto; import at.tuwien.api.user.UserDetailsDto; import at.tuwien.config.GatewayConfig; +import at.tuwien.exception.RemoteUnavailableException; import at.tuwien.exception.ServiceConnectionException; import at.tuwien.exception.ServiceException; import at.tuwien.gateway.KeycloakGateway; @@ -53,7 +54,7 @@ public class BasicAuthenticationProvider implements AuthenticationManager { final TokenDto tokenDto = keycloakGateway.obtainUserToken(auth.getName(), auth.getCredentials().toString()); final UserDetails userDetails = authTokenFilter.verifyJwt(tokenDto.getAccessToken()); return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); - } catch (ServletException | ServiceConnectionException | ServiceException e) { + } catch (ServletException | RemoteUnavailableException | ServiceException e) { throw new BadCredentialsException("Failed to authenticate with authentication service", e); } } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/config/GatewayConfig.java b/dbrepo-data-service/services/src/main/java/at/tuwien/config/GatewayConfig.java index 57df3af3a6ad468bdfcef83ef2236f7443f67d68..b04aff18ce5a49d68c01519a97b3550b14bddc6e 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/config/GatewayConfig.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/config/GatewayConfig.java @@ -19,8 +19,8 @@ import java.util.List; @Configuration public class GatewayConfig { - @Value("${dbrepo.endpoints.gatewayService}") - private String gatewayEndpoint; + @Value("${dbrepo.endpoints.metadataService}") + private String metadataEndpoint; @Value("${dbrepo.admin.username}") private String adminUsername; @@ -31,8 +31,8 @@ public class GatewayConfig { @Bean public RestTemplate restTemplate() { final RestTemplate restTemplate = new RestTemplate(); - restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(gatewayEndpoint)); - log.debug("add basic authentication for internal gateway: username={}, password=(hidden)", adminUsername); + restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(metadataEndpoint)); + log.debug("add basic authentication for metadata service: username={}, password=(hidden)", adminUsername); restTemplate.getInterceptors() .addAll(List.of(new BasicAuthenticationInterceptor(adminUsername, adminPassword), clientHttpRequestInterceptor())); diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/AnalyseServiceGateway.java b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/AnalyseServiceGateway.java deleted file mode 100644 index b10f386cd3d9267596620dbde0244311062483e4..0000000000000000000000000000000000000000 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/AnalyseServiceGateway.java +++ /dev/null @@ -1,10 +0,0 @@ -package at.tuwien.gateway; - -import at.tuwien.api.database.table.TableStatisticDto; -import at.tuwien.exception.NotAllowedException; -import at.tuwien.exception.RemoteUnavailableException; -import at.tuwien.exception.TableNotFoundException; - -public interface AnalyseServiceGateway { - TableStatisticDto analyseTable(Long databaseId, Long tableId) throws RemoteUnavailableException, NotAllowedException, TableNotFoundException; -} diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/DataDatabaseSidecarGateway.java b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/DataDatabaseSidecarGateway.java index 417fe77d7afecece0b48f2382566859e4daf9380..ecac6865f6e4704b915e10016afe8a5b25afaa63 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/DataDatabaseSidecarGateway.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/DataDatabaseSidecarGateway.java @@ -1,13 +1,11 @@ package at.tuwien.gateway; -import at.tuwien.exception.SidecarExportException; -import at.tuwien.exception.SidecarImportException; -import at.tuwien.exception.StorageNotFoundException; +import at.tuwien.exception.*; public interface DataDatabaseSidecarGateway { - void importFile(String hostname, Integer port, String filename) throws SidecarImportException, - StorageNotFoundException; + void importFile(String hostname, Integer port, String filename) throws StorageNotFoundException, + RemoteUnavailableException, ServiceException; void exportFile(String hostname, Integer port, String filename) throws StorageNotFoundException, - SidecarExportException; + ServiceException, RemoteUnavailableException; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java index a05a75a6ff890feba33e1d14f2bd1a9407845861..1058119a25c8b5de2affbc05b72cd9417c7887a7 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java @@ -1,11 +1,14 @@ package at.tuwien.gateway; import at.tuwien.api.keycloak.TokenDto; +import at.tuwien.exception.RemoteUnavailableException; import at.tuwien.exception.ServiceConnectionException; import at.tuwien.exception.ServiceException; +import javax.naming.ServiceUnavailableException; + public interface KeycloakGateway { - TokenDto obtainUserToken(String username, String password) throws ServiceConnectionException, ServiceException; + TokenDto obtainUserToken(String username, String password) throws RemoteUnavailableException, ServiceException; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/MetadataServiceGateway.java b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/MetadataServiceGateway.java index ad1cb756938d60995f4b2cecda4aef6e5850d42e..4c01a40a447954ae666bf7ef9d330b5879b85e59 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/MetadataServiceGateway.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/MetadataServiceGateway.java @@ -10,6 +10,7 @@ import at.tuwien.api.identifier.IdentifierDto; import at.tuwien.api.user.PrivilegedUserDto; import at.tuwien.api.user.UserDto; import at.tuwien.exception.*; +import jakarta.validation.constraints.NotNull; import java.util.List; import java.util.UUID; @@ -21,21 +22,12 @@ public interface MetadataServiceGateway { * * @param containerId The container id * @return The container with privileged connection information, if successful. - * @throws RemoteUnavailableException The remote service is not available and invalid data was returned. - * @throws ContainerNotFoundException The container was not found in the metadata service. + * @throws ContainerNotFoundException The table was not found in the metadata service. + * @throws RemoteUnavailableException The remote service is not available. + * @throws ServiceException The remote service returned invalid data. */ - PrivilegedContainerDto getContainerById(Long containerId) throws RemoteUnavailableException, ContainerNotFoundException; - - /** - * Get all databases from the metadata service. - * - * @return List of databases, if successful. - * @throws RemoteUnavailableException The remote service is not available and invalid data was returned. - */ - List<PrivilegedDatabaseDto> getDatabases() throws RemoteUnavailableException; - - void updateTableStatistics(Long databaseId, Long tableId, TableStatisticDto data) - throws RemoteUnavailableException; + PrivilegedContainerDto getContainerById(Long containerId) throws RemoteUnavailableException, + ContainerNotFoundException, ServiceException; /** * Get a database with given id from the metadata service. @@ -43,9 +35,11 @@ public interface MetadataServiceGateway { * @param id The database id. * @return The database, if successful. * @throws DatabaseNotFoundException The database was not found in the metadata service. - * @throws RemoteUnavailableException The remote service is not available and invalid data was returned. + * @throws RemoteUnavailableException The remote service is not available. + * @throws ServiceException The remote service returned invalid data. */ - PrivilegedDatabaseDto getDatabaseById(Long id) throws DatabaseNotFoundException, RemoteUnavailableException; + PrivilegedDatabaseDto getDatabaseById(Long id) throws DatabaseNotFoundException, RemoteUnavailableException, + ServiceException; /** * Get a database with given internal name from the metadata service. @@ -53,9 +47,11 @@ public interface MetadataServiceGateway { * @param internalName The internal name. * @return The database, if successful. * @throws DatabaseNotFoundException The database was not found in the metadata service. - * @throws RemoteUnavailableException The remote service is not available and invalid data was returned. + * @throws RemoteUnavailableException The remote service is not available. + * @throws ServiceException The remote service returned invalid data. */ - PrivilegedDatabaseDto getDatabaseByInternalName(String internalName) throws DatabaseNotFoundException, RemoteUnavailableException; + PrivilegedDatabaseDto getDatabaseByInternalName(String internalName) throws DatabaseNotFoundException, + RemoteUnavailableException, ServiceException; /** * Get a table with given database id and table id from the metadata service. @@ -64,11 +60,23 @@ public interface MetadataServiceGateway { * @param id The table id. * @return The table, if successful. * @throws TableNotFoundException The table was not found in the metadata service. - * @throws RemoteUnavailableException The remote service is not available and invalid data was returned. + * @throws RemoteUnavailableException The remote service is not available. + * @throws ServiceException The remote service returned invalid data. */ - PrivilegedTableDto getTableById(Long databaseId, Long id) throws TableNotFoundException, RemoteUnavailableException; + PrivilegedTableDto getTableById(Long databaseId, Long id) throws TableNotFoundException, RemoteUnavailableException, + ServiceException; - PrivilegedViewDto getViewById(Long databaseId, Long id) throws RemoteUnavailableException, ViewNotFoundException; + /** + * Get a view with given database id and view id from the metadata service. + * @param databaseId The database id. + * @param id The view id. + * @return The view, if successful. + * @throws ViewNotFoundException The view was not found in the metadata service. + * @throws RemoteUnavailableException The remote service is not available. + * @throws ServiceException The remote service returned invalid data. + */ + PrivilegedViewDto getViewById(Long databaseId, Long id) throws RemoteUnavailableException, ViewNotFoundException, + ServiceException; /** * Get a user with given user id from the metadata service. @@ -77,16 +85,53 @@ public interface MetadataServiceGateway { * @return The user, if successful. * @throws RemoteUnavailableException The remote service is not available and invalid data was returned. * @throws UserNotFoundException The user was not found in the metadata service. + * @throws ServiceException The remote service returned invalid data. */ - PrivilegedUserDto getUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException; + UserDto getUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException, ServiceException; - DatabaseAccessDto getAccess(Long databaseId, UUID userId) throws RemoteUnavailableException, NotAllowedException; + /** + * Get a user with given user id from the metadata service. + * + * @param userId The user id. + * @return The user, if successful. + * @throws RemoteUnavailableException The remote service is not available and invalid data was returned. + * @throws UserNotFoundException The user was not found in the metadata service. + * @throws ServiceException The remote service returned invalid data. + */ + PrivilegedUserDto getPrivilegedUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException, + ServiceException; - List<IdentifierDto> getIdentifiers(Long databaseId, Long subsetId) throws RemoteUnavailableException, - NotAllowedException; + /** + * Get database access for a given user and database id from the metadata service. + * @param databaseId The database id. + * @param userId The user id. + * @return The database access, if successful. + * @throws RemoteUnavailableException The remote service is not available and invalid data was returned. + * @throws NotAllowedException The access to this database is denied for the given user. + * @throws ServiceException The remote service returned invalid data. + */ + DatabaseAccessDto getAccess(Long databaseId, UUID userId) throws RemoteUnavailableException, NotAllowedException, + ServiceException; - List<IdentifierDto> getIdentifiers(Long databaseId) throws RemoteUnavailableException, - NotAllowedException; + /** + * Get a list of identifiers for a given database id and optional subset id. + * @param databaseId The database id. + * @param subsetId The subset id. Optional. + * @return The list of identifiers. + * @throws RemoteUnavailableException The remote service is not available and invalid data was returned. + * @throws DatabaseNotFoundException The database was not found. + * @throws ServiceException The remote service returned invalid data. + */ + List<IdentifierDto> getIdentifiers(@NotNull Long databaseId, Long subsetId) throws ServiceException, + RemoteUnavailableException, DatabaseNotFoundException; - UserDto getUser(UUID userId) throws RemoteUnavailableException, NotAllowedException, UserNotFoundException; + /** + * Update the table statistics in the metadata service. + * @param databaseId The database id. + * @param tableId The table id. + * @throws RemoteUnavailableException The remote service is not available and invalid data was returned. + * @throws TableNotFoundException The table was not found. + * @throws ServiceException The remote service returned invalid data. + */ + void updateTableStatistics(Long databaseId, Long tableId) throws TableNotFoundException, ServiceException, RemoteUnavailableException; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/AnalyseServiceGatewayImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/AnalyseServiceGatewayImpl.java deleted file mode 100644 index ff4f769a089c95cba4d9a4ae4fb7ccb818f9f813..0000000000000000000000000000000000000000 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/AnalyseServiceGatewayImpl.java +++ /dev/null @@ -1,50 +0,0 @@ -package at.tuwien.gateway.impl; - -import at.tuwien.api.database.table.TableStatisticDto; -import at.tuwien.exception.*; -import at.tuwien.gateway.AnalyseServiceGateway; -import lombok.extern.log4j.Log4j2; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpMethod; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Service; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.HttpServerErrorException; -import org.springframework.web.client.ResourceAccessException; -import org.springframework.web.client.RestTemplate; - -@Log4j2 -@Service -public class AnalyseServiceGatewayImpl implements AnalyseServiceGateway { - - private final RestTemplate restTemplate; - - @Autowired - public AnalyseServiceGatewayImpl(RestTemplate restTemplate) { - this.restTemplate = restTemplate; - } - - @Override - public TableStatisticDto analyseTable(Long databaseId, Long tableId) throws RemoteUnavailableException, - NotAllowedException, TableNotFoundException { - final ResponseEntity<TableStatisticDto> response; - final String url = "/api/analyse/database/" + databaseId + "/table/" + tableId + "/statistics"; - log.trace("mapped url: {}", url); - try { - response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(null), TableStatisticDto.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { - log.error("Failed to analyse table with id {}: {}", tableId, e.getMessage()); - throw new RemoteUnavailableException("Failed to analyse table", e); - } catch (HttpClientErrorException.NotFound e) { - log.error("Failed to analyse table with id {}: not found: {}", tableId, e.getMessage()); - throw new TableNotFoundException("Failed to analyse table: not found", e); - } - if (response.getBody() == null) { - log.error("Failed to analyse table: body is null"); - throw new NotAllowedException("Failed to analyse table: body is null"); - } - return response.getBody(); - } - -} diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/DataDatabaseSidecarGatewayImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/DataDatabaseSidecarGatewayImpl.java index 0c1a74dbcf4ba4a702ca70f87d3950cb075b26cb..b3e7c3bd41545e07b344406d00b29e9daecd0aab 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/DataDatabaseSidecarGatewayImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/DataDatabaseSidecarGatewayImpl.java @@ -1,13 +1,12 @@ package at.tuwien.gateway.impl; -import at.tuwien.exception.SidecarExportException; -import at.tuwien.exception.SidecarImportException; -import at.tuwien.exception.StorageNotFoundException; +import at.tuwien.exception.*; import at.tuwien.gateway.DataDatabaseSidecarGateway; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.*; import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestTemplate; @@ -24,38 +23,44 @@ public class DataDatabaseSidecarGatewayImpl implements DataDatabaseSidecarGatewa } @Override - public void importFile(String hostname, Integer port, String filename) throws SidecarImportException, - StorageNotFoundException { + public void importFile(String hostname, Integer port, String filename) throws StorageNotFoundException, + RemoteUnavailableException, ServiceException { final ResponseEntity<Void> response; final String url = "http://" + hostname + ":" + port + "/sidecar/import/" + filename; log.debug("import file into data database sidecar"); try { response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(null), Void.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { - log.error("Failed to import .csv in data-db sidecar: {}", e.getMessage()); - throw new StorageNotFoundException("Failed to import .csv in data-db sidecar: " + e.getMessage(), e); + } catch (ResourceAccessException | HttpServerErrorException e) { + log.error("Failed to import dataset with filename: {}: {}", filename, e.getMessage()); + throw new RemoteUnavailableException("Failed to import dataset: " + e.getMessage(), e); + } catch (HttpClientErrorException.BadRequest e) { + log.error("Failed to import dataset with filename: {}: not found: {}", filename, e.getMessage()); + throw new StorageNotFoundException("Failed to import dataset: not found: " + e.getMessage(), e); } if (!response.getStatusCode().equals(HttpStatus.ACCEPTED)) { - log.error("Failed to import .csv in data-db sidecar"); - throw new SidecarImportException("Failed to import .csv in data-db sidecar"); + log.error("Failed to import dataset with filename: {}: service responded unsuccessful: {}", filename, response.getStatusCode()); + throw new ServiceException("Failed to import dataset: service responded unsuccessful: " + response.getStatusCode()); } } @Override public void exportFile(String hostname, Integer port, String filename) throws StorageNotFoundException, - SidecarExportException { + RemoteUnavailableException, ServiceException { final ResponseEntity<Void> response; final String url = "http://" + hostname + ":" + port + "/sidecar/export/" + filename; - log.debug("export file into data database sidecar: {}", url); + log.debug("export file from data database sidecar: {}", url); try { response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(null), Void.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { - log.error("Failed to export .csv in data-db sidecar: {}", e.getMessage()); - throw new StorageNotFoundException("Failed to export .csv in data-db sidecar: " + e.getMessage(), e); + } catch (ResourceAccessException | HttpServerErrorException e) { + log.error("Failed to export dataset with filename: {}: {}", filename, e.getMessage()); + throw new RemoteUnavailableException("Failed to export dataset: " + e.getMessage(), e); + } catch (HttpClientErrorException.BadRequest e) { + log.error("Failed to export dataset with filename: {}: not found: {}", filename, e.getMessage()); + throw new StorageNotFoundException("Failed to export dataset: not found: " + e.getMessage(), e); } if (!response.getStatusCode().equals(HttpStatus.ACCEPTED)) { - log.error("Failed to export .csv in data-db sidecar"); - throw new SidecarExportException("Failed to export .csv in data-db sidecar"); + log.error("Failed to export dataset with filename: {}: service responded unsuccessful: {}", filename, response.getStatusCode()); + throw new ServiceException("Failed to export dataset: service responded unsuccessful: " + response.getStatusCode()); } } } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java index 76f3e83cef138b8d64151757e303fd05555a4591..545e259097951b3ed79d34c73bef72ccd2270b6b 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java @@ -2,10 +2,12 @@ package at.tuwien.gateway.impl; import at.tuwien.api.keycloak.TokenDto; import at.tuwien.config.KeycloakConfig; +import at.tuwien.exception.RemoteUnavailableException; import at.tuwien.exception.ServiceConnectionException; import at.tuwien.exception.ServiceException; import at.tuwien.gateway.KeycloakGateway; import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.*; import org.springframework.stereotype.Service; @@ -22,37 +24,14 @@ public class KeycloakGatewayImpl implements KeycloakGateway { private final RestTemplate restTemplate; private final KeycloakConfig keycloakConfig; - public KeycloakGatewayImpl(@Qualifier("keycloakRestTemplate") RestTemplate restTemplate, - KeycloakConfig keycloakConfig) { + @Autowired + public KeycloakGatewayImpl(RestTemplate restTemplate, KeycloakConfig keycloakConfig) { this.restTemplate = restTemplate; this.keycloakConfig = keycloakConfig; } - public TokenDto obtainToken() throws ServiceConnectionException, ServiceException { - final HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); - final MultiValueMap<String, String> payload = new LinkedMultiValueMap<>(); - payload.add("username", keycloakConfig.getKeycloakUsername()); - payload.add("password", keycloakConfig.getKeycloakPassword()); - payload.add("grant_type", "password"); - payload.add("client_id", "admin-cli"); - final String url = keycloakConfig.getKeycloakEndpoint() + "/realms/master/protocol/openid-connect/token"; - log.debug("request admin token from url {}", url); - final ResponseEntity<TokenDto> response; - try { - response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { - log.error("Failed to obtain admin token: {}", e.getMessage()); - throw new ServiceConnectionException("Failed to obtain admin token: " + e.getMessage(), e); - } catch (Exception e) { - log.error("Failed to obtain admin token: remote host answered unexpected: {}", e.getMessage(), e); - throw new ServiceException("Failed to obtain admin token: remote host answered unexpected: " + e.getMessage(), e); - } - return response.getBody(); - } - @Override - public TokenDto obtainUserToken(String username, String password) throws ServiceConnectionException, ServiceException { + public TokenDto obtainUserToken(String username, String password) throws RemoteUnavailableException, ServiceException { final HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); final MultiValueMap<String, String> payload = new LinkedMultiValueMap<>(); @@ -66,15 +45,18 @@ public class KeycloakGatewayImpl implements KeycloakGateway { log.debug("request user token from url {}", url); final ResponseEntity<TokenDto> response; try { - response = new RestTemplate() - .exchange(url, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { + response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class); + } catch (HttpServerErrorException e) { log.error("Failed to obtain user token: {}", e.getMessage()); - throw new ServiceConnectionException("Failed to obtain user token: " + e.getMessage(), e); + throw new RemoteUnavailableException("Failed to obtain user token: " + e.getMessage(), e); } catch (Exception e) { log.error("Failed to obtain user token: unexpected response: {}", e.getMessage(), e); throw new ServiceException("Failed to obtain user token: unexpected response: " + e.getMessage(), e); } + if (!response.getStatusCode().equals(HttpStatus.OK)) { + log.error("Failed to obtain user token: service responded unsuccessful: {}", response.getStatusCode()); + throw new ServiceException("obtain user token: service responded unsuccessful: " + response.getStatusCode()); + } return response.getBody(); } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/MetadataServiceGatewayImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/MetadataServiceGatewayImpl.java index cb3c57b3325e589379f07e4116eb3c6f68d023e5..1fcf3e50ee3df4487eae8492867aa4952413c699 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/MetadataServiceGatewayImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/MetadataServiceGatewayImpl.java @@ -15,6 +15,7 @@ import at.tuwien.api.user.UserDto; import at.tuwien.exception.*; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.mapper.MetadataMapper; +import jakarta.validation.constraints.NotNull; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpEntity; @@ -45,17 +46,29 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway { @Override public PrivilegedContainerDto getContainerById(Long containerId) throws RemoteUnavailableException, - ContainerNotFoundException { + ContainerNotFoundException, ServiceException { final ResponseEntity<ContainerDto> response; try { - response = restTemplate.exchange("/api/container/" + containerId, HttpMethod.GET, new HttpEntity<>(null), + response = restTemplate.exchange("/api/container/" + containerId, HttpMethod.GET, HttpEntity.EMPTY, ContainerDto.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { - log.error("Failed to find container: {}", e.getMessage()); + } catch (ResourceAccessException | HttpServerErrorException e) { + log.error("Failed to find container with id {}: {}", containerId, e.getMessage()); throw new RemoteUnavailableException("Failed to find container: " + e.getMessage(), e); } catch (HttpClientErrorException.NotFound e) { - log.error("Failed to find container: body is null"); - throw new ContainerNotFoundException("Failed to find container: body is null"); + log.error("Failed to find container with id {}: {}", containerId, e.getMessage()); + throw new ContainerNotFoundException("Failed to find container: " + e.getMessage()); + } + if (response.getStatusCode() != HttpStatus.OK) { + log.error("Failed to find container with id {}: service responded unsuccessful: {}", containerId, response.getStatusCode()); + throw new ServiceException("Failed to find container: service responded unsuccessful: " + response.getStatusCode()); + } + if (!response.getHeaders().keySet().containsAll(List.of("X-Username", "X-Password"))) { + log.error("Failed to find all privileged container headers"); + throw new ServiceException("Failed to find all privileged container headers"); + } + if (response.getBody() == null) { + log.error("Failed to find container with id {}: body is empty", containerId); + throw new ServiceException("Failed to find container with id " + containerId + ": body is empty"); } final PrivilegedContainerDto container = metadataMapper.containerDtoToPrivilegedContainerDto(response.getBody()); container.setUsername(response.getHeaders().get("X-Username").get(0)); @@ -64,89 +77,83 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway { } @Override - public List<PrivilegedDatabaseDto> getDatabases() throws RemoteUnavailableException { - final ResponseEntity<PrivilegedDatabaseDto[]> response; - try { - response = restTemplate.exchange("/api/database", HttpMethod.GET, new HttpEntity<>(null), - PrivilegedDatabaseDto[].class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { - log.error("Failed to find databases: {}", e.getMessage()); - throw new RemoteUnavailableException("Failed to find databases: " + e.getMessage(), e); - } - if (response.getBody() == null) { - log.error("Failed to find databases: body is null"); - throw new RemoteUnavailableException("Failed to find databases: body is null"); - } - return List.of(response.getBody()); - } - - @Override - public void updateTableStatistics(Long databaseId, Long tableId, TableStatisticDto data) - throws RemoteUnavailableException { - final ResponseEntity<Void> response; - try { - response = restTemplate.exchange("/api/database/" + databaseId + "/table/" + tableId, HttpMethod.PUT, - new HttpEntity<>(data), Void.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { - log.error("Failed to update table statistics: {}", e.getMessage()); - throw new RemoteUnavailableException("Failed to update table statistics: " + e.getMessage(), e); - } - if (response.getStatusCode() != HttpStatus.ACCEPTED) { - log.error("Failed to update table statistics: unexpected status code"); - throw new RemoteUnavailableException("Failed to update table statistics: unexpected status code"); - } - } - - @Override - public PrivilegedDatabaseDto getDatabaseById(Long id) throws DatabaseNotFoundException, RemoteUnavailableException { + public PrivilegedDatabaseDto getDatabaseById(Long id) throws DatabaseNotFoundException, RemoteUnavailableException, + ServiceException { final ResponseEntity<PrivilegedDatabaseDto> response; try { - response = restTemplate.exchange("/api/database/" + id, HttpMethod.GET, new HttpEntity<>(null), + response = restTemplate.exchange("/api/database/" + id, HttpMethod.GET, HttpEntity.EMPTY, PrivilegedDatabaseDto.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { + } catch (ResourceAccessException | HttpServerErrorException e) { log.error("Failed to find database with id {}: {}", id, e.getMessage()); - throw new RemoteUnavailableException("Failed to find database with id " + id + ": " + e.getMessage(), e); + throw new RemoteUnavailableException("Failed to find database: " + e.getMessage(), e); } catch (HttpClientErrorException.NotFound e) { log.error("Failed to find database with id {}: body is null", id); - throw new DatabaseNotFoundException("Failed to find database id " + id + ": body is null", e); + throw new DatabaseNotFoundException("Failed to find database: body is null", e); + } + if (response.getStatusCode() != HttpStatus.OK) { + log.error("Failed to find database with id {}: service responded unsuccessful: {}", id, response.getStatusCode()); + throw new ServiceException("Failed to find database: service responded unsuccessful: " + response.getStatusCode()); + } + if (!response.getHeaders().keySet().containsAll(List.of("X-Username", "X-Password"))) { + log.error("Failed to find all privileged database headers"); + throw new ServiceException("Failed to find all privileged database headers"); + } + if (response.getBody() == null) { + log.error("Failed to find database with id {}: body is empty", id); + throw new ServiceException("Failed to find database with id " + id + ": body is empty"); } final PrivilegedDatabaseDto database = response.getBody(); database.getContainer().setUsername(response.getHeaders().get("X-Username").get(0)); database.getContainer().setPassword(response.getHeaders().get("X-Password").get(0)); - log.debug("found privileged database username={}, password={}", database.getContainer().getUsername(), - database.getContainer().getPassword().isEmpty() ? "(empty)" : "(hidden)"); + log.debug("found privileged database username={}", database.getContainer().getUsername()); return database; } @Override public PrivilegedDatabaseDto getDatabaseByInternalName(String internalName) throws DatabaseNotFoundException, - RemoteUnavailableException { + RemoteUnavailableException, ServiceException { final ResponseEntity<PrivilegedDatabaseDto[]> response; try { - response = restTemplate.exchange("/api/database/", HttpMethod.GET, new HttpEntity<>(null), PrivilegedDatabaseDto[].class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { + response = restTemplate.exchange("/api/database/", HttpMethod.GET, HttpEntity.EMPTY, PrivilegedDatabaseDto[].class); + } catch (ResourceAccessException | HttpServerErrorException e) { log.error("Failed to find database with internal name {}: {}", internalName, e.getMessage()); - throw new RemoteUnavailableException("Failed to find database with internal name " + internalName + ": " + e.getMessage(), e); + throw new RemoteUnavailableException("Failed to find database: " + e.getMessage(), e); } - if (response.getBody() == null || response.getBody().length != 1) { - log.error("Failed to find database with internal name {}: body is null", internalName); - throw new DatabaseNotFoundException("Failed to find database with internal name " + internalName + ": body is null"); + if (!response.getStatusCode().equals(HttpStatus.OK) || response.getBody() == null) { + log.error("Failed to find database with internal name {}: service responded unsuccessful: {}", internalName, response.getStatusCode()); + throw new ServiceException("Failed to find database: service responded unsuccessful: " + response.getStatusCode()); + } + if (response.getBody().length != 1) { + log.error("Failed to find database with internal name {}: body is empty", internalName); + throw new DatabaseNotFoundException("Failed to find database: body is empty"); } return response.getBody()[0]; } @Override - public PrivilegedTableDto getTableById(Long databaseId, Long id) throws TableNotFoundException, RemoteUnavailableException { + public PrivilegedTableDto getTableById(Long databaseId, Long id) throws TableNotFoundException, + RemoteUnavailableException, ServiceException { final ResponseEntity<TableDto> response; try { - response = restTemplate.exchange("/api/database/" + databaseId + "/table/" + id, HttpMethod.GET, new HttpEntity<>(null), TableDto.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { + response = restTemplate.exchange("/api/database/" + databaseId + "/table/" + id, HttpMethod.GET, HttpEntity.EMPTY, TableDto.class); + } catch (ResourceAccessException | HttpServerErrorException e) { log.error("Failed to find table with id {}: {}", id, e.getMessage()); - throw new RemoteUnavailableException("Failed to find table with id " + id + ": " + e.getMessage(), e); + throw new RemoteUnavailableException("Failed to find table: " + e.getMessage(), e); + } catch (HttpClientErrorException.NotFound e) { + log.error("Failed to find table with id {}: not found: {}", id, e.getMessage()); + throw new TableNotFoundException("Failed to find table: " + e.getMessage()); + } + if (!response.getStatusCode().equals(HttpStatus.OK)) { + log.error("Failed to find table with id {}: service responded unsuccessful: {}", id, response.getStatusCode()); + throw new ServiceException("Failed to find table: service responded unsuccessful: " + response.getStatusCode()); + } + if (!response.getHeaders().keySet().containsAll(List.of("X-Type", "X-Host", "X-Port", "X-Username", "X-Password", "X-Database", "X-Sidecar-Host", "X-Sidecar-Port"))) { + log.error("Failed to find all privileged table headers"); + throw new ServiceException("Failed to find all privileged table headers"); } if (response.getBody() == null) { - log.error("Failed to find table with id {}: body is null", id); - throw new TableNotFoundException("Failed to find table with id " + id + ": body is null"); + log.error("Failed to find table with id {}: body is empty", id); + throw new ServiceException("Failed to find table with id " + id + ": body is empty"); } final PrivilegedTableDto table = metadataMapper.tableDtoToPrivilegedTableDto(response.getBody()); table.getDatabase().getContainer().getImage().setJdbcMethod(response.getHeaders().get("X-Type").get(0)); @@ -157,24 +164,34 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway { table.getDatabase().setInternalName(response.getHeaders().get("X-Database").get(0)); table.getDatabase().getContainer().setSidecarHost(response.getHeaders().get("X-Sidecar-Host").get(0)); table.getDatabase().getContainer().setSidecarPort(Integer.parseInt(response.getHeaders().get("X-Sidecar-Port").get(0))); - log.debug("found privileged database username={}, password={}", - table.getDatabase().getContainer().getUsername(), - table.getDatabase().getContainer().getPassword().isEmpty() ? "(empty)" : "(hidden)"); + log.debug("found privileged database username={}", table.getDatabase().getContainer().getUsername()); return table; } @Override - public PrivilegedViewDto getViewById(Long databaseId, Long id) throws RemoteUnavailableException, ViewNotFoundException { + public PrivilegedViewDto getViewById(Long databaseId, Long id) throws RemoteUnavailableException, + ViewNotFoundException, ServiceException { final ResponseEntity<ViewDto> response; try { - response = restTemplate.exchange("/api/database/" + databaseId + "/view/" + id, HttpMethod.GET, new HttpEntity<>(null), ViewDto.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { + response = restTemplate.exchange("/api/database/" + databaseId + "/view/" + id, HttpMethod.GET, HttpEntity.EMPTY, ViewDto.class); + } catch (ResourceAccessException | HttpServerErrorException e) { log.error("Failed to find view with id {}: {}", id, e.getMessage()); - throw new RemoteUnavailableException("Failed to find view with id " + id + ": " + e.getMessage(), e); + throw new RemoteUnavailableException("Failed to find view: " + e.getMessage(), e); + } catch (HttpClientErrorException.NotFound e) { + log.error("Failed to find view with id {}: not found: {}", id, e.getMessage()); + throw new ViewNotFoundException("Failed to find view: " + e.getMessage()); + } + if (!response.getStatusCode().equals(HttpStatus.OK)) { + log.error("Failed to find view with id {}: service responded unsuccessful: {}", id, response.getStatusCode()); + throw new ServiceException("Failed to find view: service responded unsuccessful: " + response.getStatusCode()); + } + if (!response.getHeaders().keySet().containsAll(List.of("X-Type", "X-Host", "X-Port", "X-Username", "X-Password", "X-Database"))) { + log.error("Failed to find all privileged view headers"); + throw new ServiceException("Failed to find all privileged view headers"); } if (response.getBody() == null) { - log.error("Failed to find view with id {}: body is null", id); - throw new ViewNotFoundException("Failed to find view with id " + id + ": body is null"); + log.error("Failed to find view with id {}: body is empty", id); + throw new ServiceException("Failed to find view with id " + id + ": body is empty"); } final PrivilegedViewDto table = metadataMapper.viewDtoToPrivilegedViewDto(response.getBody()); table.getDatabase().getContainer().getImage().setJdbcMethod(response.getHeaders().get("X-Type").get(0)); @@ -187,101 +204,128 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway { } @Override - public PrivilegedUserDto getUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException { - final ResponseEntity<PrivilegedUserDto> response; + public UserDto getUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException, + ServiceException { + final ResponseEntity<UserDto> response; try { - response = restTemplate.exchange("/api/user/" + userId, HttpMethod.GET, new HttpEntity<>(null), PrivilegedUserDto.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { + response = restTemplate.exchange("/api/user/" + userId, HttpMethod.GET, HttpEntity.EMPTY, UserDto.class); + } catch (ResourceAccessException | HttpServerErrorException e) { log.error("Failed to find user with id {}: {}", userId, e.getMessage()); - throw new RemoteUnavailableException("Failed to find user with id " + userId + ": " + e.getMessage(), e); + throw new RemoteUnavailableException("Failed to find user: " + e.getMessage(), e); + } catch (HttpClientErrorException.NotFound e) { + log.error("Failed to find user with id {}: not found: {}", userId, e.getMessage()); + throw new UserNotFoundException("Failed to find user: " + e.getMessage()); + } + if (!response.getStatusCode().equals(HttpStatus.OK)) { + log.error("Failed to find user with id {}: service responded unsuccessful: {}", userId, response.getStatusCode()); + throw new ServiceException("Failed to find user: service responded unsuccessful: " + response.getStatusCode()); } if (response.getBody() == null) { - log.error("Failed to find user: body is null"); - throw new UserNotFoundException("Failed to find user: body is null"); + log.error("Failed to find user with id {}: body is empty", userId); + throw new ServiceException("Failed to find user with id " + userId + ": body is empty"); } return response.getBody(); } @Override - public DatabaseAccessDto getAccess(Long databaseId, UUID userId) throws RemoteUnavailableException, - NotAllowedException { - final ResponseEntity<DatabaseAccessDto> response; + public PrivilegedUserDto getPrivilegedUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException, + ServiceException { + final ResponseEntity<UserDto> response; try { - response = restTemplate.exchange("/api/database/" + databaseId + "/access/" + userId, HttpMethod.GET, new HttpEntity<>(null), DatabaseAccessDto.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { - log.error("Failed to find database access for user with id {}: {}", userId, e.getMessage()); - throw new RemoteUnavailableException("Failed to find database access", e); - } catch (HttpClientErrorException.Forbidden e) { - log.error("Failed to find database access for user with id {}: foreign user: {}", userId, e.getMessage()); - throw new NotAllowedException("Failed to find database access: foreign user", e); + response = restTemplate.exchange("/api/user/" + userId, HttpMethod.GET, HttpEntity.EMPTY, UserDto.class); + } catch (ResourceAccessException | HttpServerErrorException e) { + log.error("Failed to find user with id {}: {}", userId, e.getMessage()); + throw new RemoteUnavailableException("Failed to find user: " + e.getMessage(), e); } catch (HttpClientErrorException.NotFound e) { - log.error("Failed to find database access for user with id {}: missing access: {}", userId, e.getMessage()); - throw new NotAllowedException("Failed to find database access: missing access", e); + log.error("Failed to find user with id {}: not found: {}", userId, e.getMessage()); + throw new UserNotFoundException("Failed to find user: " + e.getMessage()); + } + if (!response.getStatusCode().equals(HttpStatus.OK)) { + log.error("Failed to find user with id {}: service responded unsuccessful: {}", userId, response.getStatusCode()); + throw new ServiceException("Failed to find user: service responded unsuccessful: " + response.getStatusCode()); + } + if (!response.getHeaders().keySet().containsAll(List.of("X-Username", "X-Password"))) { + log.error("Failed to find all privileged user headers"); + throw new ServiceException("Failed to find all privileged user headers"); } if (response.getBody() == null) { - log.error("Failed to find database access: body is null"); - throw new NotAllowedException("Failed to find database access: body is null"); + log.error("Failed to find user with id {}: body is empty", userId); + throw new ServiceException("Failed to find user with id " + userId + ": body is empty"); } - return response.getBody(); + final PrivilegedUserDto user = metadataMapper.userDtoToPrivilegedUserDto(response.getBody()); + user.setUsername(response.getHeaders().get("X-Username").get(0)); + user.setPassword(response.getHeaders().get("X-Password").get(0)); + return user; } @Override - public List<IdentifierDto> getIdentifiers(Long databaseId, Long subsetId) throws RemoteUnavailableException, - NotAllowedException { - final ResponseEntity<IdentifierDto[]> response; - final String url = "/api/identifier?dbid=" + databaseId + "&qid=" + subsetId; - log.trace("mapped url: {}", url); + public DatabaseAccessDto getAccess(Long databaseId, UUID userId) throws RemoteUnavailableException, + NotAllowedException, ServiceException { + final ResponseEntity<DatabaseAccessDto> response; try { - response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(null), IdentifierDto[].class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { - log.error("Failed to find identifiers for database with id {} and subset with id {}: {}", databaseId, subsetId, e.getMessage()); - throw new RemoteUnavailableException("Failed to find identifiers", e); + response = restTemplate.exchange("/api/database/" + databaseId + "/access/" + userId, HttpMethod.GET, HttpEntity.EMPTY, DatabaseAccessDto.class); + } catch (ResourceAccessException | HttpServerErrorException e) { + log.error("Failed to find database access for user with id {}: {}", userId, e.getMessage()); + throw new RemoteUnavailableException("Failed to find database access: " + e.getMessage(), e); + } catch (HttpClientErrorException.Forbidden | HttpClientErrorException.NotFound e) { + log.error("Failed to find database access for user with id {}: foreign user: {}", userId, e.getMessage()); + throw new NotAllowedException("Failed to find database access: foreign user: " + e.getMessage(), e); + } + if (!response.getStatusCode().equals(HttpStatus.OK)) { + log.error("Failed to find database access for user with id {}: service responded unsuccessful: {}", userId, response.getStatusCode()); + throw new ServiceException("Failed to find database access: service responded unsuccessful: " + response.getStatusCode()); } if (response.getBody() == null) { - log.error("Failed to find identifiers: body is null"); - throw new NotAllowedException("Failed to find identifiers: body is null"); + log.error("Failed to find database access: body is empty"); + throw new ServiceException("Failed to find database access: body is empty"); } - return List.of(response.getBody()); + return response.getBody(); } @Override - public List<IdentifierDto> getIdentifiers(Long databaseId) throws RemoteUnavailableException, - NotAllowedException { + public List<IdentifierDto> getIdentifiers(@NotNull Long databaseId, Long subsetId) throws ServiceException, + RemoteUnavailableException, DatabaseNotFoundException { final ResponseEntity<IdentifierDto[]> response; - final String url = "/api/identifier?dbid=" + databaseId; + final String url = "/api/identifier?dbid=" + databaseId + (subsetId != null ? ("&qid=" + subsetId) : ""); log.trace("mapped url: {}", url); try { - response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(null), IdentifierDto[].class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { - log.error("Failed to find identifiers for database with id {}: {}", databaseId, e.getMessage()); - throw new RemoteUnavailableException("Failed to find identifiers", e); + response = restTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, IdentifierDto[].class); + } catch (ResourceAccessException | HttpServerErrorException e) { + log.error("Failed to find identifiers for database with id {} and subset with id {}: {}", databaseId, subsetId, e.getMessage()); + throw new RemoteUnavailableException("Failed to find identifiers: " + e.getMessage(), e); + } catch (HttpClientErrorException.NotFound e) { + log.error("Failed to find identifiers for database with id {} and subset with id {}: foreign user: {}", databaseId, subsetId, e.getMessage()); + throw new DatabaseNotFoundException("Failed to find identifiers: foreign user: " + e.getMessage(), e); + } + if (!response.getStatusCode().equals(HttpStatus.OK)) { + log.error("Failed to find identifiers for database with id {} and subset with id {}: service responded unsuccessful: {}", databaseId, subsetId, response.getStatusCode()); + throw new ServiceException("Failed to find identifiers for database: service responded unsuccessful: " + response.getStatusCode()); } if (response.getBody() == null) { log.error("Failed to find identifiers: body is null"); - throw new NotAllowedException("Failed to find identifiers: body is null"); + throw new ServiceException("Failed to find identifiers: body is null"); } return List.of(response.getBody()); } @Override - public UserDto getUser(UUID userId) throws RemoteUnavailableException, NotAllowedException, UserNotFoundException { - final ResponseEntity<UserDto> response; - final String url = "/api/user/" + userId; - log.trace("mapped url: {}", url); + public void updateTableStatistics(Long databaseId, Long tableId) throws TableNotFoundException, ServiceException, + RemoteUnavailableException { + final ResponseEntity<Void> response; + final String url = "/api/database/" + databaseId + "/table/" + tableId; try { - response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(null), UserDto.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) { - log.error("Failed to find user with id {}: {}", userId, e.getMessage()); - throw new RemoteUnavailableException("Failed to find user", e); + response = restTemplate.exchange(url, HttpMethod.PUT, HttpEntity.EMPTY, Void.class); + } catch (ResourceAccessException | HttpServerErrorException e) { + log.error("Failed to update table statistic for table with id {}: {}", tableId, e.getMessage()); + throw new RemoteUnavailableException("Failed to update table statistic: " + e.getMessage(), e); } catch (HttpClientErrorException.NotFound e) { - log.error("Failed to find user with id {}: not found: {}", userId, e.getMessage()); - throw new UserNotFoundException("Failed to find user: not found", e); + log.error("Failed to update table statistic for table with id {}: foreign user: {}", tableId, e.getMessage()); + throw new TableNotFoundException("Failed to update table statistic: foreign user: " + e.getMessage(), e); } - if (response.getBody() == null) { - log.error("Failed to find identifiers: body is null"); - throw new NotAllowedException("Failed to find identifiers: body is null"); + if (!response.getStatusCode().equals(HttpStatus.ACCEPTED)) { + log.error("Failed to update table statistic for table with id {}: service responded unsuccessful: {}", tableId, response.getStatusCode()); + throw new ServiceException("Failed to update table statistic for database: service responded unsuccessful: " + response.getStatusCode()); } - return response.getBody(); } } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/listener/DefaultListener.java b/dbrepo-data-service/services/src/main/java/at/tuwien/listener/DefaultListener.java index c9e5bda2705d1d6822c1fbffe9fae167a2468858..89b18b3275323545e0defadc3e8b851ada914072 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/listener/DefaultListener.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/listener/DefaultListener.java @@ -66,7 +66,7 @@ public class DefaultListener implements MessageListener { log.error("Failed to read object: {}", e.getMessage()); } catch (SQLException | RemoteUnavailableException e) { log.error("Failed to insert tuple: {}", e.getMessage()); - } catch (TableNotFoundException e) { + } catch (TableNotFoundException | ServiceException e) { log.error("Failed to find table: {}", e.getMessage()); } } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java index d1b033fe5bf3bb237adc09f6ab541f3260cc11b1..5be39d4f0ae9c5b3255be9782ed1a70ce1316831 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java @@ -8,15 +8,18 @@ import at.tuwien.api.database.query.ImportCsvDto; import at.tuwien.api.database.query.QueryDto; import at.tuwien.api.database.query.QueryResultDto; import at.tuwien.api.database.table.*; -import at.tuwien.api.database.table.columns.ColumnCreateDto; -import at.tuwien.api.database.table.columns.ColumnDto; -import at.tuwien.api.database.table.columns.ColumnTypeDto; +import at.tuwien.api.database.table.columns.*; import at.tuwien.api.database.table.constraints.ConstraintsDto; +import at.tuwien.api.database.table.constraints.foreign.ForeignKeyBriefDto; +import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto; +import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto; +import at.tuwien.api.database.table.constraints.foreign.ReferenceTypeDto; import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto; import at.tuwien.api.database.table.constraints.unique.UniqueDto; import at.tuwien.api.database.table.internal.PrivilegedTableDto; import at.tuwien.config.QueryConfig; import at.tuwien.exception.*; +import at.tuwien.utils.MariaDbUtil; import com.github.dockerjava.zerodep.shaded.org.apache.commons.codec.binary.Hex; import com.google.common.hash.Hashing; import net.sf.jsqlparser.JSQLParserException; @@ -25,8 +28,11 @@ import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.statement.select.*; import org.jetbrains.annotations.NotNull; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; import org.mapstruct.Named; +import javax.swing.table.TableColumn; import java.io.*; import java.math.BigInteger; import java.nio.charset.StandardCharsets; @@ -63,6 +69,45 @@ public interface MariaDbMapper { return slug.toLowerCase(Locale.ENGLISH); } + default String databaseSetPasswordQuery(String username, String password) { + final StringBuilder statement = new StringBuilder("ALTER USER `") + .append(username) + .append("`@`%` IDENTIFIED BY '") + .append(password) + .append("';"); + log.trace("mapped set password statement: {}", statement); + return statement.toString(); + } + + default String databaseCreateUserQuery(String username, String password) { + final StringBuilder statement = new StringBuilder("CREATE USER IF NOT EXISTS `") + .append(username) + .append("`@`%` IDENTIFIED BY PASSWORD '") + .append(password) + .append("';"); + log.trace("mapped create user statement: {}", statement); + return statement.toString(); + } + + default String databaseGrantPrivilegesQuery(String username, String grants) { + final StringBuilder statement = new StringBuilder("GRANT ") + .append(grants) + .append(" ON *.* TO `") + .append(username) + .append("`@`%`;"); + log.trace("mapped grant privileges statement: {}", statement); + return statement.toString(); + } + + @Named("createDatabase") + default String databaseCreateDatabaseQuery(String database) { + final StringBuilder statement = new StringBuilder("CREATE DATABASE `") + .append(database) + .append("`"); + log.trace("mapped create database statement: {}", statement); + return statement.toString(); + } + default QueryResultDto resultListToQueryResultDto(List<ColumnDto> columns, ResultSet result) throws SQLException { log.trace("mapping result list to query result, columns.size={}", columns.size()); final List<Map<String, Object>> resultList = new LinkedList<>(); @@ -107,13 +152,13 @@ public interface MariaDbMapper { } default String databaseTablesSelectRawQuery() { - final String statement = "SELECT DISTINCT t.`TABLE_NAME` FROM information_schema.TABLES t WHERE t.`TABLE_SCHEMA` = ? AND t.`TABLE_TYPE` = 'SYSTEM VERSIONED' AND t.`TABLE_NAME` != 'qs_queries'"; + final String statement = "SELECT DISTINCT t.`TABLE_NAME` FROM information_schema.TABLES t WHERE t.`TABLE_SCHEMA` = ? AND t.`TABLE_TYPE` = 'SYSTEM VERSIONED' AND t.`TABLE_NAME` != 'qs_queries' ORDER BY t.`TABLE_NAME` ASC"; log.trace("mapped select tables statement: {}", statement); return statement; } default String databaseTableSelectRawQuery() { - final String statement = "SELECT t.`TABLE_NAME`, t.`TABLE_TYPE`, t.`TABLE_ROWS`, t.`AVG_ROW_LENGTH`, t.`DATA_LENGTH`, t.`MAX_DATA_LENGTH`, COALESCE(t.`CREATE_TIME`, NOW()) as `CREATE_TIME`, t.`UPDATE_TIME`, v.`VIEW_DEFINITION` FROM information_schema.TABLES t LEFT JOIN information_schema.VIEWS v ON t.`TABLE_NAME` = v.`TABLE_NAME` WHERE t.`TABLE_SCHEMA` = ? AND t.`TABLE_TYPE` = 'SYSTEM VERSIONED' AND t.`TABLE_NAME` != 'qs_queries' AND t.`TABLE_NAME` = ?"; + final String statement = "SELECT t.`TABLE_NAME`, t.`TABLE_TYPE`, t.`TABLE_ROWS`, t.`AVG_ROW_LENGTH`, t.`DATA_LENGTH`, t.`MAX_DATA_LENGTH`, COALESCE(t.`CREATE_TIME`, NOW()) as `CREATE_TIME`, t.`UPDATE_TIME`, v.`VIEW_DEFINITION`, t.`TABLE_COMMENT` FROM information_schema.TABLES t LEFT JOIN information_schema.VIEWS v ON t.`TABLE_NAME` = v.`TABLE_NAME` WHERE t.`TABLE_SCHEMA` = ? AND t.`TABLE_TYPE` = 'SYSTEM VERSIONED' AND t.`TABLE_NAME` != 'qs_queries' AND t.`TABLE_NAME` = ?"; log.trace("mapped select table statement: {}", statement); return statement; } @@ -131,13 +176,13 @@ public interface MariaDbMapper { } default String databaseTableColumnsSelectRawQuery() { - final String statement = "SELECT `ORDINAL_POSITION`, `COLUMN_DEFAULT`, `IS_NULLABLE`, `DATA_TYPE`, `CHARACTER_MAXIMUM_LENGTH`, `NUMERIC_PRECISION`, `NUMERIC_SCALE`, `COLUMN_TYPE`, `COLUMN_KEY`, `COLUMN_NAME`, `COLUMN_COMMENT` FROM `information_schema`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?;"; + final String statement = "SELECT `ORDINAL_POSITION`, `COLUMN_DEFAULT`, `IS_NULLABLE`, `DATA_TYPE`, `CHARACTER_MAXIMUM_LENGTH`, `NUMERIC_PRECISION`, `NUMERIC_SCALE`, `COLUMN_TYPE`, `COLUMN_KEY`, `COLUMN_NAME`, IF(`COLUMN_COMMENT`='',NULL,`COLUMN_COMMENT`) AS `COLUMN_COMMENT` FROM `information_schema`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?;"; log.trace("mapped select columns statement: {}", statement); return statement; } default String databaseTableConstraintsSelectRawQuery() { - final String statement = "SELECT k.`ORDINAL_POSITION`, c.`CONSTRAINT_TYPE`, k.`CONSTRAINT_NAME`, k.`COLUMN_NAME` FROM information_schema.TABLE_CONSTRAINTS c JOIN information_schema.KEY_COLUMN_USAGE k ON c.`TABLE_NAME` = k.`TABLE_NAME` AND c.`CONSTRAINT_NAME` = k.`CONSTRAINT_NAME`WHERE c.`CONSTRAINT_TYPE` = 'UNIQUE' AND LOWER(k.`COLUMN_NAME`) != 'row_end' AND c.`TABLE_SCHEMA` = ? AND c.`TABLE_NAME` = ? ORDER BY k.`ORDINAL_POSITION` ASC;"; + final String statement = "SELECT k.`ORDINAL_POSITION`, c.`CONSTRAINT_TYPE`, k.`CONSTRAINT_NAME`, k.`COLUMN_NAME`, k.`REFERENCED_TABLE_NAME`, k.`REFERENCED_COLUMN_NAME`, r.`DELETE_RULE`, r.`UPDATE_RULE` FROM information_schema.TABLE_CONSTRAINTS c JOIN information_schema.KEY_COLUMN_USAGE k ON c.`TABLE_NAME` = k.`TABLE_NAME` AND c.`CONSTRAINT_NAME` = k.`CONSTRAINT_NAME` LEFT JOIN information_schema.REFERENTIAL_CONSTRAINTS r ON r.`CONSTRAINT_NAME` = k.`CONSTRAINT_NAME` WHERE LOWER(k.`COLUMN_NAME`) != 'row_end' AND c.`TABLE_SCHEMA` = ? AND c.`TABLE_NAME` = ? ORDER BY k.`ORDINAL_POSITION` ASC;"; log.trace("mapped select table constraints statement: {}", statement); return statement; } @@ -155,7 +200,9 @@ public interface MariaDbMapper { } default String tableCreateDtoToCreateSequenceRawQuery(at.tuwien.api.database.table.internal.TableCreateDto data) { - return "CREATE SEQUENCE IF NOT EXISTS `" + tableCreateDtoToSequenceName(data) + "` NOCACHE"; + final String statement = "CREATE SEQUENCE IF NOT EXISTS `" + tableCreateDtoToSequenceName(data) + "` NOCACHE"; + log.trace("mapped create sequence statement: {}", statement); + return statement; } default String filterToGetQueriesRawQuery(Boolean filterPersisted) { @@ -210,6 +257,31 @@ public interface MariaDbMapper { return ""; } + default String tableColumnStatisticsSelectRawQuery(List<ColumnDto> data, String table) { + final StringBuilder statement = new StringBuilder(); + final int[] idx = new int[]{0}; + data.stream() + .filter(column -> MariaDbUtil.numericDataTypes.contains(column.getColumnType())) + .forEach(column -> statement.append(idx[0]++ > 0 ? " UNION " : "") + .append("SELECT '") + .append(column.getInternalName()) + .append("' as name, MIN(`") + .append(column.getInternalName()) + .append("`) as min, MAX(`") + .append(column.getInternalName()) + .append("`) as max, MEDIAN(`") + .append(column.getInternalName()) + .append("`) OVER () as median, AVG(`") + .append(column.getInternalName()) + .append("`) as mean, STDDEV(`") + .append(column.getInternalName()) + .append("`) as std_dev FROM ") + .append(table)); + statement.append(";"); + log.trace("mapped select column statistic statement: {}", statement); + return statement.toString(); + } + default String tableCreateDtoToCreateTableRawQuery(at.tuwien.api.database.table.internal.TableCreateDto data) { final StringBuilder stringBuilder = new StringBuilder("CREATE TABLE `") .append(nameToInternalName(data.getName())) @@ -226,27 +298,35 @@ public interface MariaDbMapper { /* null expressions */ .append(column.getNullAllowed() != null && column.getNullAllowed() ? " NULL" : " NOT NULL") /* default expressions */ - .append(data.getNeedSequence() && column.getName().equals("id") ? " DEFAULT NEXTVAL(`" + tableCreateDtoToSequenceName(data) + "`)" : "") - /* comments */ - .append(!column.getDescription().isEmpty() ? (" COMMENT \"" + column.getDescription() + "\"") : ""); + .append(data.getNeedSequence() && column.getName().equals("id") ? " DEFAULT NEXTVAL(`" + tableCreateDtoToSequenceName(data) + "`)" : ""); + if (column.getDescription() != null && !column.getDescription().isEmpty()) { + /* comments */ + stringBuilder.append(" COMMENT \"") + .append(column.getDescription()) + .append("\""); + } + } /* create primary key index */ - stringBuilder.append(", PRIMARY KEY (") - .append(String.join(",", data.getConstraints() - .getPrimaryKey() - .stream() - .map(c -> { - final Optional<ColumnCreateDto> optional = data.getColumns() - .stream() - .filter(cc -> cc.getName().equals(c)) - .findFirst(); - log.trace("lookup {} in columns: {}", c, data.getColumns().stream().map(ColumnCreateDto::getName).toList()); - return "`" + nameToInternalName(c) + "`" + columnCreateDtoToPrimaryKeyLengthSpecification(optional.get()); - }) - .toArray(String[]::new))) - .append(")"); if (data.getConstraints() != null) { log.trace("constraints are {}", data.getConstraints()); + if (data.getConstraints().getPrimaryKey() != null && !data.getConstraints().getPrimaryKey().isEmpty()) { + /* create primary key index */ + stringBuilder.append(", PRIMARY KEY (") + .append(String.join(",", data.getConstraints() + .getPrimaryKey() + .stream() + .map(c -> { + final Optional<ColumnCreateDto> optional = data.getColumns() + .stream() + .filter(cc -> cc.getName().equals(c)) + .findFirst(); + log.trace("lookup {} in columns: {}", c, data.getColumns().stream().map(ColumnCreateDto::getName).toList()); + return "`" + nameToInternalName(c) + "`" + columnCreateDtoToPrimaryKeyLengthSpecification(optional.get()); + }) + .toArray(String[]::new))) + .append(")"); + } if (data.getConstraints().getUniques() != null) { /* create unique indices */ data.getConstraints().getUniques() @@ -282,15 +362,22 @@ public interface MariaDbMapper { .append(ck) .append(")")); } - if (!data.getDescription().isBlank()) { + if (data.getDescription() != null && !data.getDescription().isBlank()) { /* create table comments */ stringBuilder.append(" COMMENT \"") .append(data.getDescription()) .append("\""); } } - stringBuilder.append(") WITH SYSTEM VERSIONING;"); - log.trace("mapped create table query: {}", stringBuilder); + stringBuilder.append(") WITH SYSTEM VERSIONING"); + if (data.getDescription() != null && !data.getDescription().isBlank()) { + /* create table comments */ + stringBuilder.append(" COMMENT \"") + .append(data.getDescription()) + .append("\""); + } + stringBuilder.append(";"); + log.trace("mapped create table statement: {}", stringBuilder); return stringBuilder.toString(); } @@ -324,6 +411,23 @@ public interface MariaDbMapper { return data.getLong(1); } + default TableStatisticDto resultSetToTableStatistic(ResultSet data) throws SQLException { + final TableStatisticDto statistic = TableStatisticDto.builder() + .columns(new LinkedHashMap<>()) + .build(); + while (data.next()) { + final ColumnStatisticDto columnStatistic = ColumnStatisticDto.builder() + .min(data.getBigDecimal(2)) + .max(data.getBigDecimal(3)) + .median(data.getBigDecimal(4)) + .mean(data.getBigDecimal(5)) + .stdDev(data.getBigDecimal(6)) + .build(); + statistic.getColumns().put(data.getString(1), columnStatistic); + } + return statistic; + } + /** * Selects the dataset page from a table/view. * @@ -381,8 +485,9 @@ public interface MariaDbMapper { return statement.toString(); } + @Named("dropTableQuery") default String dropTableRawQuery(String tableName) { - return "DROP TABLE IF EXISTS `" + tableName + "`;"; + return "DROP TABLE `" + tableName + "`;"; } default String tupleToRawInsertQuery(PrivilegedTableDto table, TupleDto data) throws TableMalformedException { @@ -394,18 +499,17 @@ public interface MariaDbMapper { final StringBuilder statement = new StringBuilder("INSERT INTO `") .append(table.getInternalName()) .append("` (") - .append(table.getColumns() + .append(data.getData() + .keySet() .stream() - .filter(column -> !column.getAutoGenerated()) - .map(column -> "`" + column.getInternalName() + "`") + .map(o -> "`" + o + "`") .collect(Collectors.joining(","))) - .append(") VALUES ("); - final int[] idx = new int[]{1, 0}; - table.getColumns() - .stream() - .filter(c -> !c.getAutoGenerated()) - .forEach(c -> statement.append(idx[1]++ > 0 ? "," : "") - .append("?")); + .append(") VALUES (") + .append(data.getData() + .keySet() + .stream() + .map(o -> "?") + .collect(Collectors.joining(","))); statement.append(");"); for (int i = 0; i < table.getColumns().size(); i++) { final ColumnDto column = table.getColumns() @@ -525,6 +629,7 @@ public interface MariaDbMapper { .tdbid(database.getId()) .queueName("dbrepo") .routingKey("dbrepo") + .description(resultSet.getString(10)) .columns(new LinkedList<>()) .identifiers(new LinkedList<>()) .creator(database.getOwner()) @@ -545,10 +650,16 @@ public interface MariaDbMapper { return table; } + ForeignKeyBriefDto foreignKeyDtoToForeignKeyBriefDto(ForeignKeyDto data); + default TableDto resultSetToConstraint(ResultSet resultSet, TableDto table) throws SQLException { final String type = resultSet.getString(2); final String name = resultSet.getString(3); final String columnName = resultSet.getString(4); + final String referencedTable = resultSet.getString(5); + final String referencedColumnName = resultSet.getString(6); + final ReferenceTypeDto deleteRule = resultSet.getString(7) != null ? ReferenceTypeDto.fromType(resultSet.getString(7)) : null; + final ReferenceTypeDto updateRule = resultSet.getString(8) != null ? ReferenceTypeDto.fromType(resultSet.getString(8)) : null; final Optional<ColumnDto> optional = table.getColumns().stream() .filter(c -> c.getInternalName().equals(columnName)) .findFirst(); @@ -557,7 +668,7 @@ public interface MariaDbMapper { throw new IllegalArgumentException("Failed to find table column"); } final ColumnDto column = optional.get(); - if (type.equals("UNIQUE")) { + if (type.equals("FOREIGN KEY") || type.equals("UNIQUE")) { final Optional<UniqueDto> optional2 = table.getConstraints().getUniques().stream().filter(u -> u.getName().equals(name)).findFirst(); if (optional2.isPresent()) { optional2.get() @@ -565,19 +676,70 @@ public interface MariaDbMapper { .add(column); return table; } + if (type.equals("UNIQUE")) { + table.getConstraints() + .getUniques() + .add(UniqueDto.builder() + .name(name) + .columns(new LinkedList<>(List.of(column))) + .build()); + return table; + } + final Optional<ForeignKeyDto> optional1 = table.getConstraints() + .getForeignKeys() + .stream() + .filter(fk -> fk.getName().equals(name)) + .findFirst(); + final ForeignKeyReferenceDto foreignKeyReference = ForeignKeyReferenceDto.builder() + .column(ColumnBriefDto.builder() + .name(columnName) + .internalName(columnName) + .databaseId(table.getTdbid()) + .build()) + .referencedColumn(ColumnBriefDto.builder() + .name(referencedColumnName) + .internalName(referencedColumnName) + .databaseId(table.getTdbid()) + .build()) + .build(); + if (optional1.isPresent()) { + foreignKeyReference.setForeignKey(foreignKeyDtoToForeignKeyBriefDto(optional1.get())); + optional1.get() + .getReferences() + .add(foreignKeyReference); + log.debug("found foreign key: create part ({}) referencing table {} ({})", columnName, referencedTable, referencedColumnName); + return table; + } + final ForeignKeyDto foreignKey = ForeignKeyDto.builder() + .name(name) + .table(tableDtoToTableBriefDto(table)) + .referencedTable(TableBriefDto.builder() + .name(referencedTable) + .internalName(referencedTable) + .databaseId(table.getTdbid()) + .build()) + .references(new LinkedList<>(List.of(foreignKeyReference))) + .onDelete(deleteRule) + .onUpdate(updateRule) + .build(); + foreignKey.getReferences() + .forEach(ref -> ref.setForeignKey(foreignKeyDtoToForeignKeyBriefDto(foreignKey))); table.getConstraints() - .getUniques() - .add(UniqueDto.builder() - .name(name) - .columns(new LinkedList<>(List.of(column))) - .build()); + .getForeignKeys() + .add(foreignKey); + log.debug("create foreign key: add part ({}) referencing table {} ({})", columnName, referencedTable, referencedColumnName); return table; } return table; } + @Mappings({ + @Mapping(target = "databaseId", source = "tdbid") + }) TableBriefDto tableDtoToTableBriefDto(TableDto data); + ColumnBriefDto columnDtoToColumnBriefDto(ColumnDto data); + default TableDto resultSetToTable(ResultSet resultSet, TableDto table, QueryConfig queryConfig) throws SQLException { final ColumnDto column = ColumnDto.builder() .ordinalPosition(resultSet.getInt(1) - 1) /* start at zero */ @@ -596,7 +758,7 @@ public interface MariaDbMapper { if (resultSet.getString(9) != null && resultSet.getString(9).equals("PRI")) { table.getConstraints().getPrimaryKey().add(PrimaryKeyDto.builder() .table(tableDtoToTableBriefDto(table)) - .column(column) + .column(columnDtoToColumnBriefDto(column)) .build()); } /* fix boolean and set size for others */ @@ -659,6 +821,7 @@ public interface MariaDbMapper { } view.getColumns() .add(column); + log.trace("parsed view {}.{} column: {}", view.getDatabase().getInternalName(), view.getInternalName(), column.getInternalName()); return view; } @@ -711,15 +874,12 @@ public interface MariaDbMapper { statement.append("@") .append(column.getInternalName()); if (column.getDateFormat() != null) { - log.trace("import column has date format, need to format it differently"); /* reformat dates */ columnToDateSet(data, column, set); } else if (column.getColumnType().equals(ColumnTypeDto.BOOL)) { - log.trace("import column has boolean format, need to format it differently"); /* reformat booleans */ columnToBoolSet(data, column, set); } else { - log.trace("import column has text format"); /* reformat others */ columnToTextSet(data, column, set); } @@ -728,6 +888,7 @@ public interface MariaDbMapper { statement.append(")") .append(set.length() != 0 ? (" SET " + set) : "") .append(";"); + log.trace("mapped insert statement: {}", statement); return statement.toString(); } @@ -812,7 +973,7 @@ public interface MariaDbMapper { log.error("Failed to find table column {}", key); throw new IllegalArgumentException("Failed to find table column"); } - if (optional.get().getAutoGenerated() || value == null) { + if (optional.get().getAutoGenerated()) { return; } statement.append(idx[0]++ == 0 ? "" : ", ") @@ -831,7 +992,7 @@ public interface MariaDbMapper { log.error("Failed to find table column {}", key); throw new IllegalArgumentException("Failed to find table column"); } - if (optional.get().getAutoGenerated() || value == null) { + if (optional.get().getAutoGenerated()) { return; } statement.append(jdx[0]++ == 0 ? "" : ", ") @@ -843,13 +1004,12 @@ public interface MariaDbMapper { } default void columnToDateSet(ImportCsvDto data, ColumnDto column, StringBuilder set) { - log.trace("mapping column to date set"); + log.trace("import column has date format, need to format it: {}", column.getDateFormat().getUnixFormat()); set.append(!set.isEmpty() ? ", " : "") .append("`") .append(column.getInternalName()) .append("` = STR_TO_DATE("); if (data.getNullElement() != null) { - log.trace("import has null element present"); set.append("IF(STRCMP(@") .append(column.getInternalName()) .append(",'") @@ -873,13 +1033,11 @@ public interface MariaDbMapper { } default void columnToBoolSet(ImportCsvDto data, ColumnDto column, StringBuilder set) { - log.trace("mapping column to bool set, data={}, column={}, set=(generated)", data, column); set.append(!set.isEmpty() ? ", " : "") .append("`") .append(column.getInternalName()) .append("` = "); if (data.getNullElement() != null) { - log.trace("import has null element present"); set.append("IF(!STRCMP(@") .append(column.getInternalName()) .append(",'") @@ -893,9 +1051,7 @@ public interface MariaDbMapper { } default void columnToBoolSet2(ImportCsvDto data, ColumnDto column, StringBuilder set) { - log.trace("mapping column to inner bool set, data={}, column={}, set=(generated)", data, column); if (data.getTrueElement() != null) { - log.trace("import has true element present"); set.append("IF(!STRCMP(@") .append(column.getInternalName()) .append(",'") @@ -920,7 +1076,6 @@ public interface MariaDbMapper { return; } if (data.getFalseElement() != null) { - log.trace("import has false element present"); set.append("IF(!STRCMP(@") .append(column.getInternalName()) .append(",'") @@ -949,13 +1104,11 @@ public interface MariaDbMapper { } default void columnToTextSet(ImportCsvDto data, ColumnDto column, StringBuilder set) { - log.trace("mapping column to text set"); set.append(!set.isEmpty() ? ", " : "") .append("`") .append(column.getInternalName()) .append("` = "); if (data.getNullElement() != null) { - log.trace("import has null element present"); set.append("IF(STRCMP(@") .append(column.getInternalName()) .append(",'") @@ -970,11 +1123,11 @@ public interface MariaDbMapper { } default void prepareStatementWithColumnTypeObject(PreparedStatement statement, ColumnTypeDto columnType, int idx, - Object value) throws SQLException { + String columnName, Object value) throws SQLException { switch (columnType) { case BLOB, TINYBLOB, MEDIUMBLOB, LONGBLOB: if (value == null) { - log.trace("idx {} is null, prepare with null value", idx); + log.trace("idx {} = {} is null, prepare with null value", idx, columnName); statement.setNull(idx, Types.BLOB); break; } @@ -983,26 +1136,26 @@ public interface MariaDbMapper { try (ObjectOutputStream ois = new ObjectOutputStream(boas)) { ois.writeObject(value); statement.setBlob(idx, new ByteArrayInputStream(boas.toByteArray())); - log.trace("prepare statement idx {} blob", idx); + log.trace("prepare statement idx {} = {} blob", idx, columnName); } } catch (IOException e) { - log.error("Failed to set blob: {}", e.getMessage()); + log.error("Failed to set blob/tinyblob/mediumblob/longblob: {}", e.getMessage()); throw new SQLException("Failed to set blob: " + e.getMessage(), e); } break; case TEXT, CHAR, VARCHAR, TINYTEXT, MEDIUMTEXT, LONGTEXT, ENUM, SET: if (value == null) { - log.trace("idx {} is null, prepare with null value", idx); + log.trace("idx {} = {} is null, prepare with null value", idx, columnName); statement.setNull(idx, Types.VARCHAR); break; } - log.trace("prepare statement idx {} string: {}", idx, value); + log.trace("prepare statement idx {} = {} text/char/varchar/tinytext/mediumtext/longtext/enum/set: {}", idx, columnName, value); statement.setString(idx, String.valueOf(value)); break; case DATE: if (value == null) { - log.trace("idx {} is null, prepare with null value", idx); + log.trace("idx {} = {} is null, prepare with null value", idx, columnName); statement.setNull(idx, Types.DATE); break; } @@ -1011,113 +1164,114 @@ public interface MariaDbMapper { break; case BIGINT: if (value == null) { - log.trace("idx {} is null, prepare with null value", idx); + log.trace("idx {} = {} is null, prepare with null value", idx, columnName); statement.setNull(idx, Types.BIGINT); break; } - log.trace("prepare statement idx {} long: {}", idx, value); + log.trace("prepare statement idx {} bigint: {}", idx, value); statement.setLong(idx, Long.parseLong(String.valueOf(value))); break; case INT, MEDIUMINT: if (value == null) { - log.trace("idx {} is null, prepare with null value", idx); + log.trace("idx {} = {} is null, prepare with null value", idx, columnName); statement.setNull(idx, Types.INTEGER); break; } - log.trace("prepare statement idx {} long: {}", idx, value); + log.trace("prepare statement idx {} = {} int/mediumint: {}", idx, columnName, value); statement.setLong(idx, Long.parseLong(String.valueOf(value))); break; case TINYINT: if (value == null) { - log.trace("idx {} is null, prepare with null value", idx); + log.trace("idx {} = {} is null, prepare with null value", idx, columnName); statement.setNull(idx, Types.TINYINT); break; } - log.trace("prepare statement idx {} long: {}", idx, value); + log.trace("prepare statement idx {} = {} tinyint: {}", idx, columnName, value); statement.setLong(idx, Long.parseLong(String.valueOf(value))); break; case SMALLINT: if (value == null) { - log.trace("idx {} is null, prepare with null value", idx); + log.trace("idx {} = {} is null, prepare with null value", idx, columnName); statement.setNull(idx, Types.SMALLINT); break; } - log.trace("prepare statement idx {} long: {}", idx, value); + log.trace("prepare statement idx {} = {} smallint: {}", idx, columnName, value); statement.setLong(idx, Long.parseLong(String.valueOf(value))); break; case DECIMAL: if (value == null) { - log.trace("idx {} is null, prepare with null value", idx); + log.trace("idx {} = {} is null, prepare with null value", idx, columnName); statement.setNull(idx, Types.DECIMAL); break; } + log.trace("prepare statement idx {} = {} decimal: {}", idx, columnName, value); statement.setDouble(idx, Double.parseDouble(String.valueOf(value))); break; case FLOAT: if (value == null) { - log.trace("idx {} is null, prepare with null value", idx); + log.trace("idx {} = {} is null, prepare with null value", idx, columnName); statement.setNull(idx, Types.FLOAT); break; } - log.trace("prepare statement idx {} double: {}", idx, value); + log.trace("prepare statement idx {} = {} float: {}", idx, columnName, value); statement.setDouble(idx, Double.parseDouble(String.valueOf(value))); break; case DOUBLE: if (value == null) { - log.trace("idx {} is null, prepare with null value", idx); + log.trace("idx {} = {} is null, prepare with null value", idx, columnName); statement.setNull(idx, Types.DOUBLE); break; } - log.trace("prepare statement idx {} double: {}", idx, value); + log.trace("prepare statement idx {} = {} double: {}", idx, columnName, value); statement.setDouble(idx, Double.parseDouble(String.valueOf(value))); break; case BINARY, VARBINARY, BIT: if (value == null) { - log.trace("idx {} is null, prepare with null value", idx); + log.trace("idx {} = {} is null, prepare with null value", idx, columnName); statement.setNull(idx, Types.DECIMAL); break; } + log.trace("prepare statement idx {} = {} binary/varbinary/bit", idx, columnName); statement.setBinaryStream(idx, (InputStream) value); - log.trace("prepare statement idx {} binary stream", idx); break; case BOOL: if (value == null) { - log.trace("idx {} is null, prepare with null value", idx); + log.trace("idx {} = {} is null, prepare with null value", idx, columnName); statement.setNull(idx, Types.BOOLEAN); break; } - log.trace("prepare statement idx {} bool: {}", idx, value); + log.trace("prepare statement idx {} = {} bool: {}", idx, columnName, value); statement.setBoolean(idx, Boolean.parseBoolean(String.valueOf(value))); break; case TIMESTAMP, DATETIME: if (value == null) { - log.trace("idx {} is null, prepare with null value", idx); + log.trace("idx {} = {} is null, prepare with null value", idx, columnName); statement.setNull(idx, Types.TIMESTAMP); break; } + log.trace("prepare statement idx {} timestamp/datetime: {}", idx, value); statement.setTimestamp(idx, Timestamp.valueOf(String.valueOf(value))); - log.trace("prepare statement idx {} timestamp: {}", idx, value); break; case TIME: if (value == null) { - log.trace("idx {} is null, prepare with null value", idx); + log.trace("idx {} = {} is null, prepare with null value", idx, columnName); statement.setNull(idx, Types.TIME); break; } + log.trace("prepare statement idx {} = {} time: {}", idx, columnName, value); statement.setTime(idx, Time.valueOf(String.valueOf(value))); - log.trace("prepare statement idx {} time: {}", idx, value); break; case YEAR: if (value == null) { - log.trace("idx {} is null, prepare with null value", idx); + log.trace("idx {} = {} is null, prepare with null value", idx, columnName); statement.setNull(idx, Types.TIME); break; } - log.trace("prepare statement idx {} string: {}", idx, value); + log.trace("prepare statement idx {} = {} year: {}", idx, columnName, value); statement.setString(idx, String.valueOf(value)); break; default: - log.error("Failed to map column type {} at index {} for value {}", columnType, idx, value); + log.error("Failed to map column type {} at idx {} = {} for value {}", columnType, idx, columnName, value); throw new IllegalArgumentException("Failed to map column type " + columnType); } } @@ -1304,7 +1458,7 @@ public interface MariaDbMapper { } default boolean columnMatches(ColumnDto column, String tableOrView) { - if (column.getTable().getInternalName().equals(tableOrView)) { + if (column.getTable() != null && column.getTable().getInternalName().equals(tableOrView)) { log.trace("table '{}' found in column table", tableOrView); return true; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MetadataMapper.java b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MetadataMapper.java index 67633ba1757897a4a0f5619670e7990d9cd1559a..4cde78c7d913108bdf9d3d0d1b13c541ca44724d 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MetadataMapper.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MetadataMapper.java @@ -12,6 +12,8 @@ import at.tuwien.api.database.table.TableBriefDto; import at.tuwien.api.database.table.TableDto; import at.tuwien.api.database.table.columns.ColumnDto; import at.tuwien.api.database.table.internal.PrivilegedTableDto; +import at.tuwien.api.user.PrivilegedUserDto; +import at.tuwien.api.user.UserDto; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.Mappings; @@ -43,4 +45,6 @@ public interface MetadataMapper { ContainerDto privilegedContainerDtoToContainerDto(PrivilegedContainerDto data); + PrivilegedUserDto userDtoToPrivilegedUserDto(UserDto data); + } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/AccessService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/AccessService.java index ac86984f393e7e4a8db89f35524ed1cd98989447..a6d57dc8b6f27300c1ec960e2ea7f5ad3939ff52 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/AccessService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/AccessService.java @@ -3,17 +3,42 @@ package at.tuwien.service; import at.tuwien.api.database.AccessTypeDto; import at.tuwien.api.database.internal.PrivilegedDatabaseDto; import at.tuwien.api.user.PrivilegedUserDto; +import at.tuwien.api.user.UserDto; import at.tuwien.exception.*; import java.sql.SQLException; public interface AccessService { + + /** + * Create a user with access to a given database. + * @param database The database. + * @param user The user. + * @param access The access type. + * @throws SQLException The connection to the database could not be established. + * @throws DatabaseMalformedException The database schema is malformed. + */ void create(PrivilegedDatabaseDto database, PrivilegedUserDto user, AccessTypeDto access) throws SQLException, DatabaseMalformedException; - void update(PrivilegedDatabaseDto database, PrivilegedUserDto user, AccessTypeDto access) throws SQLException, + /** + * Update access to a given database for a given user. + * @param database The database. + * @param user The user. + * @param access The access type. + * @throws SQLException The connection to the database could not be established. + * @throws DatabaseMalformedException The database schema is malformed. + */ + void update(PrivilegedDatabaseDto database, UserDto user, AccessTypeDto access) throws SQLException, DatabaseMalformedException; - void delete(PrivilegedDatabaseDto database, PrivilegedUserDto user) throws SQLException, + /** + * Revoke access to a given database for a given user. + * @param database The database. + * @param user The user. + * @throws SQLException The connection to the database could not be established. + * @throws DatabaseMalformedException The database schema is malformed. + */ + void delete(PrivilegedDatabaseDto database, UserDto user) throws SQLException, DatabaseMalformedException; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/AnalyseService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/AnalyseService.java deleted file mode 100644 index eb1c047b0560a238ad5dfa77f0eed32e5db6af2e..0000000000000000000000000000000000000000 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/AnalyseService.java +++ /dev/null @@ -1,11 +0,0 @@ -package at.tuwien.service; - -import at.tuwien.api.database.table.TableStatisticDto; -import at.tuwien.exception.NotAllowedException; -import at.tuwien.exception.RemoteUnavailableException; -import at.tuwien.exception.TableNotFoundException; - -public interface AnalyseService { - TableStatisticDto analyseTable(Long databaseId, Long tableId) throws TableNotFoundException, - NotAllowedException, RemoteUnavailableException; -} diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/DatabaseService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/DatabaseService.java index 6c99910e67067502070d307fc55cb22b905b377e..271b2abb82918027053a357c648a1d2ac1926278 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/DatabaseService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/DatabaseService.java @@ -11,9 +11,24 @@ import java.sql.SQLException; public interface DatabaseService { + /** + * Creates a database in the given container. + * @param container The container. + * @param data The database metadata. + * @return The created database, if successful. + * @throws SQLException The connection to the database could not be established. + * @throws DatabaseMalformedException The database schema is malformed. + */ PrivilegedDatabaseDto create(PrivilegedContainerDto container, CreateDatabaseDto data) throws SQLException, DatabaseMalformedException; + /** + * Updates a user's password in a given database. + * @param database The database. + * @param data The user-password tuple. + * @throws SQLException The connection to the database could not be established. + * @throws DatabaseMalformedException The database schema is malformed. + */ void update(PrivilegedDatabaseDto database, UpdateUserPasswordDto data) throws SQLException, DatabaseMalformedException; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/SubsetService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/SubsetService.java index 9c9bc25a71c33ac388feffbf79d195fa12933ab9..7c2575b9cc348724f801dfd7e67d322b5ddd2070 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/SubsetService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/SubsetService.java @@ -28,7 +28,7 @@ public interface SubsetService { QueryResultDto execute(PrivilegedDatabaseDto database, String statement, Instant timestamp, UUID userId, Long page, Long size, SortTypeDto sortDirection, String sortColumn) - throws QueryStoreInsertException, SQLException, QueryNotFoundException, TableMalformedException, UserNotFoundException, NotAllowedException, RemoteUnavailableException; + throws QueryStoreInsertException, SQLException, QueryNotFoundException, TableMalformedException, UserNotFoundException, NotAllowedException, RemoteUnavailableException, ServiceException, DatabaseNotFoundException; QueryResultDto reExecute(PrivilegedDatabaseDto database, QueryDto query, Long page, Long size, SortTypeDto sortDirection, String sortColumn) throws TableMalformedException, @@ -45,11 +45,11 @@ public interface SubsetService { * @return The list of queries. */ List<QueryDto> findAll(PrivilegedDatabaseDto database, Boolean filterPersisted) throws SQLException, - QueryNotFoundException, NotAllowedException, RemoteUnavailableException; + QueryNotFoundException, NotAllowedException, RemoteUnavailableException, ServiceException, DatabaseNotFoundException; ExportResourceDto export(PrivilegedDatabaseDto database, QueryDto query, Instant timestamp, String filename) throws SQLException, QueryMalformedException, SidecarExportException, StorageNotFoundException, - StorageUnavailableException; + StorageUnavailableException, ServiceException, RemoteUnavailableException; Long executeCountNonPersistent(PrivilegedDatabaseDto database, String statement, Instant timestamp) throws SQLException, QueryMalformedException, TableMalformedException; @@ -62,7 +62,7 @@ public interface SubsetService { * @return The query. * @throws QueryNotFoundException The query store did not return a query */ - QueryDto findById(PrivilegedDatabaseDto database, Long queryId) throws QueryNotFoundException, SQLException, NotAllowedException, RemoteUnavailableException, UserNotFoundException; + QueryDto findById(PrivilegedDatabaseDto database, Long queryId) throws QueryNotFoundException, SQLException, NotAllowedException, RemoteUnavailableException, UserNotFoundException, ServiceException, DatabaseNotFoundException; /** * Inserts a query and metadata to the query store of a given database id. diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java index b8d2f393902545b1931a6927bc318cb606be92f6..fb045b4a19217d968fdf27e4753c2596bc0f9431 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java @@ -15,40 +15,110 @@ import java.util.List; public interface TableService { - List<TableDto> getSchemas(PrivilegedDatabaseDto database) throws SQLException, TableNotFoundException, QueryMalformedException, DatabaseMalformedException; + /** + * Get table schemas from the information_schema in the data database. + * @param database The data database privileged object. + * @return List of tables, if successful. + * @throws SQLException Failed to parse SQL query, contains invalid syntax. + * @throws TableNotFoundException The table could not be inspected in the data database. + * @throws QueryMalformedException The inspection query is malformed. + * @throws DatabaseMalformedException The database inspection was unsuccessful, likely due to a bug in the mapping. + */ + List<TableDto> getSchemas(PrivilegedDatabaseDto database) throws SQLException, TableNotFoundException, + QueryMalformedException, DatabaseMalformedException; + + /** + * Generate table statistic for a given table. Only numerical columns are calculated. + * @param table The table. + * @return The table statistic, if successful. + * @throws SQLException Failed to parse SQL query, contains invalid syntax. + * @throws TableMalformedException The table statistic generation was unsuccessful, likely due to a bug in the mapping. + * @throws QueryMalformedException The inspection query is malformed. + */ + TableStatisticDto getStatistics(PrivilegedTableDto table) throws SQLException, TableMalformedException, + QueryMalformedException; - TableDto find(PrivilegedDatabaseDto database, String tableName) throws TableNotFoundException, SQLException, QueryMalformedException; + /** + * Finds a table with given data database and table name. + * @param database The data database. + * @param tableName The table name. + * @return The table, if successful. + * @throws TableNotFoundException The table could not be inspected in the data database. + * @throws SQLException Failed to parse SQL query, contains invalid syntax. + * @throws QueryMalformedException The inspection query is malformed. + */ + TableDto find(PrivilegedDatabaseDto database, String tableName) throws TableNotFoundException, SQLException, + QueryMalformedException; + /** + * Creates a table in given data database with table definition. + * @param database The data database privileged object. + * @param data The table definition. + * @return The created table, if successful. + * @throws SQLException Failed to parse SQL query, contains invalid syntax. + * @throws TableNotFoundException The table could not be inspected in the data database. + * @throws TableExistsException The table name already exists in the information_schema. + * @throws TableNotFoundException The table could not be inspected in the data database. + * @throws QueryMalformedException The create/inspection query is malformed. + */ TableDto createTable(PrivilegedDatabaseDto database, TableCreateDto data) throws SQLException, TableMalformedException, TableExistsException, TableNotFoundException, QueryMalformedException; + /** + * Drops a table in given table object. + * @param table The table object. + * @throws SQLException Failed to parse SQL query, contains invalid syntax. + * @throws QueryMalformedException The drop table query is malformed. + */ void delete(PrivilegedTableDto table) throws SQLException, QueryMalformedException; - QueryResultDto getData(PrivilegedTableDto table, Instant timestamp, Long page, - Long size) throws SQLException, TableMalformedException; - - List<TableHistoryDto> history(PrivilegedTableDto table) throws SQLException, - TableNotFoundException; - + /** + * Obtains data from a table with given table object at timestamp, loaded as page number and length size. + * @param table The table object. + * @param timestamp The timestamp. + * @param page The page number. + * @param size The page size/length. + * @return The data. + * @throws SQLException Failed to parse SQL query, contains invalid syntax. + * @throws TableMalformedException The table schema is malformed, likely due to a bug in the application. + */ + QueryResultDto getData(PrivilegedTableDto table, Instant timestamp, Long page, Long size) throws SQLException, + TableMalformedException; + + /** + * Obtains the table history for a given table object. + * @param table The table object. + * @param size The maximum size. + * @return The table history. + * @throws SQLException Failed to parse SQL query, contains invalid syntax. + * @throws TableNotFoundException The table could not be found in the data database. + */ + List<TableHistoryDto> history(PrivilegedTableDto table, Long size) throws SQLException, TableNotFoundException; + + /** + * Obtains the table data tuples count at time. + * @param table The table object. + * @param timestamp The timestamp. + * @return Number of tuples, if successful. + * @throws SQLException Failed to parse SQL query, contains invalid syntax. + * @throws QueryMalformedException The count query is malformed, likely due to a bug in the application. + */ Long getCount(PrivilegedTableDto table, Instant timestamp) throws SQLException, QueryMalformedException; - void importTuple(PrivilegedTableDto table, TupleDto data) - throws TableMalformedException, StorageUnavailableException, StorageNotFoundException, SQLException, QueryMalformedException; - - void importDataset(PrivilegedTableDto table, ImportCsvDto data) - throws SidecarImportException, StorageNotFoundException, SQLException, QueryMalformedException; + void importDataset(PrivilegedTableDto table, ImportCsvDto data) throws SidecarImportException, + StorageNotFoundException, SQLException, QueryMalformedException, ServiceException, RemoteUnavailableException; void deleteTuple(PrivilegedTableDto table, TupleDeleteDto data) throws SQLException, TableMalformedException, QueryMalformedException; void createTuple(PrivilegedTableDto table, TupleDto data) throws SQLException, - QueryMalformedException, TableMalformedException; + QueryMalformedException, TableMalformedException, StorageUnavailableException, StorageNotFoundException; void updateTuple(PrivilegedTableDto table, TupleUpdateDto data) throws SQLException, QueryMalformedException, TableMalformedException; ExportResourceDto exportDataset(PrivilegedTableDto table, Instant timestamp) throws SQLException, SidecarExportException, StorageNotFoundException, StorageUnavailableException, - QueryMalformedException; + QueryMalformedException, ServiceException, RemoteUnavailableException; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java index 4dcd96ed535971d7b32507f998535544b0a27317..3455c320cd10c2e488220843db8ac3d644ef902d 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java @@ -58,5 +58,5 @@ public interface ViewService { ExportResourceDto exportDataset(PrivilegedDatabaseDto database, ViewDto view, Instant timestamp) throws SQLException, QueryMalformedException, SidecarExportException, StorageNotFoundException, - StorageUnavailableException; + StorageUnavailableException, ServiceException, RemoteUnavailableException; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/AccessServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/AccessServiceMariaDbImpl.java index 96ded2b074d9aa626e289bcecd418274faa31cc3..8c52e020103db210744884e1f5973f67a8e44861 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/AccessServiceMariaDbImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/AccessServiceMariaDbImpl.java @@ -3,10 +3,13 @@ package at.tuwien.service.impl; import at.tuwien.api.database.AccessTypeDto; import at.tuwien.api.database.internal.PrivilegedDatabaseDto; import at.tuwien.api.user.PrivilegedUserDto; +import at.tuwien.api.user.UserDto; import at.tuwien.exception.*; +import at.tuwien.mapper.MariaDbMapper; import at.tuwien.service.AccessService; import com.mchange.v2.c3p0.ComboPooledDataSource; import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -23,6 +26,13 @@ public class AccessServiceMariaDbImpl extends HibernateConnector implements Acce @Value("${dbrepo.grant.default.write}") private String grantDefaultWrite; + private MariaDbMapper mariaDbMapper; + + @Autowired + public AccessServiceMariaDbImpl(MariaDbMapper mariaDbMapper) { + this.mariaDbMapper = mariaDbMapper; + } + @Override public void create(PrivilegedDatabaseDto database, PrivilegedUserDto user, AccessTypeDto access) throws SQLException, DatabaseMalformedException { @@ -30,11 +40,11 @@ public class AccessServiceMariaDbImpl extends HibernateConnector implements Acce final Connection connection = dataSource.getConnection(); try { /* create user if not exists */ - connection.prepareStatement("CREATE USER IF NOT EXISTS `" + user.getUsername() + "`@`%` IDENTIFIED BY PASSWORD '" + user.getPassword() + "';") + connection.prepareStatement(mariaDbMapper.databaseCreateUserQuery(user.getUsername(), user.getPassword())) .execute(); /* grant access */ final String grants = access != AccessTypeDto.READ ? grantDefaultWrite : grantDefaultRead; - connection.prepareStatement("GRANT " + grants + " ON *.* TO `" + user.getUsername() + "`@`%`;") + connection.prepareStatement(mariaDbMapper.databaseGrantPrivilegesQuery(user.getUsername(), grants)) .execute(); /* grant query store */ connection.prepareStatement("GRANT EXECUTE ON PROCEDURE `store_query` TO `" + user.getUsername() + "`@`%`;") @@ -54,15 +64,14 @@ public class AccessServiceMariaDbImpl extends HibernateConnector implements Acce } @Override - public void update(PrivilegedDatabaseDto database, PrivilegedUserDto user, AccessTypeDto access) + public void update(PrivilegedDatabaseDto database, UserDto user, AccessTypeDto access) throws DatabaseMalformedException, SQLException { final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); final Connection connection = dataSource.getConnection(); try { /* grant access */ - connection.prepareStatement("GRANT SELECT" + - (access != AccessTypeDto.READ ? "CREATE, CREATE VIEW, CREATE ROUTINE, CREATE TEMPORARY TABLES, LOCK TABLES, INDEX, TRIGGER, INSERT, UPDATE, DELETE" : "") + - " ON *.* TO `" + user.getUsername() + "`@`%`;") + final String grants = access != AccessTypeDto.READ ? grantDefaultWrite : grantDefaultRead; + connection.prepareStatement(mariaDbMapper.databaseGrantPrivilegesQuery(user.getUsername(), grants)) .execute(); /* apply access rights */ connection.prepareStatement("FLUSH PRIVILEGES;"); @@ -78,7 +87,7 @@ public class AccessServiceMariaDbImpl extends HibernateConnector implements Acce } @Override - public void delete(PrivilegedDatabaseDto database, PrivilegedUserDto user) throws DatabaseMalformedException, + public void delete(PrivilegedDatabaseDto database, UserDto user) throws DatabaseMalformedException, SQLException { final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); final Connection connection = dataSource.getConnection(); diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/AnalyseServiceImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/AnalyseServiceImpl.java deleted file mode 100644 index 7b722597c533b39fad6615e5d6fc486ea57235f0..0000000000000000000000000000000000000000 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/AnalyseServiceImpl.java +++ /dev/null @@ -1,30 +0,0 @@ -package at.tuwien.service.impl; - -import at.tuwien.api.database.table.TableStatisticDto; -import at.tuwien.exception.NotAllowedException; -import at.tuwien.exception.RemoteUnavailableException; -import at.tuwien.exception.TableNotFoundException; -import at.tuwien.gateway.AnalyseServiceGateway; -import at.tuwien.service.AnalyseService; -import lombok.extern.log4j.Log4j2; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Log4j2 -@Service -public class AnalyseServiceImpl implements AnalyseService { - - private final AnalyseServiceGateway analyseServiceGateway; - - @Autowired - public AnalyseServiceImpl(AnalyseServiceGateway analyseServiceGateway) { - this.analyseServiceGateway = analyseServiceGateway; - } - - @Override - public TableStatisticDto analyseTable(Long databaseId, Long tableId) throws TableNotFoundException, - NotAllowedException, RemoteUnavailableException { - return analyseServiceGateway.analyseTable(databaseId, tableId); - } - -} diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceMariaDbImpl.java index 7bd233371e5b42ea8085c58ca5cae06b03af4aa7..4ee483ad5e11b4bbc3499e0d98f255e666bec1ea 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceMariaDbImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceMariaDbImpl.java @@ -11,7 +11,6 @@ import at.tuwien.api.user.internal.UpdateUserPasswordDto; import at.tuwien.config.RabbitConfig; import at.tuwien.exception.*; import at.tuwien.mapper.MariaDbMapper; -import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.DatabaseService; import at.tuwien.service.SchemaService; import com.mchange.v2.c3p0.ComboPooledDataSource; @@ -29,10 +28,12 @@ import java.sql.SQLException; public class DatabaseServiceMariaDbImpl extends HibernateConnector implements DatabaseService { private final RabbitConfig rabbitConfig; + private final MariaDbMapper mariaDbMapper; @Autowired - public DatabaseServiceMariaDbImpl(RabbitConfig rabbitConfig) { + public DatabaseServiceMariaDbImpl(RabbitConfig rabbitConfig, MariaDbMapper mariaDbMapper) { this.rabbitConfig = rabbitConfig; + this.mariaDbMapper = mariaDbMapper; } @Override @@ -42,7 +43,7 @@ public class DatabaseServiceMariaDbImpl extends HibernateConnector implements Da final Connection connection = dataSource.getConnection(); try { /* create database if not exists */ - connection.prepareStatement("CREATE DATABASE IF NOT EXISTS `" + data.getInternalName() + "`;") + connection.prepareStatement(mariaDbMapper.databaseCreateDatabaseQuery(data.getInternalName())) .execute(); connection.commit(); } catch (SQLException e) { @@ -76,7 +77,7 @@ public class DatabaseServiceMariaDbImpl extends HibernateConnector implements Da final Connection connection = dataSource.getConnection(); try { /* update user password */ - connection.prepareStatement("SET PASSWORD FOR `" + data.getUsername() + "`@`%` = '" + data.getPassword() + "';") + connection.prepareStatement(mariaDbMapper.databaseSetPasswordQuery(data.getUsername(), data.getPassword())) .execute(); connection.commit(); } catch (SQLException e) { diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SchemaServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SchemaServiceMariaDbImpl.java index c2c53c7830730ce548ea9d16afb66ef4f9bfba22..537c4878a4f44a1b47e39278b3233f03448cf439 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SchemaServiceMariaDbImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SchemaServiceMariaDbImpl.java @@ -100,6 +100,7 @@ public class SchemaServiceMariaDbImpl extends HibernateConnector implements Sche } } table.setTdbid(database.getId()); + database.getCreator().getAttributes().setMariadbPassword(null); table.setCreator(database.getCreator()); table.setCreatedBy(database.getCreator().getId()); final TableDto tmpTable = table; diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SubsetServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SubsetServiceMariaDbImpl.java index 57d7472dde490ae39143ca04fd255454e7c3b724..d298f2fada278f1eba060b030fbcc1040324adc1 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SubsetServiceMariaDbImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SubsetServiceMariaDbImpl.java @@ -84,7 +84,8 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs public QueryResultDto execute(PrivilegedDatabaseDto database, String statement, Instant timestamp, UUID userId, Long page, Long size, SortTypeDto sortDirection, String sortColumn) throws QueryStoreInsertException, SQLException, QueryNotFoundException, TableMalformedException, - UserNotFoundException, NotAllowedException, RemoteUnavailableException { + UserNotFoundException, NotAllowedException, RemoteUnavailableException, ServiceException, + DatabaseNotFoundException { final Long queryId = storeQuery(database, statement, timestamp, userId); final QueryDto query = findById(database, queryId); return reExecute(database, query, page, size, sortDirection, sortColumn); @@ -115,8 +116,8 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs @Override public List<QueryDto> findAll(PrivilegedDatabaseDto database, Boolean filterPersisted) throws SQLException, - QueryNotFoundException, NotAllowedException, RemoteUnavailableException { - final List<IdentifierDto> identifiers = metadataServiceGateway.getIdentifiers(database.getId()); + QueryNotFoundException, RemoteUnavailableException, ServiceException, DatabaseNotFoundException { + final List<IdentifierDto> identifiers = metadataServiceGateway.getIdentifiers(database.getId(), null); final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); final Connection connection = dataSource.getConnection(); try { @@ -148,7 +149,7 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs @Override public ExportResourceDto export(PrivilegedDatabaseDto database, QueryDto query, Instant timestamp, String filename) throws SQLException, QueryMalformedException, SidecarExportException, StorageNotFoundException, - StorageUnavailableException { + StorageUnavailableException, ServiceException, RemoteUnavailableException { final String filePath = s3Config.getS3FilePath() + "/" + filename; final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); final Connection connection = dataSource.getConnection(); @@ -203,7 +204,7 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs @Override public QueryDto findById(PrivilegedDatabaseDto database, Long queryId) throws QueryNotFoundException, SQLException, - NotAllowedException, RemoteUnavailableException, UserNotFoundException { + RemoteUnavailableException, UserNotFoundException, ServiceException, DatabaseNotFoundException { final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); final Connection connection = dataSource.getConnection(); try { @@ -215,7 +216,7 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs } final QueryDto query = mariaDbMapper.resultSetToQueryDto(resultSet); query.setIdentifiers(metadataServiceGateway.getIdentifiers(database.getId(), queryId)); - final UserDto creator = metadataServiceGateway.getUser(query.getCreatedBy()); + final UserDto creator = metadataServiceGateway.getUserById(query.getCreatedBy()); log.debug("retrieved creator from metadata service: creator.id={}, creator.username={}", creator.getId(), creator.getUsername()); query.setCreator(creator); query.setDatabaseId(database.getId()); diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java index 92e369e0afd2d0d24509ab3691cc32d40702de55..55e96c516185699e6c17e8e58ed43de1637da1bf 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java @@ -6,6 +6,7 @@ import at.tuwien.api.database.query.ImportCsvDto; import at.tuwien.api.database.query.QueryResultDto; import at.tuwien.api.database.table.*; import at.tuwien.api.database.table.columns.ColumnDto; +import at.tuwien.api.database.table.columns.ColumnStatisticDto; import at.tuwien.api.database.table.columns.ColumnTypeDto; import at.tuwien.api.database.table.internal.PrivilegedTableDto; import at.tuwien.api.database.table.internal.TableCreateDto; @@ -16,6 +17,7 @@ import at.tuwien.mapper.MariaDbMapper; import at.tuwien.service.SchemaService; import at.tuwien.service.StorageService; import at.tuwien.service.TableService; +import at.tuwien.utils.MariaDbUtil; import com.mchange.v2.c3p0.ComboPooledDataSource; import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.RandomStringUtils; @@ -79,6 +81,33 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table return tables; } + @Override + public TableStatisticDto getStatistics(PrivilegedTableDto table) throws SQLException, TableMalformedException, + QueryMalformedException { + final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase()); + final Connection connection = dataSource.getConnection(); + final TableStatisticDto statistic; + try { + /* obtain statistic */ + final ResultSet resultSet = connection.prepareStatement(mariaDbMapper.tableColumnStatisticsSelectRawQuery(table.getColumns(), table.getInternalName())) + .executeQuery(); + statistic = mariaDbMapper.resultSetToTableStatistic(resultSet); + statistic.setRows(getCount(table, null)); + } catch (SQLException e) { + connection.rollback(); + log.error("Failed to obtain column statistics: {}", e.getMessage()); + throw new TableMalformedException("Failed to obtain column statistics: " + e.getMessage(), e); + } finally { + dataSource.close(); + } + table.getColumns() + .stream() + .filter(column -> !MariaDbUtil.numericDataTypes.contains(column.getColumnType())) + .forEach(column -> statistic.getColumns().put(column.getInternalName(), new ColumnStatisticDto())); + log.info("Obtained column statistics for table: {}", table.getInternalName()); + return statistic; + } + @Override public TableDto find(PrivilegedDatabaseDto database, String tableName) throws TableNotFoundException, SQLException, QueryMalformedException { @@ -114,7 +143,9 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table dataSource.close(); } log.info("Created table with name {}", tableName); - return find(database, tableName); + final TableDto table = find(database, tableName); + table.setName(data.getName()); + return table; } @Override @@ -129,12 +160,12 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table connection.commit(); } catch (SQLException e) { connection.rollback(); - log.error("Failed to delete table and history view: {}", e.getMessage()); - throw new QueryMalformedException("Failed to delete table and history view: " + e.getMessage(), e); + log.error("Failed to delete table: {}", e.getMessage()); + throw new QueryMalformedException("Failed to delete table: " + e.getMessage(), e); } finally { dataSource.close(); } - log.info("Deleted table and history view with name {}", tableName); + log.info("Deleted table with name {}", tableName); } @Override @@ -145,9 +176,9 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table final QueryResultDto queryResult; try { /* find table data */ - final ResultSet resultSet = connection.prepareStatement( - mariaDbMapper.selectDatasetRawQuery(table.getDatabase().getInternalName(), table.getInternalName(), - table.getColumns(), timestamp, size, page)) + final ResultSet resultSet = connection.prepareStatement(mariaDbMapper.selectDatasetRawQuery( + table.getDatabase().getInternalName(), table.getInternalName(), table.getColumns(), + timestamp, size, page)) .executeQuery(); connection.commit(); queryResult = mariaDbMapper.resultListToQueryResultDto(table.getColumns(), resultSet); @@ -159,11 +190,12 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table dataSource.close(); } log.info("Find data from table {}.{}", table.getDatabase().getInternalName(), table.getInternalName()); + queryResult.setId(table.getId()); return queryResult; } @Override - public List<TableHistoryDto> history(PrivilegedTableDto table) throws SQLException, + public List<TableHistoryDto> history(PrivilegedTableDto table, Long size) throws SQLException, TableNotFoundException { final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase()); final Connection connection = dataSource.getConnection(); @@ -171,7 +203,7 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table try { /* find table data */ final ResultSet resultSet = connection.prepareStatement(mariaDbMapper.selectHistoryRawQuery( - table.getDatabase().getInternalName(), table.getInternalName(), 100L)) + table.getDatabase().getInternalName(), table.getInternalName(), size)) .executeQuery(); history = mariaDbMapper.resultSetToTableHistory(resultSet); connection.commit(); @@ -210,48 +242,9 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table return queryResult; } - @Override - public void importTuple(PrivilegedTableDto table, TupleDto data) - throws TableMalformedException, StorageUnavailableException, StorageNotFoundException, SQLException, QueryMalformedException { - /* for each LOB-like data-column, retrieve the bytes and replace the value */ - for (String key : data.getData().keySet()) { - final boolean found = table.getColumns() - .stream() - .filter(c -> List.of(ColumnTypeDto.BLOB, ColumnTypeDto.LONGBLOB, ColumnTypeDto.TINYBLOB, ColumnTypeDto.MEDIUMBLOB).contains(c.getColumnType())) - .anyMatch(c -> c.getInternalName().equals(key)); - if (!found || data.getData().get(key) == null) { - continue; - } - final byte[] blob = storageService.getBytes(String.valueOf(data.getData().get(key))); - log.debug("replaced S3 storage key {} with blob", key); - data.getData().replace(key, blob); - } - final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase()); - final Connection connection = dataSource.getConnection(); - try { - /* import tuple */ - final int[] idx = new int[]{1}; - final PreparedStatement statement = connection.prepareStatement(mariaDbMapper.tupleToRawInsertQuery(table, data)); - for (String column : data.getData().keySet()) { - mariaDbMapper.prepareStatementWithColumnTypeObject(statement, - getColumnType(table.getColumns(), column), idx[0], data.getData().get(column)); - idx[0]++; - } - statement.execute(); - connection.commit(); - } catch (SQLException e) { - connection.rollback(); - log.error("Failed to import tuple: {}", e.getMessage()); - throw new QueryMalformedException("Failed to import tuple: " + e.getMessage(), e); - } finally { - dataSource.close(); - } - log.info("Imported tuple into table: {}.{}", table.getDatabase().getInternalName(), table.getInternalName()); - } - @Override public void importDataset(PrivilegedTableDto table, ImportCsvDto data) - throws SidecarImportException, StorageNotFoundException, SQLException, QueryMalformedException { + throws StorageNotFoundException, SQLException, QueryMalformedException, ServiceException, RemoteUnavailableException { /* import .csv from blob storage to sidecar */ dataDatabaseSidecarGateway.importFile(table.getDatabase().getContainer().getSidecarHost(), table.getDatabase().getContainer().getSidecarPort(), data.getLocation()); /* import .csv from sidecar to database */ @@ -286,7 +279,7 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table final PreparedStatement statement = connection.prepareStatement(mariaDbMapper.tupleToRawDeleteQuery(table, data)); for (String column : data.getKeys().keySet()) { mariaDbMapper.prepareStatementWithColumnTypeObject(statement, - getColumnType(table.getColumns(), column), idx[0], data.getKeys().get(column)); + getColumnType(table.getColumns(), column), idx[0], column, data.getKeys().get(column)); idx[0]++; } statement.executeUpdate(); @@ -303,8 +296,22 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table @Override public void createTuple(PrivilegedTableDto table, TupleDto data) throws SQLException, - QueryMalformedException, TableMalformedException { + QueryMalformedException, TableMalformedException, StorageUnavailableException, StorageNotFoundException { log.trace("create tuple: {}", data); + /* for each LOB-like data-column, retrieve the bytes and replace the value */ + for (String key : data.getData().keySet()) { + final boolean found = table.getColumns() + .stream() + .filter(c -> List.of(ColumnTypeDto.BLOB, ColumnTypeDto.LONGBLOB, ColumnTypeDto.TINYBLOB, ColumnTypeDto.MEDIUMBLOB).contains(c.getColumnType())) + .anyMatch(c -> c.getInternalName().equals(key)); + if (!found || data.getData().get(key) == null) { + continue; + } + final byte[] blob = storageService.getBytes(String.valueOf(data.getData().get(key))); + log.debug("replaced S3 storage key {} with blob", key); + data.getData() + .replace(key, blob); + } /* prepare the statement */ final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase()); final Connection connection = dataSource.getConnection(); @@ -314,7 +321,7 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table final PreparedStatement statement = connection.prepareStatement(mariaDbMapper.tupleToRawCreateQuery(table, data)); for (Map.Entry<String, Object> entry : data.getData().entrySet()) { mariaDbMapper.prepareStatementWithColumnTypeObject(statement, - getColumnType(table.getColumns(), entry.getKey()), idx[0], entry.getValue()); + getColumnType(table.getColumns(), entry.getKey()), idx[0], entry.getKey(), entry.getValue()); idx[0]++; } statement.executeUpdate(); @@ -342,13 +349,13 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table /* set data */ for (Map.Entry<String, Object> entry : data.getData().entrySet()) { mariaDbMapper.prepareStatementWithColumnTypeObject(statement, - getColumnType(table.getColumns(), entry.getKey()), idx[0], entry.getValue()); + getColumnType(table.getColumns(), entry.getKey()), idx[0], entry.getKey(), entry.getValue()); idx[0]++; } /* set key(s) */ for (Map.Entry<String, Object> entry : data.getKeys().entrySet()) { mariaDbMapper.prepareStatementWithColumnTypeObject(statement, - getColumnType(table.getColumns(), entry.getKey()), idx[0], entry.getValue()); + getColumnType(table.getColumns(), entry.getKey()), idx[0], entry.getKey(), entry.getValue()); idx[0]++; } statement.executeUpdate(); @@ -375,9 +382,9 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table } @Override - public ExportResourceDto exportDataset(PrivilegedTableDto table, Instant timestamp) - throws SQLException, SidecarExportException, StorageNotFoundException, StorageUnavailableException, - QueryMalformedException { + public ExportResourceDto exportDataset(PrivilegedTableDto table, Instant timestamp) throws SQLException, + StorageNotFoundException, StorageUnavailableException, QueryMalformedException, ServiceException, + RemoteUnavailableException { final String fileName = RandomStringUtils.randomAlphabetic(40) + ".csv"; final String filePath = s3Config.getS3FilePath() + "/" + fileName; final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase()); diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java index b28e2a1dc4f0e4530b8a4a9235b7cdc4819ee0fe..c85f5bfbdba9ffbe83d512a37f3f5cdebf5e4c1d 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java @@ -16,12 +16,14 @@ import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.SchemaService; import at.tuwien.service.StorageService; import at.tuwien.service.ViewService; +import com.google.common.hash.Hashing; import com.mchange.v2.c3p0.ComboPooledDataSource; import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.RandomStringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.nio.charset.StandardCharsets; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -96,7 +98,11 @@ public class ViewServiceMariaDbImpl extends HibernateConnector implements ViewSe final Connection connection = dataSource.getConnection(); ViewDto view = ViewDto.builder() .name(data.getName()) - .internalName(data.getName()) + .internalName(mariaDbMapper.nameToInternalName(data.getName())) + .query(data.getQuery()) + .queryHash(Hashing.sha256() + .hashString(data.getQuery(), StandardCharsets.UTF_8) + .toString()) .isPublic(database.getIsPublic()) .creator(database.getOwner()) .createdBy(database.getOwner().getId()) @@ -108,12 +114,12 @@ public class ViewServiceMariaDbImpl extends HibernateConnector implements ViewSe .build(); try { /* create view if not exists */ - connection.prepareStatement(mariaDbMapper.viewCreateRawQuery(data.getName(), data.getQuery())) + connection.prepareStatement(mariaDbMapper.viewCreateRawQuery(view.getInternalName(), data.getQuery())) .execute(); /* select view columns */ final PreparedStatement statement2 = connection.prepareStatement(mariaDbMapper.databaseTableColumnsSelectRawQuery()); statement2.setString(1, database.getInternalName()); - statement2.setString(2, data.getName()); + statement2.setString(2, view.getInternalName()); final ResultSet resultSet2 = statement2.executeQuery(); while (resultSet2.next()) { view = mariaDbMapper.resultSetToTable(resultSet2, view, queryConfig); @@ -205,8 +211,8 @@ public class ViewServiceMariaDbImpl extends HibernateConnector implements ViewSe @Override public ExportResourceDto exportDataset(PrivilegedDatabaseDto database, ViewDto view, Instant timestamp) - throws SQLException, QueryMalformedException, SidecarExportException, StorageNotFoundException, - StorageUnavailableException { + throws SQLException, QueryMalformedException, StorageNotFoundException, + StorageUnavailableException, ServiceException, RemoteUnavailableException { final String fileName = RandomStringUtils.randomAlphabetic(40) + ".csv"; final String filePath = s3Config.getS3FilePath() + "/" + fileName; final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/utils/MariaDbUtil.java b/dbrepo-data-service/services/src/main/java/at/tuwien/utils/MariaDbUtil.java index 17847c15c6e6fd33b1ba0d77dff3b17ed10d58ca..a917be6d46899c62e3e166ad0610950c9463bbca 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/utils/MariaDbUtil.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/utils/MariaDbUtil.java @@ -9,16 +9,36 @@ public class MariaDbUtil { /** * https://mariadb.com/kb/en/string-data-types/ */ - final static List<ColumnTypeDto> stringDataTypes = List.of(ColumnTypeDto.BINARY, + final static List<ColumnTypeDto> stringDataTypes = List.of( + ColumnTypeDto.BINARY, + ColumnTypeDto.VARBINARY, + ColumnTypeDto.TINYBLOB, + ColumnTypeDto.MEDIUMBLOB, + ColumnTypeDto.LONGBLOB, ColumnTypeDto.BLOB, ColumnTypeDto.CHAR, + ColumnTypeDto.VARCHAR, ColumnTypeDto.ENUM, - ColumnTypeDto.MEDIUMBLOB, - ColumnTypeDto.LONGBLOB, - ColumnTypeDto.LONGTEXT, - ColumnTypeDto.TEXT, + ColumnTypeDto.SET, ColumnTypeDto.TINYTEXT, - ColumnTypeDto.SET); + ColumnTypeDto.MEDIUMTEXT, + ColumnTypeDto.LONGTEXT, + ColumnTypeDto.TEXT); + + /** + * https://mariadb.com/kb/en/numeric-data-type-overview/ + */ + final public static List<ColumnTypeDto> numericDataTypes = List.of( + ColumnTypeDto.TINYINT, + ColumnTypeDto.BOOL, + ColumnTypeDto.SMALLINT, + ColumnTypeDto.MEDIUMINT, + ColumnTypeDto.INT, + ColumnTypeDto.BIGINT, + ColumnTypeDto.DECIMAL, + ColumnTypeDto.FLOAT, + ColumnTypeDto.DOUBLE, + ColumnTypeDto.BIT); /** * https://mariadb.com/kb/en/date-and-time-data-types/ diff --git a/dbrepo-gateway-service/dbrepo.conf b/dbrepo-gateway-service/dbrepo.conf index 4ea19528f17b17f24761b3fcefd8584faa10239c..f9c0001cebfbba5bbb842984377fb01197617d96 100644 --- a/dbrepo-gateway-service/dbrepo.conf +++ b/dbrepo-gateway-service/dbrepo.conf @@ -101,7 +101,7 @@ server { proxy_read_timeout 90; } - location ~ /api/database/([0-9]+)/table/([0-9]+)/(data|history|export) { + location ~ /api/database/([0-9]+)/table/([0-9]+)/(data|history|export|statistic) { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; diff --git a/dbrepo-metadata-service/Dockerfile b/dbrepo-metadata-service/Dockerfile index b66fad27593c18dc7fad89161a7b7807fb4b21d7..75fe485c16073094c202a476cd55ddf5c6fb84e7 100644 --- a/dbrepo-metadata-service/Dockerfile +++ b/dbrepo-metadata-service/Dockerfile @@ -27,9 +27,11 @@ COPY ./test ./test RUN mvn clean install -DskipTests ###### SECOND STAGE ###### -FROM eclipse-temurin:17-jdk as runtime +FROM amazoncorretto:17-alpine3.19 as runtime MAINTAINER Martin Weise <martin.weise@tuwien.ac.at> +RUN apk add --no-cache curl bash jq + WORKDIR /app USER 65534 diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java index 35edfc6d8410c2eedbad2c9118fcad494cd01f73..337a61a637ea03437f74462c3b1c245e6943999d 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java @@ -76,6 +76,10 @@ public class ViewColumnDto { private UnitDto unit; + @Size(max = 2048) + @Schema(example = "Column comment") + private String description; + @NotNull @JsonProperty("is_public") @Schema(example = "true") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportCsvDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportCsvDto.java index 422b20527f8c0ddb98eefc646d19753f370c0c43..eac536143e1b59efce8617f740334acc74b77f5a 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportCsvDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportCsvDto.java @@ -18,7 +18,7 @@ import lombok.extern.jackson.Jacksonized; @ToString public class ImportCsvDto { - @NotBlank(message = "location is required") + @NotBlank @Schema(example = "file.csv") private String location; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableBriefDto.java index aa566a495c6ea05a5a1d1259f0577ccf37cf1d0c..11f99f48eb7cf29d06a03b7ab8b8fb6930769672 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableBriefDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableBriefDto.java @@ -33,7 +33,6 @@ public class TableBriefDto { @Schema(example = "Air Quality") private String name; - @NotBlank @Schema(example = "Air Quality in Austria") private String description; @@ -49,9 +48,4 @@ public class TableBriefDto { @NotNull private UserBriefDto owner; - - @ToString.Exclude - @JsonIgnore - @NotNull - private List<ColumnBriefDto> columns; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableStatisticDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableStatisticDto.java index bcf744c0b382e2fc1191a53753bf52009e15d545..8d41bcc7ff79ba6a51ea1caabad2fd52686cd4a5 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableStatisticDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableStatisticDto.java @@ -1,6 +1,7 @@ package at.tuwien.api.database.table; import at.tuwien.api.database.table.columns.ColumnStatisticDto; +import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; @@ -16,6 +17,10 @@ import java.util.Map; @ToString public class TableStatisticDto { + @NotNull + @JsonProperty("rows") + private Long rows; + @NotNull private Map<String, ColumnStatisticDto> columns; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnCreateDto.java index 78fb7fb84e5f0f8f171a97cafe63e68f32c47e35..37aa493020845255694d4d0fb0ac5cc7900803f2 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnCreateDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnCreateDto.java @@ -46,6 +46,12 @@ public class ColumnCreateDto { @Schema(example = "true") private Boolean nullAllowed; + @JsonProperty("concept_uri") + private String conceptUri; + + @JsonProperty("unit_uri") + private String unitUri; + @Schema(description = "date format id") private Long dfid; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java index 430bdba2704561274afbeeebcf56679e1ec7a10c..026d5d89b7dbb77a6bf4cd94b60448f8a73bc424 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java @@ -117,12 +117,12 @@ public class ColumnDto { private UnitDto unit; @Size(max = 2048) - @Schema(example = "Formatted as YYYY-MM-dd") + @Schema(example = "Column comment") private String description; @ToString.Exclude @JsonIgnore - private transient TableDto table; + private TableDto table; @ToString.Exclude @JsonIgnore diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyBriefDto.java new file mode 100644 index 0000000000000000000000000000000000000000..58a4d5b2453f617297673891f4a879fb02409f10 --- /dev/null +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyBriefDto.java @@ -0,0 +1,16 @@ +package at.tuwien.api.database.table.constraints.foreign; + +import lombok.*; +import lombok.extern.jackson.Jacksonized; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Jacksonized +@ToString +public class ForeignKeyBriefDto { + + private Long id; +} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyDto.java index 68ee2e56da310d8ab6b4ffa8e154ec6906c05135..1644c95cdcf488425f5ee6fb795bdac432169d6f 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyDto.java @@ -1,5 +1,6 @@ package at.tuwien.api.database.table.constraints.foreign; +import at.tuwien.api.database.table.TableBriefDto; import at.tuwien.api.database.table.TableDto; import at.tuwien.api.database.table.columns.ColumnDto; import com.fasterxml.jackson.annotation.JsonProperty; @@ -23,20 +24,17 @@ public class ForeignKeyDto { @NotNull private String name; - @NotNull - private ColumnDto column; - @NotNull private List<ForeignKeyReferenceDto> references; @NotNull @ToString.Exclude - private TableDto table; + private TableBriefDto table; @NotNull @ToString.Exclude @JsonProperty("referenced_table") - private TableDto referencedTable; + private TableBriefDto referencedTable; @JsonProperty("on_update") private ReferenceTypeDto onUpdate; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyReferenceDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyReferenceDto.java index fb978671bc9a2b8d9f647b5c537762977c628229..111903d9265517e4b532c46a84983843619f0835 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyReferenceDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyReferenceDto.java @@ -1,6 +1,6 @@ package at.tuwien.api.database.table.constraints.foreign; -import at.tuwien.api.database.table.columns.ColumnDto; +import at.tuwien.api.database.table.columns.ColumnBriefDto; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; import lombok.*; @@ -19,14 +19,14 @@ public class ForeignKeyReferenceDto { @NotNull @JsonProperty("foreign_key") - private ForeignKeyDto foreignKey; + private ForeignKeyBriefDto foreignKey; @NotNull @ToString.Exclude - private ColumnDto column; + private ColumnBriefDto column; @NotNull @ToString.Exclude @JsonProperty("referenced_column") - private ColumnDto referencedColumn; + private ColumnBriefDto referencedColumn; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ReferenceTypeDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ReferenceTypeDto.java index ebd2d5688764c85dffa273a88bb05d42ad8a9f28..239b95e7e916a01e596e78e41154d0fdae6e9bf8 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ReferenceTypeDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ReferenceTypeDto.java @@ -27,6 +27,17 @@ public enum ReferenceTypeDto { this.type = type; } + public static ReferenceTypeDto fromType(String type) { + return switch (type) { + case "RESTRICT" -> ReferenceTypeDto.RESTRICT; + case "CASCADE" -> ReferenceTypeDto.CASCADE; + case "SET NULL" -> ReferenceTypeDto.SET_NULL; + case "NO ACTION" -> ReferenceTypeDto.NO_ACTION; + case "SET DEFAULT" -> ReferenceTypeDto.SET_DEFAULT; + default -> null; + }; + } + @Override public String toString() { return this.type; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/primary/PrimaryKeyDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/primary/PrimaryKeyDto.java index 19c25371b2c67204a48728c705d550c8c8feec9e..25ad3f5d175cc8aeb4d07011c2bc9829da7242a6 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/primary/PrimaryKeyDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/primary/PrimaryKeyDto.java @@ -1,7 +1,7 @@ package at.tuwien.api.database.table.constraints.primary; import at.tuwien.api.database.table.TableBriefDto; -import at.tuwien.api.database.table.columns.ColumnDto; +import at.tuwien.api.database.table.columns.ColumnBriefDto; import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; @@ -15,7 +15,7 @@ import lombok.extern.jackson.Jacksonized; @ToString public class PrimaryKeyDto { - private Long pkid; + private Long id; @NotNull @ToString.Exclude @@ -23,5 +23,5 @@ public class PrimaryKeyDto { @NotNull @ToString.Exclude - private ColumnDto column; + private ColumnBriefDto column; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/unique/UniqueDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/unique/UniqueDto.java index 10f97e83904a4af1e6bcbba0d24e4e038edec573..05de53784457602248105e8ccd7a6987db53dd51 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/unique/UniqueDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/unique/UniqueDto.java @@ -21,7 +21,7 @@ import java.util.List; public class UniqueDto { @NotNull - private Long uid; + private Long id; @NotNull private String name; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImage.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImage.java index b315c7e81daf711103ab063ca2b4d9a8b438c1a9..568e16e4749c810ef8eae67872d4b2be9e29ddf3 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImage.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/ContainerImage.java @@ -23,6 +23,9 @@ import java.util.List; @EntityListeners(AuditingEntityListener.class) @EqualsAndHashCode(onlyExplicitlyIncluded = true) @Table(name = "mdb_images", uniqueConstraints = @UniqueConstraint(columnNames = {"name", "version"})) +@NamedQueries({ + @NamedQuery(name = "ContainerImage.findAll", query = "select i from ContainerImage i order by i.id asc") +}) public class ContainerImage { @Id diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKey.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKey.java index 83e0d356561c0ea47f1c6278680571e8c27bf17b..e5a58f5d0d37f14ba812f030b70a81a213e8219f 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKey.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/foreignKey/ForeignKey.java @@ -6,6 +6,7 @@ import org.hibernate.annotations.GenericGenerator; import org.springframework.data.jpa.domain.support.AuditingEntityListener; import jakarta.persistence.*; + import java.util.List; @Data @@ -23,8 +24,8 @@ public class ForeignKey { @EqualsAndHashCode.Include @GeneratedValue(generator = "foreign-key-sequence") @GenericGenerator(name = "foreign-key-sequence", strategy = "increment") - @Column(updatable = false, nullable = false) - private Long fkid; + @Column(name = "fkid", updatable = false, nullable = false) + private Long id; @Column(updatable = false, nullable = false) private String name; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/primaryKey/PrimaryKey.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/primaryKey/PrimaryKey.java index 8a30122286b09361f340b07fb2f4053c9b38a474..c4ccc379c58d88df8bc2ccc0429bd969d0e5c031 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/primaryKey/PrimaryKey.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/primaryKey/PrimaryKey.java @@ -22,8 +22,8 @@ public class PrimaryKey { @EqualsAndHashCode.Include @GeneratedValue(generator = "foreign-key-sequence") @GenericGenerator(name = "foreign-key-sequence", strategy = "increment") - @Column(updatable = false, nullable = false) - private Long pkid; + @Column(name = "pkid", updatable = false, nullable = false) + private Long id; @ToString.Exclude @org.springframework.data.annotation.Transient diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/unique/Unique.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/unique/Unique.java index 269410a8c88f3197db69c706b933ca2667d62911..25ed2eae5d551896b6836cb6bd5c8bdd36724748 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/unique/Unique.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/constraints/unique/Unique.java @@ -25,8 +25,8 @@ public class Unique { @EqualsAndHashCode.Include @GeneratedValue(generator = "constraints-unique-sequence") @GenericGenerator(name = "constraints-unique-sequence", strategy = "increment") - @Column(updatable = false, nullable = false) - private Long uid; + @Column(name = "uid", updatable = false, nullable = false) + private Long id; @Column(updatable = false, nullable = false) private String name; diff --git a/dbrepo-metadata-service/pom.xml b/dbrepo-metadata-service/pom.xml index 2e6651d9cfac0e2e7a20b403886ca18e752da2d6..563373645070c416f257ec69b25354e1d00111c5 100644 --- a/dbrepo-metadata-service/pom.xml +++ b/dbrepo-metadata-service/pom.xml @@ -34,26 +34,6 @@ <email>martin.weise@tuwien.ac.at</email> <organization>TU Wien</organization> </developer> - <developer> - <name>Moritz Staudinger</name> - <email>moritz.staudinger@tuwien.ac.at</email> - <organization>TU Wien</organization> - </developer> - <developer> - <name>Tobias Grantner</name> - <email>tobias.grantner@tuwien.ac.at</email> - <organization>TU Wien</organization> - </developer> - <developer> - <name>Sotirios Tsepelakis</name> - <email>sotirios.tsepelakis@tuwien.ac.at</email> - <organization>TU Wien</organization> - </developer> - <developer> - <name>Geoffrey Karnbach</name> - <email>geoffrey.karnbach@tuwien.ac.at</email> - <organization>TU Wien</organization> - </developer> </developers> <properties> @@ -65,7 +45,7 @@ <commons-io.version>2.15.0</commons-io.version> <commons-validator.version>1.8.0</commons-validator.version> <guava.version>33.0.0-jre</guava.version> - <jacoco.version>0.8.11</jacoco.version> + <jacoco.version>0.8.12</jacoco.version> <jwt.version>4.3.0</jwt.version> <c3p0.version>0.9.5.5</c3p0.version> <c3p0-hibernate.version>6.2.2.Final</c3p0-hibernate.version> @@ -192,6 +172,11 @@ <artifactId>commons-validator</artifactId> <version>${commons-validator.version}</version> </dependency> + <dependency> + <groupId>com.fasterxml.jackson.datatype</groupId> + <artifactId>jackson-datatype-hibernate6</artifactId> + <version>${jackson-datatype.version}</version> + </dependency> <!-- Authentication --> <dependency> <groupId>org.keycloak</groupId> @@ -294,23 +279,6 @@ <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>${jacoco.version}</version> - <configuration> - <excludes> - <exclude>at/tuwien/utils/**/*</exclude> - <exclude>at/tuwien/seeder/**/*</exclude> - <exclude>at/tuwien/mapper/**/*</exclude> - <exclude>at/tuwien/handlers/**/*</exclude> - <exclude>at/tuwien/exception/**/*</exclude> - <exclude>at/tuwien/converters/**/*</exclude> - <exclude>at/tuwien/utils/**/*</exclude> - <exclude>at/tuwien/config/**/*</exclude> - <exclude>at/tuwien/auth/**/*</exclude> - <exclude>at/tuwien/gateway/impl/ApiTemplateInterceptorImpl.class</exclude> - <exclude>**/testcontainers.properties</exclude> - <exclude>**/HibernateConnector.class</exclude> - <exclude>**/DbrepoMetadataServiceApplication.class</exclude> - </excludes> - </configuration> <executions> <execution> <id>default-prepare-agent</id> diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/AccessMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/AccessMapper.java deleted file mode 100644 index 9ce8f74cce350ce44fe4dac3247fed74bc3013e8..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/AccessMapper.java +++ /dev/null @@ -1,14 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.api.database.AccessTypeDto; -import at.tuwien.entities.database.AccessType; -import org.mapstruct.Mapper; - -@Mapper(componentModel = "spring") -public interface AccessMapper { - - AccessTypeDto accessType(AccessType data); - - AccessType accessType(AccessTypeDto data); - -} diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/AuthenticationMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/AuthenticationMapper.java deleted file mode 100644 index 9d00f7e159748aa20dcb4cbf4df067c696f18b1a..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/AuthenticationMapper.java +++ /dev/null @@ -1,19 +0,0 @@ -package at.tuwien.mapper; - -import org.mapstruct.Mapper; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; - -import java.util.Collections; - -@Mapper(componentModel = "spring", uses = {UserMapper.class}) -public interface AuthenticationMapper { - - org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AuthenticationMapper.class); - - default MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() { - final MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter(); - mappingJackson2HttpMessageConverter.setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_FORM_URLENCODED)); - return mappingJackson2HttpMessageConverter; - } -} diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/BannerMessageMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/BannerMessageMapper.java deleted file mode 100644 index 8fd2b7dc51936768af6e2d9410887c15e6f19c1b..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/BannerMessageMapper.java +++ /dev/null @@ -1,24 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.api.maintenance.BannerMessageBriefDto; -import at.tuwien.api.maintenance.BannerMessageCreateDto; -import at.tuwien.api.maintenance.BannerMessageDto; -import at.tuwien.api.maintenance.BannerMessageTypeDto; -import at.tuwien.entities.maintenance.BannerMessage; -import at.tuwien.entities.maintenance.BannerMessageType; -import org.mapstruct.Mapper; - -@Mapper(componentModel = "spring") -public interface BannerMessageMapper { - - org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(BannerMessageMapper.class); - - BannerMessageDto bannerMessageToBannerMessageDto(BannerMessage data); - - BannerMessageBriefDto bannerMessageToBannerMessageBriefDto(BannerMessage data); - - BannerMessage bannerMessageCreateDtoToBannerMessage(BannerMessageCreateDto data); - - BannerMessageType bannerMessageTypeDtoToBannerMessageType(BannerMessageTypeDto data); - -} diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ContainerMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ContainerMapper.java deleted file mode 100644 index 3f6cf3c302488634b02f8ee6999e9f6f5c247258..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ContainerMapper.java +++ /dev/null @@ -1,45 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.api.container.ContainerBriefDto; -import at.tuwien.api.container.ContainerCreateDto; -import at.tuwien.api.container.ContainerDto; -import at.tuwien.entities.container.Container; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Mappings; -import org.mapstruct.Named; - -import java.text.Normalizer; -import java.util.Locale; -import java.util.regex.Pattern; - -@Mapper(componentModel = "spring", uses = {ImageMapper.class, DatabaseMapper.class, UserMapper.class}) -public interface ContainerMapper { - - org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ContainerMapper.class); - - @Mappings({ - @Mapping(target = "internalName", source = "name", qualifiedByName = "internalNameMapping") - }) - Container containerCreateRequestDtoToContainer(ContainerCreateDto data); - - ContainerDto containerToContainerDto(Container data); - - @Mappings({ - @Mapping(target = "id", source = "id") - }) - ContainerBriefDto containerToDatabaseContainerBriefDto(Container data); - - // https://stackoverflow.com/questions/1657193/java-code-library-for-generating-slugs-for-use-in-pretty-urls#answer-1657250 - @Named("internalNameMapping") - default String containerToInternalContainerName(String containerName) { - final Pattern NONLATIN = Pattern.compile("[^\\w-]"); - final Pattern WHITESPACE = Pattern.compile("[\\s]"); - String nowhitespace = WHITESPACE.matcher(containerName).replaceAll("-"); - String normalized = Normalizer.normalize(nowhitespace, Normalizer.Form.NFD); - String slug = NONLATIN.matcher(normalized).replaceAll(""); - final String name = "dbrepo-userdb-" + slug.toLowerCase(Locale.ENGLISH); - log.trace("mapped container name {} to internal name {}", containerName, name); - return name; - } -} diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/DataCiteMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/DataCiteMapper.java deleted file mode 100644 index 749f086fcb573290a0c5213d8e33ea3d4819b9d6..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/DataCiteMapper.java +++ /dev/null @@ -1,133 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.api.datacite.doi.*; -import at.tuwien.entities.database.License; -import at.tuwien.entities.identifier.*; -import at.tuwien.utils.EnumToStringConverter; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.MappingTarget; -import org.mapstruct.Mappings; -import org.springframework.context.annotation.Profile; - -import java.util.LinkedList; -import java.util.List; - -@Profile("doi") -@Mapper(componentModel = "spring", uses = EnumToStringConverter.class) -public interface DataCiteMapper { - - default <T> List<T> list(T t) { - if (t == null) return null; - return List.of(t); - } - - @Mappings({ - @Mapping(target = "titles", source = "."), - @Mapping(target = "publisher", source = "publisher"), - @Mapping(target = "publicationYear", source = "publicationYear"), - @Mapping(target = "publicationMonth", source = "publicationMonth"), - @Mapping(target = "publicationDay", source = "publicationDay"), - @Mapping(target = "language", source = "language"), - @Mapping(target = "creators", source = "creators"), - }) - DataCiteCreateDoi identifierToDataCiteCreateDoi(Identifier identifier); - - default DataCiteCreateDoi identifierToDataCiteCreateDoi(Identifier identifier, String url, String prefix, - DataCiteDoiEvent event) { - return addParametersToCreateDoi( - identifierToDataCiteCreateDoi(identifier), - url, - prefix, - DataCiteDoiTypes.DATASET, - event - ); - } - - DataCiteDoiTitle identifierTitleToDataCiteDoiTitle(IdentifierTitle data); - - default DataCiteDoiTitle.Type titleTypeToDataCiteDoiTitleType(TitleType data) { - if (data == null) { - return null; - } - return switch (data) { - case OTHER -> DataCiteDoiTitle.Type.OTHER; - case TRANSLATED_TITLE -> DataCiteDoiTitle.Type.TRANSLATED_TITLE; - case SUBTITLE -> DataCiteDoiTitle.Type.SUBTITLE; - case ALTERNATIVE_TITLE -> DataCiteDoiTitle.Type.ALTERNATIVE_TITLE; - }; - } - - default List<DataCiteDoiTitle> identifierToDataCiteDoiTitleList(Identifier data) { - if (data.getTitles() == null) { - return new LinkedList<>(); - } - return data.getTitles() - .stream() - .map(this::identifierTitleToDataCiteDoiTitle) - .toList(); - } - - DataCiteCreateDoi addParametersToCreateDoi(@MappingTarget DataCiteCreateDoi target, String url, String prefix, - DataCiteDoiTypes types, DataCiteDoiEvent event); - - @Mappings({ - @Mapping(target = "rights", source = "identifier"), - @Mapping(target = "rightsUri", source = "uri"), - }) - DataCiteDoiRights licenseToDoiRights(License license); - - @Mappings({ - @Mapping(target = "name", expression = "java(data.getLastname() + \", \" + data.getFirstname())"), - @Mapping(target = "givenName", source = "firstname"), - @Mapping(target = "familyName", source = "lastname"), - @Mapping(target = "nameType", expression = "java(nameTypeToDataCiteNameType(data.getNameType()))"), - @Mapping(target = "affiliation", expression = "java(list(creatorToDoiCreatorAffiliation(data)))"), - @Mapping(target = "nameIdentifier", expression = "java(list(creatorToDataCiteDoiCreatorNameIdentifier(data)))"), - }) - DataCiteDoiCreator creatorToDoiCreator(Creator data); - - DataCiteDoiCreatorNameIdentifier creatorToDataCiteDoiCreatorNameIdentifier(Creator data); - - /* keep */ - default String nameIdentifierSchemeTypeToUri(NameIdentifierSchemeType data) { - switch (data) { - case ROR -> { - return "https://ror.org/"; - } - case ORCID -> { - return "https://orcid.org/"; - } - case ISNI -> { - return "https://isni.org/isni/"; - } - case GRID -> { - return "https://www.grid.ac/"; - } - } - return null; - } - - /* keep */ - default DataCiteNameType nameTypeToDataCiteNameType(NameType data) { - if (data == null) { - return null; - } - return DataCiteNameType.valueOf(data.toString()); - } - - @Mappings({ - @Mapping(target = "name", source = "affiliation"), - @Mapping(target = "affiliationIdentifier", source = "affiliationIdentifier"), - @Mapping(target = "affiliationScheme", source = "affiliationIdentifierScheme"), - @Mapping(target = "schemeUri", source = "affiliationIdentifierSchemeUri"), - }) - DataCiteDoiCreatorAffiliation creatorToDoiCreatorAffiliation(Creator data); - - @Mappings({ - @Mapping(target = "relatedIdentifier", source = "value"), - @Mapping(target = "relatedIdentifierType", source = "type"), - @Mapping(target = "relationType", source = "relation"), - }) - DataCiteDoiRelatedIdentifier relatedIdentifierToDoiRelatedIdentifier(RelatedIdentifier relatedIdentifier); -} diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/DatabaseMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/DatabaseMapper.java index c2428f5f2aaa7ffd7eef9f413a6f23e633ed5be2..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/DatabaseMapper.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/DatabaseMapper.java @@ -1,62 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.api.database.*; -import at.tuwien.entities.container.image.ContainerImage; -import at.tuwien.entities.database.*; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Mappings; -import org.mapstruct.Named; - -import java.text.Normalizer; -import java.util.Locale; -import java.util.regex.Pattern; - -@Mapper(componentModel = "spring", uses = {ContainerMapper.class, UserMapper.class, ImageMapper.class, UserMapper.class, - TableMapper.class, IdentifierMapper.class, ViewMapper.class}) -public interface DatabaseMapper { - - org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DatabaseMapper.class); - - /* keep */ - @Named("internalMapping") - default String nameToInternalName(String data) { - if (data == null || data.isEmpty()) { - return data; - } - final Pattern NONLATIN = Pattern.compile("[^\\w-]"); - final Pattern WHITESPACE = Pattern.compile("[\\s]"); - String nowhitespace = WHITESPACE.matcher(data).replaceAll("_"); - String normalized = Normalizer.normalize(nowhitespace, Normalizer.Form.NFD); - String slug = NONLATIN.matcher(normalized).replaceAll(""); - final String name = slug.toLowerCase(Locale.ENGLISH); - log.debug("mapping name {} to internal name {}", data, name); - return name; - } - - /* keep */ - @Named("languageMapping") - LanguageType languageTypeDtoToLanguageType(LanguageTypeDto data); - - @Named("engineMapping") - default String containerImageToEngine(ContainerImage data) { - return data.getName() + ":" + data.getVersion(); - } - - @Mappings({ - @Mapping(target = "created", source = "created", dateFormat = "dd-MM-yyyy HH:mm"), - }) - DatabaseDto databaseToDatabaseDto(Database data); - - @Mappings({ - @Mapping(target = "created", source = "created", dateFormat = "dd-MM-yyyy HH:mm"), - }) - DatabaseBriefDto databaseToDatabaseBriefDto(Database data); - - AccessType accessTypeDtoToAccessType(AccessTypeDto data); - - AccessTypeDto accessTypeToAccessTypeDto(AccessType data); - - DatabaseAccessDto databaseAccessToDatabaseAccessDto(DatabaseAccess data); - -} diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/DocumentMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/DocumentMapper.java deleted file mode 100644 index 9a4fc4840def5978ecd19f6ac5e5aceae168a473..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/DocumentMapper.java +++ /dev/null @@ -1,15 +0,0 @@ -package at.tuwien.mapper; - -import org.mapstruct.Mapper; - -import java.time.Instant; -import java.util.Date; - -@Mapper(componentModel = "spring") -public interface DocumentMapper { - - org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DocumentMapper.class); - - Date instantToDate(Instant data); - -} diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ExternalMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ExternalMapper.java deleted file mode 100644 index 8ab57977706326894c8a152e8b690dd049729fc5..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ExternalMapper.java +++ /dev/null @@ -1,76 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.api.crossref.CrossrefDto; -import at.tuwien.api.orcid.OrcidDto; -import at.tuwien.api.orcid.activities.employments.affiliation.OrcidAffiliationGroupDto; -import at.tuwien.api.orcid.activities.employments.affiliation.group.OrcidEmploymentSummaryDto; -import at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated.OrcidDisambiguatedDto; -import at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated.OrcidDisambiguatedSourceTypeDto; -import at.tuwien.api.ror.RorDto; -import at.tuwien.api.user.external.ExternalMetadataDto; -import at.tuwien.api.user.external.ExternalResultType; -import at.tuwien.api.user.external.affiliation.ExternalAffiliationDto; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Mappings; - -@Mapper(componentModel = "spring", imports = {ExternalResultType.class}) -public interface ExternalMapper { - - - @Mappings({ - @Mapping(target = "givenNames", source = "person.name.givenNames.value"), - @Mapping(target = "familyName", source = "person.name.familyName.value"), - @Mapping(target = "type", expression = "java(ExternalResultType.PERSONAL)"), - @Mapping(target = "affiliations", source = "activitiesSummary.employments.affiliationGroup"), - }) - ExternalMetadataDto orcidDtoToExternalMetadataDto(OrcidDto data); - - @Mappings({ - @Mapping(target = "organizationName", source = "employmentSummary.organization.name"), - @Mapping(target = "ringgoldId", expression = "java(disambiguatedOrganizationToRinggoldId(data.getEmploymentSummary().getOrganization().getDisambiguatedOrganization()))"), - }) - ExternalAffiliationDto orcidEmploymentSummaryDtoToExternalAffiliationDto(OrcidEmploymentSummaryDto data); - - default ExternalAffiliationDto orcidAffiliationGroupDtoToExternalAffiliationDto(OrcidAffiliationGroupDto data) { - if (data == null || data.getSummaries() == null || data.getSummaries().length == 0) { - return null; - } - return ExternalAffiliationDto.builder() - .organizationName(data.getSummaries()[0].getEmploymentSummary().getOrganization().getName()) - .build(); - } - - default Long disambiguatedOrganizationToRinggoldId(OrcidDisambiguatedDto data) { - if (data.getSource().equals(OrcidDisambiguatedSourceTypeDto.RINGGOLD)) { - return Long.parseLong(data.getIdentifier()); - } - return null; - } - - default ExternalMetadataDto rorDtoToExternalMetadataDto(RorDto data) { - return ExternalMetadataDto.builder() - .affiliations(new ExternalAffiliationDto[]{ - ExternalAffiliationDto.builder() - .organizationName(data.getName()) - .build()}) - .type(ExternalResultType.ORGANIZATIONAL) - .build(); - } - - default ExternalMetadataDto crossrefDtoToExternalMetadataDto(CrossrefDto data) { - return ExternalMetadataDto.builder() - .affiliations(new ExternalAffiliationDto[]{ - ExternalAffiliationDto.builder() - .crossrefFunderId(data.getId()) - .organizationName(data.getPrefLabel().getLabel().getLiteralForm().getContent()) - .build()}) - .type(ExternalResultType.ORGANIZATIONAL) - .build(); - } - - @Mappings({ - @Mapping(target = "organizationName", source = "name"), - }) - ExternalAffiliationDto rorDtoToExternalAffiliationDto(RorDto data); -} diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/IdentifierMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/IdentifierMapper.java deleted file mode 100644 index a4b7d28fa334b4ed360818537f9ef64262d56d5e..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/IdentifierMapper.java +++ /dev/null @@ -1,157 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.api.database.LanguageTypeDto; -import at.tuwien.api.database.LicenseDto; -import at.tuwien.api.identifier.*; -import at.tuwien.api.identifier.ld.LdCreatorDto; -import at.tuwien.api.identifier.ld.LdDatasetDto; -import at.tuwien.entities.database.LanguageType; -import at.tuwien.entities.database.License; -import at.tuwien.entities.identifier.*; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Mappings; -import org.mapstruct.Named; - -import java.util.List; -import java.util.Optional; - -@Mapper(componentModel = "spring", uses = {DatabaseMapper.class}) -public interface IdentifierMapper { - - org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(IdentifierMapper.class); - - Identifier identifierDtoToIdentifier(IdentifierDto data); - - @Mappings({ - @Mapping(target = "databaseId", source = "database.id"), - }) - IdentifierDto identifierToIdentifierDto(Identifier data); - - IdentifierBriefDto identifierToIdentifierBriefDto(Identifier data); - - default IdentifierTitle identifierToIdentifierTitle(Identifier data, String lang) { - final Optional<IdentifierTitle> optional = data.getTitles() - .stream() - .filter(t -> lang == null || t.getLanguage().getName().equals(lang)) - .findFirst(); - if (optional.isEmpty()) { - log.warn("no title with language {} found", lang); - return identifierToIdentifierTitle(data, "en"); - } - return optional.get(); - } - - default IdentifierDescription identifierToIdentifierDescription(Identifier data, String lang) { - final Optional<IdentifierDescription> optional = data.getDescriptions() - .stream() - .filter(t -> lang == null || t.getLanguage().getName().equals(lang)) - .findFirst(); - if (optional.isEmpty()) { - log.warn("no description with language {} found", lang); - return identifierToIdentifierDescription(data, "en"); - } - return optional.get(); - } - - @Mappings({ - @Mapping(target = "givenName", source = "firstname"), - @Mapping(target = "familyName", source = "lastname"), - @Mapping(target = "type", expression = "java(data.getNameType().equals(NameType.PERSONAL) ? \"Person\" : \"Organization\")"), - @Mapping(target = "sameAs", source = "nameIdentifier"), - @Mapping(target = "name", source = "creatorName"), - }) - LdCreatorDto creatorToLdCreatorDto(Creator data); - - default LdDatasetDto identifierToLdDatasetDto(Identifier data, String baseUrl) { - return LdDatasetDto.builder() - .context("https://schema.org/") - .type("Dataset") - .name(identifierToIdentifierTitle(data, null) - .getTitle()) - .description(identifierToIdentifierDescription(data, null) - .getDescription()) - .url(identifierToLocationUrl(baseUrl, data)) - .identifier(List.of()) - .creator(data.getCreators() - .stream() - .map(this::creatorToLdCreatorDto) - .toList()) - .citation(identifierToLocationUrl(baseUrl, data)) - .hasPart(List.of()) - .license(data.getLicenses().isEmpty() ? null : data.getLicenses().get(0).getUri()) - .temporalCoverage(null) - .version(data.getCreated()) - .build(); - } - - Identifier identifierCreateDtoToIdentifier(IdentifierCreateDto data); - - Identifier identifierUpdateDtoToIdentifier(IdentifierSaveDto data); - - LanguageType languageTypeDtoToLanguageType(LanguageTypeDto data); - - License licenseDtoToLicense(LicenseDto data); - - IdentifierTitle identifierCreateTitleDtoToIdentifierTitle(IdentifierSaveTitleDto data); - - IdentifierDescription identifierCreateDescriptionDtoToIdentifierDescription(IdentifierSaveDescriptionDto data); - - IdentifierFunder identifierFunderSaveDtoToIdentifierFunder(IdentifierFunderSaveDto data); - - IdentifierSaveDto identifierCreateDtoToIdentifierSaveDto(IdentifierCreateDto data); - - RelatedIdentifierDto relatedIdentifierToRelatedIdentifierDto(RelatedIdentifier data); - - Creator creatorDtoToCreator(CreatorDto data); - - @Mappings({ - @Mapping(target = "nameIdentifierSchemeUri", source = "nameIdentifierScheme", qualifiedByName = "nameSchemaMapper"), - @Mapping(target = "affiliationIdentifierSchemeUri", source = "affiliationIdentifierScheme", qualifiedByName = "affiliationSchemaMapper"), - }) - Creator creatorCreateDtoToCreator(CreatorSaveDto data); - - RelatedIdentifier relatedIdentifierCreateDtoToRelatedIdentifier(RelatedIdentifierSaveDto data); - - IdentifierType identifierTypeDtoToIdentifierType(IdentifierTypeDto data); - - default String identifierToLocationUrl(String baseUrl, Identifier data) { - if (data.getType().equals(IdentifierType.SUBSET)) { - return baseUrl + "/database/" + data.getDatabase().getId() + "/subset/" + data.getQueryId() + "/info?pid=" + data.getId(); - } else if (data.getType().equals(IdentifierType.DATABASE)) { - return baseUrl + "/database/" + data.getDatabase().getId() + "/info?pid=" + data.getId(); - } else if (data.getType().equals(IdentifierType.VIEW)) { - return baseUrl + "/database/" + data.getDatabase().getId() + "/view/" + data.getViewId() + "/info?pid=" + data.getId(); - } else if (data.getType().equals(IdentifierType.TABLE)) { - return baseUrl + "/database/" + data.getDatabase().getId() + "/table/" + data.getTableId() + "/info?pid=" + data.getId(); - } else { - return null; - } - } - - @Named("nameSchemaMapper") - default String nameIdentifierSchemeToNameIdentifierSchemeUri(NameIdentifierSchemeTypeDto data) { - if (data == null) { - return null; - } - return switch (data) { - case ROR -> "https://ror.org/"; - case ORCID -> "https://orcid.org/"; - case GRID -> "https://grid.ac/"; - case ISNI -> "https://grid.ac/institutes/"; - }; - } - - @Named("affiliationSchemaMapper") - default String affiliationIdentifierSchemeTypeToAffiliationIdentifier(AffiliationIdentifierSchemeTypeDto data) { - if (data == null) { - return null; - } - return switch (data) { - case ROR -> "https://ror.org/"; - case GRID -> "https://grid.ac/institutes/"; - case ISNI -> "https://isni.org/"; - }; - } - -} diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ImageMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ImageMapper.java deleted file mode 100644 index 8ea6609f164127a43bf59647f9612758483ed76d..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ImageMapper.java +++ /dev/null @@ -1,26 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.api.container.image.ImageBriefDto; -import at.tuwien.api.container.image.ImageCreateDto; -import at.tuwien.api.container.image.ImageDto; -import at.tuwien.entities.container.image.ContainerImage; -import org.mapstruct.Mapper; - -import java.time.Instant; - -@Mapper(componentModel = "spring") -public interface ImageMapper { - - org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ImageMapper.class); - - ContainerImage createImageDtoToContainerImage(ImageCreateDto data); - - ImageBriefDto containerImageToImageBriefDto(ContainerImage data); - - ImageDto containerImageToImageDto(ContainerImage data); - - default Instant dateToInstant(String date) { - return Instant.parse(date); - } - -} diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/LicenseMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/LicenseMapper.java deleted file mode 100644 index 1124c4239eef2acf4657dab94aa30d5109586a8c..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/LicenseMapper.java +++ /dev/null @@ -1,12 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.api.database.LicenseDto; -import at.tuwien.entities.database.License; -import org.mapstruct.Mapper; - -@Mapper(componentModel = "spring") -public interface LicenseMapper { - - LicenseDto licenseToLicenseDto(License data); - -} diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java index 2df2d893f79f5de9a6a7cf0de47c85b9a7656d8b..1cb8f6d3949704cb18f635f1d90af0829d7c95e6 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java @@ -1,17 +1,432 @@ package at.tuwien.mapper; -import org.mapstruct.Mapper; +import at.tuwien.api.auth.SignupRequestDto; +import at.tuwien.api.container.ContainerBriefDto; +import at.tuwien.api.container.ContainerCreateDto; +import at.tuwien.api.container.ContainerDto; +import at.tuwien.api.container.image.ImageBriefDto; +import at.tuwien.api.container.image.ImageCreateDto; +import at.tuwien.api.container.image.ImageDto; +import at.tuwien.api.crossref.CrossrefDto; +import at.tuwien.api.database.*; +import at.tuwien.api.database.table.TableBriefDto; +import at.tuwien.api.database.table.TableDto; +import at.tuwien.api.database.table.columns.ColumnCreateDto; +import at.tuwien.api.database.table.columns.ColumnDto; +import at.tuwien.api.database.table.columns.concepts.ConceptDto; +import at.tuwien.api.database.table.columns.concepts.ConceptSaveDto; +import at.tuwien.api.database.table.columns.concepts.UnitDto; +import at.tuwien.api.database.table.columns.concepts.UnitSaveDto; +import at.tuwien.api.database.table.constraints.ConstraintsCreateDto; +import at.tuwien.api.database.table.constraints.ConstraintsDto; +import at.tuwien.api.database.table.constraints.foreign.ForeignKeyBriefDto; +import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto; +import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto; +import at.tuwien.api.database.table.constraints.foreign.ReferenceTypeDto; +import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto; +import at.tuwien.api.database.table.constraints.unique.UniqueDto; +import at.tuwien.api.datacite.doi.*; +import at.tuwien.api.identifier.*; +import at.tuwien.api.identifier.ld.LdCreatorDto; +import at.tuwien.api.identifier.ld.LdDatasetDto; +import at.tuwien.api.keycloak.CredentialDto; +import at.tuwien.api.keycloak.CredentialTypeDto; +import at.tuwien.api.keycloak.UpdateCredentialsDto; +import at.tuwien.api.keycloak.UserCreateDto; +import at.tuwien.api.maintenance.BannerMessageBriefDto; +import at.tuwien.api.maintenance.BannerMessageCreateDto; +import at.tuwien.api.maintenance.BannerMessageDto; +import at.tuwien.api.maintenance.BannerMessageTypeDto; +import at.tuwien.api.orcid.OrcidDto; +import at.tuwien.api.orcid.activities.employments.affiliation.OrcidAffiliationGroupDto; +import at.tuwien.api.orcid.activities.employments.affiliation.group.OrcidEmploymentSummaryDto; +import at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated.OrcidDisambiguatedDto; +import at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated.OrcidDisambiguatedSourceTypeDto; +import at.tuwien.api.ror.RorDto; +import at.tuwien.api.semantics.EntityDto; +import at.tuwien.api.semantics.OntologyBriefDto; +import at.tuwien.api.semantics.OntologyCreateDto; +import at.tuwien.api.semantics.OntologyDto; +import at.tuwien.api.user.UserBriefDto; +import at.tuwien.api.user.UserDetailsDto; +import at.tuwien.api.user.UserDto; +import at.tuwien.api.user.external.ExternalMetadataDto; +import at.tuwien.api.user.external.ExternalResultType; +import at.tuwien.api.user.external.affiliation.ExternalAffiliationDto; +import at.tuwien.entities.container.Container; +import at.tuwien.entities.container.image.ContainerImage; +import at.tuwien.entities.database.*; +import at.tuwien.entities.database.table.Table; +import at.tuwien.entities.database.table.columns.TableColumn; +import at.tuwien.entities.database.table.columns.TableColumnConcept; +import at.tuwien.entities.database.table.columns.TableColumnUnit; +import at.tuwien.entities.database.table.constraints.Constraints; +import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKey; +import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKeyReference; +import at.tuwien.entities.database.table.constraints.foreignKey.ReferenceType; +import at.tuwien.entities.database.table.constraints.primaryKey.PrimaryKey; +import at.tuwien.entities.database.table.constraints.unique.Unique; +import at.tuwien.entities.identifier.*; +import at.tuwien.entities.maintenance.BannerMessage; +import at.tuwien.entities.maintenance.BannerMessageType; +import at.tuwien.entities.semantics.Ontology; +import at.tuwien.entities.user.User; +import org.mapstruct.*; +import java.text.Normalizer; import java.time.Instant; import java.time.ZoneId; import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.regex.Pattern; +import java.util.stream.Collectors; - -@Mapper(componentModel = "spring") +@Mapper(componentModel = "spring", imports = {LinkedList.class, ExternalResultType.class}) public interface MetadataMapper { org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MetadataMapper.class); + BannerMessageDto bannerMessageToBannerMessageDto(BannerMessage data); + + BannerMessageBriefDto bannerMessageToBannerMessageBriefDto(BannerMessage data); + + ViewColumn viewColumnDtoToViewColumn(ViewColumnDto data); + + BannerMessage bannerMessageCreateDtoToBannerMessage(BannerMessageCreateDto data); + + BannerMessageType bannerMessageTypeDtoToBannerMessageType(BannerMessageTypeDto data); + + @Mappings({ + @Mapping(target = "internalName", source = "name", qualifiedByName = "internalMapping") + }) + Container containerCreateRequestDtoToContainer(ContainerCreateDto data); + + ContainerDto containerToContainerDto(Container data); + + @Mappings({ + @Mapping(target = "id", source = "id") + }) + ContainerBriefDto containerToDatabaseContainerBriefDto(Container data); + + @Mappings({ + @Mapping(target = "titles", source = "."), + @Mapping(target = "publisher", source = "publisher"), + @Mapping(target = "publicationYear", source = "publicationYear"), + @Mapping(target = "publicationMonth", source = "publicationMonth"), + @Mapping(target = "publicationDay", source = "publicationDay"), + @Mapping(target = "language", source = "language"), + @Mapping(target = "creators", source = "creators"), + }) + DataCiteCreateDoi identifierToDataCiteCreateDoi(Identifier identifier); + + default DataCiteCreateDoi identifierToDataCiteCreateDoi(Identifier identifier, String url, String prefix, + DataCiteDoiEvent event) { + return addParametersToCreateDoi( + identifierToDataCiteCreateDoi(identifier), + url, + prefix, + DataCiteDoiTypes.DATASET, + event + ); + } + + DataCiteDoiTitle identifierTitleToDataCiteDoiTitle(IdentifierTitle data); + + default DataCiteDoiTitle.Type titleTypeToDataCiteDoiTitleType(TitleType data) { + if (data == null) { + return null; + } + return switch (data) { + case OTHER -> DataCiteDoiTitle.Type.OTHER; + case TRANSLATED_TITLE -> DataCiteDoiTitle.Type.TRANSLATED_TITLE; + case SUBTITLE -> DataCiteDoiTitle.Type.SUBTITLE; + case ALTERNATIVE_TITLE -> DataCiteDoiTitle.Type.ALTERNATIVE_TITLE; + }; + } + + default List<DataCiteDoiTitle> identifierToDataCiteDoiTitleList(Identifier data) { + if (data.getTitles() == null) { + return new LinkedList<>(); + } + return data.getTitles() + .stream() + .map(this::identifierTitleToDataCiteDoiTitle) + .toList(); + } + + DataCiteCreateDoi addParametersToCreateDoi(@MappingTarget DataCiteCreateDoi target, String url, String prefix, + DataCiteDoiTypes types, DataCiteDoiEvent event); + + @Mappings({ + @Mapping(target = "rights", source = "identifier"), + @Mapping(target = "rightsUri", source = "uri"), + }) + DataCiteDoiRights licenseToDoiRights(License license); + + default <T> List<T> list(T t) { + if (t == null) return null; + return List.of(t); + } + + @Mappings({ + @Mapping(target = "name", expression = "java(data.getLastname() + \", \" + data.getFirstname())"), + @Mapping(target = "givenName", source = "firstname"), + @Mapping(target = "familyName", source = "lastname"), + @Mapping(target = "nameType", expression = "java(nameTypeToDataCiteNameType(data.getNameType()))"), + @Mapping(target = "affiliation", expression = "java(list(creatorToDoiCreatorAffiliation(data)))"), + @Mapping(target = "nameIdentifier", expression = "java(list(creatorToDataCiteDoiCreatorNameIdentifier(data)))"), + }) + DataCiteDoiCreator creatorToDoiCreator(Creator data); + + DataCiteDoiCreatorNameIdentifier creatorToDataCiteDoiCreatorNameIdentifier(Creator data); + + /* keep */ + default String nameIdentifierSchemeTypeToUri(NameIdentifierSchemeType data) { + switch (data) { + case ROR -> { + return "https://ror.org/"; + } + case ORCID -> { + return "https://orcid.org/"; + } + case ISNI -> { + return "https://isni.org/isni/"; + } + case GRID -> { + return "https://www.grid.ac/"; + } + } + return null; + } + + /* keep */ + default DataCiteNameType nameTypeToDataCiteNameType(NameType data) { + if (data == null) { + return null; + } + return DataCiteNameType.valueOf(data.toString()); + } + + @Mappings({ + @Mapping(target = "name", source = "affiliation"), + @Mapping(target = "affiliationIdentifier", source = "affiliationIdentifier"), + @Mapping(target = "affiliationScheme", source = "affiliationIdentifierScheme"), + @Mapping(target = "schemeUri", source = "affiliationIdentifierSchemeUri"), + }) + DataCiteDoiCreatorAffiliation creatorToDoiCreatorAffiliation(Creator data); + + @Mappings({ + @Mapping(target = "relatedIdentifier", source = "value"), + @Mapping(target = "relatedIdentifierType", source = "type"), + @Mapping(target = "relationType", source = "relation"), + }) + DataCiteDoiRelatedIdentifier relatedIdentifierToDoiRelatedIdentifier(RelatedIdentifier relatedIdentifier); + + Date instantToDate(Instant data); + + @Mappings({ + @Mapping(target = "givenNames", source = "person.name.givenNames.value"), + @Mapping(target = "familyName", source = "person.name.familyName.value"), + @Mapping(target = "type", expression = "java(ExternalResultType.PERSONAL)"), + @Mapping(target = "affiliations", source = "activitiesSummary.employments.affiliationGroup"), + }) + ExternalMetadataDto orcidDtoToExternalMetadataDto(OrcidDto data); + + @Mappings({ + @Mapping(target = "organizationName", source = "employmentSummary.organization.name"), + @Mapping(target = "ringgoldId", expression = "java(disambiguatedOrganizationToRinggoldId(data.getEmploymentSummary().getOrganization().getDisambiguatedOrganization()))"), + }) + ExternalAffiliationDto orcidEmploymentSummaryDtoToExternalAffiliationDto(OrcidEmploymentSummaryDto data); + + default ExternalAffiliationDto orcidAffiliationGroupDtoToExternalAffiliationDto(OrcidAffiliationGroupDto data) { + if (data == null || data.getSummaries() == null || data.getSummaries().length == 0) { + return null; + } + return ExternalAffiliationDto.builder() + .organizationName(data.getSummaries()[0].getEmploymentSummary().getOrganization().getName()) + .build(); + } + + default Long disambiguatedOrganizationToRinggoldId(OrcidDisambiguatedDto data) { + if (data.getSource().equals(OrcidDisambiguatedSourceTypeDto.RINGGOLD)) { + return Long.parseLong(data.getIdentifier()); + } + return null; + } + + default ExternalMetadataDto rorDtoToExternalMetadataDto(RorDto data) { + return ExternalMetadataDto.builder() + .affiliations(new ExternalAffiliationDto[]{ + ExternalAffiliationDto.builder() + .organizationName(data.getName()) + .build()}) + .type(ExternalResultType.ORGANIZATIONAL) + .build(); + } + + default ExternalMetadataDto crossrefDtoToExternalMetadataDto(CrossrefDto data) { + return ExternalMetadataDto.builder() + .affiliations(new ExternalAffiliationDto[]{ + ExternalAffiliationDto.builder() + .crossrefFunderId(data.getId()) + .organizationName(data.getPrefLabel().getLabel().getLiteralForm().getContent()) + .build()}) + .type(ExternalResultType.ORGANIZATIONAL) + .build(); + } + + @Mappings({ + @Mapping(target = "organizationName", source = "name"), + }) + ExternalAffiliationDto rorDtoToExternalAffiliationDto(RorDto data); + + Identifier identifierDtoToIdentifier(IdentifierDto data); + + @Mappings({ + @Mapping(target = "databaseId", source = "database.id"), + }) + IdentifierDto identifierToIdentifierDto(Identifier data); + + IdentifierBriefDto identifierToIdentifierBriefDto(Identifier data); + + default IdentifierTitle identifierToIdentifierTitle(Identifier data, String lang) { + final Optional<IdentifierTitle> optional = data.getTitles() + .stream() + .filter(t -> lang == null || t.getLanguage().getName().equals(lang)) + .findFirst(); + if (optional.isEmpty()) { + log.warn("no title with language {} found", lang); + return identifierToIdentifierTitle(data, "en"); + } + return optional.get(); + } + + default IdentifierDescription identifierToIdentifierDescription(Identifier data, String lang) { + final Optional<IdentifierDescription> optional = data.getDescriptions() + .stream() + .filter(t -> lang == null || t.getLanguage().getName().equals(lang)) + .findFirst(); + if (optional.isEmpty()) { + log.warn("no description with language {} found", lang); + return identifierToIdentifierDescription(data, "en"); + } + return optional.get(); + } + + @Mappings({ + @Mapping(target = "givenName", source = "firstname"), + @Mapping(target = "familyName", source = "lastname"), + @Mapping(target = "type", expression = "java(data.getNameType().equals(NameType.PERSONAL) ? \"Person\" : \"Organization\")"), + @Mapping(target = "sameAs", source = "nameIdentifier"), + @Mapping(target = "name", source = "creatorName"), + }) + LdCreatorDto creatorToLdCreatorDto(Creator data); + + default LdDatasetDto identifierToLdDatasetDto(Identifier data, String baseUrl) { + return LdDatasetDto.builder() + .context("https://schema.org/") + .type("Dataset") + .name(identifierToIdentifierTitle(data, null) + .getTitle()) + .description(identifierToIdentifierDescription(data, null) + .getDescription()) + .url(identifierToLocationUrl(baseUrl, data)) + .identifier(List.of()) + .creator(data.getCreators() + .stream() + .map(this::creatorToLdCreatorDto) + .toList()) + .citation(identifierToLocationUrl(baseUrl, data)) + .hasPart(List.of()) + .license(data.getLicenses().isEmpty() ? null : data.getLicenses().get(0).getUri()) + .temporalCoverage(null) + .version(data.getCreated()) + .build(); + } + + Identifier identifierCreateDtoToIdentifier(IdentifierCreateDto data); + + Identifier identifierUpdateDtoToIdentifier(IdentifierSaveDto data); + + License licenseDtoToLicense(LicenseDto data); + + IdentifierTitle identifierCreateTitleDtoToIdentifierTitle(IdentifierSaveTitleDto data); + + IdentifierDescription identifierCreateDescriptionDtoToIdentifierDescription(IdentifierSaveDescriptionDto data); + + IdentifierFunder identifierFunderSaveDtoToIdentifierFunder(IdentifierFunderSaveDto data); + + IdentifierSaveDto identifierCreateDtoToIdentifierSaveDto(IdentifierCreateDto data); + + RelatedIdentifierDto relatedIdentifierToRelatedIdentifierDto(RelatedIdentifier data); + + Creator creatorDtoToCreator(CreatorDto data); + + NameIdentifierSchemeTypeDto nameIdentifierSchemeTypeToNameIdentifierSchemeTypeDto(NameIdentifierSchemeType data); + + CreatorDto creatorToCreatorDto(Creator data); + + @Mappings({ + @Mapping(target = "nameIdentifierSchemeUri", source = "nameIdentifierScheme", qualifiedByName = "nameSchemaMapper"), + @Mapping(target = "affiliationIdentifierSchemeUri", source = "affiliationIdentifierScheme", qualifiedByName = "affiliationSchemaMapper"), + }) + Creator creatorCreateDtoToCreator(CreatorSaveDto data); + + RelatedIdentifier relatedIdentifierCreateDtoToRelatedIdentifier(RelatedIdentifierSaveDto data); + + IdentifierType identifierTypeDtoToIdentifierType(IdentifierTypeDto data); + + default String identifierToLocationUrl(String baseUrl, Identifier data) { + if (data.getType().equals(IdentifierType.SUBSET)) { + return baseUrl + "/database/" + data.getDatabase().getId() + "/subset/" + data.getQueryId() + "/info?pid=" + data.getId(); + } else if (data.getType().equals(IdentifierType.DATABASE)) { + return baseUrl + "/database/" + data.getDatabase().getId() + "/info?pid=" + data.getId(); + } else if (data.getType().equals(IdentifierType.VIEW)) { + return baseUrl + "/database/" + data.getDatabase().getId() + "/view/" + data.getViewId() + "/info?pid=" + data.getId(); + } else if (data.getType().equals(IdentifierType.TABLE)) { + return baseUrl + "/database/" + data.getDatabase().getId() + "/table/" + data.getTableId() + "/info?pid=" + data.getId(); + } else { + return null; + } + } + + @Named("nameSchemaMapper") + default String nameIdentifierSchemeToNameIdentifierSchemeUri(NameIdentifierSchemeTypeDto data) { + if (data == null) { + return null; + } + return switch (data) { + case ROR -> "https://ror.org/"; + case ORCID -> "https://orcid.org/"; + case GRID -> "https://grid.ac/"; + case ISNI -> "https://grid.ac/institutes/"; + }; + } + + @Named("affiliationSchemaMapper") + default String affiliationIdentifierSchemeTypeToAffiliationIdentifier(AffiliationIdentifierSchemeTypeDto data) { + if (data == null) { + return null; + } + return switch (data) { + case ROR -> "https://ror.org/"; + case GRID -> "https://grid.ac/institutes/"; + case ISNI -> "https://isni.org/"; + }; + } + + ContainerImage createImageDtoToContainerImage(ImageCreateDto data); + + ImageBriefDto containerImageToImageBriefDto(ContainerImage data); + + ImageDto containerImageToImageDto(ContainerImage data); + + default Instant dateToInstant(String date) { + return Instant.parse(date); + } + + LicenseDto licenseToLicenseDto(License data); + default String instantToDatestamp(Instant data) { final String datestamp = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'") .withZone(ZoneId.systemDefault()) @@ -20,4 +435,471 @@ public interface MetadataMapper { return datestamp; } + @Mappings({ + @Mapping(target = "rdf", expression = "java(data.getRdfPath() != null)"), + @Mapping(target = "sparql", expression = "java(data.getSparqlEndpoint() != null)") + }) + OntologyDto ontologyToOntologyDto(Ontology data); + + @Mappings({ + @Mapping(target = "rdf", expression = "java(data.getRdfPath() != null)"), + @Mapping(target = "sparql", expression = "java(data.getSparqlEndpoint() != null)") + }) + OntologyBriefDto ontologyToOntologyBriefDto(Ontology data); + + Ontology ontologyCreateDtoToOntology(OntologyCreateDto data); + + ConceptDto tableColumnConceptToConceptDto(TableColumnConcept data); + + UnitDto tableColumnUnitToUnitDto(TableColumnUnit data); + + TableColumnUnit unitSaveDtoToTableColumnUnit(UnitSaveDto data); + + TableColumnUnit entityDtoToTableColumnUnit(EntityDto data); + + TableColumnConcept entityDtoToTableColumnConcept(EntityDto data); + + TableColumnConcept conceptSaveDtoToTableColumnConcept(ConceptSaveDto data); + + @Mappings({ + @Mapping(target = "databaseId", source = "tdbid"), + }) + TableBriefDto tableToTableBriefDto(Table data); + + default UniqueDto uniqueToUniqueDto(Unique data) { + data.getTable().setOwner(null); /* loop */ + data.getTable().setCreator(null); /* loop */ + return UniqueDto.builder() + .id(data.getId()) + .name(data.getName()) + .columns(data.getColumns() + .stream() + .map(this::tableColumnToColumnDto) + .toList()) + .table(tableToTableBriefDto(data.getTable())) + .build(); + } + + @Mappings({ + @Mapping(target = "table.owner", ignore = true), + @Mapping(target = "referencedTable.owner", ignore = true), + }) + ForeignKeyDto foreignKeyToForeignKeyDto(ForeignKey data); + + ForeignKeyBriefDto foreignKeyDtoToForeignKeyBriefDto(ForeignKeyDto data); + + default ConstraintsDto constraintsToConstraintsDto(Constraints data) { + if (data == null) { + return null; + } + return ConstraintsDto.builder() + .checks(data.getChecks()) + .uniques(data.getUniques() + .stream() + .map(this::uniqueToUniqueDto) + .toList()) + .foreignKeys(data.getForeignKeys() + .stream() + .map(this::foreignKeyToForeignKeyDto) + .toList()) + .primaryKey(data.getPrimaryKey() + .stream() + .map(this::primaryKeyToPrimaryKeyDto) + .collect(Collectors.toSet())) + .build(); + } + + default TableDto customTableToTableDto(Table data) { + final TableDto table = TableDto.builder() + .id(data.getId()) + .name(data.getName()) + .internalName(data.getInternalName()) + .owner(userToUserDto(data.getOwner())) + .createdBy(data.getCreatedBy()) + .creator(userToUserDto(data.getCreator())) + .tdbid(data.getTdbid()) + .routingKey("dbrepo." + data.getTdbid() + "." + data.getId()) + .queueName(data.getQueueName()) + .isPublic(data.getDatabase().getIsPublic()) + .isVersioned(true) + .avgRowLength(data.getAvgRowLength()) + .maxDataLength(data.getMaxDataLength()) + .dataLength(data.getDataLength()) + .numRows(data.getNumRows()) + .description(data.getDescription()) + .identifiers(new LinkedList<>()) + .columns(new LinkedList<>()) + .created(data.getCreated()) + .constraints(constraintsToConstraintsDto(data.getConstraints())) + .build(); + table.getConstraints() + .getPrimaryKey() + .forEach(pk -> { + pk.getTable().setDatabaseId(data.getDatabase().getId()); + pk.getColumn().setTableId(data.getId()); + pk.getColumn().setDatabaseId(data.getDatabase().getId()); + }); + for (ForeignKeyDto fk : table.getConstraints().getForeignKeys()) { + for (ForeignKeyReferenceDto ref : fk.getReferences()) { + ref.setForeignKey(foreignKeyDtoToForeignKeyBriefDto(fk)); + ref.getColumn().setTableId(table.getId()); + ref.getColumn().setDatabaseId(table.getTdbid()); + final Optional<TableColumn> optional = data.getDatabase().getTables().stream().map(Table::getColumns).flatMap(List::stream).filter(c -> c.getId().equals(ref.getReferencedColumn().getId())).findFirst(); + if (optional.isEmpty()) { + log.error("Failed to find foreign key referenced column {}.{} in columns: {}", table.getInternalName(), ref.getReferencedColumn().getInternalName(), data.getDatabase().getTables().stream().map(Table::getColumns).flatMap(List::stream).toList()); + throw new IllegalArgumentException("Failed to find foreign key referenced column"); + } + ref.getReferencedColumn().setTableId(optional.get().getTable().getId()); + ref.getReferencedColumn().setDatabaseId(optional.get().getTable().getTdbid()); + } + } + table.getConstraints() + .getUniques() + .forEach(uk -> { + uk.getTable().setDatabaseId(data.getDatabase().getId()); + uk.getColumns() + .forEach(column -> { + column.setTableId(data.getId()); + column.setDatabaseId(data.getDatabase().getId()); + }); + }); + if (data.getIdentifiers() != null) { + table.setIdentifiers(new LinkedList<>(data.getIdentifiers() + .stream() + .map(this::identifierToIdentifierDto) + .toList())); + } + if (data.getColumns() != null) { + table.setColumns(new LinkedList<>(data.getColumns() + .stream() + .map(this::tableColumnToColumnDto) + .toList())); + } + return table; + } + + @Mappings({ + @Mapping(target = "foreignKey", ignore = true), + }) + ForeignKeyReferenceDto foreignKeyReferenceToForeignKeyReferenceDto(ForeignKeyReference foreignKeyReference); + + @Mappings({ + @Mapping(target = "table", ignore = true) + }) + TableColumn columnDtoToTableColumn(ColumnDto columnDto); + + @Mappings({ + @Mapping(target = "table", ignore = true) + }) + Unique uniqueDtoToUnique(UniqueDto data); + + @Mappings({ + @Mapping(target = "ownedBy", source = "owner.id"), + }) + Table tableDtoToTable(TableDto data); + + @Mappings({ + @Mapping(target = "table.owner", ignore = true) + }) + PrimaryKeyDto primaryKeyToPrimaryKeyDto(PrimaryKey data); + + ReferenceType referenceTypeDtoToReferenceType(ReferenceTypeDto data); + + /* keep */ + default Constraints constraintsCreateDtoToConstraints(ConstraintsCreateDto data, Database database, Table table) { + final int[] idx = new int[]{0, 0}; + final Constraints constrains = Constraints.builder() + .checks(data.getChecks()) + .uniques(data.getUniques() + .stream() + .map(uniqueList -> Unique.builder() + .name("uk_" + table.getInternalName() + "_" + idx[0]++) + .table(table) + .columns(table.getColumns() + .stream() + .filter(ukColumn -> uniqueList.stream().map(this::nameToInternalName).toList().contains(nameToInternalName(ukColumn.getInternalName()))) + .toList()) + .build()) + .toList()) + .foreignKeys(data.getForeignKeys() + .stream() + .map(fk -> { + final Optional<Table> optional = database.getTables() + .stream() + .filter(t -> t.getInternalName().equals(fk.getReferencedTable())) + .findFirst(); + if (optional.isEmpty()) { + log.error("Failed to find foreign key referenced table {} in tables: {}", fk.getReferencedTable(), database.getTables().stream().map(Table::getInternalName).toList()); + throw new IllegalArgumentException("Failed to find foreign key referenced table"); + } + final List<ForeignKeyReference> references = new LinkedList<>(); + for (int i = 0; i < fk.getColumns().size(); i++) { + final int k = i; + final Optional<TableColumn> column = table.getColumns() + .stream() + .filter(cc -> cc.getInternalName().equals(fk.getColumns().get(k))) + .findFirst(); + if (column.isEmpty()) { + log.error("Failed to find foreign key column {}.{} in columns: {}", table.getInternalName(), fk.getColumns().get(k), optional.get().getColumns().stream().map(TableColumn::getInternalName).toList()); + throw new IllegalArgumentException("Failed to find foreign key column"); + } + final Optional<TableColumn> referencedColumn = optional.get() + .getColumns() + .stream() + .filter(cc -> cc.getInternalName().equals(fk.getReferencedColumns().get(k))) + .findFirst(); + if (referencedColumn.isEmpty()) { + log.error("Failed to find foreign key referenced column {} in referenced columns: {}", fk.getReferencedColumns().get(k), database.getTables().stream().filter(t -> t.getInternalName().equals(fk.getReferencedTable())).map(Table::getColumns).flatMap(List::stream).map(TableColumn::getInternalName).toList()); + throw new IllegalArgumentException("Failed to find foreign key referenced column"); + } + references.add(ForeignKeyReference.builder() + .column(column.get()) + .referencedColumn(referencedColumn.get()) + .foreignKey(null) // set at the end + .build()); + } + return ForeignKey.builder() + .name("fk_" + table.getInternalName() + "_" + idx[1]++) + .table(table) + .referencedTable(optional.get()) + .references(references) + .onDelete(referenceTypeDtoToReferenceType(fk.getOnDelete())) + .onUpdate(referenceTypeDtoToReferenceType(fk.getOnUpdate())) + .build(); + }) + .toList()) + .primaryKey(data.getPrimaryKey() + .stream() + .map(pk -> { + final Optional<TableColumn> optional = table.getColumns() + .stream() + .filter(c -> c.getInternalName().equals(nameToInternalName(pk))) + .findFirst(); + if (optional.isEmpty()) { + log.error("Failed to find primary key column '{}' in columns: {}", pk, table.getColumns().stream().map(TableColumn::getInternalName).toList()); + throw new IllegalArgumentException("Failed to find primary key column"); + } + return PrimaryKey.builder() + .table(table) + .column(optional.get()) + .build(); + }) + .toList()) + .build(); + constrains.getForeignKeys() + .forEach(fk -> fk.getReferences() + .forEach(r -> r.setForeignKey(fk))); + return constrains; + } + + /* keep */ + @Mappings({ + @Mapping(target = "tableId", source = "table.id"), + @Mapping(target = "databaseId", source = "table.database.id"), + @Mapping(target = "isPublic", source = "table.database.isPublic"), + @Mapping(target = "description", source = "description"), + @Mapping(target = "table", ignore = true), + @Mapping(target = "views", ignore = true) + }) + ColumnDto tableColumnToColumnDto(TableColumn data); + + @Mappings({ + @Mapping(target = "id", expression = "java(null)"), + @Mapping(target = "columnType", source = "data.type"), + @Mapping(target = "isNullAllowed", source = "data.nullAllowed"), + @Mapping(target = "name", source = "data.name"), + @Mapping(target = "autoGenerated", expression = "java(false)"), + @Mapping(target = "internalName", expression = "java(nameToInternalName(data.getName()))"), + }) + TableColumn columnCreateDtoToTableColumn(ColumnCreateDto data, ContainerImage image); + + default UpdateCredentialsDto passwordToUpdateCredentialsDto(String password) { + return UpdateCredentialsDto.builder() + .credentials(List.of(CredentialDto.builder() + .temporary(false) + .type(CredentialTypeDto.PASSWORD) + .value(password) + .build())) + .build(); + } + + default UserCreateDto signupRequestDtoToUserCreateDto(SignupRequestDto data) { + return UserCreateDto.builder() + .username(data.getUsername()) + .email(data.getEmail()) + .credentials(List.of(CredentialDto.builder() + .type(CredentialTypeDto.PASSWORD) + .temporary(false) + .value(data.getPassword()) + .build())) + .enabled(true) + .build(); + } + + /* keep */ + UserBriefDto keycloakUserDtoToUserBriefDto(at.tuwien.api.keycloak.UserDto data); + + /* keep */ + @Mappings({ + @Mapping(target = "id", expression = "java(data.getId().toString())") + }) + UserDetailsDto userDtoToUserDetailsDto(UserDto data); + + /* keep */ + @Mappings({ + @Mapping(target = "name", expression = "java(userToFullName(data))"), + @Mapping(target = "qualifiedName", expression = "java(userToQualifiedName(data))"), + }) + UserBriefDto userToUserBriefDto(User data); + + UserBriefDto userDtoToUserBriefDto(UserDto data); + + /* keep */ + @Mappings({ + @Mapping(target = "attributes.language", source = "language"), + @Mapping(target = "attributes.orcid", source = "orcid"), + @Mapping(target = "attributes.affiliation", source = "affiliation"), + @Mapping(target = "attributes.theme", source = "theme"), + @Mapping(target = "name", expression = "java(userToFullName(data))"), + @Mapping(target = "qualifiedName", expression = "java(userToQualifiedName(data))"), + }) + UserDto userToUserDto(User data); + + /* keep */ + User userDtoToUserDto(UserDto data); + + /* keep */ + @Named("userToFullName") + default String userToFullName(User data) { + final StringBuilder name = new StringBuilder(); + if (data.getFirstname() != null) { + name.append(data.getFirstname()); + } + if (data.getLastname() != null) { + name.append(!name.isEmpty() ? " " : null) + .append(data.getLastname()); + } + return name.isEmpty() ? null : name.toString() + .trim(); + } + + /* keep */ + @Named("userToQualifiedName") + default String userToQualifiedName(User data) { + final String fullname = userToFullName(data); + final StringBuilder name = new StringBuilder(); + if (fullname != null) { + name.append(fullname); + } + if (!name.isEmpty()) { + name.append(" — "); + } + name.append("@") + .append(data.getUsername()); + return name.toString() + .trim(); + } + + @Mappings({ + @Mapping(target = "database.views", ignore = true) + }) + ViewDto viewToViewDto(View data); + + @Mappings({ + @Mapping(target = "databaseId", source = "view.vdbid"), + @Mapping(target = "isPublic", source = "view.isPublic") + }) + ViewColumnDto viewColumnToViewColumnDto(ViewColumn data); + + ViewBriefDto viewToViewBriefDto(View data); + + @Mappings({ + @Mapping(target = "createdBy", source = "creator.id"), + }) + View viewDtoToView(ViewDto data); + + /* keep */ + @Named("internalMapping") + default String nameToInternalName(String data) { + if (data == null || data.isEmpty()) { + return data; + } + final Pattern NONLATIN = Pattern.compile("[^\\w-]"); + final Pattern WHITESPACE = Pattern.compile("[\\s]"); + String nowhitespace = WHITESPACE.matcher(data).replaceAll("_"); + String normalized = Normalizer.normalize(nowhitespace, Normalizer.Form.NFD); + String slug = NONLATIN.matcher(normalized).replaceAll(""); + final String name = slug.toLowerCase(Locale.ENGLISH); + log.debug("mapping name {} to internal name {}", data, name); + return name; + } + + LanguageType languageTypeDtoToLanguageType(LanguageTypeDto data); + + default DatabaseDto customDatabaseToDatabaseDto(Database data) { + if (data == null) { + return null; + } + final DatabaseDto database = DatabaseDto.builder() + .id(data.getId()) + .name(data.getName()) + .internalName(data.getInternalName()) + .description(data.getDescription()) + .exchangeName(data.getExchangeName()) + .image(data.getImage()) + .isPublic(data.getIsPublic()) + .container(containerToContainerDto(data.getContainer())) + .creator(userToUserDto(data.getCreator())) + .owner(userToUserDto(data.getOwner())) + .created(data.getCreated()) + .contact(userToUserDto(data.getContact())) + .subsets(new LinkedList<>()) + .accesses(new LinkedList<>()) + .tables(new LinkedList<>()) + .identifiers(new LinkedList<>()) + .build(); + if (data.getSubsets() != null) { + database.setSubsets(new LinkedList<>(data.getSubsets() + .stream() + .map(this::identifierToIdentifierDto) + .toList())); + } + if (data.getTables() != null) { + database.setTables(new LinkedList<>(data.getTables() + .stream() + .map(this::customTableToTableDto) + .toList())); + } + if (data.getViews() != null) { + database.setViews(new LinkedList<>(data.getViews() + .stream() + .map(this::viewToViewDto) + .toList())); + } + if (data.getAccesses() != null) { + database.setAccesses(new LinkedList<>(data.getAccesses() + .stream() + .map(this::databaseAccessToDatabaseAccessDto) + .toList())); + } + if (data.getIdentifiers() != null) { + database.setIdentifiers(new LinkedList<>(data.getIdentifiers() + .stream() + .map(this::identifierToIdentifierDto) + .toList())); + } + return database; + } + + @Mappings({ + @Mapping(target = "created", source = "created", dateFormat = "dd-MM-yyyy HH:mm"), + }) + DatabaseBriefDto databaseToDatabaseBriefDto(Database data); + + AccessType accessTypeDtoToAccessType(AccessTypeDto data); + + AccessTypeDto accessTypeToAccessTypeDto(AccessType data); + + DatabaseAccessDto databaseAccessToDatabaseAccessDto(DatabaseAccess data); + } diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/SemanticMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/SemanticMapper.java deleted file mode 100644 index 95c56e0a5c53be6d910b33a637de29ec43da5a32..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/SemanticMapper.java +++ /dev/null @@ -1,18 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.api.database.table.columns.concepts.ConceptDto; -import at.tuwien.api.database.table.columns.concepts.UnitDto; -import at.tuwien.entities.database.table.columns.TableColumnConcept; -import at.tuwien.entities.database.table.columns.TableColumnUnit; -import org.mapstruct.Mapper; - - -@Mapper(componentModel = "spring", uses = {TableMapper.class}) -public interface SemanticMapper { - - org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SemanticMapper.class); - - ConceptDto tableColumnConceptToConceptDto(TableColumnConcept data); - - UnitDto tableColumnUnitToUnitDto(TableColumnUnit data); -} diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/OntologyMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/SparqlMapper.java similarity index 66% rename from dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/OntologyMapper.java rename to dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/SparqlMapper.java index afb3265fdf58497cd67a102a8aac15dc472d28ec..dff867970fa59c9d0ddd5c0b7ed60750dd508e3b 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/OntologyMapper.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/SparqlMapper.java @@ -1,53 +1,15 @@ package at.tuwien.mapper; -import at.tuwien.api.database.table.columns.concepts.ConceptDto; -import at.tuwien.api.database.table.columns.concepts.ConceptSaveDto; -import at.tuwien.api.database.table.columns.concepts.UnitDto; -import at.tuwien.api.database.table.columns.concepts.UnitSaveDto; -import at.tuwien.api.semantics.EntityDto; -import at.tuwien.api.semantics.OntologyBriefDto; -import at.tuwien.api.semantics.OntologyCreateDto; -import at.tuwien.api.semantics.OntologyDto; -import at.tuwien.entities.database.table.columns.TableColumnConcept; -import at.tuwien.entities.database.table.columns.TableColumnUnit; import at.tuwien.entities.semantics.Ontology; import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Mappings; import java.util.List; @Mapper(componentModel = "spring") -public interface OntologyMapper { +public interface SparqlMapper { - org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(OntologyMapper.class); - - @Mappings({ - @Mapping(target = "rdf", expression = "java(data.getRdfPath() != null)"), - @Mapping(target = "sparql", expression = "java(data.getSparqlEndpoint() != null)") - }) - OntologyDto ontologyToOntologyDto(Ontology data); - - @Mappings({ - @Mapping(target = "rdf", expression = "java(data.getRdfPath() != null)"), - @Mapping(target = "sparql", expression = "java(data.getSparqlEndpoint() != null)") - }) - OntologyBriefDto ontologyToOntologyBriefDto(Ontology data); - - Ontology ontologyCreateDtoToOntology(OntologyCreateDto data); - - ConceptDto tableColumnConceptToConceptDto(TableColumnConcept data); - - UnitDto tableColumnUnitToUnitDto(TableColumnUnit data); - - TableColumnUnit unitSaveDtoToTableColumnUnit(UnitSaveDto data); - - TableColumnUnit entityDtoToTableColumnUnit(EntityDto data); - - TableColumnConcept entityDtoToTableColumnConcept(EntityDto data); - - TableColumnConcept conceptSaveDtoToTableColumnConcept(ConceptSaveDto data); + org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SparqlMapper.class); default String defaultNamespaces(List<Ontology> data) { return String.join("\n", diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/TableMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/TableMapper.java deleted file mode 100644 index a63bc5c9459270a0c20df9e57387c91e267d5fb1..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/TableMapper.java +++ /dev/null @@ -1,213 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.api.database.table.TableBriefDto; -import at.tuwien.api.database.table.TableDto; -import at.tuwien.api.database.table.columns.ColumnCreateDto; -import at.tuwien.api.database.table.columns.ColumnDto; -import at.tuwien.api.database.table.constraints.ConstraintsCreateDto; -import at.tuwien.api.database.table.constraints.ConstraintsDto; -import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto; -import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto; -import at.tuwien.api.database.table.constraints.unique.UniqueDto; -import at.tuwien.entities.container.image.ContainerImage; -import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.table.Table; -import at.tuwien.entities.database.table.columns.TableColumn; -import at.tuwien.entities.database.table.constraints.Constraints; -import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKey; -import at.tuwien.entities.database.table.constraints.foreignKey.ForeignKeyReference; -import at.tuwien.entities.database.table.constraints.foreignKey.ReferenceType; -import at.tuwien.entities.database.table.constraints.primaryKey.PrimaryKey; -import at.tuwien.entities.database.table.constraints.unique.Unique; -import org.mapstruct.*; - -import java.text.Normalizer; -import java.util.*; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -@Mapper(componentModel = "spring", uses = {IdentifierMapper.class, UserMapper.class}, imports = {Collectors.class, LinkedList.class}) -public interface TableMapper { - - org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TableMapper.class); - - @Mappings({ - @Mapping(source = "id", target = "id"), - @Mapping(target = "name", expression = "java(data.getName())"), - @Mapping(target = "internalName", expression = "java(data.getInternalName())") - }) - TableBriefDto tableToTableBriefDto(Table data); - - TableBriefDto tableDtoToTableBriefDto(TableDto data); - - /* keep */ - default UniqueDto uniqueToUniqueDto(Unique data) { - return UniqueDto.builder() - .uid(data.getUid()) - .name("uk") - .columns(data.getColumns().stream().map(this::tableColumnToColumnDto).toList()) - .table(tableToTableBriefDto(data.getTable())) - .build(); - } - - @Mappings({ - @Mapping(target = "name", expression = "java(data.getName())"), - @Mapping(target = "internalName", expression = "java(data.getInternalName())"), - @Mapping(target = "queueName", expression = "java(data.getQueueName())"), - @Mapping(target = "routingKey", expression = "java(\"dbrepo.\" + data.getTdbid() + \".\" + data.getId())"), - @Mapping(target = "isPublic", source = "database.isPublic"), - }) - TableDto tableToTableDto(Table data); - - @Mappings({ - @Mapping(target = "table", ignore = true), - @Mapping(target = "referencedTable", ignore = true), - }) - ForeignKeyDto foreignKeyToForeignKeyDto(ForeignKey foreignKey); - - @Mappings({ - @Mapping(target = "foreignKey", ignore = true), - }) - ForeignKeyReferenceDto foreignKeyReferenceToForeignKeyReferenceDto(ForeignKeyReference foreignKeyReference); - - @Mappings({ - @Mapping(target = "table", ignore = true) - }) - TableColumn columnDtoToTableColumn(ColumnDto columnDto); - - @Mappings({ - @Mapping(target = "table", ignore = true) - }) - Unique uniqueDtoToUnique(UniqueDto data); - - @Mappings({ - @Mapping(target = "constraints.primaryKey", expression = "java(new LinkedList<>())"), - @Mapping(target = "ownedBy", source = "owner.id"), - }) - Table tableDtoToTable(TableDto data); - - /* keep */ - default Constraints constraintsCreateDtoToConstraints(ConstraintsCreateDto data, Database database, Table table) { - final int[] idx = new int[]{0, 0}; - final Constraints constrains = Constraints.builder() - .checks(data.getChecks()) - .uniques(data.getUniques() - .stream() - .map(uniqueList -> Unique.builder() - .name("uk_" + table.getInternalName() + "_" + idx[0]++) - .table(table) - .columns(table.getColumns() - .stream() - .filter(ukColumn -> uniqueList.stream().map(this::nameToInternalName).toList().contains(nameToInternalName(ukColumn.getInternalName()))) - .toList()) - .build()) - .toList()) - .foreignKeys(data.getForeignKeys() - .stream() - .map(fk -> { - final Optional<Table> optional = database.getTables() - .stream() - .filter(t -> t.getInternalName().equals(fk.getReferencedTable())) - .findFirst(); - if (optional.isEmpty()) { - log.error("Failed to find foreign key referenced table {} in tables: {}", fk.getReferencedTable(), database.getTables().stream().map(Table::getInternalName).toList()); - throw new IllegalArgumentException("Failed to find foreign key referenced table"); - } - return ForeignKey.builder() - .name("fk_" + table.getInternalName() + "_" + idx[1]++) - .referencedTable(optional.get()) - .references(fk.getReferencedColumns() - .stream() - .map(c -> { - final Optional<TableColumn> column = table.getColumns() - .stream() - .filter(cc -> cc.getInternalName().equals(c)) - .findFirst(); - if (column.isEmpty()) { - log.error("Failed to find foreign key column {} in columns: {}", c, table.getColumns().stream().map(TableColumn::getInternalName).toList()); - throw new IllegalArgumentException("Failed to find foreign key column"); - } - final Optional<TableColumn> referencedColumn = database.getTables() - .stream() - .filter(t -> t.getInternalName().equals(fk.getReferencedTable())) - .map(Table::getColumns) - .flatMap(List::stream) - .filter(cc -> cc.getInternalName().equals(c)) - .findFirst(); - if (referencedColumn.isEmpty()) { - log.error("Failed to find foreign key referenced column {} in referenced columns: {}", c, database.getTables().stream().filter(t -> t.getInternalName().equals(fk.getReferencedTable())).map(Table::getColumns).flatMap(List::stream).map(TableColumn::getInternalName).toList()); - throw new IllegalArgumentException("Failed to find foreign key referenced column"); - } - return ForeignKeyReference.builder() - .column(column.get()) - .referencedColumn(referencedColumn.get()) - .foreignKey(null) // set later - .build(); - }) - .toList()) - .onDelete(ReferenceType.CASCADE) - .onUpdate(ReferenceType.CASCADE) - .build(); - }) - .toList()) - .primaryKey(data.getPrimaryKey() - .stream() - .map(pk -> { - final Optional<TableColumn> optional = table.getColumns() - .stream() - .filter(c -> c.getInternalName().equals(nameToInternalName(pk))) - .findFirst(); - if (optional.isEmpty()) { - log.error("Failed to find primary key column '{}' in columns: {}", pk, table.getColumns().stream().map(TableColumn::getInternalName).toList()); - throw new IllegalArgumentException("Failed to find primary key column"); - } - return PrimaryKey.builder() - .table(table) - .column(optional.get()) - .build(); - }) - .toList()) - .build(); - constrains.getForeignKeys() - .forEach(fk -> fk.getReferences() - .forEach(r -> r.setForeignKey(fk))); - return constrains; - } - - /* keep */ - @Mappings({ - @Mapping(target = "tableId", source = "table.id"), - @Mapping(target = "databaseId", source = "table.database.id"), - @Mapping(target = "isPublic", source = "table.database.isPublic"), - @Mapping(target = "description", source = "description"), - @Mapping(target = "table.columns", ignore = true), - @Mapping(target = "table.constraints", ignore = true), - @Mapping(target = "views", ignore = true) - }) - ColumnDto tableColumnToColumnDto(TableColumn data); - - @Named("internalMapping") - default String nameToInternalName(String data) { - if (data == null || data.isEmpty()) { - return data; - } - final Pattern NONLATIN = Pattern.compile("[^\\w-]"); - final Pattern WHITESPACE = Pattern.compile("[\\s]"); - String nowhitespace = WHITESPACE.matcher(data).replaceAll("_"); - String normalized = Normalizer.normalize(nowhitespace, Normalizer.Form.NFD); - String slug = NONLATIN.matcher(normalized).replaceAll("_") - .replaceAll("-", "_"); - return slug.toLowerCase(Locale.ENGLISH); - } - - @Mappings({ - @Mapping(target = "id", expression = "java(null)"), - @Mapping(target = "columnType", source = "data.type"), - @Mapping(target = "isNullAllowed", source = "data.nullAllowed"), - @Mapping(target = "name", source = "data.name"), - @Mapping(target = "autoGenerated", expression = "java(false)"), - @Mapping(target = "internalName", expression = "java(nameToInternalName(data.getName()))"), - }) - TableColumn columnCreateDtoToTableColumn(ColumnCreateDto data, ContainerImage image); - -} diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/UserMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/UserMapper.java deleted file mode 100644 index cf1d2d2ac7d2d1abf417daae233ee746e965598c..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/UserMapper.java +++ /dev/null @@ -1,113 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.api.auth.SignupRequestDto; -import at.tuwien.api.keycloak.*; -import at.tuwien.api.user.*; -import at.tuwien.api.user.UserDto; -import at.tuwien.entities.user.User; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Mappings; -import org.mapstruct.Named; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -@Mapper(componentModel = "spring") -public interface UserMapper { - - org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(UserMapper.class); - - default UpdateCredentialsDto passwordToUpdateCredentialsDto(String password) { - return UpdateCredentialsDto.builder() - .credentials(List.of(CredentialDto.builder() - .temporary(false) - .type(CredentialTypeDto.PASSWORD) - .value(password) - .build())) - .build(); - } - - default UserCreateDto signupRequestDtoToUserCreateDto(SignupRequestDto data) { - return UserCreateDto.builder() - .username(data.getUsername()) - .email(data.getEmail()) - .credentials(List.of(CredentialDto.builder() - .type(CredentialTypeDto.PASSWORD) - .temporary(false) - .value(data.getPassword()) - .build())) - .enabled(true) - .build(); - } - - /* keep */ - UserBriefDto keycloakUserDtoToUserBriefDto(at.tuwien.api.keycloak.UserDto data); - - /* keep */ - @Mappings({ - @Mapping(target = "id", expression = "java(data.getId().toString())") - }) - UserDetailsDto userDtoToUserDetailsDto(UserDto data); - - /* keep */ - @Mappings({ - @Mapping(target = "name", expression = "java(userToFullName(data))"), - @Mapping(target = "qualifiedName", expression = "java(userToQualifiedName(data))"), - }) - UserBriefDto userToUserBriefDto(User data); - - UserBriefDto userDtoToUserBriefDto(UserDto data); - - /* keep */ - @Mappings({ - @Mapping(target = "attributes.language", source = "language"), - @Mapping(target = "attributes.orcid", source = "orcid"), - @Mapping(target = "attributes.affiliation", source = "affiliation"), - @Mapping(target = "attributes.theme", source = "theme"), - @Mapping(target = "name", expression = "java(userToFullName(data))"), - @Mapping(target = "qualifiedName", expression = "java(userToQualifiedName(data))"), - }) - UserDto userToUserDto(User data); - - /* keep */ - User userDtoToUserDto(UserDto data); - - /* keep */ - @Named("userToFullName") - default String userToFullName(User data) { - final StringBuilder name = new StringBuilder(); - if (data.getFirstname() != null) { - name.append(data.getFirstname()); - } - if (data.getLastname() != null) { - name.append(!name.isEmpty() ? " " : null) - .append(data.getLastname()); - } - return name.isEmpty() ? null : name.toString() - .trim(); - } - - /* keep */ - @Named("userToQualifiedName") - default String userToQualifiedName(User data) { - final String fullname = userToFullName(data); - final StringBuilder name = new StringBuilder(); - if (fullname != null) { - name.append(fullname); - } - if (!name.isEmpty()) { - name.append(" — "); - } - name.append("@") - .append(data.getUsername()); - return name.toString() - .trim(); - } - - User signupRequestDtoToUser(SignupRequestDto data); - -} diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ViewMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ViewMapper.java deleted file mode 100644 index 7d8f2416b1896cb39cc7641208b75845754108bb..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/ViewMapper.java +++ /dev/null @@ -1,48 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.api.database.ViewBriefDto; -import at.tuwien.api.database.ViewDto; -import at.tuwien.entities.database.View; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Mappings; -import org.mapstruct.Named; - -import java.text.Normalizer; -import java.util.Locale; -import java.util.regex.Pattern; - -@Mapper(componentModel = "spring", uses = {ContainerMapper.class, UserMapper.class, TableMapper.class, - IdentifierMapper.class}) -public interface ViewMapper { - - org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ViewMapper.class); - - @Named("internalNameMapping") - default String nameToInternalName(String data) { - if (data == null || data.isEmpty()) { - return data; - } - final Pattern NONLATIN = Pattern.compile("[^\\w-]"); - final Pattern WHITESPACE = Pattern.compile("[\\s]"); - String nowhitespace = WHITESPACE.matcher(data).replaceAll("_"); - String normalized = Normalizer.normalize(nowhitespace, Normalizer.Form.NFD); - String slug = NONLATIN.matcher(normalized).replaceAll(""); - return slug.toLowerCase(Locale.ENGLISH); - } - - @Mappings({ - @Mapping(target = "database.views", ignore = true), - @Mapping(target = "database.tables", ignore = true), - @Mapping(target = "database.identifiers", ignore = true), - }) - ViewDto viewToViewDto(View data); - - ViewBriefDto viewToViewBriefDto(View data); - - @Mappings({ - @Mapping(target = "createdBy", source = "creator.id"), - }) - View viewDtoToView(ViewDto data); - -} diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ImageRepository.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ImageRepository.java index d2262f37d69bd8dc2ad5c504236e839d2ff7c523..593a4727180d55b4bc0cb1971c0aecf49313f8cb 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ImageRepository.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/ImageRepository.java @@ -4,11 +4,14 @@ import at.tuwien.entities.container.image.ContainerImage; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.List; import java.util.Optional; @Repository public interface ImageRepository extends JpaRepository<ContainerImage, Long> { + List<ContainerImage> findAll(); + Optional<ContainerImage> findByNameAndVersion(String name, String version); } diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java index ea66257cc19860534fc73d1e72630ddbb71e12f5..17c1e20978453458732be953ed05e478691444d7 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java @@ -7,7 +7,7 @@ import at.tuwien.entities.database.Database; import at.tuwien.entities.database.DatabaseAccess; import at.tuwien.entities.user.User; import at.tuwien.exception.*; -import at.tuwien.mapper.DatabaseMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.AccessService; import at.tuwien.service.DatabaseService; import at.tuwien.service.UserService; @@ -40,11 +40,11 @@ public class AccessEndpoint { private final UserService userService; private final AccessService accessService; - private final DatabaseMapper databaseMapper; + private final MetadataMapper databaseMapper; private final DatabaseService databaseService; @Autowired - public AccessEndpoint(UserService userService, AccessService accessService, DatabaseMapper databaseMapper, + public AccessEndpoint(UserService userService, AccessService accessService, MetadataMapper databaseMapper, DatabaseService databaseService) { this.userService = userService; this.accessService = accessService; diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ConceptEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ConceptEndpoint.java index 2d002e844930f7d249549dd843e8bc987658448e..cb58e62def0c45aebe04519a650d1232b681e9e9 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ConceptEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ConceptEndpoint.java @@ -1,7 +1,7 @@ package at.tuwien.endpoints; import at.tuwien.api.database.table.columns.concepts.ConceptDto; -import at.tuwien.mapper.SemanticMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.ConceptService; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; @@ -12,7 +12,6 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; @@ -26,12 +25,12 @@ import java.util.List; public class ConceptEndpoint { private final ConceptService conceptService; - private final SemanticMapper semanticMapper; + private final MetadataMapper metadataMapper; @Autowired - public ConceptEndpoint(ConceptService conceptService, SemanticMapper semanticMapper) { + public ConceptEndpoint(ConceptService conceptService, MetadataMapper metadataMapper) { this.conceptService = conceptService; - this.semanticMapper = semanticMapper; + this.metadataMapper = metadataMapper; } @GetMapping @@ -49,7 +48,7 @@ public class ConceptEndpoint { log.debug("endpoint list concepts"); final List<ConceptDto> dtos = conceptService.findAll() .stream() - .map(semanticMapper::tableColumnConceptToConceptDto) + .map(metadataMapper::tableColumnConceptToConceptDto) .toList(); log.trace("Find all concepts resulted in dtos {}", dtos); return ResponseEntity.ok() diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java index 02f5a00f2bc33a7d73f9518a755fc3b0f5133d89..9d6e24801b453b8f79caf923dcaaa90d44ba2e0b 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java @@ -8,7 +8,7 @@ import at.tuwien.entities.container.Container; import at.tuwien.exception.ContainerAlreadyExistsException; import at.tuwien.exception.ContainerNotFoundException; import at.tuwien.exception.ImageNotFoundException; -import at.tuwien.mapper.ContainerMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.ContainerService; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; @@ -42,12 +42,12 @@ import java.util.stream.Collectors; @RequestMapping(path = "/api/container") public class ContainerEndpoint { - private final ContainerMapper containerMapper; + private final MetadataMapper metadataMapper; private final ContainerService containerService; @Autowired - public ContainerEndpoint(ContainerService containerService, ContainerMapper containerMapper) { - this.containerMapper = containerMapper; + public ContainerEndpoint(ContainerService containerService, MetadataMapper metadataMapper) { + this.metadataMapper = metadataMapper; this.containerService = containerService; } @@ -66,7 +66,7 @@ public class ContainerEndpoint { log.debug("endpoint find all containers, limit={}", limit); final List<Container> containers = containerService.getAll(limit); final List<ContainerBriefDto> dtos = containers.stream() - .map(containerMapper::containerToDatabaseContainerBriefDto) + .map(metadataMapper::containerToDatabaseContainerBriefDto) .collect(Collectors.toList()); log.trace("find all containers resulted in containers {}", dtos); return ResponseEntity.ok() @@ -99,7 +99,7 @@ public class ContainerEndpoint { throws ImageNotFoundException, ContainerAlreadyExistsException { log.debug("endpoint create container, data={}", data); final Container container = containerService.create(data); - final ContainerBriefDto dto = containerMapper.containerToDatabaseContainerBriefDto(container); + final ContainerBriefDto dto = metadataMapper.containerToDatabaseContainerBriefDto(container); log.trace("create container resulted in container {}", dto); return ResponseEntity.status(HttpStatus.CREATED) .body(dto); @@ -126,7 +126,7 @@ public class ContainerEndpoint { throws ContainerNotFoundException { log.debug("endpoint find container, containerId={}", containerId); final Container container = containerService.find(containerId); - final ContainerDto dto = containerMapper.containerToContainerDto(container); + final ContainerDto dto = metadataMapper.containerToContainerDto(container); log.trace("find container resulted in container {}", dto); final HttpHeaders headers = new HttpHeaders(); if (principal != null) { diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java index b364e2dcfc6f7abc89ffc7d1a5dc2b1e521836f2..b5248ed23265c67e7a666e4364a0069ff9d5e6de 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java @@ -8,7 +8,7 @@ import at.tuwien.entities.database.Database; import at.tuwien.entities.database.DatabaseAccess; import at.tuwien.entities.user.User; import at.tuwien.exception.*; -import at.tuwien.mapper.DatabaseMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.*; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; @@ -45,13 +45,13 @@ public class DatabaseEndpoint { private final RabbitConfig rabbitConfig; private final AccessService accessService; private final BrokerService brokerService; - private final DatabaseMapper databaseMapper; + private final MetadataMapper databaseMapper; private final StorageService storageService; private final DatabaseService databaseService; @Autowired public DatabaseEndpoint(UserService userService, RabbitConfig rabbitConfig, AccessService accessService, - BrokerService brokerService, DatabaseMapper databaseMapper, + BrokerService brokerService, MetadataMapper databaseMapper, StorageService storageService, DatabaseService databaseService) { this.userService = userService; this.rabbitConfig = rabbitConfig; @@ -146,7 +146,7 @@ public class DatabaseEndpoint { log.debug("endpoint create database, data.name={}", data.getName()); final User user = userService.findByUsername(principal.getName()); final Database database = databaseService.create(data, user); - final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(database); + final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(database); return ResponseEntity.status(HttpStatus.CREATED) .body(dto); } @@ -198,7 +198,7 @@ public class DatabaseEndpoint { log.error("Failed to refresh database tables metadata: not owner"); throw new NotAllowedException("Failed to refresh tables metadata: not owner"); } - final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(databaseService.updateTableMetadata(database)); + final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(databaseService.updateTableMetadata(database)); return ResponseEntity.ok(dto); } @@ -244,7 +244,7 @@ public class DatabaseEndpoint { log.error("Failed to refresh database views metadata: not owner"); throw new NotAllowedException("Failed to refresh database views metadata: not owner"); } - final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(databaseService.updateViewMetadata(database)); + final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(databaseService.updateViewMetadata(database)); return ResponseEntity.ok(dto); } @@ -290,7 +290,7 @@ public class DatabaseEndpoint { log.error("Failed to modify database visibility: not owner"); throw new NotAllowedException("Failed to modify database visibility: not owner"); } - final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(databaseService.modifyVisibility(database, data)); + final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(databaseService.modifyVisibility(database, data)); return ResponseEntity.accepted() .body(dto); } @@ -340,7 +340,7 @@ public class DatabaseEndpoint { log.error("Failed to transfer database: not owner"); throw new NotAllowedException("Failed to transfer database: not owner"); } - final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(databaseService.modifyOwner(database, newOwner)); + final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(databaseService.modifyOwner(database, newOwner)); return ResponseEntity.accepted() .body(dto); } @@ -399,7 +399,7 @@ public class DatabaseEndpoint { if (data.getKey() != null) { image = storageService.getBytes(data.getKey()); } - dto = databaseMapper.databaseToDatabaseDto(databaseService.modifyImage(database, image)); + dto = databaseMapper.customDatabaseToDatabaseDto(databaseService.modifyImage(database, image)); return ResponseEntity.accepted() .body(dto); } @@ -435,7 +435,7 @@ public class DatabaseEndpoint { ServiceConnectionException, DatabaseNotFoundException, ExchangeNotFoundException { log.debug("endpoint find database, databaseId={}", databaseId); final Database database = databaseService.findById(databaseId); - final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(database); + final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(database); if (database.getOwner().equals(principal)) { log.debug("current logged-in user is also the owner: additionally load access list"); /* only owner sees the access rights */ diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java index 726d118f1302ccb784e6ab440a24b6f0ea19bd1a..c1bf7128400980ce12379ab521407b05dac390fa 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java @@ -16,7 +16,7 @@ import at.tuwien.entities.identifier.IdentifierType; import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; -import at.tuwien.mapper.IdentifierMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.*; import at.tuwien.utils.UserUtil; import at.tuwien.validation.EndpointValidator; @@ -57,27 +57,27 @@ public class IdentifierEndpoint { private final TableService tableService; private final AccessService accessService; private final EndpointConfig endpointConfig; + private final MetadataMapper metadataMapper; private final DatabaseService databaseService; private final MetadataService metadataService; - private final IdentifierMapper identifierMapper; private final EndpointValidator endpointValidator; private final IdentifierService identifierService; private final DataServiceGateway dataServiceGateway; @Autowired public IdentifierEndpoint(UserService userService, ViewService viewService, TableService tableService, - AccessService accessService, EndpointConfig endpointConfig, + AccessService accessService, EndpointConfig endpointConfig, MetadataMapper metadataMapper, DatabaseService databaseService, MetadataService metadataService, - IdentifierMapper identifierMapper, EndpointValidator endpointValidator, - IdentifierService identifierService, DataServiceGateway dataServiceGateway) { + EndpointValidator endpointValidator, IdentifierService identifierService, + DataServiceGateway dataServiceGateway) { this.userService = userService; this.viewService = viewService; this.tableService = tableService; this.accessService = accessService; this.endpointConfig = endpointConfig; + this.metadataMapper = metadataMapper; this.databaseService = databaseService; this.metadataService = metadataService; - this.identifierMapper = identifierMapper; this.endpointValidator = endpointValidator; this.identifierService = identifierService; this.dataServiceGateway = dataServiceGateway; @@ -121,14 +121,14 @@ public class IdentifierEndpoint { case "application/json": log.trace("accept header matches json"); final List<IdentifierDto> resource1 = identifiers.stream() - .map(identifierMapper::identifierToIdentifierDto) + .map(metadataMapper::identifierToIdentifierDto) .toList(); log.debug("find identifier resulted in identifiers {}", resource1); return ResponseEntity.ok(resource1); case "application/ld+json": log.trace("accept header matches json-ld"); final List<LdDatasetDto> resource2 = identifiers.stream() - .map(i -> identifierMapper.identifierToLdDatasetDto(i, endpointConfig.getWebsiteUrl())) + .map(i -> metadataMapper.identifierToLdDatasetDto(i, endpointConfig.getWebsiteUrl())) .toList(); log.debug("find identifier resulted in identifiers {}", resource2); return ResponseEntity.ok(resource2); @@ -209,12 +209,12 @@ public class IdentifierEndpoint { switch (accept) { case "application/json": log.trace("accept header matches json"); - final IdentifierDto resource1 = identifierMapper.identifierToIdentifierDto(identifier); + final IdentifierDto resource1 = metadataMapper.identifierToIdentifierDto(identifier); log.debug("find identifier resulted in identifier {}", resource1); return ResponseEntity.ok(resource1); case "application/ld+json": log.trace("accept header matches json-ld"); - final LdDatasetDto resource2 = identifierMapper.identifierToLdDatasetDto(identifier, endpointConfig.getWebsiteUrl()); + final LdDatasetDto resource2 = metadataMapper.identifierToLdDatasetDto(identifier, endpointConfig.getWebsiteUrl()); log.debug("find identifier resulted in identifier {}", resource2); return ResponseEntity.ok(resource2); case "text/csv": @@ -253,7 +253,7 @@ public class IdentifierEndpoint { log.trace("no accept header present"); } final HttpHeaders headers = new HttpHeaders(); - final String url = identifierMapper.identifierToLocationUrl(endpointConfig.getWebsiteUrl(), identifier); + final String url = metadataMapper.identifierToLocationUrl(endpointConfig.getWebsiteUrl(), identifier); headers.add("Location", url); log.debug("find identifier resulted in http redirect, headers={}, url={}", headers, url); return ResponseEntity.status(HttpStatus.MOVED_PERMANENTLY) @@ -353,7 +353,7 @@ public class IdentifierEndpoint { log.debug("endpoint publish identifier, identifierId={}", identifierId); final Identifier identifier = identifierService.find(identifierId); return ResponseEntity.status(HttpStatus.CREATED) - .body(identifierMapper.identifierToIdentifierDto(identifierService.publish(identifierId))); + .body(metadataMapper.identifierToIdentifierDto(identifierService.publish(identifierId))); } @PutMapping("/{identifierId}") @@ -478,7 +478,7 @@ public class IdentifierEndpoint { } } return ResponseEntity.accepted() - .body(identifierMapper.identifierToIdentifierDto(identifierService.save(database, user, data))); + .body(metadataMapper.identifierToIdentifierDto(identifierService.save(database, user, data))); } @PostMapping @@ -544,7 +544,7 @@ public class IdentifierEndpoint { } final Identifier identifier = identifierService.create(database, user, data); return ResponseEntity.status(HttpStatus.CREATED) - .body(identifierMapper.identifierToIdentifierDto(identifier)); + .body(metadataMapper.identifierToIdentifierDto(identifier)); } @GetMapping("/retrieve") diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java index 44b25250a882d0b094c0ee4a801bf2e8cbd2fb23..d295cc7a11d669dbd149dd0a9ac784dd3d432cb8 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ImageEndpoint.java @@ -9,7 +9,7 @@ import at.tuwien.entities.container.image.ContainerImage; import at.tuwien.exception.ImageAlreadyExistsException; import at.tuwien.exception.ImageInvalidException; import at.tuwien.exception.ImageNotFoundException; -import at.tuwien.mapper.ImageMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.impl.ImageServiceImpl; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; @@ -40,13 +40,13 @@ import java.util.stream.Collectors; @RequestMapping(path = "/api/image") public class ImageEndpoint { + private final MetadataMapper metadataMapper; private final ImageServiceImpl imageService; - private final ImageMapper imageMapper; @Autowired - public ImageEndpoint(ImageServiceImpl imageService, ImageMapper imageMapper) { + public ImageEndpoint(ImageServiceImpl imageService, MetadataMapper metadataMapper) { this.imageService = imageService; - this.imageMapper = imageMapper; + this.metadataMapper = metadataMapper; } @GetMapping @@ -65,7 +65,7 @@ public class ImageEndpoint { final List<ContainerImage> containers = imageService.getAll(); return ResponseEntity.ok() .body(containers.stream() - .map(imageMapper::containerImageToImageBriefDto) + .map(metadataMapper::containerImageToImageBriefDto) .collect(Collectors.toList())); } @@ -100,7 +100,7 @@ public class ImageEndpoint { throw new ImageInvalidException("Failed to create image, default port is null"); } final ContainerImage image = imageService.create(data, principal); - final ImageDto dto = imageMapper.containerImageToImageDto(image); + final ImageDto dto = metadataMapper.containerImageToImageDto(image); log.trace("create image resulted in image {}", dto); return ResponseEntity.status(HttpStatus.CREATED) .body(dto); @@ -125,7 +125,7 @@ public class ImageEndpoint { public ResponseEntity<ImageDto> findById(@NotNull @PathVariable("imageId") Long imageId) throws ImageNotFoundException { log.debug("endpoint find image, id={}", imageId); final ContainerImage image = imageService.find(imageId); - final ImageDto dto = imageMapper.containerImageToImageDto(image); + final ImageDto dto = metadataMapper.containerImageToImageDto(image); log.trace("find image resulted in image {}", dto); return ResponseEntity.ok() .body(dto); @@ -154,7 +154,7 @@ public class ImageEndpoint { log.debug("endpoint update image, id={}, changeDto={}", imageId, changeDto); ContainerImage image = imageService.find(imageId); image = imageService.update(image, changeDto); - final ImageDto dto = imageMapper.containerImageToImageDto(image); + final ImageDto dto = metadataMapper.containerImageToImageDto(image); log.trace("update image resulted in image {}", dto); return ResponseEntity.accepted() .body(dto); diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/LicenseEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/LicenseEndpoint.java index dd81274a29ffecdab3c7fdbed2dcb023d2a1a6eb..e2b47905c9196431e0545e37c05b86b151a880b7 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/LicenseEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/LicenseEndpoint.java @@ -1,7 +1,7 @@ package at.tuwien.endpoints; import at.tuwien.api.database.LicenseDto; -import at.tuwien.mapper.LicenseMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.LicenseService; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; @@ -29,13 +29,13 @@ import java.util.stream.Collectors; @RequestMapping(path = "/api/license") public class LicenseEndpoint { - private final LicenseMapper licenseMapper; private final LicenseService licenseService; + private final MetadataMapper metadataMapper; @Autowired - public LicenseEndpoint(LicenseMapper licenseMapper, LicenseService licenseService) { - this.licenseMapper = licenseMapper; + public LicenseEndpoint(LicenseService licenseService, MetadataMapper metadataMapper) { this.licenseService = licenseService; + this.metadataMapper = metadataMapper; } @GetMapping @@ -53,7 +53,7 @@ public class LicenseEndpoint { log.debug("endpoint list licenses"); final List<LicenseDto> licenses = licenseService.findAll() .stream() - .map(licenseMapper::licenseToLicenseDto) + .map(metadataMapper::licenseToLicenseDto) .collect(Collectors.toList()); log.trace("list licenses resulted in licenses {}", licenses); return ResponseEntity.status(HttpStatus.OK) diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/MessageEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/MessageEndpoint.java index bcff92bc49b00e61e9bdbea9fc4aff9435f06189..62677967b01d666ee998f7c9d30fe1019b997fe6 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/MessageEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/MessageEndpoint.java @@ -7,7 +7,7 @@ import at.tuwien.api.maintenance.BannerMessageDto; import at.tuwien.api.maintenance.BannerMessageUpdateDto; import at.tuwien.entities.maintenance.BannerMessage; import at.tuwien.exception.MessageNotFoundException; -import at.tuwien.mapper.BannerMessageMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.BannerMessageService; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; @@ -34,12 +34,12 @@ import java.util.List; @RequestMapping(path = "/api/message") public class MessageEndpoint { - private final BannerMessageMapper bannerMessageMapper; + private final MetadataMapper metadataMapper; private final BannerMessageService bannerMessageService; @Autowired - public MessageEndpoint(BannerMessageMapper bannerMessageMapper, BannerMessageService bannerMessageService) { - this.bannerMessageMapper = bannerMessageMapper; + public MessageEndpoint(MetadataMapper metadataMapper, BannerMessageService bannerMessageService) { + this.metadataMapper = metadataMapper; this.bannerMessageService = bannerMessageService; } @@ -59,12 +59,12 @@ public class MessageEndpoint { if (filter.equals("active")) { dtos = bannerMessageService.getActive() .stream() - .map(bannerMessageMapper::bannerMessageToBannerMessageDto) + .map(metadataMapper::bannerMessageToBannerMessageDto) .toList(); } else { dtos = bannerMessageService.findAll() .stream() - .map(bannerMessageMapper::bannerMessageToBannerMessageDto) + .map(metadataMapper::bannerMessageToBannerMessageDto) .toList(); } log.trace("list maintenance messages results in dtos {}", dtos); @@ -89,7 +89,7 @@ public class MessageEndpoint { public ResponseEntity<BannerMessageDto> find(@NotNull @PathVariable("messageId") Long messageId) throws MessageNotFoundException { log.debug("endpoint find one maintenance messages"); - final BannerMessageDto dto = bannerMessageMapper.bannerMessageToBannerMessageDto(bannerMessageService.find(messageId)); + final BannerMessageDto dto = metadataMapper.bannerMessageToBannerMessageDto(bannerMessageService.find(messageId)); log.trace("find one maintenance message results in dto {}", dto); return ResponseEntity.ok(dto); } @@ -107,7 +107,7 @@ public class MessageEndpoint { }) public ResponseEntity<BannerMessageDto> create(@Valid @RequestBody BannerMessageCreateDto data) { log.debug("endpoint create maintenance message, data={}", data); - final BannerMessageDto dto = bannerMessageMapper.bannerMessageToBannerMessageDto(bannerMessageService.create(data)); + final BannerMessageDto dto = metadataMapper.bannerMessageToBannerMessageDto(bannerMessageService.create(data)); log.trace("create maintenance message results in dto {}", dto); return ResponseEntity.status(HttpStatus.CREATED) .body(dto); @@ -134,7 +134,7 @@ public class MessageEndpoint { throws MessageNotFoundException { log.debug("endpoint update maintenance message, messageId={}, data={}", messageId, data); final BannerMessage message = bannerMessageService.find(messageId); - final BannerMessageDto dto = bannerMessageMapper.bannerMessageToBannerMessageDto(bannerMessageService.update(message, data)); + final BannerMessageDto dto = metadataMapper.bannerMessageToBannerMessageDto(bannerMessageService.update(message, data)); log.trace("update maintenance message results in dto {}", dto); return ResponseEntity.status(HttpStatus.ACCEPTED) .body(dto); diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/OntologyEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/OntologyEndpoint.java index d9a1b2c50b7014b30b581ecf8c5541c2a10892ba..8d626db323ee120704f099059ab4e057e8418525 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/OntologyEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/OntologyEndpoint.java @@ -4,7 +4,8 @@ import at.tuwien.api.error.ApiErrorDto; import at.tuwien.api.semantics.*; import at.tuwien.entities.semantics.Ontology; import at.tuwien.exception.*; -import at.tuwien.mapper.OntologyMapper; +import at.tuwien.mapper.MetadataMapper; +import at.tuwien.mapper.SparqlMapper; import at.tuwien.service.EntityService; import at.tuwien.service.OntologyService; import io.micrometer.observation.annotation.Observed; @@ -33,15 +34,16 @@ import java.util.List; @RequestMapping(path = "/api/ontology") public class OntologyEndpoint { - private final OntologyMapper ontologyMapper; - private final OntologyService ontologyService; private final EntityService entityService; + private final MetadataMapper metadataMapper; + private final OntologyService ontologyService; @Autowired - public OntologyEndpoint(OntologyMapper ontologyMapper, OntologyService ontologyService, EntityService entityService) { - this.ontologyMapper = ontologyMapper; - this.ontologyService = ontologyService; + public OntologyEndpoint(EntityService entityService, MetadataMapper metadataMapper, + OntologyService ontologyService) { this.entityService = entityService; + this.metadataMapper = metadataMapper; + this.ontologyService = ontologyService; } @GetMapping @@ -58,7 +60,7 @@ public class OntologyEndpoint { log.debug("endpoint find all ontologies"); final List<OntologyBriefDto> dtos = ontologyService.findAll() .stream() - .map(ontologyMapper::ontologyToOntologyBriefDto) + .map(metadataMapper::ontologyToOntologyBriefDto) .toList(); log.trace("create ontology resulted in dtos {}", dtos); return ResponseEntity.ok(dtos); @@ -82,7 +84,7 @@ public class OntologyEndpoint { public ResponseEntity<OntologyDto> find(@NotNull @PathVariable("ontologyId") Long ontologyId) throws OntologyNotFoundException { log.debug("endpoint find all ontologies, ontologyId={}", ontologyId); - final OntologyDto dto = ontologyMapper.ontologyToOntologyDto(ontologyService.find(ontologyId)); + final OntologyDto dto = metadataMapper.ontologyToOntologyDto(ontologyService.find(ontologyId)); log.trace("create ontology resulted in dto {}", dto); return ResponseEntity.ok(dto); } @@ -101,7 +103,7 @@ public class OntologyEndpoint { public ResponseEntity<OntologyDto> create(@NotNull @Valid @RequestBody OntologyCreateDto data, @NotNull Principal principal) { log.debug("endpoint create ontology, data={}", data); - final OntologyDto dto = ontologyMapper.ontologyToOntologyDto(ontologyService.create(data, principal)); + final OntologyDto dto = metadataMapper.ontologyToOntologyDto(ontologyService.create(data, principal)); log.trace("create ontology resulted in dto {}", dto); return ResponseEntity.status(HttpStatus.CREATED) .body(dto); @@ -128,7 +130,7 @@ public class OntologyEndpoint { throws OntologyNotFoundException { log.debug("endpoint update ontology, data={}", data); final Ontology ontology = ontologyService.find(ontologyId); - final OntologyDto dto = ontologyMapper.ontologyToOntologyDto(ontologyService.update(ontology, data)); + final OntologyDto dto = metadataMapper.ontologyToOntologyDto(ontologyService.update(ontology, data)); log.trace("update ontology resulted in dto {}", dto); return ResponseEntity.accepted() .body(dto); diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java index 6e008287baeba357273319a8263a06843f012049..c87b4039c1425c6b15a7665c8def80125fa46be6 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java @@ -4,7 +4,6 @@ import at.tuwien.api.amqp.QueueDto; import at.tuwien.api.database.table.TableBriefDto; import at.tuwien.api.database.table.TableCreateDto; import at.tuwien.api.database.table.TableDto; -import at.tuwien.api.database.table.TableStatisticDto; import at.tuwien.api.database.table.columns.ColumnCreateDto; import at.tuwien.api.database.table.columns.ColumnDto; import at.tuwien.api.database.table.columns.ColumnTypeDto; @@ -18,7 +17,7 @@ import at.tuwien.entities.database.table.Table; import at.tuwien.entities.database.table.columns.TableColumn; import at.tuwien.entities.user.User; import at.tuwien.exception.*; -import at.tuwien.mapper.TableMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.*; import at.tuwien.utils.UserUtil; import at.tuwien.validation.EndpointValidator; @@ -52,25 +51,25 @@ import java.util.stream.Collectors; @RequestMapping(path = "/api/database/{databaseId}/table") public class TableEndpoint { - private final TableMapper tableMapper; private final UserService userService; private final TableService tableService; private final RabbitConfig rabbitMqConfig; private final EntityService entityService; private final BrokerService messageQueueService; + private final MetadataMapper metadataMapper; private final DatabaseService databaseService; private final EndpointValidator endpointValidator; @Autowired - public TableEndpoint(TableMapper tableMapper, UserService userService, TableService tableService, - RabbitConfig rabbitMqConfig, EntityService entityService, BrokerService messageQueueService, + public TableEndpoint(UserService userService, TableService tableService, RabbitConfig rabbitMqConfig, + EntityService entityService, BrokerService messageQueueService, MetadataMapper metadataMapper, DatabaseService databaseService, EndpointValidator endpointValidator) { - this.tableMapper = tableMapper; this.userService = userService; this.tableService = tableService; this.rabbitMqConfig = rabbitMqConfig; this.entityService = entityService; this.messageQueueService = messageQueueService; + this.metadataMapper = metadataMapper; this.databaseService = databaseService; this.endpointValidator = endpointValidator; } @@ -105,7 +104,7 @@ public class TableEndpoint { endpointValidator.validateOnlyPrivateHasRole(database, principal, "list-tables"); final List<TableBriefDto> dto = database.getTables() .stream() - .map(tableMapper::tableToTableBriefDto) + .map(metadataMapper::tableToTableBriefDto) .collect(Collectors.toList()); log.trace("list tables resulted in tables {}", dto); return ResponseEntity.ok(dto); @@ -156,19 +155,19 @@ public class TableEndpoint { @PutMapping("/{tableId}") @Transactional - @PreAuthorize("hasAuthority('admin')") + @PreAuthorize("hasAuthority('update-table-statistic') or hasAuthority('admin')") @Observed(name = "dbrepo_statistic_table_update") @Operation(summary = "Update table statistics", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "202", description = "Updated table statistics successfully"), - @ApiResponse(responseCode = "400", - description = "Payload malformed", + @ApiResponse(responseCode = "404", + description = "Failed to find database/table in metadata database", content = {@Content( mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), - @ApiResponse(responseCode = "404", - description = "Failed to find database/table in metadata database", + @ApiResponse(responseCode = "400", + description = "Failed to map column statistic to known columns", content = {@Content( mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), @@ -184,14 +183,12 @@ public class TableEndpoint { schema = @Schema(implementation = ApiErrorDto.class))}), }) public ResponseEntity<Void> updateStatistic(@NotNull @PathVariable("databaseId") Long databaseId, - @NotNull @PathVariable("tableId") Long tableId, - @NotNull @Valid @RequestBody TableStatisticDto data) - throws MalformedException, TableNotFoundException, DatabaseNotFoundException, SearchServiceException, - SearchServiceConnectionException { - log.debug("endpoint update table statistics, databaseId={}, tableId={}, data.columns.size={}", databaseId, - tableId, data.getColumns().size()); + @NotNull @PathVariable("tableId") Long tableId) + throws TableNotFoundException, DatabaseNotFoundException, SearchServiceException, + SearchServiceConnectionException, MalformedException, ServiceException, ServiceConnectionException { + log.debug("endpoint update table statistics, databaseId={}, tableId={}", databaseId, tableId); final Table table = tableService.findById(databaseId, tableId); - tableService.updateStatistics(table, data); + tableService.updateStatistics(table); return ResponseEntity.accepted() .build(); } @@ -251,7 +248,7 @@ public class TableEndpoint { TableColumn column = tableService.findColumnById(table, columnId); column = tableService.update(column, updateDto); log.info("Updated table semantics of table with id {}", tableId); - final ColumnDto columnDto = tableMapper.tableColumnToColumnDto(column); + final ColumnDto columnDto = metadataMapper.tableColumnToColumnDto(column); log.trace("find table data resulted in column {}", columnDto); return ResponseEntity.accepted() .body(columnDto); @@ -344,7 +341,7 @@ public class TableEndpoint { @NotNull Principal principal) throws NotAllowedException, MalformedException, ServiceException, ServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException, TableNotFoundException, TableExistsException, SearchServiceException, - SearchServiceConnectionException { + SearchServiceConnectionException, OntologyNotFoundException, SemanticEntityNotFoundException { log.debug("endpoint create table, databaseId={}, data.name={}", databaseId, data.getName()); final Database database = databaseService.findById(databaseId); endpointValidator.validateOnlyAccess(database, principal, true); @@ -359,7 +356,7 @@ public class TableEndpoint { throw new MalformedException("Failed to create table: date column(s) " + failedDateColumns.stream().map(ColumnCreateDto::getName).toList() + " do not contain date format id"); } final Table table = tableService.createTable(database, data, principal); - final TableDto dto = tableMapper.tableToTableDto(table); + final TableDto dto = metadataMapper.customTableToTableDto(table); log.debug("create table resulted in table.id={}", dto.getId()); return ResponseEntity.status(HttpStatus.CREATED) .body(dto); @@ -402,7 +399,7 @@ public class TableEndpoint { ServiceConnectionException, TableNotFoundException, DatabaseNotFoundException, QueueNotFoundException { log.debug("endpoint find table, databaseId={}, tableId={}", databaseId, tableId); final Table table = tableService.findById(databaseId, tableId); - final TableDto dto = tableMapper.tableToTableDto(table); + final TableDto dto = metadataMapper.customTableToTableDto(table); final HttpHeaders headers = new HttpHeaders(); if (principal != null) { /* extra effort only when logged-in */ diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UnitEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UnitEndpoint.java index 7808b1b2918eb55a901335f119e14d2dc9deb284..71dfa78ceff621861c1191e84790032dc6924a13 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UnitEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UnitEndpoint.java @@ -1,7 +1,7 @@ package at.tuwien.endpoints; import at.tuwien.api.database.table.columns.concepts.UnitDto; -import at.tuwien.mapper.SemanticMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.UnitService; import io.micrometer.observation.annotation.Observed; import io.swagger.v3.oas.annotations.Operation; @@ -12,7 +12,6 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; @@ -26,11 +25,11 @@ import java.util.List; public class UnitEndpoint { private final UnitService unitService; - private final SemanticMapper semanticMapper; + private final MetadataMapper metadataMapper; @Autowired - public UnitEndpoint(SemanticMapper semanticMapper, UnitService unitService) { - this.semanticMapper = semanticMapper; + public UnitEndpoint(MetadataMapper metadataMapper, UnitService unitService) { + this.metadataMapper = metadataMapper; this.unitService = unitService; } @@ -49,7 +48,7 @@ public class UnitEndpoint { log.debug("endpoint list units"); final List<UnitDto> dtos = unitService.findAll() .stream() - .map(semanticMapper::tableColumnUnitToUnitDto) + .map(metadataMapper::tableColumnUnitToUnitDto) .toList(); log.trace("Find all units resulted in dtos {}", dtos); return ResponseEntity.ok() diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java index 4d5ad8164b97934f6d2b511266ca8a78d998614d..fb9ddc0096db6a279011b2d8f0677493c12a22af 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java @@ -9,7 +9,7 @@ import at.tuwien.api.user.*; import at.tuwien.entities.database.Database; import at.tuwien.entities.user.User; import at.tuwien.exception.*; -import at.tuwien.mapper.UserMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.AuthenticationService; import at.tuwien.service.DatabaseService; import at.tuwien.service.UserService; @@ -22,7 +22,6 @@ import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.security.SecurityRequirement; -import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import lombok.extern.log4j.Log4j2; @@ -43,16 +42,16 @@ import java.util.UUID; @RequestMapping(path = "/api/user") public class UserEndpoint { - private final UserMapper userMapper; private final UserService userService; + private final MetadataMapper userMapper; private final DatabaseService databaseService; private final AuthenticationService authenticationService; @Autowired - public UserEndpoint(UserMapper userMapper, UserService userService, DatabaseService databaseService, + public UserEndpoint(UserService userService, MetadataMapper userMapper, DatabaseService databaseService, AuthenticationService authenticationService) { - this.userMapper = userMapper; this.userService = userService; + this.userMapper = userMapper; this.databaseService = databaseService; this.authenticationService = authenticationService; } diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java index a6627689aa3f4c52098b90271b77aa64881bd90b..701e3172fb648af3edc459001c197609c7410633 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java @@ -8,7 +8,7 @@ import at.tuwien.entities.database.Database; import at.tuwien.entities.database.View; import at.tuwien.entities.user.User; import at.tuwien.exception.*; -import at.tuwien.mapper.ViewMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.DatabaseService; import at.tuwien.service.UserService; import at.tuwien.service.ViewService; @@ -42,17 +42,17 @@ import java.util.stream.Collectors; @RequestMapping(path = "/api/database/{databaseId}/view") public class ViewEndpoint { - private final ViewMapper viewMapper; private final UserService userService; private final ViewService viewService; + private final MetadataMapper metadataMapper; private final DatabaseService databaseService; @Autowired - public ViewEndpoint(ViewService viewService, DatabaseService databaseService, - ViewMapper viewMapper, UserService userService) { - this.viewMapper = viewMapper; + public ViewEndpoint(UserService userService, ViewService viewService, MetadataMapper metadataMapper, + DatabaseService databaseService) { this.userService = userService; this.viewService = viewService; + this.metadataMapper = metadataMapper; this.databaseService = databaseService; } @@ -81,7 +81,7 @@ public class ViewEndpoint { log.trace("find all views for database {}", database); final List<ViewBriefDto> views = viewService.findAll(database, user) .stream() - .map(viewMapper::viewToViewBriefDto) + .map(metadataMapper::viewToViewBriefDto) .collect(Collectors.toList()); return ResponseEntity.ok(views); } @@ -153,7 +153,7 @@ public class ViewEndpoint { log.trace("create view for database {}", database); final View view; view = viewService.create(database, user, data); - final ViewBriefDto dto = viewMapper.viewToViewBriefDto(view); + final ViewBriefDto dto = metadataMapper.viewToViewBriefDto(view); return ResponseEntity.status(HttpStatus.CREATED) .body(dto); } @@ -201,7 +201,7 @@ public class ViewEndpoint { } return ResponseEntity.status(HttpStatus.OK) .headers(headers) - .body(viewMapper.viewToViewDto(view)); + .body(metadataMapper.viewToViewDto(view)); } @DeleteMapping("/{viewId}") diff --git a/dbrepo-metadata-service/rest-service/src/main/resources/application-local.yml b/dbrepo-metadata-service/rest-service/src/main/resources/application-local.yml index 6f69d7737cb69c1aab6d3af2b8f3bf0082e6c4ee..3312af7c5af638096be77f207d0b6524ea9d0dab 100644 --- a/dbrepo-metadata-service/rest-service/src/main/resources/application-local.yml +++ b/dbrepo-metadata-service/rest-service/src/main/resources/application-local.yml @@ -62,11 +62,12 @@ dbrepo: username: admin password: admin endpoints: - searchService: http://localhost:4000 + searchService: http://localhost + analyseService: http://localhost dataService: http://localhost:9093 brokerService: http://localhost/admin/broker - authService: http://localhost:8080 - storageService: http://storage-service:9000 + authService: http://localhost/api/auth + storageService: http://localhost/api/storage pid: base: http://localhost/pid/ jwt: diff --git a/dbrepo-metadata-service/rest-service/src/main/resources/application.yml b/dbrepo-metadata-service/rest-service/src/main/resources/application.yml index 326e628b2cf096c8fb8cd2c969ee1219d825dadd..ca7cec2ea5045c077bc58c4817546aff8d0d1f75 100644 --- a/dbrepo-metadata-service/rest-service/src/main/resources/application.yml +++ b/dbrepo-metadata-service/rest-service/src/main/resources/application.yml @@ -51,7 +51,7 @@ logging: dbrepo: repository-name: "${REPOSITORY_NAME:Database Repository}" base-url: "${BASE_URL:http://localhost}" - admin-email: "${ADMIN_MAIL:noreply@example.com}" + admin-email: "${ADMIN_EMAIL:noreply@example.com}" deleted-record: "${DELETED_RECORD:persistent}" granularity: "${GRANULARITY:YYYY-MM-DDThh:mm:ssZ}" exchangeName: "${BROKER_EXCHANGE_NAME:dbrepo}" @@ -66,11 +66,12 @@ dbrepo: username: "${ADMIN_USERNAME:admin}" password: "${ADMIN_PASSWORD:admin}" endpoints: - searchService: "${SEARCH_SERVICE_ENDPOINT:http://search-service:8080}" + searchService: "${SEARCH_SERVICE_ENDPOINT:http://gateway-service}" + analyseService: "${ANALYSE_SERVICE_ENDPOINT:http://gateway-service}" dataService: "${DATA_SERVICE_ENDPOINT:http://data-service:8080}" brokerService: "${BROKER_SERVICE_ENDPOINT:http://gateway-service/admin/broker}" - authService: "${AUTH_SERVICE_ENDPOINT:http://auth-service:8080}" - storageService: "${S3_ENDPOINT:http://storage-service:9000}" + authService: "${AUTH_SERVICE_ENDPOINT:http://gateway-service/api/auth}" + storageService: "${S3_ENDPOINT:http://gateway-service/api/storage}" pid: base: "${PID_BASE:http://localhost/pid/}" jwt: diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java index 10a9afc94c172f76d977ce1b59e474a176f9651f..0444a766901a3a33ed9cde1b19b874a42fa6ec87 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java @@ -1,5 +1,6 @@ package at.tuwien.endpoints; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.test.AbstractUnitTest; import at.tuwien.api.database.AccessTypeDto; import at.tuwien.api.database.DatabaseAccessDto; @@ -7,7 +8,6 @@ import at.tuwien.entities.database.Database; import at.tuwien.entities.database.DatabaseAccess; import at.tuwien.entities.user.User; import at.tuwien.exception.*; -import at.tuwien.mapper.AccessMapper; import at.tuwien.repository.DatabaseRepository; import at.tuwien.repository.UserRepository; import at.tuwien.service.AccessService; @@ -49,7 +49,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { private AccessEndpoint accessEndpoint; @Autowired - private AccessMapper accessMapper; + private MetadataMapper metadataMapper; @Test @WithAnonymousUser @@ -264,7 +264,9 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { final DatabaseAccessDto dto = response.getBody(); assertEquals(userId, dto.getHuserid()); assertEquals(databaseId, dto.getHdbid()); - assertEquals(accessMapper.accessType(access.getType()), dto.getType()); + if (access != null) { + assertEquals(metadataMapper.accessTypeToAccessTypeDto(access.getType()), dto.getType()); + } } protected void generic_update(DatabaseAccess access, String otherUsername, User otherUser, Principal principal, diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java index 6bc0b98692a24b29f30d04c1dc4784e89c027cb0..e5e5097edeedebed520ce7156af79b6e3f88bd3b 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java @@ -897,7 +897,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { Principal principal, User user, DatabaseAccess access) throws MalformedException, NotAllowedException, ServiceException, ServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, AccessNotFoundException, TableNotFoundException, - TableExistsException, SearchServiceException, SearchServiceConnectionException { + TableExistsException, SearchServiceException, SearchServiceConnectionException, OntologyNotFoundException, SemanticEntityNotFoundException { /* mock */ if (principal != null) { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/ContainerMapperTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/ContainerMapperTest.java deleted file mode 100644 index effb6e04a586d16f708195c13abc2acfdcc0154f..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/ContainerMapperTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.entities.container.Container; -import lombok.extern.log4j.Log4j2; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; - -@Log4j2 -@SpringBootTest -@ExtendWith(SpringExtension.class) -public class ContainerMapperTest extends AbstractUnitTest { - - @Test - public void equals_fails() { - - /* test */ - assertNotEquals(CONTAINER_1, CONTAINER_2); - } - - @Test - public void equals_identity_succeeds() { - - /* test */ - assertEquals(CONTAINER_1, CONTAINER_1); - } - - @Test - public void equals_similar_succeeds() { - final Container tmp = Container.builder() - .id(CONTAINER_1_ID) - .build(); - - /* test */ - assertEquals(CONTAINER_1, tmp); - } - -} diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/DatabaseMapperUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/DatabaseMapperUnitTest.java deleted file mode 100644 index 4dfdadd102f9aca7f0017fdc4e7db35c7a335a37..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/DatabaseMapperUnitTest.java +++ /dev/null @@ -1,64 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.identifier.IdentifierDto; -import at.tuwien.test.AbstractUnitTest; -import lombok.extern.log4j.Log4j2; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -@Log4j2 -@SpringBootTest -public class DatabaseMapperUnitTest extends AbstractUnitTest { - - @Autowired - private DatabaseMapper databaseMapper; - - @BeforeEach - public void beforeEach() { - genesis(); - } - - @Test - public void databaseToDatabaseDto_succeeds() { - - /* test */ - final DatabaseDto response = databaseMapper.databaseToDatabaseDto(DATABASE_1); - assertEquals(DATABASE_1_ID, response.getId()); - assertEquals(4, response.getIdentifiers().size()); - /* identifier 1 */ - final IdentifierDto identifier1 = response.getIdentifiers().get(0); - assertEquals(DATABASE_1_ID, identifier1.getDatabaseId()); - assertNotNull(identifier1.getCreator()); - assertEquals(IDENTIFIER_1_CREATED_BY, identifier1.getCreator().getId()); - assertNotNull(identifier1.getCreated()); - assertNotNull(identifier1.getLastModified()); - /* identifier 2 */ - final IdentifierDto identifier2 = response.getIdentifiers().get(1); - assertEquals(DATABASE_1_ID, identifier2.getDatabaseId()); - assertNotNull(identifier2.getCreator()); - assertEquals(IDENTIFIER_2_CREATED_BY, identifier2.getCreator().getId()); - assertNotNull(identifier2.getCreated()); - assertNotNull(identifier2.getLastModified()); - /* identifier 3 */ - final IdentifierDto identifier3 = response.getIdentifiers().get(2); - assertEquals(DATABASE_1_ID, identifier3.getDatabaseId()); - assertNotNull(identifier3.getCreator()); - assertEquals(IDENTIFIER_3_CREATED_BY, identifier3.getCreator().getId()); - assertNotNull(identifier3.getCreated()); - assertNotNull(identifier3.getLastModified()); - /* identifier 4 */ - final IdentifierDto identifier4 = response.getIdentifiers().get(3); - assertEquals(DATABASE_1_ID, identifier4.getDatabaseId()); - assertNotNull(identifier4.getCreator()); - assertEquals(IDENTIFIER_4_CREATED_BY, identifier4.getCreator().getId()); - assertNotNull(identifier4.getCreated()); - assertNotNull(identifier4.getLastModified()); - } - -} diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/IdentifierMapperUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/IdentifierMapperUnitTest.java deleted file mode 100644 index 0089ad8a047b1053b5118c949fdbc4877b1c491f..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/IdentifierMapperUnitTest.java +++ /dev/null @@ -1,84 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.api.identifier.IdentifierTypeDto; -import at.tuwien.entities.identifier.Identifier; -import at.tuwien.entities.identifier.IdentifierType; -import at.tuwien.test.AbstractUnitTest; -import lombok.extern.log4j.Log4j2; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; - -@Log4j2 -@SpringBootTest -public class IdentifierMapperUnitTest extends AbstractUnitTest { - - @Autowired - private IdentifierMapper identifierMapper; - - @Test - public void identifierTypeDtoToIdentifierType_succeeds() { - - /* test */ - assertEquals(IdentifierType.VIEW, identifierMapper.identifierTypeDtoToIdentifierType(IdentifierTypeDto.VIEW)); - assertEquals(IdentifierType.TABLE, identifierMapper.identifierTypeDtoToIdentifierType(IdentifierTypeDto.TABLE)); - assertEquals(IdentifierType.SUBSET, identifierMapper.identifierTypeDtoToIdentifierType(IdentifierTypeDto.SUBSET)); - assertEquals(IdentifierType.DATABASE, identifierMapper.identifierTypeDtoToIdentifierType(IdentifierTypeDto.DATABASE)); - } - - @Test - public void identifierCreateDtoToIdentifier_succeeds() { - - /* test */ - final Identifier response = identifierMapper.identifierCreateDtoToIdentifier(IDENTIFIER_1_CREATE_DTO); - assertNull(response.getDatabase()); - assertNull(response.getViewId()); - assertNull(response.getQueryId()); - assertNull(response.getTableId()); - assertNull(response.getDoi()); - assertEquals(IDENTIFIER_1_TYPE, response.getType()); - } - - @Test - public void identifierCreateDtoToIdentifier_withDoi_succeeds() { - - /* test */ - final Identifier response = identifierMapper.identifierCreateDtoToIdentifier(IDENTIFIER_1_CREATE_WITH_DOI_DTO); - assertNull(response.getDatabase()); - assertNull(response.getViewId()); - assertNull(response.getQueryId()); - assertNull(response.getTableId()); - assertEquals(IDENTIFIER_1_DOI_NOT_NULL, response.getDoi()); - assertEquals(IDENTIFIER_1_TYPE, response.getType()); - } - - @Test - public void identifierCreateDtoToIdentifier_subset_succeeds() { - - /* test */ - final Identifier response = identifierMapper.identifierCreateDtoToIdentifier(IDENTIFIER_2_CREATE_DTO); - assertNull(response.getDatabase()); - assertNull(response.getViewId()); - assertNull(response.getTableId()); - assertEquals(IDENTIFIER_2_QUERY_ID, response.getQueryId()); - assertNull(response.getDoi()); - assertEquals(IDENTIFIER_2_TYPE, response.getType()); - } - - @Test - public void identifierCreateDtoToIdentifier_view_succeeds() { - - /* test */ - final Identifier response = identifierMapper.identifierCreateDtoToIdentifier(IDENTIFIER_3_CREATE_DTO); - assertNull(response.getDatabase()); - assertNull(response.getQueryId()); - assertNull(response.getTableId()); - assertEquals(IDENTIFIER_3_VIEW_ID, response.getViewId()); - assertNull(response.getDoi()); - assertEquals(IDENTIFIER_3_TYPE, response.getType()); - } - -} diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..28ab4ccb41133b237c033adbf77c85e9dcf7bb3f --- /dev/null +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java @@ -0,0 +1,480 @@ +package at.tuwien.mapper; + +import at.tuwien.api.database.DatabaseDto; +import at.tuwien.api.database.ViewDto; +import at.tuwien.api.database.table.TableDto; +import at.tuwien.api.database.table.columns.ColumnTypeDto; +import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto; +import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto; +import at.tuwien.api.database.table.constraints.foreign.ReferenceTypeDto; +import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto; +import at.tuwien.api.database.table.constraints.unique.UniqueDto; +import at.tuwien.api.identifier.IdentifierDto; +import at.tuwien.api.identifier.IdentifierTypeDto; +import at.tuwien.api.user.UserBriefDto; +import at.tuwien.api.user.UserDto; +import at.tuwien.entities.container.Container; +import at.tuwien.entities.database.Database; +import at.tuwien.entities.database.table.Table; +import at.tuwien.entities.identifier.Identifier; +import at.tuwien.entities.identifier.IdentifierType; +import at.tuwien.test.AbstractUnitTest; +import lombok.extern.log4j.Log4j2; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; + +@Log4j2 +@SpringBootTest +public class MetadataMapperUnitTest extends AbstractUnitTest { + + private final DateTimeFormatter mariaDbFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[.SSS]") + .withZone(ZoneId.of("UTC")); + + @Autowired + private MetadataMapper metadataMapper; + + @BeforeEach + public void beforeEach() { + genesis(); + } + + @Test + public void mapMariaDbInstant_succeeds() { + final String timestamp = "2023-01-08 08:49:29"; + final Instant compare = Instant.ofEpochSecond(1673167769); + + /* test */ + final Instant response = LocalDateTime.parse(timestamp, mariaDbFormatter) + .atZone(ZoneId.of("UTC")) + .toInstant(); + assertEquals(compare, response); + } + + @Test + public void containerEquals_fails() { + + /* test */ + assertNotEquals(CONTAINER_1, CONTAINER_2); + } + + @Test + public void containerEquals_identity_succeeds() { + + /* test */ + assertEquals(CONTAINER_1, CONTAINER_1); + } + + @Test + public void containerEquals_similar_succeeds() { + final Container tmp = Container.builder() + .id(CONTAINER_1_ID) + .build(); + + /* test */ + assertEquals(CONTAINER_1, tmp); + } + + @Test + public void identifierTypeDtoToIdentifierType_succeeds() { + + /* test */ + assertEquals(IdentifierType.VIEW, metadataMapper.identifierTypeDtoToIdentifierType(IdentifierTypeDto.VIEW)); + assertEquals(IdentifierType.TABLE, metadataMapper.identifierTypeDtoToIdentifierType(IdentifierTypeDto.TABLE)); + assertEquals(IdentifierType.SUBSET, metadataMapper.identifierTypeDtoToIdentifierType(IdentifierTypeDto.SUBSET)); + assertEquals(IdentifierType.DATABASE, metadataMapper.identifierTypeDtoToIdentifierType(IdentifierTypeDto.DATABASE)); + } + + @Test + public void identifierCreateDtoToIdentifier_succeeds() { + + /* test */ + final Identifier response = metadataMapper.identifierCreateDtoToIdentifier(IDENTIFIER_1_CREATE_DTO); + assertNull(response.getDatabase()); + assertNull(response.getViewId()); + assertNull(response.getQueryId()); + assertNull(response.getTableId()); + assertNull(response.getDoi()); + assertEquals(IDENTIFIER_1_TYPE, response.getType()); + } + + @Test + public void identifierCreateDtoToIdentifier_withDoi_succeeds() { + + /* test */ + final Identifier response = metadataMapper.identifierCreateDtoToIdentifier(IDENTIFIER_1_CREATE_WITH_DOI_DTO); + assertNull(response.getDatabase()); + assertNull(response.getViewId()); + assertNull(response.getQueryId()); + assertNull(response.getTableId()); + assertEquals(IDENTIFIER_1_DOI_NOT_NULL, response.getDoi()); + assertEquals(IDENTIFIER_1_TYPE, response.getType()); + } + + @Test + public void identifierCreateDtoToIdentifier_subset_succeeds() { + + /* test */ + final Identifier response = metadataMapper.identifierCreateDtoToIdentifier(IDENTIFIER_2_CREATE_DTO); + assertNull(response.getDatabase()); + assertNull(response.getViewId()); + assertNull(response.getTableId()); + assertEquals(IDENTIFIER_2_QUERY_ID, response.getQueryId()); + assertNull(response.getDoi()); + assertEquals(IDENTIFIER_2_TYPE, response.getType()); + } + + @Test + public void identifierCreateDtoToIdentifier_view_succeeds() { + + /* test */ + final Identifier response = metadataMapper.identifierCreateDtoToIdentifier(IDENTIFIER_3_CREATE_DTO); + assertNull(response.getDatabase()); + assertNull(response.getQueryId()); + assertNull(response.getTableId()); + assertEquals(IDENTIFIER_3_VIEW_ID, response.getViewId()); + assertNull(response.getDoi()); + assertEquals(IDENTIFIER_3_TYPE, response.getType()); + } + + @Test + public void customDatabaseToDatabaseDto_succeeds() { + + /* test */ + final DatabaseDto response = metadataMapper.customDatabaseToDatabaseDto(DATABASE_1); + assertEquals(DATABASE_1_ID, response.getId()); + assertNotNull(response.getContact()); + assertEquals(USER_1_ID, response.getContact().getId()); + /* identifiers formatted */ + assertEquals(4, response.getIdentifiers().size()); + final IdentifierDto identifier1 = response.getIdentifiers().get(0); + assertEquals(DATABASE_1_ID, identifier1.getDatabaseId()); + assertNotNull(identifier1.getCreator()); + assertEquals(IDENTIFIER_1_CREATED_BY, identifier1.getCreator().getId()); + assertNotNull(identifier1.getCreated()); + assertNotNull(identifier1.getLastModified()); + final IdentifierDto identifier2 = response.getIdentifiers().get(1); + assertEquals(DATABASE_1_ID, identifier2.getDatabaseId()); + assertNotNull(identifier2.getCreator()); + assertEquals(IDENTIFIER_2_CREATED_BY, identifier2.getCreator().getId()); + assertNotNull(identifier2.getCreated()); + assertNotNull(identifier2.getLastModified()); + final IdentifierDto identifier3 = response.getIdentifiers().get(2); + assertEquals(DATABASE_1_ID, identifier3.getDatabaseId()); + assertNotNull(identifier3.getCreator()); + assertEquals(IDENTIFIER_3_CREATED_BY, identifier3.getCreator().getId()); + assertNotNull(identifier3.getCreated()); + assertNotNull(identifier3.getLastModified()); + final IdentifierDto identifier4 = response.getIdentifiers().get(3); + assertEquals(DATABASE_1_ID, identifier4.getDatabaseId()); + assertNotNull(identifier4.getCreator()); + assertEquals(IDENTIFIER_4_CREATED_BY, identifier4.getCreator().getId()); + assertNotNull(identifier4.getCreated()); + assertNotNull(identifier4.getLastModified()); + /* Table 1 formatted */ + final TableDto table0 = response.getTables().get(0); + assertEquals(TABLE_1_ID, table0.getId()); + assertEquals(TABLE_1_NAME, table0.getName()); + assertEquals(TABLE_1_INTERNALNAME, table0.getInternalName()); + assertEquals(TABLE_1_DESCRIPTION, table0.getDescription()); + assertEquals(DATABASE_1_ID, table0.getTdbid()); + assertEquals(USER_1_ID, table0.getCreatedBy()); + assertEquals(USER_1_ID, table0.getOwner().getId()); + assertEquals(USER_1_ID, table0.getCreator().getId()); + assertEquals(TABLE_1_AVG_ROW_LENGTH, table0.getAvgRowLength()); + assertEquals(TABLE_1_NUM_ROWS, table0.getNumRows()); + assertEquals(TABLE_1_DATA_LENGTH, table0.getDataLength()); + assertEquals(TABLE_1_MAX_DATA_LENGTH, table0.getMaxDataLength()); + assertNotNull(table0.getCreated()); + /* columns formatted */ + assertEquals(TABLE_1_COLUMNS.size(), table0.getColumns().size()); + for (int i = 0; i < TABLE_1_COLUMNS.size(); i++) { + assertEquals(TABLE_1_COLUMNS.get(i).getId(), table0.getColumns().get(i).getId()); + assertEquals(TABLE_1_COLUMNS.get(i).getOrdinalPosition(), table0.getColumns().get(i).getOrdinalPosition()); + assertNotNull(table0.getColumns().get(i).getOrdinalPosition()); + assertEquals(TABLE_1_COLUMNS.get(i).getTable().getId(), table0.getColumns().get(i).getTableId()); + assertEquals(TABLE_1_COLUMNS.get(i).getName(), table0.getColumns().get(i).getName()); + assertEquals(TABLE_1_COLUMNS.get(i).getInternalName(), table0.getColumns().get(i).getInternalName()); + assertEquals(List.of(ColumnTypeDto.BIGINT, ColumnTypeDto.DATE, ColumnTypeDto.VARCHAR, ColumnTypeDto.DECIMAL, ColumnTypeDto.DECIMAL).get(i), table0.getColumns().get(i).getColumnType()); + assertEquals(TABLE_1_COLUMNS.get(i).getSize(), table0.getColumns().get(i).getSize()); + assertEquals(TABLE_1_COLUMNS.get(i).getD(), table0.getColumns().get(i).getD()); + assertEquals(TABLE_1_COLUMNS.get(i).getIsNullAllowed(), table0.getColumns().get(i).getIsNullAllowed()); + assertEquals(TABLE_1_COLUMNS.get(i).getAutoGenerated(), table0.getColumns().get(i).getAutoGenerated()); + assertEquals(TABLE_1_COLUMNS.get(i).getEnums(), table0.getColumns().get(i).getEnums()); + assertEquals(TABLE_1_COLUMNS.get(i).getSets(), table0.getColumns().get(i).getSets()); + } + /* constraints formatted */ + assertNotNull(table0.getConstraints()); + assertEquals(0, table0.getConstraints().getUniques().size()); + assertEquals(0, table0.getConstraints().getChecks().size()); + assertEquals(0, table0.getConstraints().getForeignKeys().size()); + assertEquals(1, table0.getConstraints().getPrimaryKey().size()); + final PrimaryKeyDto table0pk = new ArrayList<>(table0.getConstraints().getPrimaryKey()).get(0); + assertEquals(1L, table0pk.getId()); + assertEquals(TABLE_1_COLUMNS_BRIEF_0_DTO.getId(), table0pk.getColumn().getId()); + assertEquals(TABLE_1_COLUMNS_BRIEF_0_DTO.getName(), table0pk.getColumn().getName()); + assertEquals(TABLE_1_COLUMNS_BRIEF_0_DTO.getId(), table0pk.getColumn().getId()); + assertEquals(TABLE_1_COLUMNS_BRIEF_0_DTO.getName(), table0pk.getColumn().getName()); + assertEquals(TABLE_1_COLUMNS_BRIEF_0_DTO.getInternalName(), table0pk.getColumn().getInternalName()); + assertEquals(TABLE_1_ID, table0pk.getTable().getId()); + assertEquals(DATABASE_1_ID, table0pk.getTable().getDatabaseId()); + assertEquals(ColumnTypeDto.BIGINT, table0pk.getColumn().getColumnType()); + assertNull(table0pk.getColumn().getAlias()); + assertEquals(TABLE_1_ID, table0pk.getColumn().getTableId()); + assertEquals(DATABASE_1_ID, table0pk.getColumn().getDatabaseId()); + /* Table 2 formatted */ + final TableDto table1 = response.getTables().get(1); + assertEquals(TABLE_2_ID, table1.getId()); + assertEquals(TABLE_2_NAME, table1.getName()); + assertEquals(TABLE_2_INTERNALNAME, table1.getInternalName()); + assertEquals(TABLE_2_DESCRIPTION, table1.getDescription()); + assertEquals(DATABASE_1_ID, table1.getTdbid()); + assertEquals(USER_2_ID, table1.getCreatedBy()); + assertEquals(USER_2_ID, table1.getOwner().getId()); + assertEquals(USER_2_ID, table1.getCreator().getId()); + assertEquals(TABLE_2_AVG_ROW_LENGTH, table1.getAvgRowLength()); + assertEquals(TABLE_2_NUM_ROWS, table1.getNumRows()); + assertEquals(TABLE_2_DATA_LENGTH, table1.getDataLength()); + assertEquals(TABLE_2_MAX_DATA_LENGTH, table1.getMaxDataLength()); + assertNotNull(table1.getCreated()); + /* columns formatted */ + assertEquals(TABLE_2_COLUMNS.size(), table1.getColumns().size()); + for (int i = 0; i < TABLE_2_COLUMNS.size(); i++) { + assertEquals(TABLE_2_COLUMNS.get(i).getId(), table1.getColumns().get(i).getId()); + assertEquals(TABLE_2_COLUMNS.get(i).getOrdinalPosition(), table1.getColumns().get(i).getOrdinalPosition()); + assertNotNull(table1.getColumns().get(i).getOrdinalPosition()); + assertEquals(TABLE_2_COLUMNS.get(i).getTable().getId(), table1.getColumns().get(i).getTableId()); + assertEquals(TABLE_2_COLUMNS.get(i).getName(), table1.getColumns().get(i).getName()); + assertEquals(TABLE_2_COLUMNS.get(i).getInternalName(), table1.getColumns().get(i).getInternalName()); + assertEquals(List.of(ColumnTypeDto.VARCHAR, ColumnTypeDto.DECIMAL, ColumnTypeDto.DECIMAL).get(i), table1.getColumns().get(i).getColumnType()); + assertEquals(TABLE_2_COLUMNS.get(i).getSize(), table1.getColumns().get(i).getSize()); + assertEquals(TABLE_2_COLUMNS.get(i).getD(), table1.getColumns().get(i).getD()); + assertEquals(TABLE_2_COLUMNS.get(i).getIsNullAllowed(), table1.getColumns().get(i).getIsNullAllowed()); + assertEquals(TABLE_2_COLUMNS.get(i).getAutoGenerated(), table1.getColumns().get(i).getAutoGenerated()); + assertEquals(TABLE_2_COLUMNS.get(i).getEnums(), table1.getColumns().get(i).getEnums()); + assertEquals(TABLE_2_COLUMNS.get(i).getSets(), table1.getColumns().get(i).getSets()); + } + /* constraints formatted */ + assertNotNull(table1.getConstraints()); + assertEquals(1, table1.getConstraints().getUniques().size()); + final UniqueDto table1uk = table1.getConstraints().getUniques().get(0); + assertEquals(1L, table1uk.getId()); + assertEquals(TABLE_2_ID, table1uk.getTable().getId()); + assertEquals(DATABASE_1_ID, table1uk.getTable().getDatabaseId()); + assertEquals("uk_1", table1uk.getName()); + assertEquals(TABLE_2_COLUMNS_DTO.get(1).getId(), table1uk.getColumns().get(0).getId()); + assertEquals(1, table1.getConstraints().getChecks().size()); + assertEquals("`mintemp` > 0", new ArrayList<>(table1.getConstraints().getChecks()).get(0)); + assertEquals(1, table1.getConstraints().getForeignKeys().size()); + final ForeignKeyDto table1fk = new ArrayList<>(table1.getConstraints().getForeignKeys()).get(0); + assertEquals("fk_location", table1fk.getName()); + assertEquals(ReferenceTypeDto.NO_ACTION, table1fk.getOnDelete()); + assertEquals(ReferenceTypeDto.NO_ACTION, table1fk.getOnUpdate()); + assertEquals(TABLE_1_ID, table1fk.getTable().getId()); + assertEquals(TABLE_2_ID, table1fk.getReferencedTable().getId()); + final ForeignKeyReferenceDto table1fkr = table1fk.getReferences().get(0); + assertEquals(1L, table1fkr.getId()); + assertEquals(TABLE_2_COLUMNS_DTO.get(2).getId(), table1fkr.getColumn().getId()); + assertEquals(TABLE_2_COLUMNS_DTO.get(2).getTable().getId(), table1fkr.getColumn().getTableId()); + assertEquals(TABLE_2_COLUMNS_DTO.get(2).getDatabaseId(), table1fkr.getColumn().getDatabaseId()); + assertEquals(TABLE_1_COLUMNS_DTO.get(0).getDatabaseId(), table1fkr.getReferencedColumn().getId()); + assertEquals(TABLE_1_COLUMNS_DTO.get(0).getDatabaseId(), table1fkr.getReferencedColumn().getTableId()); + assertEquals(TABLE_1_COLUMNS_DTO.get(0).getDatabaseId(), table1fkr.getReferencedColumn().getDatabaseId()); + assertEquals(1, table1.getConstraints().getPrimaryKey().size()); + final PrimaryKeyDto table1pk = new ArrayList<>(table1.getConstraints().getPrimaryKey()).get(0); + assertEquals(2L, table1pk.getId()); + assertEquals(TABLE_2_COLUMNS_BRIEF_0_DTO.getId(), table1pk.getColumn().getId()); + assertEquals(TABLE_2_COLUMNS_BRIEF_0_DTO.getName(), table1pk.getColumn().getName()); + assertEquals(TABLE_2_COLUMNS_BRIEF_0_DTO.getId(), table1pk.getColumn().getId()); + assertEquals(TABLE_2_COLUMNS_BRIEF_0_DTO.getName(), table1pk.getColumn().getName()); + assertEquals(TABLE_2_COLUMNS_BRIEF_0_DTO.getInternalName(), table1pk.getColumn().getInternalName()); + assertEquals(ColumnTypeDto.VARCHAR, table1pk.getColumn().getColumnType()); + assertNull(table1pk.getColumn().getAlias()); + assertEquals(TABLE_2_ID, table1pk.getColumn().getTableId()); + assertEquals(DATABASE_1_ID, table1pk.getColumn().getDatabaseId()); + /* Table 3 formatted */ + final TableDto table2 = response.getTables().get(2); + assertEquals(TABLE_3_ID, table2.getId()); + assertEquals(TABLE_3_NAME, table2.getName()); + assertEquals(TABLE_3_INTERNALNAME, table2.getInternalName()); + assertEquals(TABLE_3_DESCRIPTION, table2.getDescription()); + assertEquals(DATABASE_1_ID, table2.getTdbid()); + assertEquals(USER_3_ID, table2.getCreatedBy()); + assertEquals(USER_3_ID, table2.getOwner().getId()); + assertEquals(USER_3_ID, table2.getCreator().getId()); + assertEquals(TABLE_3_AVG_ROW_LENGTH, table2.getAvgRowLength()); + assertEquals(TABLE_3_NUM_ROWS, table2.getNumRows()); + assertEquals(TABLE_3_DATA_LENGTH, table2.getDataLength()); + assertEquals(TABLE_3_MAX_DATA_LENGTH, table2.getMaxDataLength()); + assertNotNull(table2.getCreated()); + /* columns formatted */ + assertEquals(TABLE_3_COLUMNS.size(), table2.getColumns().size()); + for (int i = 0; i < TABLE_3_COLUMNS.size(); i++) { + assertEquals(TABLE_3_COLUMNS.get(i).getId(), table2.getColumns().get(i).getId()); + assertEquals(TABLE_3_COLUMNS.get(i).getOrdinalPosition(), table2.getColumns().get(i).getOrdinalPosition()); + assertNotNull(table2.getColumns().get(i).getOrdinalPosition()); + assertEquals(TABLE_3_COLUMNS.get(i).getTable().getId(), table2.getColumns().get(i).getTableId()); + assertEquals(TABLE_3_COLUMNS.get(i).getName(), table2.getColumns().get(i).getName()); + assertEquals(TABLE_3_COLUMNS.get(i).getInternalName(), table2.getColumns().get(i).getInternalName()); + assertEquals(List.of(ColumnTypeDto.BIGINT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.DATE, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.DATE, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.DATE, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT, ColumnTypeDto.INT).get(i), table2.getColumns().get(i).getColumnType()); + assertEquals(TABLE_3_COLUMNS.get(i).getSize(), table2.getColumns().get(i).getSize()); + assertEquals(TABLE_3_COLUMNS.get(i).getD(), table2.getColumns().get(i).getD()); + assertEquals(TABLE_3_COLUMNS.get(i).getIsNullAllowed(), table2.getColumns().get(i).getIsNullAllowed()); + assertEquals(TABLE_3_COLUMNS.get(i).getAutoGenerated(), table2.getColumns().get(i).getAutoGenerated()); + assertEquals(TABLE_3_COLUMNS.get(i).getEnums(), table2.getColumns().get(i).getEnums()); + assertEquals(TABLE_3_COLUMNS.get(i).getSets(), table2.getColumns().get(i).getSets()); + } + /* constraints formatted */ + final PrimaryKeyDto table2pk = new ArrayList<>(table2.getConstraints().getPrimaryKey()).get(0); + assertEquals(TABLE_3_COLUMNS_BRIEF_0_DTO.getId(), table2pk.getColumn().getId()); + assertEquals(TABLE_3_COLUMNS_BRIEF_0_DTO.getName(), table2pk.getColumn().getName()); + assertEquals(TABLE_3_COLUMNS_BRIEF_0_DTO.getId(), table2pk.getColumn().getId()); + assertEquals(TABLE_3_COLUMNS_BRIEF_0_DTO.getName(), table2pk.getColumn().getName()); + assertEquals(TABLE_3_COLUMNS_BRIEF_0_DTO.getInternalName(), table2pk.getColumn().getInternalName()); + assertEquals(ColumnTypeDto.BIGINT, table2pk.getColumn().getColumnType()); + assertNull(table2pk.getColumn().getAlias()); + assertEquals(TABLE_3_ID, table2pk.getColumn().getTableId()); + assertEquals(DATABASE_1_ID, table2pk.getColumn().getDatabaseId()); + /* Table 4 formatted */ + final TableDto table3 = response.getTables().get(3); + assertEquals(TABLE_4_ID, table3.getId()); + assertEquals(TABLE_4_NAME, table3.getName()); + assertEquals(TABLE_4_INTERNALNAME, table3.getInternalName()); + assertEquals(TABLE_4_DESCRIPTION, table3.getDescription()); + assertEquals(DATABASE_1_ID, table3.getTdbid()); + assertEquals(USER_1_ID, table3.getCreatedBy()); + assertEquals(USER_1_ID, table3.getOwner().getId()); + assertEquals(USER_1_ID, table3.getCreator().getId()); + assertEquals(TABLE_4_AVG_ROW_LENGTH, table3.getAvgRowLength()); + assertEquals(TABLE_4_NUM_ROWS, table3.getNumRows()); + assertEquals(TABLE_4_DATA_LENGTH, table3.getDataLength()); + assertEquals(TABLE_4_MAX_DATA_LENGTH, table3.getMaxDataLength()); + assertNotNull(table3.getCreated()); + /* columns formatted */ + assertEquals(TABLE_4_COLUMNS.size(), table3.getColumns().size()); + for (int i = 0; i < TABLE_4_COLUMNS.size(); i++) { + assertEquals(TABLE_4_COLUMNS.get(i).getId(), table3.getColumns().get(i).getId()); + assertEquals(TABLE_4_COLUMNS.get(i).getOrdinalPosition(), table3.getColumns().get(i).getOrdinalPosition()); + assertNotNull(table3.getColumns().get(i).getOrdinalPosition()); + assertEquals(TABLE_4_COLUMNS.get(i).getTable().getId(), table3.getColumns().get(i).getTableId()); + assertEquals(TABLE_4_COLUMNS.get(i).getName(), table3.getColumns().get(i).getName()); + assertEquals(TABLE_4_COLUMNS.get(i).getInternalName(), table3.getColumns().get(i).getInternalName()); + assertEquals(List.of(ColumnTypeDto.TIMESTAMP, ColumnTypeDto.DECIMAL).get(i), table3.getColumns().get(i).getColumnType()); + assertEquals(TABLE_4_COLUMNS.get(i).getSize(), table3.getColumns().get(i).getSize()); + assertEquals(TABLE_4_COLUMNS.get(i).getD(), table3.getColumns().get(i).getD()); + assertEquals(TABLE_4_COLUMNS.get(i).getIsNullAllowed(), table3.getColumns().get(i).getIsNullAllowed()); + assertEquals(TABLE_4_COLUMNS.get(i).getAutoGenerated(), table3.getColumns().get(i).getAutoGenerated()); + assertEquals(TABLE_4_COLUMNS.get(i).getEnums(), table3.getColumns().get(i).getEnums()); + assertEquals(TABLE_4_COLUMNS.get(i).getSets(), table3.getColumns().get(i).getSets()); + } + /* constraints formatted */ + final PrimaryKeyDto table3pk = new ArrayList<>(table3.getConstraints().getPrimaryKey()).get(0); + assertEquals(TABLE_4_COLUMNS_BRIEF_0_DTO.getId(), table3pk.getColumn().getId()); + assertEquals(TABLE_4_COLUMNS_BRIEF_0_DTO.getName(), table3pk.getColumn().getName()); + assertEquals(TABLE_4_COLUMNS_BRIEF_0_DTO.getId(), table3pk.getColumn().getId()); + assertEquals(TABLE_4_COLUMNS_BRIEF_0_DTO.getName(), table3pk.getColumn().getName()); + assertEquals(TABLE_4_COLUMNS_BRIEF_0_DTO.getInternalName(), table3pk.getColumn().getInternalName()); + assertEquals(ColumnTypeDto.TIMESTAMP, table3pk.getColumn().getColumnType()); + assertNull(table3pk.getColumn().getAlias()); + assertEquals(TABLE_4_ID, table3pk.getColumn().getTableId()); + assertEquals(DATABASE_1_ID, table3pk.getColumn().getDatabaseId()); + } + + public static Stream<Arguments> nameToInternalName_parameters() { + return Stream.of( + Arguments.arguments("dash_minus", "OE/NO-027", "oeno-027"), + Arguments.arguments("percent", "OE%NO-027", "oeno-027"), + Arguments.arguments("umlaut", "OE/NÖ-027", "oeno-027"), + Arguments.arguments("dot", "OE.NO-027", "oeno-027") + ); + } + + @ParameterizedTest + @MethodSource("nameToInternalName_parameters") + public void nameToInternalName_succeeds(String name, String request, String compare) { + + /* test */ + final String response = metadataMapper.nameToInternalName(request); + assertEquals(compare, response); + } + + @Test + public void userEquals_fails() { + + /* test */ + assertNotEquals(USER_1_DTO, USER_2_DTO); + } + + @Test + public void userEquals_identity_succeeds() { + + /* test */ + assertEquals(USER_1_DTO, USER_1_DTO); + } + + @Test + public void userEquals_similar_succeeds() { + final UserDto tmp = UserDto.builder() + .id(USER_1_ID) + .build(); + + /* test */ + assertEquals(USER_1_DTO, tmp); + } + + @Test + public void userToUserBriefDto_succeeds() { + + /* test */ + final UserBriefDto response = metadataMapper.userToUserBriefDto(USER_1); + assertEquals(USER_1_NAME, response.getName()); + assertEquals(USER_1_NAME + " — @" + USER_1_USERNAME, response.getQualifiedName()); + } + + @Test + public void userToUserDto_succeeds() { + + /* test */ + final UserDto response = metadataMapper.userToUserDto(USER_1); + assertEquals(USER_1_NAME, response.getName()); + assertEquals(USER_1_NAME + " — @" + USER_1_USERNAME, response.getQualifiedName()); + } + + @Test + public void viewToViewDto_succeeds() { + + /* test */ + final ViewDto response = metadataMapper.viewToViewDto(VIEW_1); + assertEquals(VIEW_1_ID, response.getId()); + assertEquals(VIEW_1_DATABASE_ID, response.getVdbid()); + assertEquals(VIEW_1_NAME, response.getName()); + assertEquals(VIEW_1_INTERNAL_NAME, response.getInternalName()); + assertNotNull(response.getDatabase()); + assertEquals(VIEW_1_DATABASE_ID, response.getDatabase().getId()); + assertEquals(VIEW_1_QUERY, response.getQuery()); + assertEquals(VIEW_1_QUERY_HASH, response.getQueryHash()); + assertNotNull(response.getIdentifiers()); + assertEquals(1, response.getIdentifiers().size()); + final IdentifierDto identifier0 = response.getIdentifiers().get(0); + assertEquals(IDENTIFIER_3_ID, identifier0.getId()); + assertEquals(VIEW_1_DATABASE_ID, identifier0.getDatabaseId()); + assertEquals(VIEW_1_ID, identifier0.getViewId()); + assertEquals(VIEW_1_QUERY, identifier0.getQuery()); + assertEquals(VIEW_1_QUERY_HASH, identifier0.getQueryHash()); + } + +} diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/StoreMapperUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/StoreMapperUnitTest.java deleted file mode 100644 index 202c1cf2240d2684e806feda17e7d0caba47a625..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/StoreMapperUnitTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.test.AbstractUnitTest; -import lombok.extern.log4j.Log4j2; -import org.junit.jupiter.api.Test; - -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -@Log4j2 -public class StoreMapperUnitTest extends AbstractUnitTest { - - private final DateTimeFormatter mariaDbFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss[.SSS]") - .withZone(ZoneId.of("UTC")); - - @Test - public void mapMariaDbInstant_succeeds() { - final String timestamp = "2023-01-08 08:49:29"; - final Instant compare = Instant.ofEpochSecond(1673167769); - - /* test */ - final Instant response = LocalDateTime.parse(timestamp, mariaDbFormatter) - .atZone(ZoneId.of("UTC")) - .toInstant(); - assertEquals(compare, response); - } - -} diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/TableMapperUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/TableMapperUnitTest.java deleted file mode 100644 index b02d660e0b4948fb20c334ce51d85874b4441fc6..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/TableMapperUnitTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.test.AbstractUnitTest; -import lombok.extern.log4j.Log4j2; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -@Log4j2 -@EnableAutoConfiguration(exclude = RabbitAutoConfiguration.class) -@SpringBootTest -@ExtendWith(SpringExtension.class) -public class TableMapperUnitTest extends AbstractUnitTest { - - @Autowired - private TableMapper tableMapper; - - public static Stream<Arguments> nameToInternalName_parameters() { - return Stream.of( - Arguments.arguments("dash_minus", "OE/NO-027", "oe_no_027"), - Arguments.arguments("percent", "OE%NO-027", "oe_no_027"), - Arguments.arguments("umlaut", "OE/NÖ-027", "oe_no__027"), - Arguments.arguments("dot", "OE.NO-027", "oe_no_027") - ); - } - - @ParameterizedTest - @MethodSource("nameToInternalName_parameters") - public void nameToInternalName_succeeds(String name, String request, String compare) { - - /* test */ - final String response = tableMapper.nameToInternalName(request); - assertEquals(compare, response); - } - -} diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/UserMapperUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/UserMapperUnitTest.java deleted file mode 100644 index dab115605f3ff553a611da84fff081cf70ac69c5..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/UserMapperUnitTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.user.UserBriefDto; -import at.tuwien.api.user.UserDto; -import lombok.extern.log4j.Log4j2; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; - -@Log4j2 -@SpringBootTest -public class UserMapperUnitTest extends AbstractUnitTest { - - @Autowired - private UserMapper userMapper; - - @Test - public void equals_fails() { - - /* test */ - assertNotEquals(USER_1_DTO, USER_2_DTO); - } - - @Test - public void equals_identity_succeeds() { - - /* test */ - assertEquals(USER_1_DTO, USER_1_DTO); - } - - @Test - public void equals_similar_succeeds() { - final UserDto tmp = UserDto.builder() - .id(USER_1_ID) - .build(); - - /* test */ - assertEquals(USER_1_DTO, tmp); - } - - @Test - public void userToUserBriefDto_succeeds() { - - /* test */ - final UserBriefDto response = userMapper.userToUserBriefDto(USER_1); - assertEquals(USER_1_NAME, response.getName()); - assertEquals(USER_1_NAME + " — @" + USER_1_USERNAME, response.getQualifiedName()); - } - - @Test - public void userToUserDto_succeeds() { - - /* test */ - final UserDto response = userMapper.userToUserDto(USER_1); - assertEquals(USER_1_NAME, response.getName()); - assertEquals(USER_1_NAME + " — @" + USER_1_USERNAME, response.getQualifiedName()); - } - -} diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/ViewMapperUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/ViewMapperUnitTest.java deleted file mode 100644 index 07a70982644653a5df5040305f666036f826b6ec..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/ViewMapperUnitTest.java +++ /dev/null @@ -1,50 +0,0 @@ -package at.tuwien.mapper; - -import at.tuwien.api.database.ViewDto; -import at.tuwien.api.identifier.IdentifierDto; -import at.tuwien.test.AbstractUnitTest; -import lombok.extern.log4j.Log4j2; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -@Log4j2 -@SpringBootTest -public class ViewMapperUnitTest extends AbstractUnitTest { - - @Autowired - private ViewMapper viewMapper; - - @BeforeEach - public void beforeEach() { - genesis(); - } - - @Test - public void viewToViewDto_succeeds() { - - /* test */ - final ViewDto response = viewMapper.viewToViewDto(VIEW_1); - assertEquals(VIEW_1_ID, response.getId()); - assertEquals(VIEW_1_DATABASE_ID, response.getVdbid()); - assertEquals(VIEW_1_NAME, response.getName()); - assertEquals(VIEW_1_INTERNAL_NAME, response.getInternalName()); - assertNotNull(response.getDatabase()); - assertEquals(VIEW_1_DATABASE_ID, response.getDatabase().getId()); - assertEquals(VIEW_1_QUERY, response.getQuery()); - assertEquals(VIEW_1_QUERY_HASH, response.getQueryHash()); - assertNotNull(response.getIdentifiers()); - assertEquals(1, response.getIdentifiers().size()); - final IdentifierDto identifier0 = response.getIdentifiers().get(0); - assertEquals(IDENTIFIER_3_ID, identifier0.getId()); - assertEquals(VIEW_1_DATABASE_ID, identifier0.getDatabaseId()); - assertEquals(VIEW_1_ID, identifier0.getViewId()); - assertEquals(VIEW_1_QUERY, identifier0.getQuery()); - assertEquals(VIEW_1_QUERY_HASH, identifier0.getQueryHash()); - } - -} diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java index 76678a1fe376b77926d1929b5888a649e2c9d512..44b924f39613f1dbf0dfe951164d6210a6c3d51d 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java @@ -538,7 +538,7 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest { /* ignore */ } try { - tableEndpoint.updateStatistic(DATABASE_1_ID, TABLE_1_ID, TableStatisticDto.builder().build()); + tableEndpoint.updateStatistic(DATABASE_1_ID, TABLE_1_ID); } catch (Exception e) { /* ignore */ } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServicePersistenceTest.java index ed5f21281d71961317a4779aa67b38d0d9b9dca1..1d6d1c30e45f04b20f10985ec7ea67e2c8c88a4a 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServicePersistenceTest.java @@ -5,7 +5,6 @@ import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; import at.tuwien.gateway.SearchServiceGateway; import at.tuwien.repository.*; -import at.tuwien.service.impl.DatabaseServiceImpl; import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; @@ -17,7 +16,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.transaction.annotation.Transactional; import java.util.List; @@ -64,7 +62,6 @@ public class DatabaseServicePersistenceTest extends AbstractUnitTest { } @Test - @Transactional(readOnly = true) public void findById_succeeds() throws DatabaseNotFoundException { /* test */ diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java index 91b64ef93c52e38a83a42fb4d39cd0c966f2ce67..24536a9ca56a9686e13905a46d7326d4863fa6c7 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java @@ -37,7 +37,6 @@ import static org.mockito.Mockito.*; @Log4j2 @SpringBootTest -@Disabled("CI/CD") @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) @ExtendWith(SpringExtension.class) public class TableServicePersistenceTest extends AbstractUnitTest { @@ -79,7 +78,7 @@ public class TableServicePersistenceTest extends AbstractUnitTest { @Test @Transactional public void create_succeeds() throws MalformedException, ServiceException, ServiceConnectionException, - UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, TableExistsException, SearchServiceException, SearchServiceConnectionException { + UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, TableExistsException, SearchServiceException, SearchServiceConnectionException, OntologyNotFoundException, SemanticEntityNotFoundException { final TableCreateDto request = TableCreateDto.builder() .name("New Table") .description("A wonderful table") diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java index 0e74c54947e0693090f43a3a25809473c6c6a609..c16a4191f90cdf1a3228bad5879a40f375abe409 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java @@ -119,7 +119,8 @@ public class TableServiceUnitTest extends AbstractUnitTest { @Test public void createTable_succeeds() throws ServiceException, ServiceConnectionException, UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, TableExistsException, SearchServiceException, - SearchServiceConnectionException, MalformedException { + SearchServiceConnectionException, MalformedException, OntologyNotFoundException, + SemanticEntityNotFoundException { /* mock */ when(userService.findByUsername(USER_1_USERNAME)) @@ -140,7 +141,8 @@ public class TableServiceUnitTest extends AbstractUnitTest { @Test public void createTable_nonStandardColumnNames_succeeds() throws ServiceException, ServiceConnectionException, UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, TableExistsException, - SearchServiceException, SearchServiceConnectionException, MalformedException { + SearchServiceException, SearchServiceConnectionException, MalformedException, OntologyNotFoundException, + SemanticEntityNotFoundException { final TableCreateDto request = TableCreateDto.builder() .name("New Table") .description("A wonderful table") @@ -182,7 +184,7 @@ public class TableServiceUnitTest extends AbstractUnitTest { assertTrue(column0.getAutoGenerated()); final TableColumn column1 = response.getColumns().get(1); assertEquals("I Am Späshül", column1.getName()); - assertEquals("i_am_spa_shu_l", column1.getInternalName()); + assertEquals("i_am_spashul", column1.getInternalName()); assertEquals(TableColumnType.TEXT, column1.getColumnType()); assertTrue(column1.getIsNullAllowed()); assertFalse(column1.getAutoGenerated()); @@ -240,7 +242,8 @@ public class TableServiceUnitTest extends AbstractUnitTest { @Test public void create_succeeds() throws MalformedException, ServiceException, ServiceConnectionException, UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, TableExistsException, - SearchServiceException, SearchServiceConnectionException { + SearchServiceException, SearchServiceConnectionException, OntologyNotFoundException, + SemanticEntityNotFoundException { /* mock */ when(userService.findByUsername(USER_1_USERNAME)) diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java index f686a1c23a15b4728395ee3ca0c0ec0353071a45..fc83d3a650b5642bbe0e8cdc252e95ef59c9dcf5 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java @@ -1,7 +1,10 @@ package at.tuwien.service; +import at.tuwien.entities.database.Database; import at.tuwien.entities.database.View; import at.tuwien.exception.*; +import at.tuwien.gateway.DataServiceGateway; +import at.tuwien.gateway.SearchServiceGateway; import at.tuwien.repository.ContainerRepository; import at.tuwien.repository.DatabaseRepository; import at.tuwien.repository.LicenseRepository; @@ -14,12 +17,16 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit.jupiter.SpringExtension; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; @Log4j2 @SpringBootTest @@ -43,6 +50,12 @@ public class ViewServicePersistenceTest extends AbstractUnitTest { @Autowired private ViewService viewService; + @MockBean + private DataServiceGateway dataServiceGateway; + + @MockBean + private SearchServiceGateway searchServiceGateway; + @BeforeEach public void beforeEach() { genesis(); @@ -65,4 +78,19 @@ public class ViewServicePersistenceTest extends AbstractUnitTest { assertEquals(VIEW_1_COLUMNS.size(), response.getColumns().size()); } + @Test + public void delete_succeeds() throws SearchServiceException, ServiceException, ServiceConnectionException, + DatabaseNotFoundException, SearchServiceConnectionException, ViewNotFoundException { + + /* mock */ + doNothing() + .when(dataServiceGateway) + .deleteView(DATABASE_1_ID, VIEW_1_ID); + when(searchServiceGateway.update(any(Database.class))) + .thenReturn(DATABASE_1_DTO); + + /* test */ + viewService.delete(VIEW_1); + } + } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/GatewayConfig.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/GatewayConfig.java index d0029e9458d26144a0921ab3008f202bd01e4c63..c64fc52282af3dc8fb3f6bc075ad080e5f162f0c 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/GatewayConfig.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/GatewayConfig.java @@ -30,6 +30,9 @@ public class GatewayConfig { @Value("${dbrepo.endpoints.dataService}") private String dataEndpoint; + @Value("${dbrepo.endpoints.analyseService}") + private String analyseEndpoint; + @Value("${dbrepo.endpoints.searchService}") private String searchEndpoint; @@ -54,6 +57,7 @@ public class GatewayConfig { public RestTemplate brokerRestTemplate() { final RestTemplate restTemplate = new RestTemplate(); restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(brokerEndpoint)); + log.debug("add basic authentication for broker service: username={}, password=(hidden)", brokerUsername); restTemplate.getInterceptors() .addAll(List.of(new BasicAuthenticationInterceptor(brokerUsername, brokerPassword), clientHttpRequestInterceptor())); @@ -64,7 +68,18 @@ public class GatewayConfig { public RestTemplate dataServiceRestTemplate() { final RestTemplate restTemplate = new RestTemplate(); restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(dataEndpoint)); - log.debug("add basic authentication for internal data service: username={}, password=(hidden)", adminUsername); + log.debug("add basic authentication for data service: username={}, password=(hidden)", adminUsername); + restTemplate.getInterceptors() + .addAll(List.of(new BasicAuthenticationInterceptor(adminUsername, adminPassword), + clientHttpRequestInterceptor())); + return restTemplate; + } + + @Bean("analyseServiceRestTemplate") + public RestTemplate analyseServiceRestTemplate() { + final RestTemplate restTemplate = new RestTemplate(); + restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(analyseEndpoint)); + log.debug("add basic authentication for analyse service: username={}, password=(hidden)", adminUsername); restTemplate.getInterceptors() .addAll(List.of(new BasicAuthenticationInterceptor(adminUsername, adminPassword), clientHttpRequestInterceptor())); @@ -75,7 +90,7 @@ public class GatewayConfig { public RestTemplate searchServiceRestTemplate() { final RestTemplate restTemplate = new RestTemplate(); restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(searchEndpoint)); - log.debug("add basic authentication for internal search service: username={}, password=(hidden)", adminUsername); + log.debug("add basic authentication for search service: username={}, password=(hidden)", adminUsername); restTemplate.getInterceptors() .addAll(List.of(new BasicAuthenticationInterceptor(adminUsername, adminPassword), clientHttpRequestInterceptor())); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/JacksonConfig.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/JacksonConfig.java index c4944a469174ad1962d5c54cc483400dbee12f1d..a451032e9de8d40f04724e44e85eb928dfba2653 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/JacksonConfig.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/JacksonConfig.java @@ -3,6 +3,7 @@ package at.tuwien.config; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.hibernate6.Hibernate6Module; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import lombok.extern.slf4j.Slf4j; @@ -21,6 +22,7 @@ public class JacksonConfig { final ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new Jdk8Module()); objectMapper.registerModule(new JavaTimeModule()); + objectMapper.registerModule(new Hibernate6Module()); /* lazy load mapping on REST endpoints */ objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); objectMapper.setTimeZone(TimeZone.getTimeZone("UTC")); log.debug("current time is {}", objectMapper.writeValueAsString(new Date())); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java index d8ba8a490fc41d3bff8234a1d2ea6e0fd9c42951..9edb9f388da8ef481f2ec1b18522f8bc4695b954 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java @@ -9,6 +9,7 @@ import at.tuwien.api.database.internal.CreateDatabaseDto; import at.tuwien.api.database.query.QueryDto; import at.tuwien.api.database.table.TableCreateDto; import at.tuwien.api.database.table.TableDto; +import at.tuwien.api.database.table.TableStatisticDto; import at.tuwien.api.user.internal.UpdateUserPasswordDto; import at.tuwien.exception.*; @@ -41,4 +42,6 @@ public interface DataServiceGateway { List<TableDto> getTableSchemas(Long databaseId) throws ServiceConnectionException, ServiceException, QueryNotFoundException; List<ViewDto> getViewSchemas(Long databaseId) throws ServiceConnectionException, ServiceException, QueryNotFoundException; + + TableStatisticDto getTableStatistics(Long databaseId, Long tableId) throws ServiceConnectionException, ServiceException, TableNotFoundException; } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/BrokerServiceGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/BrokerServiceGatewayImpl.java index 8ab7c8a7309d319949f3abde033534e5fb76f5a7..b86780f5c43401f7a206be3125f54d593ac641ac 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/BrokerServiceGatewayImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/BrokerServiceGatewayImpl.java @@ -2,7 +2,6 @@ package at.tuwien.gateway.impl; import at.tuwien.api.amqp.*; import at.tuwien.api.user.ExchangeUpdatePermissionsDto; -import at.tuwien.config.GatewayConfig; import at.tuwien.config.RabbitConfig; import at.tuwien.exception.*; import at.tuwien.gateway.BrokerServiceGateway; @@ -21,15 +20,12 @@ import org.springframework.web.client.RestTemplate; public class BrokerServiceGatewayImpl implements BrokerServiceGateway { private final RestTemplate restTemplate; - private final GatewayConfig gatewayConfig; private final RabbitConfig rabbitConfig; @Autowired - public BrokerServiceGatewayImpl(GatewayConfig gatewayConfig, - @Qualifier("brokerRestTemplate") RestTemplate restTemplate, + public BrokerServiceGatewayImpl(@Qualifier("brokerRestTemplate") RestTemplate restTemplate, RabbitConfig rabbitMqConfig) { this.restTemplate = restTemplate; - this.gatewayConfig = gatewayConfig; this.rabbitConfig = rabbitMqConfig; } @@ -37,7 +33,6 @@ public class BrokerServiceGatewayImpl implements BrokerServiceGateway { public void grantTopicPermission(String username, ExchangeUpdatePermissionsDto data) throws ServiceConnectionException, ServiceException { final String url = "/api/topic-permissions/" + rabbitConfig.getVirtualHost() + "/" + username; - log.debug("grant topic permission in url {}{}", gatewayConfig.getBrokerEndpoint(), url); final ResponseEntity<Void> response; try { response = restTemplate.exchange(url, HttpMethod.PUT, new HttpEntity<>(data), Void.class); @@ -57,7 +52,6 @@ public class BrokerServiceGatewayImpl implements BrokerServiceGateway { @Override public void grantVirtualHostPermission(String username, GrantVirtualHostPermissionsDto data) throws ServiceConnectionException, ServiceException { final String url = "/api/permissions/" + rabbitConfig.getVirtualHost() + "/" + username; - log.debug("grant virtual host permissions in url {}{}", gatewayConfig.getBrokerEndpoint(), url); final ResponseEntity<Void> response; try { response = restTemplate.exchange(url, HttpMethod.PUT, new HttpEntity<>(data), Void.class); @@ -77,7 +71,6 @@ public class BrokerServiceGatewayImpl implements BrokerServiceGateway { @Override public void grantExchangePermission(String username, GrantExchangePermissionsDto data) throws ServiceConnectionException, ServiceException { final String url = "/api/topic-permissions/" + rabbitConfig.getVirtualHost() + "/" + username; - log.debug("grant topic permissions in url {}{}", gatewayConfig.getBrokerEndpoint(), url); final ResponseEntity<Void> response; try { response = restTemplate.exchange(url, HttpMethod.PUT, new HttpEntity<>(data), Void.class); @@ -99,8 +92,6 @@ public class BrokerServiceGatewayImpl implements BrokerServiceGateway { final String url = "/api/queues/" + rabbitConfig.getVirtualHost() + "/" + name; final HttpHeaders headers = new HttpHeaders(); headers.set("Accept", "application/json"); - log.trace("gateway broker find queue, virtual host={}, queue={}", rabbitConfig.getVirtualHost(), name); - log.debug("find queue from url {}{}", gatewayConfig.getBrokerEndpoint(), url); final ResponseEntity<QueueDto> response; try { response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(null, headers), QueueDto.class); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java index a278fc60b97ecfa0bc58aa771965ddf6b60f8f91..6c09d6d50067be958efc69cfbc28fa866cfec803 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java @@ -6,6 +6,7 @@ import at.tuwien.api.database.internal.CreateDatabaseDto; import at.tuwien.api.database.query.QueryDto; import at.tuwien.api.database.table.TableCreateDto; import at.tuwien.api.database.table.TableDto; +import at.tuwien.api.database.table.TableStatisticDto; import at.tuwien.api.user.internal.UpdateUserPasswordDto; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; @@ -15,7 +16,6 @@ import org.springframework.http.*; import org.springframework.stereotype.Service; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpServerErrorException; -import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestTemplate; import java.util.Arrays; @@ -37,12 +37,10 @@ public class DataServiceGatewayImpl implements DataServiceGateway { throws ServiceConnectionException, ServiceException, DatabaseNotFoundException { final ResponseEntity<Void> response; final String url = "/api/database/" + databaseId + "/access/" + userId; - log.debug("create access in data service"); try { response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(UpdateDatabaseAccessDto.builder().type(access).build()), Void.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable | - HttpServerErrorException.InternalServerError e) { + } catch (HttpServerErrorException e) { log.error("Failed to create access: {}", e.getMessage()); throw new ServiceConnectionException("Failed to create access: " + e.getMessage(), e); } catch (HttpClientErrorException.NotFound e) { @@ -63,12 +61,10 @@ public class DataServiceGatewayImpl implements DataServiceGateway { throws ServiceConnectionException, ServiceException, AccessNotFoundException { final ResponseEntity<Void> response; final String url = "/api/database/" + databaseId + "/access/" + userId; - log.debug("update access in data service"); try { response = restTemplate.exchange(url, HttpMethod.PUT, new HttpEntity<>(UpdateDatabaseAccessDto.builder().type(access).build()), Void.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable | - HttpServerErrorException.InternalServerError e) { + } catch (HttpServerErrorException e) { log.error("Failed to update access: {}", e.getMessage()); throw new ServiceConnectionException("Failed to update access: " + e.getMessage(), e); } catch (HttpClientErrorException.NotFound e) { @@ -89,11 +85,9 @@ public class DataServiceGatewayImpl implements DataServiceGateway { AccessNotFoundException { final ResponseEntity<Void> response; final String url = "/api/database/" + databaseId + "/access/" + userId; - log.debug("delete access in data service"); try { - response = restTemplate.exchange(url, HttpMethod.DELETE, new HttpEntity<>(null), Void.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable | - HttpServerErrorException.InternalServerError e) { + response = restTemplate.exchange(url, HttpMethod.DELETE, HttpEntity.EMPTY, Void.class); + } catch (HttpServerErrorException e) { log.error("Failed to delete access: {}", e.getMessage()); throw new ServiceConnectionException("Failed to delete access: " + e.getMessage(), e); } catch (HttpClientErrorException.NotFound e) { @@ -113,11 +107,9 @@ public class DataServiceGatewayImpl implements DataServiceGateway { public DatabaseDto createDatabase(CreateDatabaseDto data) throws ServiceConnectionException, ServiceException { final ResponseEntity<DatabaseDto> response; final String url = "/api/database"; - log.debug("create database in data service"); try { response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(data), DatabaseDto.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable | - HttpServerErrorException.InternalServerError e) { + } catch (HttpServerErrorException e) { log.error("Failed to create database: {}", e.getMessage()); throw new ServiceConnectionException("Failed to create database: " + e.getMessage(), e); } catch (HttpClientErrorException.BadRequest | HttpClientErrorException.Unauthorized e) { @@ -136,11 +128,9 @@ public class DataServiceGatewayImpl implements DataServiceGateway { ServiceException, DatabaseNotFoundException { final ResponseEntity<Void> response; final String url = "/api/database/" + databaseId; - log.debug("update database in data service"); try { response = restTemplate.exchange(url, HttpMethod.PUT, new HttpEntity<>(data), Void.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable | - HttpServerErrorException.InternalServerError e) { + } catch (HttpServerErrorException e) { log.error("Failed to update user password in database: {}", e.getMessage()); throw new ServiceConnectionException("Failed to update user password in database: " + e.getMessage(), e); } catch (HttpClientErrorException.NotFound e) { @@ -161,11 +151,9 @@ public class DataServiceGatewayImpl implements DataServiceGateway { DatabaseNotFoundException, TableExistsException { final ResponseEntity<Void> response; final String url = "/api/database/" + databaseId + "/table"; - log.debug("create table in data service"); try { response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(data), Void.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable | - HttpServerErrorException.InternalServerError e) { + } catch (HttpServerErrorException e) { log.error("Failed to create table: {}", e.getMessage()); throw new ServiceConnectionException("Failed to create table: " + e.getMessage(), e); } catch (HttpClientErrorException.NotFound e) { @@ -189,11 +177,9 @@ public class DataServiceGatewayImpl implements DataServiceGateway { TableNotFoundException { final ResponseEntity<Void> response; final String url = "/api/database/" + databaseId + "/table/" + tableId; - log.debug("delete table in data service"); try { - response = restTemplate.exchange(url, HttpMethod.DELETE, new HttpEntity<>(null), Void.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable | - HttpServerErrorException.InternalServerError e) { + response = restTemplate.exchange(url, HttpMethod.DELETE, HttpEntity.EMPTY, Void.class); + } catch (HttpServerErrorException e) { log.error("Failed to delete table: {}", e.getMessage()); throw new ServiceConnectionException("Failed to delete table: " + e.getMessage(), e); } catch (HttpClientErrorException.NotFound e) { @@ -213,11 +199,9 @@ public class DataServiceGatewayImpl implements DataServiceGateway { public ViewDto createView(Long databaseId, ViewCreateDto data) throws ServiceConnectionException, ServiceException { final ResponseEntity<ViewDto> response; final String url = "/api/database/" + databaseId + "/view"; - log.debug("create view in data service"); try { response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(data), ViewDto.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable | - HttpServerErrorException.InternalServerError e) { + } catch (HttpServerErrorException e) { log.error("Failed to create view: {}", e.getMessage()); throw new ServiceConnectionException("Failed to create view: " + e.getMessage(), e); } catch (HttpClientErrorException.BadRequest | HttpClientErrorException.Unauthorized e) { @@ -240,11 +224,9 @@ public class DataServiceGatewayImpl implements DataServiceGateway { ViewNotFoundException { final ResponseEntity<Void> response; final String url = "/api/database/" + databaseId + "/view/" + viewId; - log.debug("delete view in data service"); try { - response = restTemplate.exchange(url, HttpMethod.DELETE, new HttpEntity<>(null), Void.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable | - HttpServerErrorException.InternalServerError e) { + response = restTemplate.exchange(url, HttpMethod.DELETE, HttpEntity.EMPTY, Void.class); + } catch (HttpServerErrorException e) { log.error("Failed to delete view: {}", e.getMessage()); throw new ServiceConnectionException("Failed to delete view: " + e.getMessage(), e); } catch (HttpClientErrorException.NotFound e) { @@ -265,11 +247,9 @@ public class DataServiceGatewayImpl implements DataServiceGateway { QueryNotFoundException { final ResponseEntity<QueryDto> response; final String url = "/api/database/" + databaseId + "/subset/" + queryId; - log.debug("get query in data service"); try { - response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(null), QueryDto.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable | - HttpServerErrorException.InternalServerError e) { + response = restTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, QueryDto.class); + } catch (HttpServerErrorException e) { log.error("Failed to find query: {}", e.getMessage()); throw new ServiceConnectionException("Failed to find query", e); } catch (HttpClientErrorException.NotFound e) { @@ -294,11 +274,9 @@ public class DataServiceGatewayImpl implements DataServiceGateway { ServiceException, QueryNotFoundException { final ResponseEntity<ExportResourceDto> response; final String url = "/api/database/" + databaseId + "/subset/" + queryId; - log.debug("export query in data service"); try { - response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(null), ExportResourceDto.class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable | - HttpServerErrorException.InternalServerError e) { + response = restTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, ExportResourceDto.class); + } catch (HttpServerErrorException e) { log.error("Failed to export query: {}", e.getMessage()); throw new ServiceConnectionException("Failed to export query: " + e.getMessage(), e); } catch (HttpClientErrorException.NotFound e) { @@ -319,11 +297,9 @@ public class DataServiceGatewayImpl implements DataServiceGateway { public List<TableDto> getTableSchemas(Long databaseId) throws ServiceConnectionException, ServiceException, QueryNotFoundException { final ResponseEntity<TableDto[]> response; final String url = "/api/database/" + databaseId + "/table"; - log.debug("retrieve table schema metadata in data service"); try { - response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(null), TableDto[].class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable | - HttpServerErrorException.InternalServerError e) { + response = restTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, TableDto[].class); + } catch (HttpServerErrorException e) { log.error("Failed to get table schemas: {}", e.getMessage()); throw new ServiceConnectionException("Failed to get table schemas: " + e.getMessage(), e); } catch (HttpClientErrorException.NotFound e) { @@ -351,9 +327,8 @@ public class DataServiceGatewayImpl implements DataServiceGateway { final ResponseEntity<ViewDto[]> response; final String url = "/api/database/" + databaseId + "/view"; try { - response = restTemplate.exchange(url, HttpMethod.GET, new HttpEntity<>(null), ViewDto[].class); - } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable | - HttpServerErrorException.InternalServerError e) { + response = restTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, ViewDto[].class); + } catch (HttpServerErrorException e) { log.error("Failed to get view schemas: {}", e.getMessage()); throw new ServiceConnectionException("Failed to get view schemas: " + e.getMessage(), e); } catch (HttpClientErrorException.NotFound e) { @@ -376,4 +351,31 @@ public class DataServiceGatewayImpl implements DataServiceGateway { return views; } + @Override + public TableStatisticDto getTableStatistics(Long databaseId, Long tableId) throws ServiceConnectionException, ServiceException, TableNotFoundException { + final ResponseEntity<TableStatisticDto> response; + final String url = "/api/database/" + databaseId + "/table/" + tableId + "/statistic"; + try { + response = restTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, TableStatisticDto.class); + } catch (HttpServerErrorException e) { + log.error("Failed to analyse table statistic: {}", e.getMessage()); + throw new ServiceConnectionException("Failed to analyse table statistic: " + e.getMessage(), e); + } catch (HttpClientErrorException.NotFound e) { + log.error("Failed to analyse table statistic: not found: {}", e.getMessage()); + throw new TableNotFoundException("Failed to analyse table statistic: not found: " + e.getMessage(), e); + } catch (HttpClientErrorException.Unauthorized e) { + log.error("Failed to analyse table statistic: {}", e.getMessage()); + throw new ServiceException("Failed to analyse table statistic: " + e.getMessage(), e); + } + if (!response.getStatusCode().equals(HttpStatus.OK)) { + log.error("Failed to analyse table statistic: wrong http code: {}", response.getStatusCode()); + throw new ServiceException("Failed to analyse table statistic: wrong http code: " + response.getStatusCode()); + } + if (response.getBody() == null) { + log.error("Failed to analyse table statistic: empty body: {}", response.getStatusCode()); + throw new ServiceException("Failed to analyse table statistic: empty body: " + response.getStatusCode()); + } + return response.getBody(); + } + } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java index 0e96a47b709040978e9a9ec589218917890af860..1ad9cc46c0bbf9aee9273cc722f266843c951f2c 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java @@ -6,7 +6,7 @@ import at.tuwien.api.user.UserPasswordDto; import at.tuwien.config.KeycloakConfig; import at.tuwien.exception.*; import at.tuwien.gateway.KeycloakGateway; -import at.tuwien.mapper.UserMapper; +import at.tuwien.mapper.MetadataMapper; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.*; @@ -24,15 +24,15 @@ import java.util.UUID; @Service public class KeycloakGatewayImpl implements KeycloakGateway { - private final UserMapper userMapper; private final RestTemplate restTemplate; private final KeycloakConfig keycloakConfig; + private final MetadataMapper metadataMapper; - public KeycloakGatewayImpl(UserMapper userMapper, @Qualifier("keycloakRestTemplate") RestTemplate restTemplate, - KeycloakConfig keycloakConfig) { - this.userMapper = userMapper; + public KeycloakGatewayImpl(@Qualifier("keycloakRestTemplate") RestTemplate restTemplate, + KeycloakConfig keycloakConfig, MetadataMapper metadataMapper) { this.restTemplate = restTemplate; this.keycloakConfig = keycloakConfig; + this.metadataMapper = metadataMapper; } public TokenDto obtainToken() throws ServiceConnectionException, ServiceException { @@ -192,7 +192,7 @@ public class KeycloakGatewayImpl implements KeycloakGateway { /* obtain admin token */ final HttpHeaders headers = new HttpHeaders(); headers.set("Authorization", "Bearer " + obtainToken().getAccessToken()); - final UpdateCredentialsDto payload = userMapper.passwordToUpdateCredentialsDto(data.getPassword()); + final UpdateCredentialsDto payload = metadataMapper.passwordToUpdateCredentialsDto(data.getPassword()); final String url = keycloakConfig.getKeycloakEndpoint() + "/admin/realms/dbrepo/users/" + id; log.debug("update user credentials at url {}", url); final ResponseEntity<Void> response; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java index 487e088062fc7ccef2c830b857f721026337d1ea..deba8360f21d2ac982c00dd959617f4c49f7059e 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java @@ -1,13 +1,10 @@ package at.tuwien.gateway.impl; import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.table.constraints.unique.UniqueDto; import at.tuwien.entities.database.Database; -import at.tuwien.entities.database.View; import at.tuwien.exception.*; import at.tuwien.gateway.SearchServiceGateway; -import at.tuwien.mapper.DatabaseMapper; -import at.tuwien.mapper.TableMapper; +import at.tuwien.mapper.MetadataMapper; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -18,62 +15,30 @@ import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestTemplate; -import java.util.LinkedList; -import java.util.List; - @Log4j2 @Service public class SearchServiceGatewayImpl implements SearchServiceGateway { - private final TableMapper tableMapper; private final RestTemplate restTemplate; - private final DatabaseMapper databaseMapper; + private final MetadataMapper metadataMapper; @Autowired - public SearchServiceGatewayImpl(TableMapper tableMapper, - @Qualifier("searchServiceRestTemplate") RestTemplate restTemplate, - DatabaseMapper databaseMapper) { - this.tableMapper = tableMapper; + public SearchServiceGatewayImpl(@Qualifier("searchServiceRestTemplate") RestTemplate restTemplate, + MetadataMapper metadataMapper) { this.restTemplate = restTemplate; - this.databaseMapper = databaseMapper; + this.metadataMapper = metadataMapper; } @Override public DatabaseDto update(Database database) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException { final ResponseEntity<DatabaseDto> response; - final DatabaseDto payload = databaseMapper.databaseToDatabaseDto(database); - payload.getTables() - .forEach(table -> { - table.setIsPublic(database.getIsPublic()); - table.getColumns() - .forEach(column -> { - column.setTable(table); - column.setTableId(table.getId()); - column.setDatabaseId(payload.getId()); - column.setIsPublic(payload.getIsPublic()); - }); - table.getConstraints() - .getUniques() - .forEach(uk -> { - uk.setTable(tableMapper.tableDtoToTableBriefDto(table)); - uk.getTable().setDatabaseId(database.getId()); - uk.setColumns(new LinkedList<>()); -// uk.getColumns() -// .forEach(column -> { -// column.setTable(table); -// column.setTableId(table.getId()); -// column.setDatabaseId(database.getId()); -// column.setIsPublic(database.getIsPublic()); -// }); - }); - }); final HttpHeaders headers = new HttpHeaders(); headers.set("Accept", "application/json"); headers.set("Content-Type", "application/json"); final String url = "/api/search/database/" + database.getId(); - log.debug("update database in search service"); try { - response = restTemplate.exchange(url, HttpMethod.PUT, new HttpEntity<>(payload, headers), DatabaseDto.class); + response = restTemplate.exchange(url, HttpMethod.PUT, new HttpEntity<>( + metadataMapper.customDatabaseToDatabaseDto(database), headers), DatabaseDto.class); } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable | HttpServerErrorException.InternalServerError e) { log.error("Failed to update database: {}", e.getMessage()); @@ -83,7 +48,7 @@ public class SearchServiceGatewayImpl implements SearchServiceGateway { throw new DatabaseNotFoundException("Failed to update database: not found", e); } catch (HttpClientErrorException.BadRequest | HttpClientErrorException.Unauthorized e) { log.error("Failed to update database: malformed payload: {}", e.getMessage()); - throw new SearchServiceException("Failed to update database: malformed payload", e); + throw new SearchServiceException("Failed to update database: malformed payload: " + e.getMessage(), e); } if (!response.getStatusCode().equals(HttpStatus.ACCEPTED)) { log.error("Failed to update database: response code is not 202"); @@ -96,7 +61,6 @@ public class SearchServiceGatewayImpl implements SearchServiceGateway { public void delete(Long databaseId) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException { final ResponseEntity<Void> response; final String url = "/api/search/database/" + databaseId; - log.trace("delete to url {}", url); try { response = restTemplate.exchange(url, HttpMethod.DELETE, new HttpEntity<>(null), Void.class); } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable | diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ConceptService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ConceptService.java index 88e90908f8bf225cfb973c44b46551bd16435ea6..94fa1e0c890637d62e3faa20382c0fb668d8904a 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ConceptService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ConceptService.java @@ -7,6 +7,8 @@ import java.util.List; public interface ConceptService { + TableColumnConcept create(TableColumnConcept concept); + /** * Finds all table column concepts in the metadata database. * diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/TableService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/TableService.java index 22d0f1781b6f045599302b14d8344652bc077256..0eb228ccd5d0a284b3c94e5735cff525ff86dfe1 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/TableService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/TableService.java @@ -44,7 +44,7 @@ public interface TableService { */ Table createTable(Database database, TableCreateDto createDto, Principal principal) throws TableNotFoundException, ServiceException, ServiceConnectionException, UserNotFoundException, - DatabaseNotFoundException, TableExistsException, SearchServiceException, SearchServiceConnectionException, MalformedException; + DatabaseNotFoundException, TableExistsException, SearchServiceException, SearchServiceConnectionException, MalformedException, OntologyNotFoundException, SemanticEntityNotFoundException; /** * Deletes a table from the database in the metadata database and data database. @@ -58,8 +58,5 @@ public interface TableService { TableColumn findColumnById(Table table, Long columnId) throws MalformedException; - TableColumn findColumnByName(Table table, String name) throws MalformedException; - - @Transactional - void updateStatistics(Table table, TableStatisticDto data) throws MalformedException, SearchServiceException, DatabaseNotFoundException, SearchServiceConnectionException; + void updateStatistics(Table table) throws SearchServiceException, DatabaseNotFoundException, SearchServiceConnectionException, MalformedException, TableNotFoundException, ServiceException, ServiceConnectionException; } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UnitService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UnitService.java index c45d78c48c2bc68a700d44876f157cd8f1282803..93824eeb62b94ca5191526b5cb8c576acc9ed433 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UnitService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UnitService.java @@ -2,11 +2,14 @@ package at.tuwien.service; import at.tuwien.entities.database.table.columns.TableColumnUnit; import at.tuwien.exception.UnitNotFoundException; +import org.springframework.transaction.annotation.Transactional; import java.util.List; public interface UnitService { + TableColumnUnit create(TableColumnUnit unit); + /** * Finds all table column units in the metadata database. * diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ViewService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ViewService.java index f2346ec34064b0a1b0ef44b6ca3790c6330b3c7f..d19a3be73beab67d160e09dc892f2a0c46faaee1 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ViewService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ViewService.java @@ -33,7 +33,8 @@ public interface ViewService { * * @param view The view. */ - void delete(View view) throws ServiceException, ServiceConnectionException, DatabaseNotFoundException, ViewNotFoundException, SearchServiceException, SearchServiceConnectionException; + void delete(View view) throws ServiceException, ServiceConnectionException, DatabaseNotFoundException, + ViewNotFoundException, SearchServiceException, SearchServiceConnectionException; /** * Creates a view in the container with given id and database with id with the given query. diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java index 57bb2c9df730f9796815c2c7eb181858acb39f17..5de1366e9f21b5fb468b38029fc37b98db0323e7 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AccessServiceImpl.java @@ -7,7 +7,7 @@ import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; import at.tuwien.gateway.SearchServiceGateway; -import at.tuwien.mapper.DatabaseMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.repository.DatabaseRepository; import at.tuwien.service.AccessService; import at.tuwien.service.DatabaseService; @@ -23,17 +23,17 @@ import java.util.Optional; @Service public class AccessServiceImpl implements AccessService { - private final DatabaseMapper databaseMapper; + private final MetadataMapper metadataMapper; private final DatabaseService databaseService; private final DatabaseRepository databaseRepository; private final DataServiceGateway dataServiceGateway; private final SearchServiceGateway searchServiceGateway; @Autowired - public AccessServiceImpl(DatabaseMapper databaseMapper, DatabaseService databaseService, + public AccessServiceImpl(MetadataMapper metadataMapper, DatabaseService databaseService, DatabaseRepository databaseRepository, DataServiceGateway dataServiceGateway, SearchServiceGateway searchServiceGateway) { - this.databaseMapper = databaseMapper; + this.metadataMapper = metadataMapper; this.databaseService = databaseService; this.databaseRepository = databaseRepository; this.dataServiceGateway = dataServiceGateway; @@ -73,7 +73,7 @@ public class AccessServiceImpl implements AccessService { .hdbid(database.getId()) .database(database) .huserid(user.getId()) - .type(databaseMapper.accessTypeDtoToAccessType(access)) + .type(metadataMapper.accessTypeDtoToAccessType(access)) .build()); database = databaseRepository.save(database); /* create in search service */ @@ -94,7 +94,7 @@ public class AccessServiceImpl implements AccessService { .database(database) .huserid(user.getId()) .user(user) - .type(databaseMapper.accessTypeDtoToAccessType(access)) + .type(metadataMapper.accessTypeDtoToAccessType(access)) .build(); final int idx = database.getAccesses().indexOf(entity); if (idx == -1) { diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java index c47c93c86748b935527e7bd86d37950519c1d446..6fa8b250562dd89ade7dcecbe69a1a0d92b9fa66 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java @@ -8,7 +8,7 @@ import at.tuwien.api.user.UserPasswordDto; import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.gateway.KeycloakGateway; -import at.tuwien.mapper.UserMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.AuthenticationService; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; @@ -20,19 +20,19 @@ import java.util.UUID; @Service public class AuthenticationServiceImpl implements AuthenticationService { - private final UserMapper userMapper; + private final MetadataMapper metadataMapper; private final KeycloakGateway keycloakGateway; @Autowired - public AuthenticationServiceImpl(UserMapper userMapper, KeycloakGateway keycloakGateway) { - this.userMapper = userMapper; + public AuthenticationServiceImpl(MetadataMapper metadataMapper, KeycloakGateway keycloakGateway) { + this.metadataMapper = metadataMapper; this.keycloakGateway = keycloakGateway; } @Override public void create(SignupRequestDto data) throws UserExistsException, ServiceException, ServiceConnectionException, EmailExistsException { - keycloakGateway.createUser(userMapper.signupRequestDtoToUserCreateDto(data)); + keycloakGateway.createUser(metadataMapper.signupRequestDtoToUserCreateDto(data)); } @Override diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/BannerMessageServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/BannerMessageServiceImpl.java index 86d28ddde2e3796bb4ec8d01ebf09215383842d6..ac465232503374a1bd3df7d09e46bef00c473673 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/BannerMessageServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/BannerMessageServiceImpl.java @@ -4,7 +4,7 @@ import at.tuwien.api.maintenance.BannerMessageCreateDto; import at.tuwien.api.maintenance.BannerMessageUpdateDto; import at.tuwien.entities.maintenance.BannerMessage; import at.tuwien.exception.MessageNotFoundException; -import at.tuwien.mapper.BannerMessageMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.repository.BannerMessageRepository; import at.tuwien.service.BannerMessageService; import lombok.extern.log4j.Log4j2; @@ -18,13 +18,13 @@ import java.util.Optional; @Service public class BannerMessageServiceImpl implements BannerMessageService { - private final BannerMessageMapper bannerMessageMapper; + private final MetadataMapper metadataMapper; private final BannerMessageRepository bannerMessageRepository; @Autowired - public BannerMessageServiceImpl(BannerMessageMapper bannerMessageMapper, + public BannerMessageServiceImpl(MetadataMapper metadataMapper, BannerMessageRepository bannerMessageRepository) { - this.bannerMessageMapper = bannerMessageMapper; + this.metadataMapper = metadataMapper; this.bannerMessageRepository = bannerMessageRepository; } @@ -50,7 +50,7 @@ public class BannerMessageServiceImpl implements BannerMessageService { @Override public BannerMessage create(BannerMessageCreateDto data) { - final BannerMessage entity = bannerMessageMapper.bannerMessageCreateDtoToBannerMessage(data); + final BannerMessage entity = metadataMapper.bannerMessageCreateDtoToBannerMessage(data); final BannerMessage message = bannerMessageRepository.save(entity); log.info("Created banner message with id {}", message.getId()); return message; @@ -61,7 +61,7 @@ public class BannerMessageServiceImpl implements BannerMessageService { message.setMessage(data.getMessage()); message.setDisplayEnd(data.getDisplayEnd()); message.setDisplayStart(data.getDisplayStart()); - message.setType(bannerMessageMapper.bannerMessageTypeDtoToBannerMessageType(data.getType())); + message.setType(metadataMapper.bannerMessageTypeDtoToBannerMessageType(data.getType())); message = bannerMessageRepository.save(message); log.info("Updated banner message with id {}", message.getId()); return message; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ConceptServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ConceptServiceImpl.java index 8dd0b76a844dde64ff395eff8dcd8fe808ffef75..647d4fe198abc4b4ab4caf3836ab552bb521ce2c 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ConceptServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ConceptServiceImpl.java @@ -23,6 +23,12 @@ public class ConceptServiceImpl implements ConceptService { this.conceptRepository = conceptRepository; } + @Override + @Transactional + public TableColumnConcept create(TableColumnConcept concept) { + return conceptRepository.save(concept); + } + @Override @Transactional(readOnly = true) public List<TableColumnConcept> findAll() { diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java index 80c564c989b3538e936e0ecc9becc50b9f420aa4..91db7736db7d9a4a4e931c744a938e78d72308c9 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java @@ -6,7 +6,7 @@ import at.tuwien.entities.container.image.ContainerImage; import at.tuwien.exception.ContainerAlreadyExistsException; import at.tuwien.exception.ContainerNotFoundException; import at.tuwien.exception.ImageNotFoundException; -import at.tuwien.mapper.ContainerMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.repository.ContainerRepository; import at.tuwien.repository.ImageRepository; import at.tuwien.service.ContainerService; @@ -24,14 +24,14 @@ import java.util.Optional; @Service public class ContainerServiceImpl implements ContainerService { - private final ContainerMapper containerMapper; + private final MetadataMapper metadataMapper; private final ImageRepository imageRepository; private final ContainerRepository containerRepository; @Autowired - public ContainerServiceImpl(ContainerMapper containerMapper, ImageRepository imageRepository, + public ContainerServiceImpl(MetadataMapper metadataMapper, ImageRepository imageRepository, ContainerRepository containerRepository) { - this.containerMapper = containerMapper; + this.metadataMapper = metadataMapper; this.imageRepository = imageRepository; this.containerRepository = containerRepository; } @@ -40,9 +40,9 @@ public class ContainerServiceImpl implements ContainerService { @Transactional public Container create(ContainerCreateDto data) throws ImageNotFoundException, ContainerAlreadyExistsException { + final String containerName = "dbrepo-userdb-" + metadataMapper.nameToInternalName(data.getName()); /* check */ - final Optional<Container> optional = containerRepository.findByInternalName( - containerMapper.containerToInternalContainerName(data.getName())); + final Optional<Container> optional = containerRepository.findByInternalName(containerName); if (optional.isPresent()) { log.error("Failed to create container with name {}: exists in metadata database", data.getName()); throw new ContainerAlreadyExistsException("Failed to create container: exists in metadata database"); @@ -56,7 +56,7 @@ public class ContainerServiceImpl implements ContainerService { Container container = Container.builder() .image(optional2.get()) .name(data.getName()) - .internalName(containerMapper.containerToInternalContainerName(data.getName())) + .internalName(containerName) .host(data.getHost()) .port(data.getPort()) .privilegedUsername(data.getPrivilegedUsername()) diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java index bb5691514a3b6d6f71d9d247950f932f0b89a270..87f178b1c0d7e0d0bdf4c2be9e883a1a56b26861 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java @@ -15,8 +15,7 @@ import at.tuwien.entities.database.Database; import at.tuwien.entities.identifier.Identifier; import at.tuwien.entities.user.User; import at.tuwien.exception.*; -import at.tuwien.mapper.DataCiteMapper; -import at.tuwien.mapper.IdentifierMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.repository.IdentifierRepository; import at.tuwien.service.IdentifierService; import lombok.extern.slf4j.Slf4j; @@ -42,7 +41,7 @@ public class DataCiteIdentifierServiceImpl implements IdentifierService { private final RestTemplate restTemplate; private final DataCiteConfig dataCiteConfig; - private final DataCiteMapper dataCiteMapper; + private final MetadataMapper metadataMapper; private final EndpointConfig endpointConfig; private final IdentifierService identifierService; private final IdentifierRepository identifierRepository; @@ -51,12 +50,12 @@ public class DataCiteIdentifierServiceImpl implements IdentifierService { }; public DataCiteIdentifierServiceImpl(@Qualifier("dataCiteRestTemplate") RestTemplate restTemplate, - DataCiteConfig dataCiteConfig, DataCiteMapper dataCiteMapper, + DataCiteConfig dataCiteConfig, MetadataMapper metadataMapper, EndpointConfig endpointConfig, IdentifierServiceImpl identifierService, IdentifierRepository identifierRepository) { this.restTemplate = restTemplate; this.dataCiteConfig = dataCiteConfig; - this.dataCiteMapper = dataCiteMapper; + this.metadataMapper = metadataMapper; this.endpointConfig = endpointConfig; this.identifierService = identifierService; this.identifierRepository = identifierRepository; @@ -130,7 +129,7 @@ public class DataCiteIdentifierServiceImpl implements IdentifierService { DataCiteBody.<DataCiteCreateDoi>builder() .data(DataCiteData.<DataCiteCreateDoi>builder() .type("dois") - .attributes(dataCiteMapper.identifierToDataCiteCreateDoi(identifier, + .attributes(metadataMapper.identifierToDataCiteCreateDoi(identifier, endpointConfig.getWebsiteUrl() + "/pid/" + identifier.getId(), dataCiteConfig.getPrefix(), event)) .build()) diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java index f695267a4a5c089be5f8235e3cd8abd59d81f826..16d23d7af1d31c4bbefa50c607f6ad42b23eac8e 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java @@ -18,9 +18,7 @@ import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; import at.tuwien.gateway.SearchServiceGateway; -import at.tuwien.mapper.DatabaseMapper; -import at.tuwien.mapper.TableMapper; -import at.tuwien.mapper.ViewMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.repository.DatabaseRepository; import at.tuwien.service.*; import lombok.extern.log4j.Log4j2; @@ -35,21 +33,17 @@ import java.util.*; @Service public class DatabaseServiceImpl implements DatabaseService { - private final ViewMapper viewMapper; - private final TableMapper tableMapper; - private final DatabaseMapper databaseMapper; + private final MetadataMapper metadataMapper; private final ContainerService containerService; private final DatabaseRepository databaseRepository; private final DataServiceGateway dataServiceGateway; private final SearchServiceGateway searchServiceGateway; @Autowired - public DatabaseServiceImpl(ViewMapper viewMapper, TableMapper tableMapper, DatabaseMapper databaseMapper, - ContainerService containerService, DatabaseRepository databaseRepository, - DataServiceGateway dataServiceGateway, SearchServiceGateway searchServiceGateway) { - this.viewMapper = viewMapper; - this.tableMapper = tableMapper; - this.databaseMapper = databaseMapper; + public DatabaseServiceImpl(MetadataMapper metadataMapper, ContainerService containerService, + DatabaseRepository databaseRepository, DataServiceGateway dataServiceGateway, + SearchServiceGateway searchServiceGateway) { + this.metadataMapper = metadataMapper; this.containerService = containerService; this.databaseRepository = databaseRepository; this.dataServiceGateway = dataServiceGateway; @@ -96,7 +90,7 @@ public class DatabaseServiceImpl implements DatabaseService { Database database = Database.builder() .isPublic(data.getIsPublic()) .name(data.getName()) - .internalName(databaseMapper.nameToInternalName(data.getName()) + "_" + RandomStringUtils.randomAlphabetic(4).toLowerCase()) + .internalName(metadataMapper.nameToInternalName(data.getName()) + "_" + RandomStringUtils.randomAlphabetic(4).toLowerCase()) .cid(data.getCid()) .container(container) .ownedBy(user.getId()) @@ -206,7 +200,7 @@ public class DatabaseServiceImpl implements DatabaseService { continue; } log.debug("fetched unknown table from data service: {}.{}", database.getInternalName(), table.getInternalName()); - final Table tableEntity = tableMapper.tableDtoToTable(table); + final Table tableEntity = metadataMapper.tableDtoToTable(table); tableEntity.setDatabase(database); tableEntity.getColumns() .forEach(column -> { @@ -229,7 +223,7 @@ public class DatabaseServiceImpl implements DatabaseService { fk.setTable(tableEntity); }); /* map primary key constraint */ - for (PrimaryKeyDto key : table.getConstraints().getPrimaryKey()) { + for (PrimaryKey key : tableEntity.getConstraints().getPrimaryKey()) { final Optional<TableColumn> optional = tableEntity.getColumns() .stream() .filter(c -> c.getInternalName().equals(key.getColumn().getInternalName())) @@ -238,12 +232,8 @@ public class DatabaseServiceImpl implements DatabaseService { log.error("Failed to find primary key column {} in table {}.{}", key.getColumn().getInternalName(), database.getInternalName(), table.getInternalName()); throw new MalformedException("Failed to find primary key column: " + key.getColumn().getInternalName()); } - tableEntity.getConstraints() - .getPrimaryKey() - .add(PrimaryKey.builder() - .table(tableEntity) - .column(optional.get()) - .build()); + key.setTable(tableEntity); + key.setColumn(optional.get()); } database.getTables() .add(tableEntity); @@ -267,7 +257,7 @@ public class DatabaseServiceImpl implements DatabaseService { continue; } log.debug("fetched unknown view from data service: {}.{}", database.getInternalName(), view.getInternalName()); - final View viewEntity = viewMapper.viewDtoToView(view); + final View viewEntity = metadataMapper.viewDtoToView(view); viewEntity.setDatabase(database); for (ViewColumn column : viewEntity.getColumns()) { column.setView(viewEntity); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/EntityServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/EntityServiceImpl.java index 6dee3f7d71364ad733b40af155a51bd7f1781761..dba30481f5c3884ddea7da87930e295df91be37d 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/EntityServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/EntityServiceImpl.java @@ -7,10 +7,9 @@ import at.tuwien.entities.database.table.Table; import at.tuwien.entities.database.table.columns.TableColumn; import at.tuwien.entities.semantics.Ontology; import at.tuwien.exception.*; -import at.tuwien.mapper.OntologyMapper; +import at.tuwien.mapper.SparqlMapper; import at.tuwien.service.EntityService; import at.tuwien.service.OntologyService; -import at.tuwien.service.TableService; import lombok.extern.log4j.Log4j2; import org.apache.jena.query.*; import org.apache.jena.rdf.model.RDFNode; @@ -23,7 +22,6 @@ import org.springframework.transaction.annotation.Transactional; import java.util.Iterator; import java.util.LinkedList; import java.util.List; -import java.util.Optional; import java.util.concurrent.TimeUnit; @Log4j2 @@ -32,11 +30,11 @@ public class EntityServiceImpl implements EntityService { private final Dataset dataset; private final JenaConfig jenaConfig; - private final OntologyMapper ontologyMapper; + private final SparqlMapper ontologyMapper; private final OntologyService ontologyService; @Autowired - public EntityServiceImpl(Dataset dataset, JenaConfig jenaConfig, OntologyMapper ontologyMapper, + public EntityServiceImpl(Dataset dataset, JenaConfig jenaConfig, SparqlMapper ontologyMapper, OntologyService ontologyService) { this.dataset = dataset; this.jenaConfig = jenaConfig; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java index a41e36877ae0b4ba7d6f6252381347c0acbe6c43..37215d0787d6532eb03d8bf3ebdd8557f28d83e0 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java @@ -14,7 +14,6 @@ import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; import at.tuwien.gateway.SearchServiceGateway; -import at.tuwien.mapper.IdentifierMapper; import at.tuwien.mapper.MetadataMapper; import at.tuwien.repository.IdentifierRepository; import at.tuwien.service.*; @@ -39,21 +38,18 @@ public class IdentifierServiceImpl implements IdentifierService { private final MetadataConfig metadataConfig; private final MetadataMapper metadataMapper; private final TemplateEngine templateEngine; - private final IdentifierMapper identifierMapper; private final DataServiceGateway dataServiceGateway; private final IdentifierRepository identifierRepository; private final SearchServiceGateway searchServiceGateway; public IdentifierServiceImpl(ViewService viewService, TemplateEngine templateEngine, MetadataMapper metadataMapper, - IdentifierMapper identifierMapper, MetadataConfig metadataConfig, - DataServiceGateway dataServiceGateway, IdentifierRepository identifierRepository, - SearchServiceGateway searchServiceGateway) { + MetadataConfig metadataConfig, DataServiceGateway dataServiceGateway, + IdentifierRepository identifierRepository, SearchServiceGateway searchServiceGateway) { this.viewService = viewService; this.metadataConfig = metadataConfig; this.metadataMapper = metadataMapper; this.templateEngine = templateEngine; - this.identifierMapper = identifierMapper; this.dataServiceGateway = dataServiceGateway; this.identifierRepository = identifierRepository; this.searchServiceGateway = searchServiceGateway; @@ -117,7 +113,7 @@ public class IdentifierServiceImpl implements IdentifierService { if (type != null) { log.trace("filter by type: {}", type); stream = stream.filter(i -> Objects.nonNull(i.getType())) - .filter(i -> i.getType().equals(identifierMapper.identifierTypeDtoToIdentifierType(type))); + .filter(i -> i.getType().equals(metadataMapper.identifierTypeDtoToIdentifierType(type))); } if (databaseId != null) { log.trace("filter by database id: {}", databaseId); @@ -171,20 +167,20 @@ public class IdentifierServiceImpl implements IdentifierService { identifier.setQueryId(data.getQueryId()); identifier.setViewId(data.getViewId()); identifier.setDoi(data.getDoi()); - identifier.setLanguage(identifierMapper.languageTypeDtoToLanguageType(data.getLanguage())); + identifier.setLanguage(metadataMapper.languageTypeDtoToLanguageType(data.getLanguage())); identifier.setLicenses(new LinkedList<>(data.getLicenses() .stream() - .map(identifierMapper::licenseDtoToLicense) + .map(metadataMapper::licenseDtoToLicense) .toList())); identifier.setPublicationDay(data.getPublicationDay()); identifier.setPublicationMonth(data.getPublicationMonth()); identifier.setPublicationYear(data.getPublicationYear()); - identifier.setType(identifierMapper.identifierTypeDtoToIdentifierType(data.getType())); + identifier.setType(metadataMapper.identifierTypeDtoToIdentifierType(data.getType())); /* create in metadata database */ if (data.getCreators() != null) { identifier.setCreators(new LinkedList<>(data.getCreators() .stream() - .map(identifierMapper::creatorCreateDtoToCreator) + .map(metadataMapper::creatorCreateDtoToCreator) .peek(c -> c.setIdentifier(identifier)) .toList())); log.debug("set {} creator(s)", identifier.getCreators().size()); @@ -192,7 +188,7 @@ public class IdentifierServiceImpl implements IdentifierService { if (data.getRelatedIdentifiers() != null) { identifier.setRelatedIdentifiers(new LinkedList<>(data.getRelatedIdentifiers() .stream() - .map(identifierMapper::relatedIdentifierCreateDtoToRelatedIdentifier) + .map(metadataMapper::relatedIdentifierCreateDtoToRelatedIdentifier) .peek(r -> r.setIdentifier(identifier)) .toList())); log.debug("set {} related identifier(s)", identifier.getRelatedIdentifiers().size()); @@ -200,7 +196,7 @@ public class IdentifierServiceImpl implements IdentifierService { if (data.getTitles() != null) { identifier.setTitles(new LinkedList<>(data.getTitles() .stream() - .map(identifierMapper::identifierCreateTitleDtoToIdentifierTitle) + .map(metadataMapper::identifierCreateTitleDtoToIdentifierTitle) .peek(t -> t.setIdentifier(identifier)) .toList())); log.debug("set {} title(s)", identifier.getTitles().size()); @@ -208,7 +204,7 @@ public class IdentifierServiceImpl implements IdentifierService { if (data.getDescriptions() != null) { identifier.setDescriptions(new LinkedList<>(data.getDescriptions() .stream() - .map(identifierMapper::identifierCreateDescriptionDtoToIdentifierDescription) + .map(metadataMapper::identifierCreateDescriptionDtoToIdentifierDescription) .peek(d -> d.setIdentifier(identifier)) .toList())); log.debug("set {} description(s)", identifier.getDescriptions().size()); @@ -216,7 +212,7 @@ public class IdentifierServiceImpl implements IdentifierService { if (data.getFunders() != null) { identifier.setFunders(new LinkedList<>(data.getFunders() .stream() - .map(identifierMapper::identifierFunderSaveDtoToIdentifierFunder) + .map(metadataMapper::identifierFunderSaveDtoToIdentifierFunder) .peek(d -> d.setIdentifier(identifier)) .toList())); log.debug("set {} funder(s)", identifier.getFunders().size()); @@ -229,7 +225,7 @@ public class IdentifierServiceImpl implements IdentifierService { public Identifier create(Database database, User user, IdentifierCreateDto data) throws SearchServiceException, ServiceException, QueryNotFoundException, ServiceConnectionException, DatabaseNotFoundException, SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException { - final Identifier identifier = identifierMapper.identifierCreateDtoToIdentifier(data); + final Identifier identifier = metadataMapper.identifierCreateDtoToIdentifier(data); identifier.setDatabase(database); identifier.setCreatedBy(user.getId()); identifier.setCreator(user); @@ -238,7 +234,7 @@ public class IdentifierServiceImpl implements IdentifierService { if (data.getCreators() != null) { identifier.setCreators(new LinkedList<>(data.getCreators() .stream() - .map(identifierMapper::creatorCreateDtoToCreator) + .map(metadataMapper::creatorCreateDtoToCreator) .peek(c -> c.setIdentifier(identifier)) .toList())); log.debug("set {} creator(s)", identifier.getCreators().size()); @@ -246,7 +242,7 @@ public class IdentifierServiceImpl implements IdentifierService { if (data.getRelatedIdentifiers() != null) { identifier.setRelatedIdentifiers(new LinkedList<>(data.getRelatedIdentifiers() .stream() - .map(identifierMapper::relatedIdentifierCreateDtoToRelatedIdentifier) + .map(metadataMapper::relatedIdentifierCreateDtoToRelatedIdentifier) .peek(r -> r.setIdentifier(identifier)) .toList())); log.debug("set {} related identifier(s)", identifier.getRelatedIdentifiers().size()); @@ -255,7 +251,7 @@ public class IdentifierServiceImpl implements IdentifierService { identifier.setTitles(null); identifier.setTitles(new LinkedList<>(data.getTitles() .stream() - .map(identifierMapper::identifierCreateTitleDtoToIdentifierTitle) + .map(metadataMapper::identifierCreateTitleDtoToIdentifierTitle) .peek(t -> t.setIdentifier(identifier)) .toList())); log.debug("set {} title(s)", identifier.getTitles().size()); @@ -263,7 +259,7 @@ public class IdentifierServiceImpl implements IdentifierService { if (data.getDescriptions() != null) { identifier.setDescriptions(new LinkedList<>(data.getDescriptions() .stream() - .map(identifierMapper::identifierCreateDescriptionDtoToIdentifierDescription) + .map(metadataMapper::identifierCreateDescriptionDtoToIdentifierDescription) .peek(d -> d.setIdentifier(identifier)) .toList())); log.debug("set {} description(s)", identifier.getDescriptions().size()); @@ -271,7 +267,7 @@ public class IdentifierServiceImpl implements IdentifierService { if (data.getFunders() != null) { identifier.setFunders(new LinkedList<>(data.getFunders() .stream() - .map(identifierMapper::identifierFunderSaveDtoToIdentifierFunder) + .map(metadataMapper::identifierFunderSaveDtoToIdentifierFunder) .peek(d -> d.setIdentifier(identifier)) .toList())); log.debug("set {} funder(s)", identifier.getFunders().size()); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ImageServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ImageServiceImpl.java index f7c9dcec9f5e82810aad6dcdbdb64c7734e96f36..8e4decfc1724a010e4d62f38491ad3404d259b1d 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ImageServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ImageServiceImpl.java @@ -5,7 +5,7 @@ import at.tuwien.api.container.image.ImageCreateDto; import at.tuwien.entities.container.image.ContainerImage; import at.tuwien.exception.ImageAlreadyExistsException; import at.tuwien.exception.ImageNotFoundException; -import at.tuwien.mapper.ImageMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.repository.ImageRepository; import at.tuwien.service.ImageService; import jakarta.validation.ConstraintViolationException; @@ -23,13 +23,13 @@ import java.util.Optional; @Service public class ImageServiceImpl implements ImageService { - private final ImageMapper imageMapper; + private final MetadataMapper metadataMapper; private final ImageRepository imageRepository; @Autowired - public ImageServiceImpl(ImageRepository imageRepository, ImageMapper imageMapper) { + public ImageServiceImpl(ImageRepository imageRepository, MetadataMapper metadataMapper) { this.imageRepository = imageRepository; - this.imageMapper = imageMapper; + this.metadataMapper = metadataMapper; } @Override @@ -52,7 +52,7 @@ public class ImageServiceImpl implements ImageService { @Override @Transactional public ContainerImage create(ImageCreateDto createDto, Principal principal) throws ImageAlreadyExistsException { - final ContainerImage image = imageMapper.createImageDtoToContainerImage(createDto); + final ContainerImage image = metadataMapper.createImageDtoToContainerImage(createDto); if (imageRepository.findByNameAndVersion(createDto.getName(), createDto.getVersion()).isPresent()) { log.error("Failed to create image {}:{}: exists in the metadata database", createDto.getName(), createDto.getVersion()); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/MetadataServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/MetadataServiceImpl.java index a89188c02c418d9574c6b25459f331aebebffeef..9dfefd18cca20a2f6c2e90182c112af147930f18 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/MetadataServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/MetadataServiceImpl.java @@ -10,7 +10,6 @@ import at.tuwien.exception.*; import at.tuwien.gateway.CrossrefGateway; import at.tuwien.gateway.OrcidGateway; import at.tuwien.gateway.RorGateway; -import at.tuwien.mapper.ExternalMapper; import at.tuwien.mapper.MetadataMapper; import at.tuwien.oaipmh.OaiErrorType; import at.tuwien.oaipmh.OaiListIdentifiersParameters; @@ -26,18 +25,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.Context; -import org.w3c.dom.Document; -import org.xml.sax.InputSource; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import java.io.StringReader; -import java.io.StringWriter; -import java.io.Writer; import java.time.Instant; import java.util.List; import java.util.Optional; @@ -48,7 +36,6 @@ public class MetadataServiceImpl implements MetadataService { private final RorGateway rorGateway; private final OrcidGateway orcidGateway; - private final ExternalMapper externalMapper; private final MetadataConfig metadataConfig; private final MetadataMapper metadataMapper; private final TemplateEngine templateEngine; @@ -57,13 +44,12 @@ public class MetadataServiceImpl implements MetadataService { private final IdentifierRepository identifierRepository; @Autowired - public MetadataServiceImpl(RorGateway rorGateway, OrcidGateway orcidGateway, ExternalMapper externalMapper, - MetadataConfig metadataConfig, MetadataMapper metadataMapper, - TemplateEngine templateEngine, CrossrefGateway crossrefGateway, - IdentifierService identifierService, IdentifierRepository identifierRepository) { + public MetadataServiceImpl(RorGateway rorGateway, OrcidGateway orcidGateway, MetadataConfig metadataConfig, + MetadataMapper metadataMapper, TemplateEngine templateEngine, + CrossrefGateway crossrefGateway, IdentifierService identifierService, + IdentifierRepository identifierRepository) { this.rorGateway = rorGateway; this.orcidGateway = orcidGateway; - this.externalMapper = externalMapper; this.metadataConfig = metadataConfig; this.metadataMapper = metadataMapper; this.templateEngine = templateEngine; @@ -175,7 +161,7 @@ public class MetadataServiceImpl implements MetadataService { DoiNotFoundException, IdentifierNotSupportedException { if (url.contains("orcid.org")) { final OrcidDto orcidDto = orcidGateway.findByUrl(url); - return externalMapper.orcidDtoToExternalMetadataDto(orcidDto); + return metadataMapper.orcidDtoToExternalMetadataDto(orcidDto); } else if (url.contains("ror.org")) { final int idx = url.lastIndexOf('/'); if (idx + 1 >= url.length()) { @@ -184,7 +170,7 @@ public class MetadataServiceImpl implements MetadataService { } final String id = url.substring(idx + 1); final RorDto rorDto = rorGateway.findById(id); - return externalMapper.rorDtoToExternalMetadataDto(rorDto); + return metadataMapper.rorDtoToExternalMetadataDto(rorDto); } else if (url.contains("doi.org")) { final int idx = url.indexOf("doi.org/"); if (idx + 1 >= url.length()) { @@ -193,7 +179,7 @@ public class MetadataServiceImpl implements MetadataService { } final String id = url.substring(idx + 8); final CrossrefDto crossrefDto = crossrefGateway.findById(id); - return externalMapper.crossrefDtoToExternalMetadataDto(crossrefDto); + return metadataMapper.crossrefDtoToExternalMetadataDto(crossrefDto); } log.error("Failed to find metadata: unsupported identifier {}", url); throw new IdentifierNotSupportedException("Failed to find metadata: unsupported identifier " + url); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/OntologyServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/OntologyServiceImpl.java index 92d1cec924b20e53bf4bc6dd3bc3cb419e46cd0e..3f242914e9ac0f187b7e05258d7fe16edf0715c2 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/OntologyServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/OntologyServiceImpl.java @@ -4,7 +4,8 @@ import at.tuwien.api.semantics.OntologyCreateDto; import at.tuwien.api.semantics.OntologyModifyDto; import at.tuwien.entities.semantics.Ontology; import at.tuwien.exception.OntologyNotFoundException; -import at.tuwien.mapper.OntologyMapper; +import at.tuwien.mapper.MetadataMapper; +import at.tuwien.mapper.SparqlMapper; import at.tuwien.repository.OntologyRepository; import at.tuwien.service.OntologyService; import lombok.extern.log4j.Log4j2; @@ -21,12 +22,15 @@ import java.util.Optional; @Service public class OntologyServiceImpl implements OntologyService { - private final OntologyMapper ontologyMapper; + private final SparqlMapper sparqlMapper; + private final MetadataMapper metadataMapper; private final OntologyRepository ontologyRepository; @Autowired - public OntologyServiceImpl(OntologyMapper ontologyMapper, OntologyRepository ontologyRepository) { - this.ontologyMapper = ontologyMapper; + public OntologyServiceImpl(SparqlMapper ontologyMapper, MetadataMapper metadataMapper, + OntologyRepository ontologyRepository) { + this.sparqlMapper = ontologyMapper; + this.metadataMapper = metadataMapper; this.ontologyRepository = ontologyRepository; } @@ -71,7 +75,7 @@ public class OntologyServiceImpl implements OntologyService { @Override public Ontology create(OntologyCreateDto data, Principal principal) { /* delete in metadata database */ - final Ontology entity = ontologyMapper.ontologyCreateDtoToOntology(data); + final Ontology entity = metadataMapper.ontologyCreateDtoToOntology(data); final Ontology ontology = ontologyRepository.save(entity); log.info("Created ontology with id {} ", ontology.getId()); return ontology; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java index d53e1c04347a1f94b16857ef27611beac2b3b8ce..e8fecdf300095d9d936a6bdf1a9269b141952bcd 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java @@ -18,8 +18,8 @@ import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; import at.tuwien.gateway.SearchServiceGateway; -import at.tuwien.mapper.OntologyMapper; -import at.tuwien.mapper.TableMapper; +import at.tuwien.mapper.MetadataMapper; +import at.tuwien.mapper.SparqlMapper; import at.tuwien.repository.DatabaseRepository; import at.tuwien.service.*; import lombok.extern.log4j.Log4j2; @@ -34,31 +34,28 @@ import java.util.*; @Service public class TableServiceImpl implements TableService { - private final TableMapper tableMapper; private final UserService userService; private final UnitService unitService; private final RabbitConfig rabbitConfig; private final EntityService entityService; private final ConceptService conceptService; - private final OntologyMapper ontologyMapper; + private final MetadataMapper metadataMapper; private final DatabaseService databaseService; private final DataServiceGateway dataServiceGateway; private final DatabaseRepository databaseRepository; private final SearchServiceGateway searchServiceGateway; @Autowired - public TableServiceImpl(TableMapper tableMapper, UserService userService, UnitService unitService, - RabbitConfig rabbitConfig, EntityService entityService, ConceptService conceptService, - OntologyMapper ontologyMapper, DatabaseService databaseService, - DataServiceGateway dataServiceGateway, DatabaseRepository databaseRepository, - SearchServiceGateway searchServiceGateway) { - this.tableMapper = tableMapper; + public TableServiceImpl(UserService userService, UnitService unitService, RabbitConfig rabbitConfig, + EntityService entityService, ConceptService conceptService, MetadataMapper metadataMapper, + DatabaseService databaseService, DataServiceGateway dataServiceGateway, + DatabaseRepository databaseRepository, SearchServiceGateway searchServiceGateway) { this.userService = userService; this.unitService = unitService; this.rabbitConfig = rabbitConfig; this.entityService = entityService; this.conceptService = conceptService; - this.ontologyMapper = ontologyMapper; + this.metadataMapper = metadataMapper; this.databaseService = databaseService; this.dataServiceGateway = dataServiceGateway; this.databaseRepository = databaseRepository; @@ -101,7 +98,7 @@ public class TableServiceImpl implements TableService { @Transactional public Table createTable(Database database, TableCreateDto data, Principal principal) throws ServiceException, ServiceConnectionException, UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, - TableExistsException, SearchServiceException, SearchServiceConnectionException, MalformedException { + TableExistsException, SearchServiceException, SearchServiceConnectionException, MalformedException, OntologyNotFoundException, SemanticEntityNotFoundException { final User owner = userService.findByUsername(principal.getName()); /* check */ if (data.getConstraints().getPrimaryKey().isEmpty()) { @@ -125,7 +122,7 @@ public class TableServiceImpl implements TableService { final Table table = Table.builder() .isVersioned(true) .name(data.getName()) - .internalName(tableMapper.nameToInternalName(data.getName())) + .internalName(metadataMapper.nameToInternalName(data.getName())) .description(data.getDescription()) .queueName(rabbitConfig.getQueueName()) .tdbid(database.getId()) @@ -134,38 +131,61 @@ public class TableServiceImpl implements TableService { .creator(owner) .ownedBy(owner.getId()) .owner(owner) + .numRows(0L) + .dataLength(0L) .identifiers(new LinkedList<>()) .columns(new LinkedList<>()) .build(); try { /* set the ordinal position for the columns */ - table.getColumns() - .addAll(data.getColumns() + final int[] idx = new int[]{0}; + for (int i = 0; i < data.getColumns().size(); i++) { + final ColumnCreateDto c = data.getColumns().get(i); + final TableColumn column = metadataMapper.columnCreateDtoToTableColumn(c, database.getContainer().getImage()); + column.setOrdinalPosition(idx[0]++); + column.setTable(table); + if (data.isNeedSequence() && column.getName().equals("id")) { + column.setAutoGenerated(true); + } + if (c.getUnitUri() != null) { + log.trace("column {} has assigned unit uri: {}", column.getInternalName(), c.getUnitUri()); + TableColumnUnit unit; + try { + unit = unitService.find(c.getUnitUri()); + } catch (UnitNotFoundException e) { + unit = unitService.create(metadataMapper.entityDtoToTableColumnUnit(entityService.findOneByUri(c.getUnitUri()))); + } + column.setUnit(unit); + } + if (c.getConceptUri() != null) { + log.trace("column {} has assigned concept uri: {}", column.getInternalName(), c.getConceptUri()); + TableColumnConcept concept; + try { + concept = conceptService.find(c.getConceptUri()); + } catch (ConceptNotFoundException e) { + concept = conceptService.create(metadataMapper.entityDtoToTableColumnConcept(entityService.findOneByUri(c.getConceptUri()))); + } + column.setConcept(concept); + } + if (List.of(TableColumnType.TIME, TableColumnType.TIMESTAMP, TableColumnType.DATE, TableColumnType.DATETIME).contains(column.getColumnType())) { + final Optional<ContainerImageDate> optional = database.getContainer() + .getImage() + .getDateFormats() .stream() - .map(c -> { - final TableColumn column = tableMapper.columnCreateDtoToTableColumn(c, database.getContainer().getImage()); - if (data.isNeedSequence() && column.getName().equals("id")) { - column.setAutoGenerated(true); - } - if (List.of(TableColumnType.TIME, TableColumnType.TIMESTAMP, TableColumnType.DATE, TableColumnType.DATETIME).contains(column.getColumnType())) { - final Optional<ContainerImageDate> optional = database.getContainer() - .getImage() - .getDateFormats() - .stream() - .filter(df -> df.getId().equals(c.getDfid())) - .findFirst(); - if (optional.isEmpty()) { - log.error("Failed to find date format with id {} in metadata database", c.getDfid()); - throw new IllegalArgumentException("Failed to find date format in metadata database"); - } - column.setDateFormat(optional.get()); - log.debug("column is of temporal type: added date format with id {}", column.getDateFormat().getId()); - } - return column; - }) - .toList()); + .filter(df -> df.getId().equals(c.getDfid())) + .findFirst(); + if (optional.isEmpty()) { + log.error("Failed to find date format with id {} in metadata database", c.getDfid()); + throw new IllegalArgumentException("Failed to find date format in metadata database"); + } + column.setDateFormat(optional.get()); + log.debug("column is of temporal type: added date format with id {}", column.getDateFormat().getId()); + } + table.getColumns() + .add(column); + } /* set constraints */ - table.setConstraints(tableMapper.constraintsCreateDtoToConstraints(data.getConstraints(), database, table)); + table.setConstraints(metadataMapper.constraintsCreateDtoToConstraints(data.getConstraints(), database, table)); } catch (IllegalArgumentException e) { throw new MalformedException(e); } @@ -176,13 +196,8 @@ public class TableServiceImpl implements TableService { throw new MalformedException("Failed to create table: some unique constraint(s) reference non-existing table columns"); } } - int[] idx = {0}; - table.getColumns() - .forEach(column -> { - column.setTable(table); - column.setOrdinalPosition(idx[0]++); - }); - database.getTables().add(table); + database.getTables() + .add(table); /* create in data service */ dataServiceGateway.createTable(database.getId(), data); /* update in metadata database */ @@ -228,7 +243,7 @@ public class TableServiceImpl implements TableService { try { unit = unitService.find(data.getUnitUri()); } catch (UnitNotFoundException e) { - unit = ontologyMapper.entityDtoToTableColumnUnit(entityService.findOneByUri(data.getUnitUri())); + unit = metadataMapper.entityDtoToTableColumnUnit(entityService.findOneByUri(data.getUnitUri())); } column.setUnit(unit); } else { @@ -239,7 +254,7 @@ public class TableServiceImpl implements TableService { try { concept = conceptService.find(data.getConceptUri()); } catch (ConceptNotFoundException e) { - concept = ontologyMapper.entityDtoToTableColumnConcept(entityService.findOneByUri(data.getConceptUri())); + concept = metadataMapper.entityDtoToTableColumnConcept(entityService.findOneByUri(data.getConceptUri())); } column.setConcept(concept); } else { @@ -270,51 +285,35 @@ public class TableServiceImpl implements TableService { return optional.get(); } - @Override - @Transactional(readOnly = true) - public TableColumn findColumnByName(Table table, String name) throws MalformedException { - final Optional<TableColumn> optional = table.getColumns() - .stream() - .filter(c -> c.getInternalName().equals(name)) - .findFirst(); - if (optional.isEmpty()) { - log.error("Failed to find column with name {} in table with name {}", name, table.getInternalName()); - throw new MalformedException("Failed to find column in metadata database"); - } - return optional.get(); - } - @Override @Transactional - public void updateStatistics(Table table, TableStatisticDto data) throws MalformedException, SearchServiceException, - DatabaseNotFoundException, SearchServiceConnectionException { - final List<String> notFound = data.getColumns() - .keySet() - .stream() - .filter(key -> table.getColumns().stream().noneMatch(c -> c.getInternalName().equals(key))) - .toList(); - if (!notFound.isEmpty()) { - log.error("Failed to update statistics: column(s) not found: {}", notFound); - throw new MalformedException("Failed to update statistics: column(s) not found"); + public void updateStatistics(Table table) throws SearchServiceException, + DatabaseNotFoundException, SearchServiceConnectionException, MalformedException, TableNotFoundException, + ServiceException, ServiceConnectionException { + final TableStatisticDto statistic = dataServiceGateway.getTableStatistics(table.getTdbid(), table.getId()); + table.setNumRows(statistic.getRows()); + for (Map.Entry<String, ColumnStatisticDto> entry : statistic.getColumns().entrySet()) { + final Optional<TableColumn> optional = table.getColumns().stream().filter(c -> c.getInternalName().equals(entry.getKey())).findFirst(); + if (optional.isEmpty()) { + log.error("Failed to assign table column statistic: column {} does not exist in table {}.{}", entry.getKey(), table.getDatabase().getInternalName(), table.getInternalName()); + throw new MalformedException("Failed to assign table column statistic: column does not exist"); + } + final TableColumn column = optional.get(); + final ColumnStatisticDto columnStatistic = statistic.getColumns().get(entry.getKey()); + column.setMean(columnStatistic.getMean()); + column.setMedian(columnStatistic.getMedian()); + column.setMin(columnStatistic.getMin()); + column.setMax(columnStatistic.getMax()); + column.setStdDev(columnStatistic.getStdDev()); } - table.getColumns() - .forEach(column -> { - if (!data.getColumns().containsKey(column.getInternalName())) { - return; - } - final ColumnStatisticDto statistic = data.getColumns().get(column.getInternalName()); - column.setMean(statistic.getMean()); - column.setMedian(statistic.getMedian()); - column.setMin(statistic.getMin()); - column.setMax(statistic.getMax()); - }); /* update in metadata database */ final Database database = table.getDatabase(); database.getTables() .set(database.getTables().indexOf(table), table); + databaseRepository.save(database); /* update in open search service */ searchServiceGateway.update(database); - log.info("Updated table statistics"); + log.info("Updated statistics of table with id: {}", table.getId()); } } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UnitServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UnitServiceImpl.java index c0bcf19f2881cd3cbf01803a5fd7bbaa9becbfc9..03270abcd597683a39e106a1bb12325719a9dde0 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UnitServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UnitServiceImpl.java @@ -23,6 +23,12 @@ public class UnitServiceImpl implements UnitService { this.unitRepository = unitRepository; } + @Override + @Transactional + public TableColumnUnit create(TableColumnUnit unit) { + return unitRepository.save(unit); + } + @Override @Transactional(readOnly = true) public List<TableColumnUnit> findAll() { diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java index ec269391996948f47ad0a3b55c7996eb73a3b9f2..a91e03284403b63453f129467f6ce7adaf7c0f90 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java @@ -8,7 +8,7 @@ import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; import at.tuwien.gateway.SearchServiceGateway; -import at.tuwien.mapper.ViewMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.repository.DatabaseRepository; import at.tuwien.service.ViewService; import com.google.common.hash.Hashing; @@ -26,15 +26,15 @@ import java.util.Optional; @Service public class ViewServiceImpl implements ViewService { - private final ViewMapper viewMapper; + private final MetadataMapper metadataMapper; private final DataServiceGateway dataServiceGateway; private final DatabaseRepository databaseRepository; private final SearchServiceGateway searchServiceGateway; @Autowired - public ViewServiceImpl(ViewMapper viewMapper, DataServiceGateway dataServiceGateway, + public ViewServiceImpl(MetadataMapper metadataMapper, DataServiceGateway dataServiceGateway, DatabaseRepository databaseRepository, SearchServiceGateway searchServiceGateway) { - this.viewMapper = viewMapper; + this.metadataMapper = metadataMapper; this.dataServiceGateway = dataServiceGateway; this.databaseRepository = databaseRepository; this.searchServiceGateway = searchServiceGateway; @@ -91,7 +91,7 @@ public class ViewServiceImpl implements ViewService { .vdbid(database.getId()) .database(database) .name(data.getName()) - .internalName(viewMapper.nameToInternalName(data.getName())) + .internalName(metadataMapper.nameToInternalName(data.getName())) .createdBy(creator.getId()) .creator(creator) .identifiers(new LinkedList<>()) @@ -105,7 +105,13 @@ public class ViewServiceImpl implements ViewService { .build(); /* create in data service */ data.setName(view.getInternalName()); - final ViewDto dto = dataServiceGateway.createView(database.getId(), data); + final ViewDto rawView = dataServiceGateway.createView(database.getId(), data); + view.setColumns(rawView.getColumns() + .stream() + .map(metadataMapper::viewColumnDtoToViewColumn) + .toList()); + view.getColumns() + .forEach(column -> column.setView(view)); database.getViews() .add(view); database = databaseRepository.save(database); diff --git a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java index a7808196311e875f354a997d364e160d510a9f81..cf32bf4f005830c3aff5ff22b13dea03df26bb3e 100644 --- a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java +++ b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java @@ -20,6 +20,7 @@ public abstract class AbstractUnitTest extends BaseTest { /* USER_4 */ USER_5.setAccesses(new LinkedList<>()); /* DATABASE 1 */ + DATABASE_1.setSubsets(new LinkedList<>()); DATABASE_1.setAccesses(new LinkedList<>(List.of(DATABASE_1_USER_1_READ_ACCESS, DATABASE_1_USER_2_WRITE_OWN_ACCESS, DATABASE_1_USER_3_WRITE_ALL_ACCESS))); DATABASE_1_PRIVILEGED_DTO.setAccesses(new LinkedList<>(List.of(DATABASE_1_USER_1_READ_ACCESS_DTO, DATABASE_1_USER_2_WRITE_OWN_ACCESS_DTO, DATABASE_1_USER_3_WRITE_ALL_ACCESS_DTO))); TABLE_1.setDatabase(DATABASE_1); @@ -27,6 +28,7 @@ public abstract class AbstractUnitTest extends BaseTest { TABLE_1.setConstraints(TABLE_1_CONSTRAINTS); TABLE_1_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_1_COLUMNS_DTO)); TABLE_1_PRIVILEGED_DTO.setDatabase(DATABASE_1_PRIVILEGED_DTO); + VIEW_1_DTO.setDatabase(DATABASE_1_DTO); DATABASE_1.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_1, IDENTIFIER_2, IDENTIFIER_3, IDENTIFIER_4))); DATABASE_1.setTables(new LinkedList<>(List.of(TABLE_1, TABLE_2, TABLE_3, TABLE_4))); DATABASE_1.setViews(new LinkedList<>(List.of(VIEW_1, VIEW_2, VIEW_3))); @@ -40,6 +42,7 @@ public abstract class AbstractUnitTest extends BaseTest { TABLE_2_CONSTRAINTS.getForeignKeys().get(0).getReferences().get(0).setForeignKey(TABLE_2_CONSTRAINTS.getForeignKeys().get(0)); TABLE_2.setConstraints(TABLE_2_CONSTRAINTS); TABLE_2_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_2_COLUMNS_DTO)); + TABLE_2_PRIVILEGED_DTO.setDatabase(DATABASE_1_PRIVILEGED_DTO); TABLE_2_DTO.setColumns(TABLE_2_COLUMNS_DTO); TABLE_2_DTO.setConstraints(TABLE_2_CONSTRAINTS_DTO); TABLE_3.setDatabase(DATABASE_1); @@ -67,6 +70,7 @@ public abstract class AbstractUnitTest extends BaseTest { IDENTIFIER_3.setDatabase(DATABASE_1); IDENTIFIER_4.setDatabase(DATABASE_1); /* DATABASE 2 */ + DATABASE_2.setSubsets(new LinkedList<>()); DATABASE_2.setAccesses(new LinkedList<>(List.of(DATABASE_2_USER_2_WRITE_ALL_ACCESS, DATABASE_2_USER_3_READ_ACCESS))); DATABASE_2.setTables(new LinkedList<>(List.of(TABLE_5, TABLE_6, TABLE_7))); DATABASE_2.setViews(new LinkedList<>(List.of(VIEW_4))); @@ -74,6 +78,8 @@ public abstract class AbstractUnitTest extends BaseTest { TABLE_5.setDatabase(DATABASE_2); TABLE_5.setColumns(new LinkedList<>(TABLE_5_COLUMNS)); TABLE_5.setConstraints(TABLE_5_CONSTRAINTS); + TABLE_5_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_5_COLUMNS_DTO)); + TABLE_5_PRIVILEGED_DTO.setDatabase(DATABASE_2_PRIVILEGED_DTO); TABLE_5_DTO.setColumns(TABLE_5_COLUMNS_DTO); TABLE_5_DTO.setConstraints(TABLE_5_CONSTRAINTS_DTO); TABLE_6.setDatabase(DATABASE_2); @@ -86,11 +92,12 @@ public abstract class AbstractUnitTest extends BaseTest { TABLE_7_CONSTRAINTS.getForeignKeys().get(1).getReferences().get(0).setForeignKey(TABLE_7_CONSTRAINTS.getForeignKeys().get(1)); TABLE_7_DTO.setColumns(TABLE_7_COLUMNS_DTO); TABLE_7_DTO.setConstraints(TABLE_7_CONSTRAINTS_DTO); - TABLE_7_CONSTRAINTS_DTO.getForeignKeys().get(0).getReferences().get(0).setForeignKey(TABLE_7_CONSTRAINTS_DTO.getForeignKeys().get(0)); - TABLE_7_CONSTRAINTS_DTO.getForeignKeys().get(1).getReferences().get(0).setForeignKey(TABLE_7_CONSTRAINTS_DTO.getForeignKeys().get(1)); + TABLE_7_CONSTRAINTS_DTO.getForeignKeys().get(0).getReferences().get(0).setForeignKey(TABLE_7_CONSTRAINTS_FOREIGN_KEY_BRIEF_0_DTO); + TABLE_7_CONSTRAINTS_DTO.getForeignKeys().get(1).getReferences().get(0).setForeignKey(TABLE_7_CONSTRAINTS_FOREIGN_KEY_BRIEF_1_DTO); VIEW_4.setDatabase(DATABASE_2); IDENTIFIER_5.setDatabase(DATABASE_2); /* DATABASE 3 */ + DATABASE_3.setSubsets(new LinkedList<>()); DATABASE_3.setAccesses(new LinkedList<>(List.of(DATABASE_3_USER_1_WRITE_ALL_ACCESS))); DATABASE_3.setTables(new LinkedList<>(List.of(TABLE_8))); DATABASE_3.setViews(new LinkedList<>(List.of(VIEW_5))); @@ -106,6 +113,7 @@ public abstract class AbstractUnitTest extends BaseTest { VIEW_5.setColumns(VIEW_5_COLUMNS); IDENTIFIER_6.setDatabase(DATABASE_3); /* DATABASE 4 */ + DATABASE_4.setSubsets(new LinkedList<>()); DATABASE_4.setAccesses(new LinkedList<>(List.of(DATABASE_4_USER_1_READ_ACCESS, DATABASE_4_USER_2_WRITE_OWN_ACCESS, DATABASE_4_USER_3_WRITE_ALL_ACCESS))); DATABASE_4.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_7))); IDENTIFIER_7.setDatabase(DATABASE_4); diff --git a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java index e0275f5d6eb97dd096b8ad4143b1f085c4955c7a..fa47be8af84496f5fcbd96fb9c485a9fffdc3ceb 100644 --- a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java +++ b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java @@ -18,17 +18,11 @@ import at.tuwien.api.database.table.TableBriefDto; import at.tuwien.api.database.table.TableCreateDto; import at.tuwien.api.database.table.TableDto; import at.tuwien.api.database.table.TableStatisticDto; -import at.tuwien.api.database.table.columns.ColumnCreateDto; -import at.tuwien.api.database.table.columns.ColumnDto; -import at.tuwien.api.database.table.columns.ColumnStatisticDto; -import at.tuwien.api.database.table.columns.ColumnTypeDto; +import at.tuwien.api.database.table.columns.*; import at.tuwien.api.database.table.columns.concepts.*; import at.tuwien.api.database.table.constraints.ConstraintsCreateDto; import at.tuwien.api.database.table.constraints.ConstraintsDto; -import at.tuwien.api.database.table.constraints.foreign.ForeignKeyCreateDto; -import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto; -import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto; -import at.tuwien.api.database.table.constraints.foreign.ReferenceTypeDto; +import at.tuwien.api.database.table.constraints.foreign.*; import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto; import at.tuwien.api.database.table.constraints.unique.UniqueDto; import at.tuwien.api.database.table.internal.PrivilegedTableDto; @@ -192,7 +186,8 @@ public abstract class BaseTest { public final static String[] ESCALATED_QUERY_HANDLING = new String[]{"escalated-query-handling"}; public final static String[] DEFAULT_TABLE_HANDLING = new String[]{"default-table-handling", - "list-tables", "create-table", "modify-table-column-semantics", "find-table", "delete-table"}; + "list-tables", "create-table", "modify-table-column-semantics", "find-table", "delete-table", + "update-table-statistic"}; public final static String[] ESCALATED_TABLE_HANDLING = new String[]{"escalated-table-handling", "delete-foreign-table"}; @@ -1246,6 +1241,7 @@ public abstract class BaseTest { .containerId(CONTAINER_1_ID) .username(USER_1_USERNAME) .password(USER_1_PASSWORD) + .userId(USER_1_ID) .privilegedUsername(CONTAINER_1_PRIVILEGED_USERNAME) .privilegedPassword(CONTAINER_1_PRIVILEGED_PASSWORD) .build(); @@ -1513,10 +1509,14 @@ public abstract class BaseTest { public final static String TABLE_1_INTERNALNAME = "weather_aus"; public final static Boolean TABLE_1_VERSIONED = true; public final static Boolean TABLE_1_PROCESSED_CONSTRAINTS = true; - public final static String TABLE_1_DESCRIPTION = "Weather in the world"; + public final static String TABLE_1_DESCRIPTION = "Weather in Australia"; public final static String TABLE_1_QUEUE_NAME = TABLE_1_INTERNALNAME; public final static String TABLE_1_ROUTING_KEY = "dbrepo\\." + DATABASE_1_ID + "\\." + TABLE_1_ID; public final static Long TABLE_1_DATABASE_ID = DATABASE_1_ID; + public final static Long TABLE_1_AVG_ROW_LENGTH = 3L; + public final static Long TABLE_1_NUM_ROWS = 3L; + public final static Long TABLE_1_DATA_LENGTH = 2000L; + public final static Long TABLE_1_MAX_DATA_LENGTH = Long.MAX_VALUE; public final static Instant TABLE_1_CREATED = Instant.ofEpochSecond(1677399975L) /* 2023-02-26 08:26:15 (UTC) */; public final static Instant TABLE_1_LAST_MODIFIED = Instant.ofEpochSecond(1677399975L) /* 2023-02-26 08:26:15 (UTC) */; @@ -1537,6 +1537,10 @@ public abstract class BaseTest { .createdBy(USER_1_ID) .owner(USER_1_DTO) .isPublic(DATABASE_1_PUBLIC) + .avgRowLength(TABLE_1_AVG_ROW_LENGTH) + .numRows(TABLE_1_NUM_ROWS) + .dataLength(TABLE_1_DATA_LENGTH) + .maxDataLength(TABLE_1_MAX_DATA_LENGTH) .build(); public final static Table TABLE_1 = Table.builder() @@ -1557,6 +1561,10 @@ public abstract class BaseTest { .ownedBy(USER_1_ID) .owner(USER_1) .lastModified(TABLE_1_LAST_MODIFIED) + .avgRowLength(TABLE_1_AVG_ROW_LENGTH) + .numRows(TABLE_1_NUM_ROWS) + .dataLength(TABLE_1_DATA_LENGTH) + .maxDataLength(TABLE_1_MAX_DATA_LENGTH) .build(); public final static TableDto TABLE_1_DTO = TableDto.builder() @@ -1574,11 +1582,17 @@ public abstract class BaseTest { .constraints(null) /* TABLE_1_CONSTRAINT_DTO */ .createdBy(USER_1_ID) .owner(USER_1_DTO) + .avgRowLength(TABLE_1_AVG_ROW_LENGTH) + .numRows(TABLE_1_NUM_ROWS) + .dataLength(TABLE_1_DATA_LENGTH) + .maxDataLength(TABLE_1_MAX_DATA_LENGTH) .build(); public final static List<ColumnDto> TABLE_1_COLUMNS_DTO = List.of(ColumnDto.builder() .id(1L) .table(TABLE_1_DTO) + .tableId(TABLE_1_ID) + .databaseId(DATABASE_1_ID) .name("id") .internalName("id") .ordinalPosition(0) @@ -1591,6 +1605,8 @@ public abstract class BaseTest { ColumnDto.builder() .id(2L) .table(TABLE_1_DTO) + .tableId(TABLE_1_ID) + .databaseId(DATABASE_1_ID) .name("Date") .internalName("date") .ordinalPosition(1) @@ -1604,6 +1620,8 @@ public abstract class BaseTest { ColumnDto.builder() .id(3L) .table(TABLE_1_DTO) + .tableId(TABLE_1_ID) + .databaseId(DATABASE_1_ID) .name("Location") .internalName("location") .ordinalPosition(2) @@ -1617,6 +1635,8 @@ public abstract class BaseTest { ColumnDto.builder() .id(4L) .table(TABLE_1_DTO) + .tableId(TABLE_1_ID) + .databaseId(DATABASE_1_ID) .name("MinTemp") .internalName("mintemp") .ordinalPosition(3) @@ -1631,6 +1651,8 @@ public abstract class BaseTest { ColumnDto.builder() .id(5L) .table(TABLE_1_DTO) + .tableId(TABLE_1_ID) + .databaseId(DATABASE_1_ID) .name("Rainfall") .internalName("rainfall") .ordinalPosition(4) @@ -1651,7 +1673,6 @@ public abstract class BaseTest { .isVersioned(TABLE_1_VERSIONED) .description(TABLE_1_DESCRIPTION) .name(TABLE_1_NAME) - .columns(new LinkedList<>() /* TABLE_1_COLUMNS */) .owner(USER_1_BRIEF_DTO) .build(); @@ -1665,6 +1686,10 @@ public abstract class BaseTest { public final static String TABLE_2_ROUTING_KEY = "dbrepo\\." + DATABASE_1_ID + "\\." + TABLE_2_ID; public final static Instant TABLE_2_CREATED = Instant.ofEpochSecond(1677400007L) /* 2023-02-26 08:26:47 (UTC) */; public final static Instant TABLE_2_LAST_MODIFIED = Instant.ofEpochSecond(1677400007L) /* 2023-02-26 08:26:47 (UTC) */; + public final static Long TABLE_2_AVG_ROW_LENGTH = 3L; + public final static Long TABLE_2_NUM_ROWS = 3L; + public final static Long TABLE_2_DATA_LENGTH = 2000L; + public final static Long TABLE_2_MAX_DATA_LENGTH = Long.MAX_VALUE; public final static Table TABLE_2 = Table.builder() .id(TABLE_2_ID) @@ -1679,9 +1704,14 @@ public abstract class BaseTest { .queueName(TABLE_2_QUEUE_NAME) .columns(new LinkedList<>() /* TABLE_2_COLUMNS */) .constraints(null) /* TABLE_2_CONSTRAINTS */ + .creator(USER_2) .createdBy(USER_2_ID) - .ownedBy(USER_2_ID) .owner(USER_2) + .ownedBy(USER_2_ID) + .avgRowLength(TABLE_2_AVG_ROW_LENGTH) + .numRows(TABLE_2_NUM_ROWS) + .dataLength(TABLE_2_DATA_LENGTH) + .maxDataLength(TABLE_2_MAX_DATA_LENGTH) .build(); public final static PrivilegedTableDto TABLE_2_PRIVILEGED_DTO = PrivilegedTableDto.builder() @@ -1698,8 +1728,13 @@ public abstract class BaseTest { .identifiers(new LinkedList<>()) .columns(new LinkedList<>() /* TABLE_2_COLUMNS_DTO */) .constraints(null) /* TABLE_2_CONSTRAINTS_DTO */ - .createdBy(USER_1_ID) - .owner(USER_1_DTO) + .creator(USER_2_DTO) + .createdBy(USER_2_ID) + .owner(USER_2_DTO) + .avgRowLength(TABLE_2_AVG_ROW_LENGTH) + .numRows(TABLE_2_NUM_ROWS) + .dataLength(TABLE_2_DATA_LENGTH) + .maxDataLength(TABLE_2_MAX_DATA_LENGTH) .build(); public final static TableDto TABLE_2_DTO = TableDto.builder() @@ -1714,8 +1749,13 @@ public abstract class BaseTest { .routingKey(TABLE_2_ROUTING_KEY) .columns(new LinkedList<>() /* TABLE_2_COLUMNS_DTO */) .constraints(null) /* TABLE_2_CONSTRAINTS_DTO */ + .creator(USER_2_DTO) .createdBy(USER_2_ID) .owner(USER_2_DTO) + .avgRowLength(TABLE_2_AVG_ROW_LENGTH) + .numRows(TABLE_2_NUM_ROWS) + .dataLength(TABLE_2_DATA_LENGTH) + .maxDataLength(TABLE_2_MAX_DATA_LENGTH) .build(); public final static TableBriefDto TABLE_2_BRIEF_DTO = TableBriefDto.builder() @@ -1724,7 +1764,6 @@ public abstract class BaseTest { .isVersioned(TABLE_2_VERSIONED) .description(TABLE_2_DESCRIPTION) .name(TABLE_2_NAME) - .columns(new LinkedList<>() /* TABLE_2_COLUMNS */) .owner(USER_2_BRIEF_DTO) .build(); @@ -1738,6 +1777,10 @@ public abstract class BaseTest { public final static String TABLE_3_ROUTING_KEY = "dbrepo\\." + DATABASE_1_ID + "\\." + TABLE_3_ID; public final static Instant TABLE_3_CREATED = Instant.ofEpochSecond(1677400031L) /* 2023-02-26 08:27:11 (UTC) */; public final static Instant TABLE_3_LAST_MODIFIED = Instant.ofEpochSecond(1677400031L) /* 2023-02-26 08:27:11 (UTC) */; + public final static Long TABLE_3_AVG_ROW_LENGTH = 6L; + public final static Long TABLE_3_NUM_ROWS = 6L; + public final static Long TABLE_3_DATA_LENGTH = 1800L; + public final static Long TABLE_3_MAX_DATA_LENGTH = Long.MAX_VALUE; public final static Table TABLE_3 = Table.builder() .id(TABLE_3_ID) @@ -1752,9 +1795,14 @@ public abstract class BaseTest { .queueName(TABLE_3_QUEUE_NAME) .columns(new LinkedList<>() /* TABLE_3_COLUMNS */) .constraints(null) /* TABLE_3_CONSTRAINTS */ + .creator(USER_3) .createdBy(USER_3_ID) - .ownedBy(USER_3_ID) .owner(USER_3) + .ownedBy(USER_3_ID) + .avgRowLength(TABLE_3_AVG_ROW_LENGTH) + .numRows(TABLE_3_NUM_ROWS) + .dataLength(TABLE_3_DATA_LENGTH) + .maxDataLength(TABLE_3_MAX_DATA_LENGTH) .build(); public final static TableDto TABLE_3_DTO = TableDto.builder() @@ -1769,8 +1817,13 @@ public abstract class BaseTest { .routingKey(TABLE_3_ROUTING_KEY) .columns(new LinkedList<>() /* TABLE_3_COLUMNS_DTO */) .constraints(null) /* TABLE_3_CONSTRAINTS_DTO */ + .creator(USER_3_DTO) .createdBy(USER_3_ID) .owner(USER_3_DTO) + .avgRowLength(TABLE_3_AVG_ROW_LENGTH) + .numRows(TABLE_3_NUM_ROWS) + .dataLength(TABLE_3_DATA_LENGTH) + .maxDataLength(TABLE_3_MAX_DATA_LENGTH) .build(); public final static TableBriefDto TABLE_3_BRIEF_DTO = TableBriefDto.builder() @@ -1779,7 +1832,6 @@ public abstract class BaseTest { .isVersioned(TABLE_3_VERSIONED) .description(TABLE_3_DESCRIPTION) .name(TABLE_3_NAME) - .columns(new LinkedList<>() /* TABLE_3_COLUMNS */) .owner(USER_3_BRIEF_DTO) .build(); @@ -1822,6 +1874,10 @@ public abstract class BaseTest { public final static String TABLE_5_ROUTING_KEY = "dbrepo\\." + DATABASE_2_ID + "\\." + TABLE_5_ID; public final static Instant TABLE_5_CREATED = Instant.ofEpochSecond(1677400067L) /* 2023-02-26 08:27:47 (UTC) */; public final static Instant TABLE_5_LAST_MODIFIED = Instant.ofEpochSecond(1677400067L) /* 2023-02-26 08:27:47 (UTC) */; + public final static Long TABLE_5_AVG_ROW_LENGTH = 1080L; + public final static Long TABLE_5_NUM_ROWS = 101L; + public final static Long TABLE_5_DATA_LENGTH = 15200L; + public final static Long TABLE_5_MAX_DATA_LENGTH = Long.MAX_VALUE; public final static Table TABLE_5 = Table.builder() .id(TABLE_5_ID) @@ -1856,13 +1912,35 @@ public abstract class BaseTest { .owner(USER_1_DTO) .build(); - public final static TableBriefDto TABLE_5_BRIEF_DTO = TableBriefDto.builder() + public final static PrivilegedTableDto TABLE_5_PRIVILEGED_DTO = PrivilegedTableDto.builder() .id(TABLE_5_ID) + .tdbid(DATABASE_2_ID) + .database(null) /* DATABASE_2_PRIVILEGED_DTO */ + .created(TABLE_5_CREATED) .internalName(TABLE_5_INTERNALNAME) .isVersioned(TABLE_5_VERSIONED) .description(TABLE_5_DESCRIPTION) .name(TABLE_5_NAME) + .queueName(TABLE_5_QUEUE_NAME) + .routingKey(TABLE_5_ROUTING_KEY) + .identifiers(new LinkedList<>()) .columns(new LinkedList<>() /* TABLE_5_COLUMNS_DTO */) + .constraints(null) /* TABLE_5_CONSTRAINTS_DTO */ + .createdBy(USER_5_ID) + .owner(USER_5_DTO) + .isPublic(DATABASE_2_PUBLIC) + .avgRowLength(TABLE_5_AVG_ROW_LENGTH) + .numRows(TABLE_5_NUM_ROWS) + .dataLength(TABLE_5_DATA_LENGTH) + .maxDataLength(TABLE_5_MAX_DATA_LENGTH) + .build(); + + public final static TableBriefDto TABLE_5_BRIEF_DTO = TableBriefDto.builder() + .id(TABLE_5_ID) + .internalName(TABLE_5_INTERNALNAME) + .isVersioned(TABLE_5_VERSIONED) + .description(TABLE_5_DESCRIPTION) + .name(TABLE_5_NAME) .owner(USER_1_BRIEF_DTO) .build(); @@ -1918,7 +1996,6 @@ public abstract class BaseTest { .isVersioned(TABLE_6_VERSIONED) .description(TABLE_6_DESCRIPTION) .name(TABLE_6_NAME) - .columns(new LinkedList<>()) /* TABLE_6_COLUMNS_DTO */ .owner(USER_1_BRIEF_DTO) .build(); @@ -1974,25 +2051,28 @@ public abstract class BaseTest { .isVersioned(TABLE_7_VERSIONED) .description(TABLE_7_DESCRIPTION) .name(TABLE_7_NAME) - .columns(new LinkedList<>()) /* TABLE_7_COLUMNS_DTO */ .owner(USER_1_BRIEF_DTO) .build(); public final static Long TABLE_4_ID = 4L; public final static String TABLE_4_NAME = "Sensor 2"; - public final static String TABLE_4_INTERNAL_NAME = "sensor_2"; + public final static String TABLE_4_INTERNALNAME = "sensor_2"; public final static Boolean TABLE_4_VERSIONED = true; public final static Boolean TABLE_4_PROCESSED_CONSTRAINTS = true; public final static String TABLE_4_DESCRIPTION = "Hello sensor"; - public final static String TABLE_4_QUEUE_NAME = TABLE_4_INTERNAL_NAME; + public final static String TABLE_4_QUEUE_NAME = TABLE_4_INTERNALNAME; public final static String TABLE_4_ROUTING_KEY = "dbrepo\\." + DATABASE_1_ID + "\\." + TABLE_4_ID; public final static Instant TABLE_4_CREATED = Instant.ofEpochSecond(1677400175L) /* 2023-02-26 08:29:35 (UTC) */; public final static Instant TABLE_4_LAST_MODIFIED = Instant.ofEpochSecond(1677400175L) /* 2023-02-26 08:29:35 (UTC) */; + public final static Long TABLE_4_AVG_ROW_LENGTH = 0L; + public final static Long TABLE_4_NUM_ROWS = 0L; + public final static Long TABLE_4_DATA_LENGTH = 1000L; + public final static Long TABLE_4_MAX_DATA_LENGTH = Long.MAX_VALUE; public final static Table TABLE_4 = Table.builder() .id(TABLE_4_ID) .tdbid(DATABASE_1_ID) - .internalName(TABLE_4_INTERNAL_NAME) + .internalName(TABLE_4_INTERNALNAME) .description(TABLE_4_DESCRIPTION) .database(null /* DATABASE_1 */) .name(TABLE_4_NAME) @@ -2000,17 +2080,22 @@ public abstract class BaseTest { .columns(new LinkedList<>()) /* TABLE_4_COLUMNS */ .constraints(null) /* TABLE_4_CONSTRAINTS */ .isVersioned(TABLE_4_VERSIONED) + .creator(USER_1) .createdBy(USER_1_ID) - .ownedBy(USER_1_ID) .owner(USER_1) + .ownedBy(USER_1_ID) .created(TABLE_4_CREATED) .lastModified(TABLE_4_LAST_MODIFIED) + .avgRowLength(TABLE_4_AVG_ROW_LENGTH) + .numRows(TABLE_4_NUM_ROWS) + .dataLength(TABLE_4_DATA_LENGTH) + .maxDataLength(TABLE_4_MAX_DATA_LENGTH) .build(); public final static TableDto TABLE_4_DTO = TableDto.builder() .id(TABLE_4_ID) .tdbid(DATABASE_1_ID) - .internalName(TABLE_4_INTERNAL_NAME) + .internalName(TABLE_4_INTERNALNAME) .description(TABLE_4_DESCRIPTION) .name(TABLE_4_NAME) .queueName(TABLE_4_QUEUE_NAME) @@ -2018,21 +2103,32 @@ public abstract class BaseTest { .columns(new LinkedList<>()) /* TABLE_4_COLUMNS_DTO */ .constraints(null) /* TABLE_4_CONSTRAINTS_DTO */ .isVersioned(TABLE_4_VERSIONED) + .creator(USER_1_DTO) .createdBy(USER_1_ID) .owner(USER_1_DTO) .created(TABLE_4_CREATED) + .avgRowLength(TABLE_4_AVG_ROW_LENGTH) + .numRows(TABLE_4_NUM_ROWS) + .dataLength(TABLE_4_DATA_LENGTH) + .maxDataLength(TABLE_4_MAX_DATA_LENGTH) .build(); public final static TableBriefDto TABLE_4_BRIEF_DTO = TableBriefDto.builder() .id(TABLE_4_ID) - .internalName(TABLE_4_INTERNAL_NAME) + .internalName(TABLE_4_INTERNALNAME) .description(TABLE_4_DESCRIPTION) .name(TABLE_4_NAME) - .columns(new LinkedList<>() /* TABLE_4_COLUMNS */) .isVersioned(TABLE_4_VERSIONED) .owner(USER_1_BRIEF_DTO) .build(); + public final static ColumnBriefDto TABLE_4_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() + .id(44L) + .name("Timestamp") + .internalName("timestamp") + .columnType(ColumnTypeDto.TIMESTAMP) + .build(); + public final static List<TableColumn> TABLE_4_COLUMNS = List.of(TableColumn.builder() .id(44L) .ordinalPosition(0) @@ -2165,7 +2261,6 @@ public abstract class BaseTest { .description(TABLE_8_DESCRIPTION) .isVersioned(TABLE_8_VERSIONED) .name(TABLE_8_NAME) - .columns(new LinkedList<>()) /* TABLE_8_COLUMNS_DTO */ .owner(USER_1_BRIEF_DTO) .build(); @@ -2339,6 +2434,13 @@ public abstract class BaseTest { public final static List<String> COLUMN_8_2_SET_VALUES = null; public final static List<String> COLUMN_8_2_SET_VALUES_DTO = null; + public final static ColumnBriefDto TABLE_8_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() + .id(COLUMN_8_1_ID) + .name(COLUMN_8_1_NAME) + .internalName(COLUMN_8_1_INTERNAL_NAME) + .columnType(ColumnTypeDto.BIGINT) + .build(); + public final static List<TableColumn> TABLE_8_COLUMNS = List.of(TableColumn.builder() .id(COLUMN_8_1_ID) .ordinalPosition(COLUMN_8_1_ORDINALPOS) @@ -2658,6 +2760,13 @@ public abstract class BaseTest { .isPersisted(QUERY_6_PERSISTED) .build(); + public final static ColumnBriefDto TABLE_1_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() + .id(1L) + .name("id") + .internalName("id") + .columnType(ColumnTypeDto.BIGINT) + .build(); + public final static List<TableColumn> TABLE_1_COLUMNS = List.of(TableColumn.builder() .id(1L) .ordinalPosition(0) @@ -2667,8 +2776,6 @@ public abstract class BaseTest { .columnType(TableColumnType.BIGINT) .isNullAllowed(false) .autoGenerated(false) - .enums(null) - .sets(null) .build(), TableColumn.builder() .id(2L) @@ -2680,8 +2787,6 @@ public abstract class BaseTest { .dateFormat(IMAGE_DATE_1) .isNullAllowed(true) .autoGenerated(false) - .enums(null) - .sets(null) .build(), TableColumn.builder() .id(3L) @@ -2693,8 +2798,6 @@ public abstract class BaseTest { .size(255L) .isNullAllowed(true) .autoGenerated(false) - .enums(null) - .sets(null) .build(), TableColumn.builder() .id(4L) @@ -2707,8 +2810,6 @@ public abstract class BaseTest { .d(0L) .isNullAllowed(true) .autoGenerated(false) - .enums(null) - .sets(null) .build(), TableColumn.builder() .id(5L) @@ -2723,10 +2824,69 @@ public abstract class BaseTest { .unit(UNIT_1) .isNullAllowed(true) .autoGenerated(false) + .build()); + + public final static List<ColumnCreateDto> TABLE_1_COLUMNS_CREATE_DTO = List.of(ColumnCreateDto.builder() + .name("id") + .type(ColumnTypeDto.BIGINT) + .nullAllowed(false) .enums(null) .sets(null) + .build(), + ColumnCreateDto.builder() + .name("Date") + .type(ColumnTypeDto.DATE) + .nullAllowed(true) + .dfid(IMAGE_DATE_1_ID) + .build(), + ColumnCreateDto.builder() + .name("Location") + .type(ColumnTypeDto.VARCHAR) + .size(255L) + .nullAllowed(true) + .dfid(IMAGE_DATE_1_ID) + .build(), + ColumnCreateDto.builder() + .name("MinTemp") + .type(ColumnTypeDto.DECIMAL) + .size(10L) + .d(0L) + .nullAllowed(true) + .dfid(IMAGE_DATE_1_ID) + .build(), + ColumnCreateDto.builder() + .name("Rainfall") + .type(ColumnTypeDto.DECIMAL) + .size(10L) + .d(0L) + .nullAllowed(true) + .dfid(IMAGE_DATE_1_ID) + .conceptUri(CONCEPT_1_URI) + .unitUri(UNIT_1_URI) .build()); + public final static ConstraintsCreateDto TABLE_1_CONSTRAINTS_CREATE_DTO = ConstraintsCreateDto.builder() + .checks(new LinkedHashSet<>()) + .primaryKey(new LinkedHashSet<>(List.of("id"))) + .foreignKeys(new LinkedList<>()) + .uniques(List.of(List.of("date"))) + .build(); + + public final static TableCreateDto TABLE_1_CREATE_DTO = TableCreateDto.builder() + .name(TABLE_1_NAME) + .description(TABLE_1_DESCRIPTION) + .columns(TABLE_1_COLUMNS_CREATE_DTO) + .constraints(TABLE_1_CONSTRAINTS_CREATE_DTO) + .build(); + + public final static at.tuwien.api.database.table.internal.TableCreateDto TABLE_1_CREATE_INTERNAL_DTO = at.tuwien.api.database.table.internal.TableCreateDto.builder() + .name(TABLE_1_NAME) + .description(TABLE_1_DESCRIPTION) + .columns(TABLE_1_COLUMNS_CREATE_DTO) + .constraints(TABLE_1_CONSTRAINTS_CREATE_DTO) + .needSequence(true) + .build(); + public final static List<TableColumn> TABLE_2_COLUMNS = List.of(TableColumn.builder() .id(6L) .ordinalPosition(0) @@ -2772,9 +2932,25 @@ public abstract class BaseTest { .sets(null) .build()); + public final static ColumnBriefDto TABLE_2_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() + .id(6L) + .name("location") + .internalName("location") + .columnType(ColumnTypeDto.VARCHAR) + .build(); + + public final static ColumnBriefDto TABLE_2_COLUMNS_BRIEF_2_DTO = ColumnBriefDto.builder() + .id(8L) + .name("lng") + .internalName("lng") + .columnType(ColumnTypeDto.DECIMAL) + .build(); + public final static List<ColumnDto> TABLE_2_COLUMNS_DTO = List.of(ColumnDto.builder() .id(6L) .table(TABLE_2_DTO) + .tableId(TABLE_2_ID) + .databaseId(DATABASE_1_ID) .name("location") .internalName("location") .ordinalPosition(0) @@ -2788,12 +2964,13 @@ public abstract class BaseTest { ColumnDto.builder() .id(7L) .table(TABLE_2_DTO) + .tableId(TABLE_2_ID) + .databaseId(DATABASE_1_ID) .name("lat") .internalName("lat") .ordinalPosition(1) - .columnType(ColumnTypeDto.DECIMAL) - .size(10L) - .d(0L) + .columnType(ColumnTypeDto.DOUBLE) + .size(22L) .isNullAllowed(true) .autoGenerated(false) .enums(null) @@ -2802,18 +2979,26 @@ public abstract class BaseTest { ColumnDto.builder() .id(8L) .table(TABLE_2_DTO) + .tableId(TABLE_2_ID) + .databaseId(DATABASE_1_ID) .name("lng") .internalName("lng") .ordinalPosition(2) - .columnType(ColumnTypeDto.DECIMAL) - .size(10L) - .d(0L) + .columnType(ColumnTypeDto.DOUBLE) + .size(22L) .isNullAllowed(true) .autoGenerated(false) .enums(null) .sets(null) .build()); + public final static ColumnBriefDto TABLE_3_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() + .id(9L) + .columnType(ColumnTypeDto.BIGINT) + .name("id") + .internalName("id") + .build(); + public final static List<TableColumn> TABLE_3_COLUMNS = List.of(TableColumn.builder() .id(9L) .table(TABLE_3) @@ -3270,6 +3455,7 @@ public abstract class BaseTest { public final static List<ColumnDto> TABLE_3_COLUMNS_DTO = List.of(ColumnDto.builder() .id(9L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(true) .columnType(ColumnTypeDto.BIGINT) @@ -3283,6 +3469,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(10L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3296,6 +3483,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(11L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3309,6 +3497,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(12L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.DATE) @@ -3322,6 +3511,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(13L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3335,6 +3525,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(14L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3348,6 +3539,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(15L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3361,6 +3553,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(16L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3374,6 +3567,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(17L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3387,6 +3581,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(18L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3400,6 +3595,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(19L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.DATE) @@ -3413,6 +3609,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(20L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3426,6 +3623,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(21L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3439,6 +3637,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(22L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3452,6 +3651,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(23L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3465,6 +3665,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(24L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3478,6 +3679,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(25L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3491,6 +3693,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(26L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3504,6 +3707,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(27L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3517,6 +3721,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(28L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.DATE) @@ -3530,6 +3735,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(29L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3543,6 +3749,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(30L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3556,6 +3763,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(31L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3569,6 +3777,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(32L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3582,6 +3791,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(33L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3595,6 +3805,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(34L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3608,6 +3819,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(35L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3621,6 +3833,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(36L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3634,6 +3847,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(37L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3647,6 +3861,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(38L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3660,6 +3875,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(39L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3673,6 +3889,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(40L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3686,6 +3903,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(41L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3699,6 +3917,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(42L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3712,6 +3931,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(43L) .tableId(TABLE_3_ID) + .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) .autoGenerated(false) .columnType(ColumnTypeDto.INT) @@ -3723,6 +3943,13 @@ public abstract class BaseTest { .sets(new LinkedList<>()) .build()); + public final static ColumnBriefDto TABLE_5_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() + .id(45L) + .name("id") + .internalName("id") + .columnType(ColumnTypeDto.BIGINT) + .build(); + public final static List<TableColumn> TABLE_5_COLUMNS = List.of(TableColumn.builder() .id(45L) .ordinalPosition(0) @@ -3937,6 +4164,7 @@ public abstract class BaseTest { public final static List<ColumnDto> TABLE_5_COLUMNS_DTO = List.of(ColumnDto.builder() .id(45L) .ordinalPosition(0) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("id") .internalName("id") @@ -3947,6 +4175,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(46L) .ordinalPosition(1) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("Animal Name") .internalName("animal_name") @@ -3957,6 +4186,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(47L) .ordinalPosition(2) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("Hair") .internalName("hair") @@ -3967,6 +4197,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(48L) .ordinalPosition(3) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("Feathers") .internalName("feathers") @@ -3977,6 +4208,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(49L) .ordinalPosition(4) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("Bread") .internalName("bread") @@ -3987,6 +4219,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(50L) .ordinalPosition(5) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("Eggs") .internalName("eggs") @@ -3997,6 +4230,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(51L) .ordinalPosition(6) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("Milk") .internalName("milk") @@ -4007,6 +4241,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(52L) .ordinalPosition(7) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("Water") .internalName("water") @@ -4017,6 +4252,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(53L) .ordinalPosition(8) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("Airborne") .internalName("airborne") @@ -4027,6 +4263,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(54L) .ordinalPosition(9) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("Waterborne") .internalName("waterborne") @@ -4037,6 +4274,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(55L) .ordinalPosition(10) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("Aquantic") .internalName("aquantic") @@ -4047,6 +4285,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(56L) .ordinalPosition(11) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("Predator") .internalName("predator") @@ -4057,6 +4296,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(57L) .ordinalPosition(12) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("Backbone") .internalName("backbone") @@ -4067,6 +4307,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(58L) .ordinalPosition(13) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("Breathes") .internalName("breathes") @@ -4077,6 +4318,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(59L) .ordinalPosition(14) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("Venomous") .internalName("venomous") @@ -4087,6 +4329,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(60L) .ordinalPosition(15) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("Fin") .internalName("fin") @@ -4097,6 +4340,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(61L) .ordinalPosition(16) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("Legs") .internalName("legs") @@ -4107,6 +4351,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(62L) .ordinalPosition(17) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("Tail") .internalName("tail") @@ -4117,6 +4362,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(63L) .ordinalPosition(18) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("Domestic") .internalName("domestic") @@ -4127,6 +4373,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(64L) .ordinalPosition(19) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("Catsize") .internalName("catsize") @@ -4137,6 +4384,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(64L) .ordinalPosition(20) + .tableId(TABLE_5_ID) .table(TABLE_5_DTO) .name("Class Type") .internalName("class_type") @@ -4344,9 +4592,17 @@ public abstract class BaseTest { .autoGenerated(false) .build()); + public final static ColumnBriefDto TABLE_6_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() + .id(66L) + .name("id") + .internalName("id") + .columnType(ColumnTypeDto.BIGINT) + .build(); + public final static List<ColumnDto> TABLE_6_COLUMNS_DTO = List.of(ColumnDto.builder() .id(66L) .ordinalPosition(0) + .tableId(TABLE_6_ID) .table(TABLE_6_DTO) .name("id") .internalName("id") @@ -4357,6 +4613,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(67L) .ordinalPosition(1) + .tableId(TABLE_6_ID) .table(TABLE_6_DTO) .name("firstname") .internalName("firstname") @@ -4367,6 +4624,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(68L) .ordinalPosition(2) + .tableId(TABLE_6_ID) .table(TABLE_6_DTO) .name("lastname") .internalName("lastname") @@ -4377,6 +4635,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(69L) .ordinalPosition(3) + .tableId(TABLE_6_ID) .table(TABLE_6_DTO) .name("birth") .internalName("birth") @@ -4387,6 +4646,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(70L) .ordinalPosition(4) + .tableId(TABLE_6_ID) .table(TABLE_6_DTO) .name("reminder") .internalName("reminder") @@ -4398,6 +4658,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(71L) .ordinalPosition(5) + .tableId(TABLE_6_ID) .table(TABLE_6_DTO) .name("ref_id") .internalName("ref_id") @@ -4444,6 +4705,20 @@ public abstract class BaseTest { .constraints(TABLE_6_CONSTRAINTS_CREATE) .build(); + public final static ColumnBriefDto TABLE_7_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() + .id(26L) + .name("name_id") + .internalName("name_id") + .columnType(ColumnTypeDto.BIGINT) + .build(); + + public final static ColumnBriefDto TABLE_7_COLUMNS_BRIEF_1_DTO = ColumnBriefDto.builder() + .id(27L) + .name("zoo_id") + .internalName("zoo_id") + .columnType(ColumnTypeDto.BIGINT) + .build(); + public final static List<TableColumn> TABLE_7_COLUMNS = List.of(TableColumn.builder() .id(26L) .ordinalPosition(0) @@ -4468,6 +4743,7 @@ public abstract class BaseTest { public final static List<ColumnDto> TABLE_7_COLUMNS_DTO = List.of(ColumnDto.builder() .id(26L) .ordinalPosition(0) + .tableId(TABLE_7_ID) .table(TABLE_7_DTO) .name("name_id") .internalName("name_id") @@ -4478,6 +4754,7 @@ public abstract class BaseTest { ColumnDto.builder() .id(27L) .ordinalPosition(1) + .tableId(TABLE_7_ID) .table(TABLE_7_DTO) .name("zoo_id") .internalName("zoo_id") @@ -4499,6 +4776,7 @@ public abstract class BaseTest { public final static List<ViewColumnDto> VIEW_1_COLUMNS_DTO = List.of( ViewColumnDto.builder() .id(1L) + .databaseId(DATABASE_1_ID) .name("location") .internalName("location") .ordinalPosition(0) @@ -4509,23 +4787,23 @@ public abstract class BaseTest { .build(), ViewColumnDto.builder() .id(2L) + .databaseId(DATABASE_1_ID) .name("lat") .internalName("lat") .ordinalPosition(1) - .columnType(ColumnTypeDto.DECIMAL) - .size(10L) - .d(0L) + .columnType(ColumnTypeDto.DOUBLE) + .size(22L) .isNullAllowed(true) .autoGenerated(false) .build(), ViewColumnDto.builder() .id(3L) + .databaseId(DATABASE_1_ID) .name("lng") .internalName("lng") .ordinalPosition(2) - .columnType(ColumnTypeDto.DECIMAL) - .size(10L) - .d(0L) + .columnType(ColumnTypeDto.DOUBLE) + .size(22L) .isNullAllowed(true) .autoGenerated(false) .build() @@ -4622,6 +4900,7 @@ public abstract class BaseTest { .query(VIEW_1_QUERY) .queryHash(VIEW_1_QUERY_HASH) .columns(VIEW_1_COLUMNS_DTO) + .database(null) .build(); public final static PrivilegedViewDto VIEW_1_PRIVILEGED_DTO = PrivilegedViewDto.builder() @@ -6745,6 +7024,7 @@ public abstract class BaseTest { .owner(USER_1) .contactPerson(USER_1_ID) .contact(USER_1) + .subsets(new LinkedList<>()) .tables(new LinkedList<>()) .views(new LinkedList<>()) .accesses(new LinkedList<>()) @@ -7249,7 +7529,7 @@ public abstract class BaseTest { .primaryKey(new LinkedList<>(List.of(PrimaryKey.builder() .table(TABLE_1) .column(TABLE_1_COLUMNS.get(0)) - .pkid(1L) + .id(1L) .build()))) .build(); @@ -7259,8 +7539,8 @@ public abstract class BaseTest { .uniques(new LinkedList<>()) .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder() .table(TABLE_1_BRIEF_DTO) - .column(TABLE_1_COLUMNS_DTO.get(0)) - .pkid(1L) + .column(TABLE_1_COLUMNS_BRIEF_0_DTO) + .id(1L) .build()))) .build(); @@ -7280,7 +7560,7 @@ public abstract class BaseTest { .onUpdate(ReferenceType.NO_ACTION) .build()))) .uniques(new LinkedList<>(List.of(Unique.builder() - .uid(1L) + .id(1L) .table(TABLE_2) .name("uk_1") .columns(new LinkedList<>(List.of(TABLE_2_COLUMNS.get(1)))) @@ -7288,35 +7568,36 @@ public abstract class BaseTest { .primaryKey(new LinkedList<>(List.of(PrimaryKey.builder() .table(TABLE_2) .column(TABLE_2_COLUMNS.get(0)) - .pkid(2L) + .id(2L) .build()))) .build(); public final static ConstraintsDto TABLE_2_CONSTRAINTS_DTO = ConstraintsDto.builder() .checks(new LinkedHashSet<>(List.of("`mintemp` > 0"))) .foreignKeys(new LinkedList<>(List.of(ForeignKeyDto.builder() + .id(1L) .name("fk_location") .onDelete(ReferenceTypeDto.NO_ACTION) .references(new LinkedList<>(List.of(ForeignKeyReferenceDto.builder() .id(1L) - .column(TABLE_2_COLUMNS_DTO.get(2)) - .referencedColumn(TABLE_1_COLUMNS_DTO.get(0)) + .column(TABLE_2_COLUMNS_BRIEF_2_DTO) + .referencedColumn(TABLE_1_COLUMNS_BRIEF_0_DTO) .foreignKey(null) // set later .build()))) - .table(TABLE_1_DTO) - .referencedTable(TABLE_2_DTO) + .table(TABLE_1_BRIEF_DTO) + .referencedTable(TABLE_2_BRIEF_DTO) .onUpdate(ReferenceTypeDto.NO_ACTION) .build()))) .uniques(new LinkedList<>(List.of(UniqueDto.builder() - .uid(1L) + .id(1L) .table(TABLE_2_BRIEF_DTO) .name("uk_1") .columns(new LinkedList<>(List.of(TABLE_2_COLUMNS_DTO.get(1)))) .build()))) .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder() .table(TABLE_2_BRIEF_DTO) - .column(TABLE_2_COLUMNS_DTO.get(0)) - .pkid(2L) + .column(TABLE_2_COLUMNS_BRIEF_0_DTO) + .id(2L) .build()))) .build(); @@ -7327,7 +7608,7 @@ public abstract class BaseTest { .primaryKey(new LinkedList<>(List.of(PrimaryKey.builder() .table(TABLE_3) .column(TABLE_3_COLUMNS.get(0)) - .pkid(3L) + .id(3L) .build()))) .build(); @@ -7337,8 +7618,8 @@ public abstract class BaseTest { .uniques(new LinkedList<>()) .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder() .table(TABLE_3_BRIEF_DTO) - .column(TABLE_3_COLUMNS_DTO.get(0)) - .pkid(3L) + .column(TABLE_3_COLUMNS_BRIEF_0_DTO) + .id(3L) .build()))) .build(); @@ -7349,7 +7630,7 @@ public abstract class BaseTest { .primaryKey(new LinkedList<>(List.of(PrimaryKey.builder() .table(TABLE_4) .column(TABLE_4_COLUMNS.get(0)) - .pkid(4L) + .id(4L) .build()))) .build(); @@ -7359,8 +7640,8 @@ public abstract class BaseTest { .uniques(new LinkedList<>()) .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder() .table(TABLE_4_BRIEF_DTO) - .column(TABLE_4_COLUMNS_DTO.get(0)) - .pkid(4L) + .column(TABLE_4_COLUMNS_BRIEF_0_DTO) + .id(4L) .build()))) .build(); @@ -7371,7 +7652,7 @@ public abstract class BaseTest { .primaryKey(new LinkedList<>(List.of(PrimaryKey.builder() .table(TABLE_5) .column(TABLE_5_COLUMNS.get(0)) - .pkid(5L) + .id(5L) .build()))) .build(); @@ -7381,8 +7662,8 @@ public abstract class BaseTest { .uniques(new LinkedList<>()) .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder() .table(TABLE_5_BRIEF_DTO) - .column(TABLE_5_COLUMNS_DTO.get(0)) - .pkid(5L) + .column(TABLE_5_COLUMNS_BRIEF_0_DTO) + .id(5L) .build()))) .build(); @@ -7393,7 +7674,7 @@ public abstract class BaseTest { .primaryKey(new LinkedList<>(List.of(PrimaryKey.builder() .table(TABLE_6) .column(TABLE_6_COLUMNS.get(0)) - .pkid(6L) + .id(6L) .build()))) .build(); @@ -7403,8 +7684,8 @@ public abstract class BaseTest { .uniques(new LinkedList<>()) .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder() .table(TABLE_6_BRIEF_DTO) - .column(TABLE_6_COLUMNS_DTO.get(0)) - .pkid(6L) + .column(TABLE_6_COLUMNS_BRIEF_0_DTO) + .id(6L) .build()))) .build(); @@ -7440,43 +7721,57 @@ public abstract class BaseTest { .primaryKey(new LinkedList<>(List.of(PrimaryKey.builder() .table(TABLE_7) .column(TABLE_7_COLUMNS.get(0)) - .pkid(7L) + .id(7L) .build()))) .build(); + public final static ForeignKeyDto TABLE_7_CONSTRAINTS_FOREIGN_KEY_0_DTO = ForeignKeyDto.builder() + .id(2L) + .name("fk_name_id") + .onDelete(ReferenceTypeDto.NO_ACTION) + .references(new LinkedList<>(List.of(ForeignKeyReferenceDto.builder() + .id(2L) + .column(TABLE_6_COLUMNS_BRIEF_0_DTO) + .referencedColumn(TABLE_7_COLUMNS_BRIEF_0_DTO) + .foreignKey(null) // set later + .build()))) + .table(TABLE_7_BRIEF_DTO) + .referencedTable(TABLE_6_BRIEF_DTO) + .onUpdate(ReferenceTypeDto.NO_ACTION) + .build(); + + public final static ForeignKeyBriefDto TABLE_7_CONSTRAINTS_FOREIGN_KEY_BRIEF_0_DTO = ForeignKeyBriefDto.builder() + .id(2L) + .build(); + + public final static ForeignKeyDto TABLE_7_CONSTRAINTS_FOREIGN_KEY_1_DTO = ForeignKeyDto.builder() + .id(3L) + .name("fk_zoo_id") + .onDelete(ReferenceTypeDto.NO_ACTION) + .references(new LinkedList<>(List.of(ForeignKeyReferenceDto.builder() + .id(3L) + .column(TABLE_5_COLUMNS_BRIEF_0_DTO) + .referencedColumn(TABLE_7_COLUMNS_BRIEF_1_DTO) + .foreignKey(null) // set later + .build()))) + .table(TABLE_7_BRIEF_DTO) + .referencedTable(TABLE_5_BRIEF_DTO) + .onUpdate(ReferenceTypeDto.NO_ACTION) + .build(); + + public final static ForeignKeyBriefDto TABLE_7_CONSTRAINTS_FOREIGN_KEY_BRIEF_1_DTO = ForeignKeyBriefDto.builder() + .id(3L) + .build(); + public final static ConstraintsDto TABLE_7_CONSTRAINTS_DTO = ConstraintsDto.builder() .checks(new LinkedHashSet<>()) - .foreignKeys(new LinkedList<>(List.of(ForeignKeyDto.builder() - .name("fk_name_id") - .onDelete(ReferenceTypeDto.NO_ACTION) - .references(new LinkedList<>(List.of(ForeignKeyReferenceDto.builder() - .id(2L) - .column(TABLE_6_COLUMNS_DTO.get(0)) - .referencedColumn(TABLE_7_COLUMNS_DTO.get(0)) - .foreignKey(null) // set later - .build()))) - .table(TABLE_7_DTO) - .referencedTable(TABLE_6_DTO) - .onUpdate(ReferenceTypeDto.NO_ACTION) - .build(), - ForeignKeyDto.builder() - .name("fk_zoo_id") - .onDelete(ReferenceTypeDto.NO_ACTION) - .references(new LinkedList<>(List.of(ForeignKeyReferenceDto.builder() - .id(3L) - .column(TABLE_5_COLUMNS_DTO.get(0)) - .referencedColumn(TABLE_7_COLUMNS_DTO.get(1)) - .foreignKey(null) // set later - .build()))) - .table(TABLE_7_DTO) - .referencedTable(TABLE_5_DTO) - .onUpdate(ReferenceTypeDto.NO_ACTION) - .build()))) + .foreignKeys(new LinkedList<>(List.of(TABLE_7_CONSTRAINTS_FOREIGN_KEY_0_DTO, + TABLE_7_CONSTRAINTS_FOREIGN_KEY_1_DTO))) .uniques(new LinkedList<>()) .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder() .table(TABLE_7_BRIEF_DTO) - .column(TABLE_7_COLUMNS_DTO.get(0)) - .pkid(7L) + .column(TABLE_7_COLUMNS_BRIEF_0_DTO) + .id(7L) .build()))) .build(); @@ -7487,7 +7782,7 @@ public abstract class BaseTest { .primaryKey(new LinkedList<>(List.of(PrimaryKey.builder() .table(TABLE_8) .column(TABLE_8_COLUMNS.get(0)) - .pkid(8L) + .id(8L) .build()))) .build(); @@ -7497,8 +7792,8 @@ public abstract class BaseTest { .uniques(new LinkedList<>()) .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder() .table(TABLE_8_BRIEF_DTO) - .column(TABLE_8_COLUMNS_DTO.get(0)) - .pkid(8L) + .column(TABLE_8_COLUMNS_BRIEF_0_DTO) + .id(8L) .build()))) .build(); diff --git a/dbrepo-search-service/Dockerfile b/dbrepo-search-service/Dockerfile index dfa23dfe8ce0a2b79694be158cdf93d3a2801114..875a9f28bdce23969ac1687e3a2af6fd8b6d0ccf 100644 --- a/dbrepo-search-service/Dockerfile +++ b/dbrepo-search-service/Dockerfile @@ -1,7 +1,7 @@ FROM python:3.11-alpine MAINTAINER Martin Weise <martin.weise@tuwien.ac.at> -RUN apk add bash curl +RUN apk add --no-cache curl bash jq WORKDIR /home/alpine diff --git a/dbrepo-search-service/Pipfile.lock b/dbrepo-search-service/Pipfile.lock index 1c60362635327df0034e268b2e037d9dd4a73430..a0b551b34afeaa080332b83e6ece463440df3676 100644 --- a/dbrepo-search-service/Pipfile.lock +++ b/dbrepo-search-service/Pipfile.lock @@ -132,11 +132,11 @@ }, "certifi": { "hashes": [ - "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", - "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" + "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", + "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" ], "markers": "python_version >= '3.6'", - "version": "==2024.2.2" + "version": "==2024.6.2" }, "cffi": { "hashes": [ @@ -302,48 +302,47 @@ }, "cryptography": { "hashes": [ - "sha256:02c0eee2d7133bdbbc5e24441258d5d2244beb31da5ed19fbb80315f4bbbff55", - "sha256:0d563795db98b4cd57742a78a288cdbdc9daedac29f2239793071fe114f13785", - "sha256:16268d46086bb8ad5bf0a2b5544d8a9ed87a0e33f5e77dd3c3301e63d941a83b", - "sha256:1a58839984d9cb34c855197043eaae2c187d930ca6d644612843b4fe8513c886", - "sha256:2954fccea107026512b15afb4aa664a5640cd0af630e2ee3962f2602693f0c82", - "sha256:2e47577f9b18723fa294b0ea9a17d5e53a227867a0a4904a1a076d1646d45ca1", - "sha256:31adb7d06fe4383226c3e963471f6837742889b3c4caa55aac20ad951bc8ffda", - "sha256:3577d029bc3f4827dd5bf8bf7710cac13527b470bbf1820a3f394adb38ed7d5f", - "sha256:36017400817987670037fbb0324d71489b6ead6231c9604f8fc1f7d008087c68", - "sha256:362e7197754c231797ec45ee081f3088a27a47c6c01eff2ac83f60f85a50fe60", - "sha256:3de9a45d3b2b7d8088c3fbf1ed4395dfeff79d07842217b38df14ef09ce1d8d7", - "sha256:4f698edacf9c9e0371112792558d2f705b5645076cc0aaae02f816a0171770fd", - "sha256:5482e789294854c28237bba77c4c83be698be740e31a3ae5e879ee5444166582", - "sha256:5e44507bf8d14b36b8389b226665d597bc0f18ea035d75b4e53c7b1ea84583cc", - "sha256:779245e13b9a6638df14641d029add5dc17edbef6ec915688f3acb9e720a5858", - "sha256:789caea816c6704f63f6241a519bfa347f72fbd67ba28d04636b7c6b7da94b0b", - "sha256:7f8b25fa616d8b846aef64b15c606bb0828dbc35faf90566eb139aa9cff67af2", - "sha256:8cb8ce7c3347fcf9446f201dc30e2d5a3c898d009126010cbd1f443f28b52678", - "sha256:93a3209f6bb2b33e725ed08ee0991b92976dfdcf4e8b38646540674fc7508e13", - "sha256:a3a5ac8b56fe37f3125e5b72b61dcde43283e5370827f5233893d461b7360cd4", - "sha256:a47787a5e3649008a1102d3df55424e86606c9bae6fb77ac59afe06d234605f8", - "sha256:a79165431551042cc9d1d90e6145d5d0d3ab0f2d66326c201d9b0e7f5bf43604", - "sha256:a987f840718078212fdf4504d0fd4c6effe34a7e4740378e59d47696e8dfb477", - "sha256:a9bc127cdc4ecf87a5ea22a2556cab6c7eda2923f84e4f3cc588e8470ce4e42e", - "sha256:bd13b5e9b543532453de08bcdc3cc7cebec6f9883e886fd20a92f26940fd3e7a", - "sha256:c65f96dad14f8528a447414125e1fc8feb2ad5a272b8f68477abbcc1ea7d94b9", - "sha256:d8e3098721b84392ee45af2dd554c947c32cc52f862b6a3ae982dbb90f577f14", - "sha256:e6b79d0adb01aae87e8a44c2b64bc3f3fe59515280e00fb6d57a7267a2583cda", - "sha256:e6b8f1881dac458c34778d0a424ae5769de30544fc678eac51c1c8bb2183e9da", - "sha256:e9b2a6309f14c0497f348d08a065d52f3020656f675819fc405fb63bbcd26562", - "sha256:ecbfbc00bf55888edda9868a4cf927205de8499e7fabe6c050322298382953f2", - "sha256:efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9" + "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad", + "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583", + "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b", + "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c", + "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1", + "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648", + "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949", + "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba", + "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c", + "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9", + "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d", + "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c", + "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e", + "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2", + "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d", + "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7", + "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70", + "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2", + "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7", + "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14", + "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe", + "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e", + "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71", + "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961", + "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7", + "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c", + "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28", + "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842", + "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902", + "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801", + "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a", + "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e" ], "markers": "python_version >= '3.7'", - "version": "==42.0.7" + "version": "==42.0.8" }, "dbrepo": { "hashes": [ - "sha256:ceab260cf76c050e118ce0f0589fec66059396751e03f2ec41fa489cfacc4e7b" + "sha256:2bdb48c70b4c99b5044fbfc12aa653c1e9281ca8913a433cc08a1e14cb4bd2ef" ], - "path": "./lib/dbrepo-1.4.4.tar.gz", - "version": "==1.4.4" + "path": "./lib/dbrepo-1.4.4.tar.gz" }, "docker": { "hashes": [ @@ -353,6 +352,12 @@ "markers": "python_version >= '3.8'", "version": "==7.1.0" }, + "events": { + "hashes": [ + "sha256:a7286af378ba3e46640ac9825156c93bdba7502174dd696090fdfcd4d80a1abd" + ], + "version": "==0.5" + }, "flasgger": { "hashes": [ "sha256:ca098e10bfbb12f047acc6299cc70a33851943a746e550d86e65e60d4df245fb" @@ -366,6 +371,7 @@ "sha256:f69fcd559dc907ed196ab9df0e48471709175e696d6e698dd4dbe940f96ce66b" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==2.3.3" }, "flask-cors": { @@ -390,6 +396,7 @@ "sha256:9215d05a9413d3855764bcd67035e75819d23af2fafb6b55197eb5a3313fdfb2" ], "index": "pypi", + "markers": "python_version >= '3.7' and python_version < '4'", "version": "==4.6.0" }, "flask-sqlalchemy": { @@ -398,6 +405,7 @@ "sha256:e4b68bb881802dda1a7d878b2fc84c06d1ee57fb40b874d3dc97dabfa36b8312" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==3.1.1" }, "frozenlist": { @@ -553,6 +561,7 @@ "sha256:4a0b436239ff76fb33f11c07a16482c521a7e09c1ce3cc293c2330afe01bec63" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==22.0.0" }, "idna": { @@ -615,6 +624,7 @@ "sha256:61c9170f92e736b530655e75374681d4fcca9cfa8763ab42be57353b2b203494" ], "index": "pypi", + "markers": "python_version >= '3.6'", "version": "==1.3.1" }, "markupsafe": { @@ -831,11 +841,12 @@ }, "opensearch-py": { "hashes": [ - "sha256:0dde4ac7158a717d92a8cd81964cb99705a4b80bcf9258ba195b9a9f23f5226d", - "sha256:cf093a40e272b60663f20417fc1264ac724dcf1e03c1a4542a6b44835b1e6c49" + "sha256:0b7c27e8ed84c03c99558406927b6161f186a72502ca6d0325413d8e5523ba96", + "sha256:b6e78b685dd4e9c016d7a4299cf1de69e299c88322e3f81c716e6e23fe5683c1" ], "index": "pypi", - "version": "==2.5.0" + "markers": "python_version >= '3.8' and python_version < '4'", + "version": "==2.6.0" }, "packaging": { "hashes": [ @@ -922,96 +933,96 @@ }, "pydantic": { "hashes": [ - "sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5", - "sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc" + "sha256:c46c76a40bb1296728d7a8b99aa73dd70a48c3510111ff290034f860c99c419e", + "sha256:ea91b002777bf643bb20dd717c028ec43216b24a6001a280f83877fd2655d0b4" ], "markers": "python_version >= '3.8'", - "version": "==2.7.1" + "version": "==2.7.3" }, "pydantic-core": { "hashes": [ - "sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b", - "sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a", - "sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90", - "sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d", - "sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e", - "sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d", - "sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027", - "sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804", - "sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347", - "sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400", - "sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3", - "sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399", - "sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349", - "sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd", - "sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c", - "sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e", - "sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413", - "sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3", - "sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e", - "sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3", - "sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91", - "sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce", - "sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c", - "sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb", - "sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664", - "sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6", - "sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd", - "sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3", - "sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af", - "sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043", - "sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350", - "sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7", - "sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0", - "sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563", - "sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761", - "sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72", - "sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3", - "sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb", - "sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788", - "sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b", - "sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c", - "sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038", - "sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250", - "sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec", - "sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c", - "sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74", - "sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81", - "sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439", - "sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75", - "sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0", - "sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8", - "sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150", - "sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438", - "sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae", - "sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857", - "sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038", - "sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374", - "sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f", - "sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241", - "sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592", - "sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4", - "sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d", - "sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b", - "sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b", - "sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182", - "sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e", - "sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641", - "sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70", - "sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9", - "sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a", - "sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543", - "sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b", - "sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f", - "sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38", - "sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845", - "sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2", - "sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0", - "sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4", - "sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242" + "sha256:01dd777215e2aa86dfd664daed5957704b769e726626393438f9c87690ce78c3", + "sha256:0eb2a4f660fcd8e2b1c90ad566db2b98d7f3f4717c64fe0a83e0adb39766d5b8", + "sha256:0fbbdc827fe5e42e4d196c746b890b3d72876bdbf160b0eafe9f0334525119c8", + "sha256:123c3cec203e3f5ac7b000bd82235f1a3eced8665b63d18be751f115588fea30", + "sha256:14601cdb733d741b8958224030e2bfe21a4a881fb3dd6fbb21f071cabd48fa0a", + "sha256:18f469a3d2a2fdafe99296a87e8a4c37748b5080a26b806a707f25a902c040a8", + "sha256:19894b95aacfa98e7cb093cd7881a0c76f55731efad31073db4521e2b6ff5b7d", + "sha256:1b4de2e51bbcb61fdebd0ab86ef28062704f62c82bbf4addc4e37fa4b00b7cbc", + "sha256:1d886dc848e60cb7666f771e406acae54ab279b9f1e4143babc9c2258213daa2", + "sha256:1f4d26ceb5eb9eed4af91bebeae4b06c3fb28966ca3a8fb765208cf6b51102ab", + "sha256:21a5e440dbe315ab9825fcd459b8814bb92b27c974cbc23c3e8baa2b76890077", + "sha256:293afe532740370aba8c060882f7d26cfd00c94cae32fd2e212a3a6e3b7bc15e", + "sha256:2f5966897e5461f818e136b8451d0551a2e77259eb0f73a837027b47dc95dab9", + "sha256:2fd41f6eff4c20778d717af1cc50eca52f5afe7805ee530a4fbd0bae284f16e9", + "sha256:2fdf2156aa3d017fddf8aea5adfba9f777db1d6022d392b682d2a8329e087cef", + "sha256:3c40d4eaad41f78e3bbda31b89edc46a3f3dc6e171bf0ecf097ff7a0ffff7cb1", + "sha256:43d447dd2ae072a0065389092a231283f62d960030ecd27565672bd40746c507", + "sha256:44a688331d4a4e2129140a8118479443bd6f1905231138971372fcde37e43528", + "sha256:44c7486a4228413c317952e9d89598bcdfb06399735e49e0f8df643e1ccd0558", + "sha256:44cd83ab6a51da80fb5adbd9560e26018e2ac7826f9626bc06ca3dc074cd198b", + "sha256:46387e38bd641b3ee5ce247563b60c5ca098da9c56c75c157a05eaa0933ed154", + "sha256:4701b19f7e3a06ea655513f7938de6f108123bf7c86bbebb1196eb9bd35cf724", + "sha256:4748321b5078216070b151d5271ef3e7cc905ab170bbfd27d5c83ee3ec436695", + "sha256:4b06beb3b3f1479d32befd1f3079cc47b34fa2da62457cdf6c963393340b56e9", + "sha256:4d0dcc59664fcb8974b356fe0a18a672d6d7cf9f54746c05f43275fc48636851", + "sha256:4e99bc050fe65c450344421017f98298a97cefc18c53bb2f7b3531eb39bc7805", + "sha256:509daade3b8649f80d4e5ff21aa5673e4ebe58590b25fe42fac5f0f52c6f034a", + "sha256:51991a89639a912c17bef4b45c87bd83593aee0437d8102556af4885811d59f5", + "sha256:53db086f9f6ab2b4061958d9c276d1dbe3690e8dd727d6abf2321d6cce37fa94", + "sha256:564d7922e4b13a16b98772441879fcdcbe82ff50daa622d681dd682175ea918c", + "sha256:574d92eac874f7f4db0ca653514d823a0d22e2354359d0759e3f6a406db5d55d", + "sha256:578e24f761f3b425834f297b9935e1ce2e30f51400964ce4801002435a1b41ef", + "sha256:59ff3e89f4eaf14050c8022011862df275b552caef8082e37b542b066ce1ff26", + "sha256:5f09baa656c904807e832cf9cce799c6460c450c4ad80803517032da0cd062e2", + "sha256:6891a2ae0e8692679c07728819b6e2b822fb30ca7445f67bbf6509b25a96332c", + "sha256:6a750aec7bf431517a9fd78cb93c97b9b0c496090fee84a47a0d23668976b4b0", + "sha256:6f5c4d41b2771c730ea1c34e458e781b18cc668d194958e0112455fff4e402b2", + "sha256:77450e6d20016ec41f43ca4a6c63e9fdde03f0ae3fe90e7c27bdbeaece8b1ed4", + "sha256:81b5efb2f126454586d0f40c4d834010979cb80785173d1586df845a632e4e6d", + "sha256:823be1deb01793da05ecb0484d6c9e20baebb39bd42b5d72636ae9cf8350dbd2", + "sha256:834b5230b5dfc0c1ec37b2fda433b271cbbc0e507560b5d1588e2cc1148cf1ce", + "sha256:847a35c4d58721c5dc3dba599878ebbdfd96784f3fb8bb2c356e123bdcd73f34", + "sha256:86110d7e1907ab36691f80b33eb2da87d780f4739ae773e5fc83fb272f88825f", + "sha256:8951eee36c57cd128f779e641e21eb40bc5073eb28b2d23f33eb0ef14ffb3f5d", + "sha256:8a7164fe2005d03c64fd3b85649891cd4953a8de53107940bf272500ba8a788b", + "sha256:8b8bab4c97248095ae0c4455b5a1cd1cdd96e4e4769306ab19dda135ea4cdb07", + "sha256:90afc12421df2b1b4dcc975f814e21bc1754640d502a2fbcc6d41e77af5ec312", + "sha256:938cb21650855054dc54dfd9120a851c974f95450f00683399006aa6e8abb057", + "sha256:942ba11e7dfb66dc70f9ae66b33452f51ac7bb90676da39a7345e99ffb55402d", + "sha256:972658f4a72d02b8abfa2581d92d59f59897d2e9f7e708fdabe922f9087773af", + "sha256:97736815b9cc893b2b7f663628e63f436018b75f44854c8027040e05230eeddb", + "sha256:98906207f29bc2c459ff64fa007afd10a8c8ac080f7e4d5beff4c97086a3dabd", + "sha256:99457f184ad90235cfe8461c4d70ab7dd2680e28821c29eca00252ba90308c78", + "sha256:a0d829524aaefdebccb869eed855e2d04c21d2d7479b6cada7ace5448416597b", + "sha256:a2fdd81edd64342c85ac7cf2753ccae0b79bf2dfa063785503cb85a7d3593223", + "sha256:a55b5b16c839df1070bc113c1f7f94a0af4433fcfa1b41799ce7606e5c79ce0a", + "sha256:a642295cd0c8df1b86fc3dced1d067874c353a188dc8e0f744626d49e9aa51c4", + "sha256:ab86ce7c8f9bea87b9d12c7f0af71102acbf5ecbc66c17796cff45dae54ef9a5", + "sha256:abc267fa9837245cc28ea6929f19fa335f3dc330a35d2e45509b6566dc18be23", + "sha256:ae1d6df168efb88d7d522664693607b80b4080be6750c913eefb77e34c12c71a", + "sha256:b2ebef0e0b4454320274f5e83a41844c63438fdc874ea40a8b5b4ecb7693f1c4", + "sha256:b48ece5bde2e768197a2d0f6e925f9d7e3e826f0ad2271120f8144a9db18d5c8", + "sha256:b7cdf28938ac6b8b49ae5e92f2735056a7ba99c9b110a474473fd71185c1af5d", + "sha256:bb4462bd43c2460774914b8525f79b00f8f407c945d50881568f294c1d9b4443", + "sha256:bc4ff9805858bd54d1a20efff925ccd89c9d2e7cf4986144b30802bf78091c3e", + "sha256:c1322d7dd74713dcc157a2b7898a564ab091ca6c58302d5c7b4c07296e3fd00f", + "sha256:c67598100338d5d985db1b3d21f3619ef392e185e71b8d52bceacc4a7771ea7e", + "sha256:ca26a1e73c48cfc54c4a76ff78df3727b9d9f4ccc8dbee4ae3f73306a591676d", + "sha256:d323a01da91851a4f17bf592faf46149c9169d68430b3146dcba2bb5e5719abc", + "sha256:dc1803ac5c32ec324c5261c7209e8f8ce88e83254c4e1aebdc8b0a39f9ddb443", + "sha256:e00a3f196329e08e43d99b79b286d60ce46bed10f2280d25a1718399457e06be", + "sha256:e85637bc8fe81ddb73fda9e56bab24560bdddfa98aa64f87aaa4e4b6730c23d2", + "sha256:e858ac0a25074ba4bce653f9b5d0a85b7456eaddadc0ce82d3878c22489fa4ee", + "sha256:eae237477a873ab46e8dd748e515c72c0c804fb380fbe6c85533c7de51f23a8f", + "sha256:ebef0dd9bf9b812bf75bda96743f2a6c5734a02092ae7f721c048d156d5fabae", + "sha256:ec3beeada09ff865c344ff3bc2f427f5e6c26401cc6113d77e372c3fdac73864", + "sha256:f76d0ad001edd426b92233d45c746fd08f467d56100fd8f30e9ace4b005266e4", + "sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951", + "sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc" ], "markers": "python_version >= '3.8'", - "version": "==2.18.2" + "version": "==2.18.4" }, "pyjwt": { "hashes": [ @@ -1031,11 +1042,12 @@ }, "pytest": { "hashes": [ - "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd", - "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1" + "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343", + "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977" ], "index": "pypi", - "version": "==8.2.1" + "markers": "python_version >= '3.8'", + "version": "==8.2.2" }, "python-dateutil": { "hashes": [ @@ -1051,6 +1063,7 @@ "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==1.0.1" }, "pytz": { @@ -1123,6 +1136,7 @@ "sha256:9995eb8569428059b8c1affd26b25eac510d64f5043d9ce8c84e0d0036e995ae" ], "index": "pypi", + "markers": "python_full_version >= '3.8.1' and python_full_version < '4.0.0'", "version": "==7.0.0" }, "referencing": { @@ -1135,11 +1149,11 @@ }, "requests": { "hashes": [ - "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289", - "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c" + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" ], "markers": "python_version >= '3.8'", - "version": "==2.32.2" + "version": "==2.32.3" }, "rpds-py": { "hashes": [ @@ -1315,6 +1329,7 @@ "sha256:bc599c8c3b3319e53ce6c5c3c471120bd325d0071fb6f38a10e924e3d07b9990" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==0.41.2" }, "testcontainers-core": { @@ -1329,6 +1344,7 @@ "sha256:0bdf270b5b7f53915832f7c31dd2bd3ffdc20b534ea6b32231cc7003049bd0e1" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==0.0.1rc1" }, "tinydb": { @@ -1349,11 +1365,11 @@ }, "typing-extensions": { "hashes": [ - "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8", - "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594" + "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a", + "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1" ], "markers": "python_version >= '3.8'", - "version": "==4.12.0" + "version": "==4.12.1" }, "tzdata": { "hashes": [ @@ -1365,11 +1381,11 @@ }, "urllib3": { "hashes": [ - "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07", - "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0" + "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", + "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.26.18" + "markers": "python_version >= '3.10'", + "version": "==2.2.1" }, "werkzeug": { "hashes": [ @@ -1555,61 +1571,62 @@ "develop": { "coverage": { "hashes": [ - "sha256:06d96b9b19bbe7f049c2be3c4f9e06737ec6d8ef8933c7c3a4c557ef07936e46", - "sha256:13017a63b0e499c59b5ba94a8542fb62864ba3016127d1e4ef30d354fc2b00e9", - "sha256:1acc2e2ef098a1d4bf535758085f508097316d738101a97c3f996bccba963ea5", - "sha256:1aef719b6559b521ae913ddeb38f5048c6d1a3d366865e8b320270b7bc4693c2", - "sha256:1e4225990a87df898e40ca31c9e830c15c2c53b1d33df592bc8ef314d71f0281", - "sha256:1f11f98753800eb1ec872562a398081f6695f91cd01ce39819e36621003ec52a", - "sha256:1f29bf497d51a5077994b265e976d78b09d9d0dff6ca5763dbb4804534a5d380", - "sha256:1f96aa94739593ae0707eda9813ce363a0a0374a810ae0eced383340fc4a1f73", - "sha256:20e611fc36e1a0fc7bbf957ef9c635c8807d71fbe5643e51b2769b3cc0fb0b51", - "sha256:23f2f16958b16152b43a39a5ecf4705757ddd284b3b17a77da3a62aef9c057ef", - "sha256:24bb4c7859a3f757a116521d4d3a8a82befad56ea1bdacd17d6aafd113b0071e", - "sha256:26716a1118c6ce2188283b4b60a898c3be29b480acbd0a91446ced4fe4e780d8", - "sha256:29da75ce20cb0a26d60e22658dd3230713c6c05a3465dd8ad040ffc991aea318", - "sha256:2b144d142ec9987276aeff1326edbc0df8ba4afbd7232f0ca10ad57a115e95b6", - "sha256:2c79f058e7bec26b5295d53b8c39ecb623448c74ccc8378631f5cb5c16a7e02c", - "sha256:3bb5b92a0ab3d22dfdbfe845e2fef92717b067bdf41a5b68c7e3e857c0cff1a4", - "sha256:3d3f7744b8a8079d69af69d512e5abed4fb473057625588ce126088e50d05493", - "sha256:3d9c62cff2ffb4c2a95328488fd7aa96a7a4b34873150650fe76b19c08c9c792", - "sha256:3e12536446ad4527ac8ed91d8a607813085683bcce27af69e3b31cd72b3c5960", - "sha256:40dbb8e7727560fe8ab65efcddfec1ae25f30ef02e2f2e5d78cfb52a66781ec5", - "sha256:431a3917e32223fcdb90b79fe60185864a9109631ebc05f6c5aa03781a00b513", - "sha256:448ec61ea9ea7916d5579939362509145caaecf03161f6f13e366aebb692a631", - "sha256:482df956b055d3009d10fce81af6ffab28215d7ed6ad4a15e5c8e67cb7c5251c", - "sha256:4a00bd5ba8f1a4114720bef283cf31583d6cb1c510ce890a6da6c4268f0070b7", - "sha256:51b6cee539168a912b4b3b040e4042b9e2c9a7ad9c8546c09e4eaeff3eacba6b", - "sha256:554c7327bf0fd688050348e22db7c8e163fb7219f3ecdd4732d7ed606b417263", - "sha256:5662bf0f6fb6757f5c2d6279c541a5af55a39772c2362ed0920b27e3ce0e21f7", - "sha256:5997d418c219dcd4dcba64e50671cca849aaf0dac3d7a2eeeb7d651a5bd735b8", - "sha256:59a75e6aa5c25b50b5a1499f9718f2edff54257f545718c4fb100f48d570ead4", - "sha256:60b66b0363c5a2a79fba3d1cd7430c25bbd92c923d031cae906bdcb6e054d9a2", - "sha256:6e34680049eecb30b6498784c9637c1c74277dcb1db75649a152f8004fbd6646", - "sha256:74eeaa13e8200ad72fca9c5f37395fb310915cec6f1682b21375e84fd9770e84", - "sha256:7c5c5b7ae2763533152880d5b5b451acbc1089ade2336b710a24b2b0f5239d20", - "sha256:829fb55ad437d757c70d5b1c51cfda9377f31506a0a3f3ac282bc6a387d6a5f1", - "sha256:878243e1206828908a6b4a9ca7b1aa8bee9eb129bf7186fc381d2646f4524ce9", - "sha256:8809c0ea0e8454f756e3bd5c36d04dddf222989216788a25bfd6724bfcee342c", - "sha256:8941e35a0e991a7a20a1fa3e3182f82abe357211f2c335a9e6007067c3392fcf", - "sha256:894b1acded706f1407a662d08e026bfd0ff1e59e9bd32062fea9d862564cfb65", - "sha256:900532713115ac58bc3491b9d2b52704a05ed408ba0918d57fd72c94bc47fba1", - "sha256:976cd92d9420e6e2aa6ce6a9d61f2b490e07cb468968adf371546b33b829284b", - "sha256:97de509043d3f0f2b2cd171bdccf408f175c7f7a99d36d566b1ae4dd84107985", - "sha256:9a42970ce74c88bdf144df11c52c5cf4ad610d860de87c0883385a1c9d9fa4ab", - "sha256:9e41c94035e5cdb362beed681b58a707e8dc29ea446ea1713d92afeded9d1ddd", - "sha256:9f805481d5eff2a96bac4da1570ef662bf970f9a16580dc2c169c8c3183fa02b", - "sha256:a35c97af60a5492e9e89f8b7153fe24eadfd61cb3a2fb600df1a25b5dab34b7e", - "sha256:a7c6574225f34ce45466f04751d957b5c5e6b69fca9351db017c9249786172ce", - "sha256:c7ebf2a37e4f5fea3c1a11e1f47cea7d75d0f2d8ef69635ddbd5c927083211fc", - "sha256:d0305e02e40c7cfea5d08d6368576537a74c0eea62b77633179748d3519d6705", - "sha256:e1046aab24c48c694f0793f669ac49ea68acde6a0798ac5388abe0a5615b5ec8", - "sha256:e5d22eba19273b2069e4efeff88c897a26bdc64633cbe0357a198f92dca94268", - "sha256:ec27e93bbf5976f0465e8936f02eb5add99bbe4e4e7b233607e4d7622912d68d", - "sha256:fe76d6dee5e4febefa83998b17926df3a04e5089e3d2b1688c74a9157798d7a2" + "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523", + "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f", + "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d", + "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb", + "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0", + "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c", + "sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98", + "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83", + "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8", + "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7", + "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac", + "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84", + "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb", + "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3", + "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884", + "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614", + "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd", + "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807", + "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd", + "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8", + "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc", + "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db", + "sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0", + "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08", + "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232", + "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d", + "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a", + "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1", + "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286", + "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303", + "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341", + "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84", + "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45", + "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc", + "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec", + "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd", + "sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155", + "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52", + "sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d", + "sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485", + "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31", + "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d", + "sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d", + "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d", + "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85", + "sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce", + "sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb", + "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974", + "sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24", + "sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56", + "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9", + "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35" ], "index": "pypi", - "version": "==7.5.2" + "markers": "python_version >= '3.8'", + "version": "==7.5.3" }, "iniconfig": { "hashes": [ @@ -1637,11 +1654,12 @@ }, "pytest": { "hashes": [ - "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd", - "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1" + "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343", + "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977" ], "index": "pypi", - "version": "==8.2.1" + "markers": "python_version >= '3.8'", + "version": "==8.2.2" } } } diff --git a/dbrepo-search-service/app.py b/dbrepo-search-service/app.py index be4481cf08ee80a38a666e3db3303f12b8fc6613..5d3c816ffd35b6e923ffa91644d8c08db7a58723 100644 --- a/dbrepo-search-service/app.py +++ b/dbrepo-search-service/app.py @@ -62,8 +62,7 @@ swagger_config = { { "endpoint": "api-search", "route": "/api-search.json", - "rule_filter": lambda rule: rule.endpoint.startswith('actuator') or rule.endpoint.startswith( - 'search') or rule.endpoint.startswith('database'), + "rule_filter": lambda rule: rule.endpoint.startswith('search'), "model_filter": lambda tag: True, # all in } ], @@ -75,6 +74,79 @@ swagger_config = { template = { "openapi": "3.0.0", "components": { + "schemas": { + "IndexDto": { + "required": ["results", "type"], + "properties": { + "results": { + "type": "array", + "items": { + "type": "object", + } + }, + "type": { + "type": "string", + "description": "Same as the requested type", + "enum": ["database", "table", "view", "column", "user", "identifier", "concept", "unit"] + } + } + }, + "IndexFieldsDto": { + "required": ["results"], + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IndexFieldDto" + } + } + } + }, + "IndexFieldDto": { + "required": ["attr_name", "attr_friendly_name", "type"], + "type": "object", + "properties": { + "attr_name": { + "type": "string", + "example": "name" + }, + "attr_friendly_name": { + "type": "string", + "example": "Name" + }, + "type": { + "type": "string", + "example": "string", + "description": "OpenSearch data types." + } + } + }, + "SearchResultDto": { + "required": ["results"], + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "type": "object" + } + } + } + }, + "SearchRequestDto": { + "required": ["search_term", "field_value_pairs"], + "type": "object", + "properties": { + "search_term": { + "type": "string" + }, + "field_value_pairs": { + "type": "object" + } + } + } + }, "securitySchemes": { "bearerAuth": { "type": "http", @@ -92,7 +164,7 @@ template = { "info": { "title": "Database Repository Search Service API", "description": "Service that searches the search database", - "version": "__APPVERSION__", + "version": "1.4.4", "contact": { "name": "Prof. Andreas Rauber", "email": "andreas.rauber@tuwien.ac.at" @@ -104,7 +176,7 @@ template = { }, "externalDocs": { "description": "Sourcecode Documentation", - "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/__APPVERSION__/" + "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.4/" }, "servers": [ { @@ -211,7 +283,6 @@ def general_filter(index, results): @app.route("/health", methods=["GET"], endpoint="actuator_health") -@swag_from("os-yml/health.yml") def health(): return dict({"status": "UP"}), 200 @@ -356,12 +427,11 @@ def post_general_search(type): return dict({'results': response, 'type': type}), 200 -@app.route("/api/search/database/<int:database_id>", methods=["PUT"], endpoint="database_put_database") +@app.route("/api/search/database/<int:database_id>", methods=["PUT"], endpoint="search_put_database") @metrics.gauge(name='dbrepo_search_update_database', description='Time needed to update a database in the search database') @auth.login_required(role=['admin']) -@swag_from("os-yml/update_database.yml") -def update_database(database_id: int): +def update_database(database_id: int) -> Database | ApiError: logging.debug(f"updating database with id: {database_id}") try: payload: Database = Database.model_validate(request.json) @@ -385,7 +455,6 @@ def update_database(database_id: int): @metrics.gauge(name='dbrepo_search_delete_database', description='Time needed to delete a database in the search database') @auth.login_required(role=['admin']) -@swag_from("os-yml/delete_database.yml") def delete_database(database_id: int): try: OpenSearchClient().delete_database(database_id) diff --git a/dbrepo-search-service/init/database.json b/dbrepo-search-service/init/database.json index 8e5d443965673d9f9a4ff25b8f42af2e7481401d..d87d33b5e29abae3ffbb9beab8bad45a00d0ff56 100644 --- a/dbrepo-search-service/init/database.json +++ b/dbrepo-search-service/init/database.json @@ -2,38 +2,123 @@ "aliases": {}, "mappings": { "properties": { - "contact": { - "type": "object", + "accesses": { "properties": { - "firstname": { - "type": "keyword" + "created": { + "type": "date" }, - "id": { - "type": "keyword" + "type": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, - "lastname": { - "type": "keyword" + "user": { + "properties": { + "attributes": { + "properties": { + "theme": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "qualified_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "username": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + } + } + }, + "contact": { + "properties": { + "attributes": { + "properties": { + "theme": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } }, - "name": { - "type": "keyword" + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "qualified_name": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "username": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } } } }, "container": { - "type": "object", "properties": { "created": { - "type": "date", - "format": "strict_date_optional_time" + "type": "date" }, "host": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "id": { "type": "long" @@ -43,8 +128,7 @@ "date_formats": { "properties": { "created_at": { - "type": "date", - "format": "strict_date_optional_time" + "type": "date" }, "database_format": { "type": "text", @@ -84,6 +168,15 @@ } } }, + "driver_class": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, "id": { "type": "long" }, @@ -105,6 +198,15 @@ } } }, + "registry": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, "version": { "type": "text", "fields": { @@ -117,505 +219,406 @@ } }, "internal_name": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "name": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "port": { - "type": "integer" + "type": "long" }, "sidecar_host": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "sidecar_port": { - "type": "integer" + "type": "long" }, "ui_host": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "ui_port": { - "type": "integer" + "type": "long" } } }, "created": { - "type": "date", - "format": "strict_date_optional_time" + "type": "date" }, - "description": { - "type": "text" + "creator": { + "properties": { + "attributes": { + "properties": { + "theme": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "qualified_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "username": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } }, "exchange_name": { - "type": "keyword" - }, - "exchange_type": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "id": { - "type": "keyword" + "type": "long" }, "identifiers": { - "type": "object", "properties": { "created": { - "type": "date", - "format": "strict_date_optional_time" + "type": "date" }, "creator": { - "type": "object", "properties": { - "firstname": { - "type": "keyword" - }, "id": { - "type": "keyword" - }, - "lastname": { - "type": "keyword" - }, - "name": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "qualified_name": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "username": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } } } }, "creators": { - "type": "object", "properties": { - "affiliation": { - "type": "keyword" - }, - "affiliation_identifier": { - "type": "keyword" - }, - "affiliation_identifier_scheme": { - "type": "keyword" - }, - "affiliation_identifier_scheme_uri": { - "type": "keyword" - }, "creator_name": { - "type": "text" - }, - "firstname": { - "type": "text" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "id": { - "type": "keyword" - }, - "lastname": { - "type": "text" + "type": "long" }, "name_identifier": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "name_identifier_scheme": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "name_identifier_scheme_uri": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "name_type": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } } } }, "database_id": { - "type": "keyword" + "type": "long" }, "descriptions": { - "type": "object", "properties": { "description": { - "type": "text" - }, - "id": { - "type": "keyword" - }, - "language": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - } - }, - "doi": { - "type": "keyword" - }, - "execution": { - "type": "date", - "format": "strict_date_optional_time" - }, - "funders": { - "type": "object", - "properties": { - "award_number": { - "type": "keyword" - }, - "award_title": { - "type": "keyword" - }, - "funder_identifier": { - "type": "keyword" - }, - "funder_identifier_type": { - "type": "keyword" - }, - "funder_name": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "id": { - "type": "keyword" - }, - "scheme_uri": { - "type": "keyword" + "type": "long" } } }, "id": { - "type": "keyword" + "type": "long" }, - "language": { - "type": "keyword" + "last_modified": { + "type": "date" }, "licenses": { - "type": "object", "properties": { + "description": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, "identifier": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "uri": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } } } }, "publication_day": { - "type": "integer" + "type": "long" }, "publication_month": { - "type": "integer" + "type": "long" }, "publication_year": { - "type": "integer" + "type": "long" }, "publisher": { - "type": "text" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "query": { - "type": "text" - }, - "query_hash": { - "type": "text" - }, - "query_id": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "query_normalized": { - "type": "text" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, - "related_identifiers": { - "type": "object", - "properties": { - "created": { - "type": "date", - "format": "strict_date_optional_time" - }, - "id": { - "type": "keyword" - }, - "relation": { - "type": "keyword" - }, - "type": { - "type": "keyword" - }, - "value": { - "type": "keyword" + "status": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 } } }, - "result_hash": { - "type": "text" - }, - "result_number": { - "type": "long" - }, - "status": { - "type": "keyword" - }, - "table_id": { - "type": "keyword" - }, "titles": { - "type": "object", "properties": { "id": { - "type": "keyword" - }, - "language": { - "type": "keyword" + "type": "long" }, "title": { - "type": "keyword" - }, - "type": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } } } }, "type": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "view_id": { - "type": "keyword" + "type": "long" + } + } + }, + "image": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 } } }, "internal_name": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "is_public": { "type": "boolean" }, "name": { - "type": "keyword" - }, - "owner": { - "type": "object", - "properties": { - "firstname": { - "type": "keyword" - }, - "id": { - "type": "keyword" - }, - "lastname": { - "type": "keyword" - }, - "name": { - "type": "keyword" - }, - "qualified_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 } } }, - "subsets": { - "type": "object", + "owner": { "properties": { - "created": { - "type": "date", - "format": "strict_date_optional_time" - }, - "creators": { - "type": "object", - "properties": { - "affiliation": { - "type": "keyword" - }, - "affiliation_identifier": { - "type": "keyword" - }, - "affiliation_identifier_scheme": { - "type": "keyword" - }, - "affiliation_identifier_scheme_uri": { - "type": "keyword" - }, - "creator_name": { - "type": "text" - }, - "firstname": { - "type": "text" - }, - "id": { - "type": "keyword" - }, - "lastname": { - "type": "text" - }, - "name_identifier": { - "type": "keyword" - }, - "name_identifier_scheme": { - "type": "keyword" - }, - "name_identifier_scheme_uri": { - "type": "keyword" - }, - "name_type": { - "type": "keyword" - } - } - }, - "database_id": { - "type": "keyword" - }, - "descriptions": { - "type": "object", - "properties": { - "description": { - "type": "text" - }, - "id": { - "type": "keyword" - }, - "language": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - } - }, - "doi": { - "type": "keyword" - }, - "execution": { - "type": "date", - "format": "strict_date_optional_time" - }, - "funders": { - "type": "object", + "attributes": { "properties": { - "award_number": { - "type": "keyword" - }, - "award_title": { - "type": "keyword" - }, - "funder_identifier": { - "type": "keyword" - }, - "funder_identifier_type": { - "type": "keyword" - }, - "funder_name": { - "type": "keyword" - }, - "id": { - "type": "keyword" - }, - "scheme_uri": { - "type": "keyword" + "theme": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } } } }, "id": { - "type": "keyword" - }, - "language": { - "type": "keyword" - }, - "licenses": { - "type": "object", - "properties": { - "identifier": { - "type": "keyword" - }, - "uri": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 } } }, - "publication_day": { - "type": "integer" - }, - "publication_month": { - "type": "integer" - }, - "publication_year": { - "type": "integer" - }, - "publisher": { - "type": "text" - }, - "query": { - "type": "text" - }, - "query_hash": { - "type": "text" - }, - "query_id": { - "type": "keyword" - }, - "query_normalized": { - "type": "text" - }, - "related_identifiers": { - "type": "object", - "properties": { - "created": { - "type": "date", - "format": "strict_date_optional_time" - }, - "id": { - "type": "keyword" - }, - "relation": { - "type": "keyword" - }, - "type": { - "type": "keyword" - }, - "value": { - "type": "keyword" + "qualified_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 } } }, - "result_hash": { - "type": "text" - }, - "result_number": { - "type": "long" - }, - "status": { - "type": "keyword" - }, - "table_id": { - "type": "keyword" - }, - "titles": { - "type": "object", - "properties": { - "id": { - "type": "keyword" - }, - "language": { - "type": "keyword" - }, - "title": { - "type": "keyword" - }, - "type": { - "type": "keyword" + "username": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 } } - }, - "type": { - "type": "keyword" - }, - "view_id": { - "type": "keyword" } } }, "tables": { - "type": "object", "properties": { - "avg_row_length": { - "type": "long" - }, "columns": { "properties": { "auto_generated": { @@ -630,30 +633,43 @@ } } }, - "concept": { - "type": "object", + "d": { + "type": "long" + }, + "database_id": { + "type": "long" + }, + "date_format": { "properties": { - "created": { - "type": "date", - "format": "strict_date_optional_time" + "created_at": { + "type": "date" + }, + "database_format": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "has_time": { + "type": "boolean" }, "id": { "type": "long" }, - "uri": { - "type": "keyword" + "unix_format": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } } } }, - "database_id": { - "type": "long" - }, - "data_length": { - "type": "long" - }, - "description": { - "type": "text" - }, "id": { "type": "long" }, @@ -672,6 +688,9 @@ "is_public": { "type": "boolean" }, + "mean": { + "type": "float" + }, "name": { "type": "text", "fields": { @@ -681,310 +700,163 @@ } } }, - "num_rows": { - "type": "long" - }, - "max_data_length": { + "size": { "type": "long" }, - "mean": { - "type": "double" - }, - "median": { - "type": "double" - }, "std_dev": { - "type": "double" - }, - "size": { - "type": "long" + "type": "float" }, "table_id": { "type": "long" - }, - "unit": { - "type": "object", - "properties": { - "created": { - "type": "date", - "format": "strict_date_optional_time" - }, - "id": { - "type": "long" - }, - "uri": { - "type": "keyword" - } - } - }, - "val_min": { - "type": "double" - }, - "val_max": { - "type": "double" } } }, "constraints": { - "type": "object", "properties": { - "foreign_keys": { - "type": "object", + "primary_key": { "properties": { - "name": { - "type": "keyword" - }, - "columns": { - "type": "keyword" - }, - "referenced_table": { - "type": "keyword" - }, - "referenced_columns": { - "type": "keyword" + "column": { + "properties": { + "database_id": { + "type": "long" + }, + "id": { + "type": "long" + }, + "table_id": { + "type": "long" + } + } }, - "on_delete": { - "type": "keyword" + "id": { + "type": "long" }, - "on_update": { - "type": "keyword" + "table": { + "properties": { + "database_id": { + "type": "long" + }, + "id": { + "type": "long" + } + } } } }, "uniques": { - "type": "object", "properties": { + "columns": { + "properties": { + "database_id": { + "type": "long" + }, + "id": { + "type": "long" + }, + "table_id": { + "type": "long" + } + } + }, "id": { - "type": "keyword" + "type": "long" + }, + "table": { + "properties": { + "database_id": { + "type": "long" + }, + "id": { + "type": "long" + } + } } } - }, - "checks": { - "type": "keyword" - }, - "primary_key": { - "type": "keyword" } } }, "created": { - "type": "date", - "format": "strict_date_optional_time" - }, - "database_id": { - "type": "keyword" - }, - "data_length": { - "type": "long" - }, - "description": { - "type": "text" - }, - "id": { - "type": "keyword" + "type": "date" + }, + "created_by": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, - "identifiers": { - "type": "object", + "creator": { "properties": { - "created": { - "type": "date", - "format": "strict_date_optional_time" - }, - "creators": { - "type": "object", + "attributes": { "properties": { - "affiliation": { - "type": "keyword" - }, - "affiliation_identifier": { - "type": "keyword" - }, - "affiliation_identifier_scheme": { - "type": "keyword" - }, - "affiliation_identifier_scheme_uri": { - "type": "keyword" - }, - "creator_name": { - "type": "text" - }, - "firstname": { - "type": "text" - }, - "id": { - "type": "keyword" - }, - "lastname": { - "type": "text" - }, - "name_identifier": { - "type": "keyword" - }, - "name_identifier_scheme": { - "type": "keyword" - }, - "name_identifier_scheme_uri": { - "type": "keyword" - }, - "name_type": { - "type": "keyword" - } - } - }, - "database_id": { - "type": "keyword" - }, - "descriptions": { - "type": "object", - "properties": { - "description": { - "type": "text" - }, - "id": { - "type": "keyword" - }, - "language": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - } - }, - "doi": { - "type": "keyword" - }, - "execution": { - "type": "date", - "format": "strict_date_optional_time" - }, - "funders": { - "type": "object", - "properties": { - "award_number": { - "type": "keyword" - }, - "award_title": { - "type": "keyword" - }, - "funder_identifier": { - "type": "keyword" - }, - "funder_identifier_type": { - "type": "keyword" - }, - "funder_name": { - "type": "keyword" - }, - "id": { - "type": "keyword" - }, - "scheme_uri": { - "type": "keyword" + "theme": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } } } }, "id": { - "type": "keyword" - }, - "language": { - "type": "keyword" - }, - "licenses": { - "type": "object", - "properties": { - "identifier": { - "type": "keyword" - }, - "uri": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 } } }, - "publication_day": { - "type": "integer" - }, - "publication_month": { - "type": "integer" - }, - "publication_year": { - "type": "integer" - }, - "publisher": { - "type": "text" - }, - "query": { - "type": "text" - }, - "query_hash": { - "type": "text" - }, - "query_id": { - "type": "keyword" - }, - "query_normalized": { - "type": "text" - }, - "related_identifiers": { - "type": "object", - "properties": { - "created": { - "type": "date", - "format": "strict_date_optional_time" - }, - "id": { - "type": "keyword" - }, - "relation": { - "type": "keyword" - }, - "type": { - "type": "keyword" - }, - "value": { - "type": "keyword" + "qualified_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 } } }, - "result_hash": { - "type": "text" - }, - "result_number": { - "type": "long" - }, - "status": { - "type": "keyword" - }, - "table_id": { - "type": "keyword" - }, - "titles": { - "type": "object", - "properties": { - "id": { - "type": "keyword" - }, - "language": { - "type": "keyword" - }, - "title": { - "type": "keyword" - }, - "type": { - "type": "keyword" + "username": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 } } - }, - "type": { - "type": "keyword" - }, - "view_id": { - "type": "keyword" } } }, + "data_length": { + "type": "long" + }, + "database_id": { + "type": "long" + }, + "description": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "id": { + "type": "long" + }, "internal_name": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "is_public": { "type": "boolean" @@ -993,258 +865,429 @@ "type": "boolean" }, "name": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "num_rows": { "type": "long" }, - "max_data_length": { - "type": "long" - }, "owner": { - "type": "object", "properties": { - "firstname": { - "type": "keyword" + "attributes": { + "properties": { + "theme": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } }, "id": { - "type": "keyword" - }, - "lastname": { - "type": "keyword" - }, - "name": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "qualified_name": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "username": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } } } }, "queue_name": { - "type": "keyword" - }, - "queue_type": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "routing_key": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } } } }, "views": { - "type": "object", "properties": { + "columns": { + "properties": { + "auto_generated": { + "type": "boolean" + }, + "column_type": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "database_id": { + "type": "long" + }, + "date_format": { + "properties": { + "created_at": { + "type": "date" + }, + "database_format": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "has_time": { + "type": "boolean" + }, + "id": { + "type": "long" + }, + "unix_format": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "id": { + "type": "long" + }, + "internal_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "is_null_allowed": { + "type": "boolean" + }, + "is_public": { + "type": "boolean" + }, + "name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, "created": { - "type": "date", - "format": "strict_date_optional_time" + "type": "date" + }, + "creator": { + "properties": { + "attributes": { + "properties": { + "theme": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "qualified_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "username": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } }, "database_id": { - "type": "keyword" + "type": "long" }, "id": { - "type": "keyword" + "type": "long" }, "identifiers": { - "type": "object", "properties": { "created": { - "type": "date", - "format": "strict_date_optional_time" + "type": "date" }, - "creators": { - "type": "object", + "creator": { "properties": { - "affiliation": { - "type": "keyword" - }, - "affiliation_identifier": { - "type": "keyword" - }, - "affiliation_identifier_scheme": { - "type": "keyword" + "id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, - "affiliation_identifier_scheme_uri": { - "type": "keyword" + "qualified_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, + "username": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + }, + "creators": { + "properties": { "creator_name": { - "type": "text" - }, - "firstname": { - "type": "text" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "id": { - "type": "keyword" - }, - "lastname": { - "type": "text" + "type": "long" }, "name_identifier": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "name_identifier_scheme": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "name_identifier_scheme_uri": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "name_type": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } } } }, "database_id": { - "type": "keyword" + "type": "long" }, "descriptions": { - "type": "object", "properties": { "description": { - "type": "text" - }, - "id": { - "type": "keyword" - }, - "language": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - } - }, - "doi": { - "type": "keyword" - }, - "execution": { - "type": "date", - "format": "strict_date_optional_time" - }, - "funders": { - "type": "object", - "properties": { - "award_number": { - "type": "keyword" - }, - "award_title": { - "type": "keyword" - }, - "funder_identifier": { - "type": "keyword" - }, - "funder_identifier_type": { - "type": "keyword" - }, - "funder_name": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "id": { - "type": "keyword" - }, - "scheme_uri": { - "type": "keyword" + "type": "long" } } }, "id": { - "type": "keyword" + "type": "long" }, - "language": { - "type": "keyword" + "last_modified": { + "type": "date" }, "licenses": { - "type": "object", "properties": { + "description": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, "identifier": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "uri": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } } } }, "publication_day": { - "type": "integer" + "type": "long" }, "publication_month": { - "type": "integer" + "type": "long" }, "publication_year": { - "type": "integer" + "type": "long" }, "publisher": { - "type": "text" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "query": { - "type": "text" - }, - "query_hash": { - "type": "text" - }, - "query_id": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "query_normalized": { - "type": "text" - }, - "related_identifiers": { - "type": "object", - "properties": { - "created": { - "type": "date", - "format": "strict_date_optional_time" - }, - "id": { - "type": "keyword" - }, - "relation": { - "type": "keyword" - }, - "type": { - "type": "keyword" - }, - "value": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 } } }, - "result_hash": { - "type": "text" - }, - "result_number": { - "type": "long" - }, "status": { - "type": "keyword" - }, - "table_id": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "titles": { - "type": "object", "properties": { "id": { - "type": "keyword" - }, - "language": { - "type": "keyword" + "type": "long" }, "title": { - "type": "keyword" - }, - "type": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } } } }, "type": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "view_id": { - "type": "keyword" + "type": "long" } } }, @@ -1252,19 +1295,46 @@ "type": "boolean" }, "internal_name": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "is_public": { "type": "boolean" }, + "last_modified": { + "type": "date" + }, "name": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "query": { - "type": "text" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } }, "query_hash": { - "type": "keyword" + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } } } } diff --git a/dbrepo-search-service/lib/dbrepo-1.4.3-py3-none-any.whl b/dbrepo-search-service/lib/dbrepo-1.4.3-py3-none-any.whl deleted file mode 100644 index 2e19eddac149ac401c67a52ba56577132e32869a..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/lib/dbrepo-1.4.3-py3-none-any.whl and /dev/null differ diff --git a/dbrepo-search-service/lib/dbrepo-1.4.3.tar.gz b/dbrepo-search-service/lib/dbrepo-1.4.3.tar.gz deleted file mode 100644 index ffb89654bab83c6f72a9381825e41f0dbe7d37c9..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/lib/dbrepo-1.4.3.tar.gz and /dev/null differ diff --git a/dbrepo-search-service/lib/dbrepo-1.4.4-py3-none-any.whl b/dbrepo-search-service/lib/dbrepo-1.4.4-py3-none-any.whl index 11873004972bb08703994ba1fb0ddf18f96f6a2c..694a6fc02560b3b5d858df0e5a0bd9acf45c8f20 100644 Binary files a/dbrepo-search-service/lib/dbrepo-1.4.4-py3-none-any.whl and b/dbrepo-search-service/lib/dbrepo-1.4.4-py3-none-any.whl differ diff --git a/dbrepo-search-service/lib/dbrepo-1.4.4.tar.gz b/dbrepo-search-service/lib/dbrepo-1.4.4.tar.gz index f7452a0e12c9a2d44f663bc1f338204b7579144b..f344d01026b92476d80703cbfb7d884cb7822e05 100644 Binary files a/dbrepo-search-service/lib/dbrepo-1.4.4.tar.gz and b/dbrepo-search-service/lib/dbrepo-1.4.4.tar.gz differ diff --git a/dbrepo-search-service/os-yml/get_fields.yml b/dbrepo-search-service/os-yml/get_fields.yml index 6ff4c879741babf74f6a72d403b564d9e0acb1ce..bf7f48764327969d3665c9dce8f5bed74779f6eb 100644 --- a/dbrepo-search-service/os-yml/get_fields.yml +++ b/dbrepo-search-service/os-yml/get_fields.yml @@ -16,22 +16,6 @@ responses: content: application/json: schema: - type: object - properties: - results: - type: array - items: - type: object - properties: - attr_name: - type: "string" - example: "name" - attr_friendly_name: - type: "string" - example: "Name" - type: - type: "string" - example: "string" - description: OpenSearch data types. + $ref: '#/components/schemas/IndexFieldsDto' "404": description: Invalid type. diff --git a/dbrepo-search-service/os-yml/get_fuzzy_search.yml b/dbrepo-search-service/os-yml/get_fuzzy_search.yml index 3dbd5d19d5c0d46d7ec904bdc0a0ac5e08f6d2d9..bc54419eb9735fe731fb12a5e911070ebc29f80e 100644 --- a/dbrepo-search-service/os-yml/get_fuzzy_search.yml +++ b/dbrepo-search-service/os-yml/get_fuzzy_search.yml @@ -8,25 +8,17 @@ consumes: produces: - application/json parameters: - - in: query + - name: q + in: query required: true schema: - type: "string" - properties: - q: - type: "string" - example: "air quality" + type: string responses: 200: description: OK, contains the elements formatted as an array of JSON arrays content: application/json: schema: - type: object - properties: - results: - type: array - items: - type: object + $ref: '#/components/schemas/SearchResultDto' 415: description: Wrong accept type diff --git a/dbrepo-search-service/os-yml/get_index.yml b/dbrepo-search-service/os-yml/get_index.yml index 48fc4ca286288ba94f0de1b9030d2c0eae49ed9f..fe4941810c66d97d6f26752dfa61f08e98d98e3f 100644 --- a/dbrepo-search-service/os-yml/get_index.yml +++ b/dbrepo-search-service/os-yml/get_index.yml @@ -38,13 +38,4 @@ responses: content: application/json: schema: - type: object - properties: - results: - type: array - items: - type: object - type: - type: string - enum: [ database, table, view, column, user, identifier, concept, unit ] - description: "Same as the requested type" + $ref: '#/components/schemas/IndexDto' diff --git a/dbrepo-search-service/os-yml/health.yml b/dbrepo-search-service/os-yml/health.yml deleted file mode 100644 index a4b273a2bf739abc5385a1ba1bce5c0ebafef1aa..0000000000000000000000000000000000000000 --- a/dbrepo-search-service/os-yml/health.yml +++ /dev/null @@ -1,24 +0,0 @@ -summary: Return a healthcheck -description: | - Return UP if the instance is ready to serve connections. -consumes: - - application/json -produces: - - application/json -parameters: [] -definitions: - Health: - type: object - properties: - status: - type: string - description: UP -responses: - 200: - description: OK, service is up and running - schema: - $ref: "#/definitions/Column" - 404: - description: Service is not yet ready -tags: - - actuator \ No newline at end of file diff --git a/dbrepo-search-service/os-yml/post_general_search.yml b/dbrepo-search-service/os-yml/post_general_search.yml index 33cbea636730a13b518434284178bd8d21b2711b..cbff09b7fc686af87ee9f2086e34c2b85ea0df54 100644 --- a/dbrepo-search-service/os-yml/post_general_search.yml +++ b/dbrepo-search-service/os-yml/post_general_search.yml @@ -27,13 +27,7 @@ parameters: name: "body" required: true schema: - type: "object" - properties: - search_term: - type: "string" - example: "air quality" - field_value_pairs: - type: "object" + $ref: '#/components/schemas/SearchRequestDto' responses: 200: description: OK, contains the elements formatted as an array of JSON arrays diff --git a/dbrepo-search-service/os-yml/update_database.yml b/dbrepo-search-service/os-yml/update_database.yml index f1f2911d3e87258c714fd0bdcce9dd49c6b0faea..e9cd0d56f967a62144dba4af10edea38b055a11c 100644 --- a/dbrepo-search-service/os-yml/update_database.yml +++ b/dbrepo-search-service/os-yml/update_database.yml @@ -12,14 +12,7 @@ parameters: name: "body" required: true schema: - type: "object" - properties: - name: - type: "string" - example: "Air Quality" - internal_name: - type: "string" - example: "air_quality_abcd" + $ref: '#/components/schemas/DatabaseDto' security: - bearerAuth: [ ] - basicAuth: [ ] diff --git a/dbrepo-search-service/test/test_opensearch_client.py b/dbrepo-search-service/test/test_opensearch_client.py index 51f3a9feaa5ea95b04162a38538f3dc930a758da..906aae0ccc0862703abc740622d793ed8388192b 100644 --- a/dbrepo-search-service/test/test_opensearch_client.py +++ b/dbrepo-search-service/test/test_opensearch_client.py @@ -2,7 +2,8 @@ import datetime import unittest import opensearchpy -from dbrepo.api.dto import Database, User, UserAttributes, Container, Image, Table, Column, ColumnType, Constraints +from dbrepo.api.dto import Database, User, UserAttributes, Container, Image, Table, Column, ColumnType, Constraints, \ + PrimaryKey, TableMinimal, ColumnMinimal from app import app from clients.opensearch_client import OpenSearchClient @@ -56,7 +57,11 @@ class OpenSearchClientTest(unittest.TestCase): routing_key="dbrepo.test_tuw1.test_table", is_public=True, database_id=req.id, - constraints=Constraints(uniques=[], foreign_keys=[], checks=[], primary_key=["id"]), + constraints=Constraints(uniques=[], foreign_keys=[], checks=[], + primary_key=[PrimaryKey(id=1, + table=TableMinimal(id=1, database_id=1), + column=ColumnMinimal(id=1, table_id=1, + database_id=1))]), is_versioned=True, created_by="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", creator=User(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", diff --git a/dbrepo-ui/bun.lockb b/dbrepo-ui/bun.lockb index d02f3f8c7351adf0b5c84fae2cc06eb90708a85c..2ae1649f86a2cfc2d75d6e45a0c9490ad434ae02 100755 Binary files a/dbrepo-ui/bun.lockb and b/dbrepo-ui/bun.lockb differ diff --git a/dbrepo-ui/components/TimeDrift.vue b/dbrepo-ui/components/TimeDrift.vue index 0617da8c4b6f18cf9412d9fd14ad613efd362415..362fa28aaf445bc93c2f2b91e6cf6ffcd4676645 100644 --- a/dbrepo-ui/components/TimeDrift.vue +++ b/dbrepo-ui/components/TimeDrift.vue @@ -43,6 +43,3 @@ export default { } } </script> - -<script setup lang="ts"> -</script> diff --git a/dbrepo-ui/components/database/DatabaseCreate.vue b/dbrepo-ui/components/database/DatabaseCreate.vue index a805af0e02d0e83454ae58b4064ba4e901477cd2..f7e2b005974e15afe7aeab285fd006ca5410baf3 100644 --- a/dbrepo-ui/components/database/DatabaseCreate.vue +++ b/dbrepo-ui/components/database/DatabaseCreate.vue @@ -113,7 +113,8 @@ export default { this.loadingContainers = false }) .catch(({code}) => { - this.$toast.error(this.$t(code)) + const toast = useToastInstance() + toast.error(this.$t(code)) this.loadingContainers = false }) }, @@ -127,7 +128,8 @@ export default { this.loading = false }) .catch(({code}) => { - this.$toast.error(this.$t(code)) + const toast = useToastInstance() + toast.error(this.$t(code)) this.loading = false }) }, diff --git a/dbrepo-ui/components/dialogs/DropTable.vue b/dbrepo-ui/components/dialogs/DropTable.vue index 9421d1154ba3fd273206cb57ca9a11b91d095ec3..1f62735de5e6ce549386894f525074f53d5cdd5a 100644 --- a/dbrepo-ui/components/dialogs/DropTable.vue +++ b/dbrepo-ui/components/dialogs/DropTable.vue @@ -92,7 +92,8 @@ export default { .then(() => { console.info('Deleted table with id ', this.table.id) this.cacheStore.reloadDatabase() - this.$toast.success('Successfully deleted table with id ' + this.table.id) + const toast = useToastInstance() + toast.success('Successfully deleted table with id ' + this.table.id) this.$router.push(`/database/${this.$route.params.database_id}/table`) }) .finally(() => { diff --git a/dbrepo-ui/components/dialogs/EditAccess.vue b/dbrepo-ui/components/dialogs/EditAccess.vue index 90ac7e3169174d358f83e832feae28e8fd31b1f5..8132adddf5935ae357893f8f91a2c4c597e6cf94 100644 --- a/dbrepo-ui/components/dialogs/EditAccess.vue +++ b/dbrepo-ui/components/dialogs/EditAccess.vue @@ -171,7 +171,8 @@ export default { const accessService = useAccessService() accessService.remove(this.$route.params.database_id, this.userId) .then(() => { - this.$toast.success(this.$t('notifications.access.revoked')) + const toast = useToastInstance() + toast.success(this.$t('notifications.access.revoked')) this.$emit('close-dialog', { success: true }) }) .finally(() => { @@ -182,7 +183,8 @@ export default { const accessService = useAccessService() accessService.modify(this.$route.params.database_id, this.userId, this.modify) .then(() => { - this.$toast.success(this.$t('notifications.access.modified')) + const toast = useToastInstance() + toast.success(this.$t('notifications.access.modified')) this.$emit('close-dialog', { success: true }) }) .finally(() => { @@ -193,7 +195,8 @@ export default { const accessService = useAccessService() accessService.create(this.$route.params.database_id, this.userId, this.modify) .then(() => { - this.$toast.success(this.$t('notifications.access.created')) + const toast = useToastInstance() + toast.success(this.$t('notifications.access.created')) this.$emit('close-dialog', { success: true }) }) .finally(() => { diff --git a/dbrepo-ui/components/dialogs/EditTuple.vue b/dbrepo-ui/components/dialogs/EditTuple.vue index 475e44328f889d637f723f5448e74988703e2f31..3f40a93175b6f3515f9e8b15500ac183cfe95769 100644 --- a/dbrepo-ui/components/dialogs/EditTuple.vue +++ b/dbrepo-ui/components/dialogs/EditTuple.vue @@ -280,12 +280,14 @@ export default { this.loading = true tupleService.update(this.$route.params.database_id, this.$route.params.table_id, { data: this.tuple, keys: constraints }) .then(() => { - this.$toast.success(this.$t('success.data.update')) + const toast = useToastInstance() + toast.success(this.$t('success.data.update')) this.$emit('close', { success: true }) this.loading = false }) .catch(({message}) => { - this.$toast.error(message) + const toast = useToastInstance() + toast.error(message) this.loading = false }) .finally(() => { @@ -308,12 +310,14 @@ export default { this.loading = true tupleService.create(this.$route.params.database_id, this.$route.params.table_id, { data: this.tuple }) .then(() => { - this.$toast.success(this.$t('success.data.add')) + const toast = useToastInstance() + toast.success(this.$t('success.data.add')) this.$emit('close', { success: true }) this.loading = false }) .catch(({message}) => { - this.$toast.error(message) + const toast = useToastInstance() + toast.error(message) this.loading = false }) .finally(() => { @@ -321,7 +325,8 @@ export default { }) }, onUpload ({column, s3key}) { - this.$toast.success(this.$t('success.upload.blob')) + const toast = useToastInstance() + toast.success(this.$t('success.upload.blob')) this.tuple[column.internal_name] = s3key } } diff --git a/dbrepo-ui/components/dialogs/Semantics.vue b/dbrepo-ui/components/dialogs/Semantics.vue index fd64efa9e702dcbc3f8aa629a599c0a04d270f03..a4a7104788ce1e12460ad693ac543058b60cdf6c 100644 --- a/dbrepo-ui/components/dialogs/Semantics.vue +++ b/dbrepo-ui/components/dialogs/Semantics.vue @@ -243,7 +243,8 @@ export default { this.recommendations = recommendations }) .catch((error) => { - this.$toast.error(this.$t('error.semantics.timeout')) + const toast = useToastInstance() + toast.error(this.$t('error.semantics.timeout')) }) .finally(() => { this.loadingSemantics = false diff --git a/dbrepo-ui/components/identifier/Creators.vue b/dbrepo-ui/components/identifier/Creators.vue index 6c5857d978cf8859b58a6987181bdd2b3020b28c..706736b21b155f5dc0265b0993f23b435bd5c345 100644 --- a/dbrepo-ui/components/identifier/Creators.vue +++ b/dbrepo-ui/components/identifier/Creators.vue @@ -69,13 +69,16 @@ export default { this.creators.push(creator) return } + this.creators.push(creator) + if (!(personOrOrg.affiliation || personOrOrg.affiliation_identifier || personOrOrg.affiliation_identifier_scheme)) { + return + } this.affiliations.push({ name: personOrOrg.affiliation, name_identifier: personOrOrg.affiliation_identifier, name_identifier_scheme: personOrOrg.affiliation_identifier_scheme }) creator.affiliation_index = this.getIndex(creator) + 1 - this.creators.push(creator) }) }, methods: { diff --git a/dbrepo-ui/components/identifier/Persist.vue b/dbrepo-ui/components/identifier/Persist.vue index 2af517a68b5f55bc57d5d29e23285c44954ba2d8..3b9321ad3644bcbf9fb55d24cf6725b0dedeb21d 100644 --- a/dbrepo-ui/components/identifier/Persist.vue +++ b/dbrepo-ui/components/identifier/Persist.vue @@ -1339,7 +1339,8 @@ export default { }, createOrSave () { if (!this.formValid) { - this.$toast.info(this.$t('error.identifier.form')) + const toast = useToastInstance() + toast.info(this.$t('error.identifier.form')) return } if (!this.identifier.id) { @@ -1355,12 +1356,14 @@ export default { identifierService.save(payload) .then((identifier) => { this.cacheStore.reloadDatabase() - this.$toast.success(this.$t('success.pid.saved')) + const toast = useToastInstance() + toast.success(this.$t('success.pid.saved')) this.identifier = identifier this.loadingSave = false }) - .catch((error) => { - this.$toast.error(this.$t(error.code)) + .catch(({code}) => { + const toast = useToastInstance() + toast.error(this.$t(code)) this.loadingSave = false }) .finally(() => { @@ -1374,13 +1377,15 @@ export default { identifierService.create(payload) .then((identifier) => { this.cacheStore.reloadDatabase() - this.$toast.success(this.$t('success.pid.created')) + const toast = useToastInstance() + toast.success(this.$t('success.pid.created')) this.identifier = identifier this.$router.push(this.nextTo) this.loadingSave = false }) - .catch((error) => { - this.$toast.error(this.$t(error.code)) + .catch(({code}) => { + const toast = useToastInstance() + toast.error(this.$t(code)) this.loadingSave = false }) .finally(() => { @@ -1392,7 +1397,8 @@ export default { const identifierService = useIdentifierService() identifierService.publish(this.identifier.id) .then(() => { - this.$toast.success(this.$t('success.pid.published')) + const toast = useToastInstance() + toast.success(this.$t('success.pid.published')) this.cacheStore.reloadDatabase() this.loadingPublish = false }) @@ -1409,7 +1415,8 @@ export default { identifierService.remove(this.identifier.id) .then(() => { this.cacheStore.reloadDatabase() - this.$toast.success(this.$t('success.pid.deleted')) + const toast = useToastInstance() + toast.success(this.$t('success.pid.deleted')) this.$router.push(this.backTo) this.loadingDelete = false }) diff --git a/dbrepo-ui/components/subset/Builder.vue b/dbrepo-ui/components/subset/Builder.vue index f379a59084494cb4cf006068bff1e561222e6c07..e8e60d6559de7a401ac53e9aa769733045145ea7 100644 --- a/dbrepo-ui/components/subset/Builder.vue +++ b/dbrepo-ui/components/subset/Builder.vue @@ -503,12 +503,14 @@ export default { const queryService = useQueryService() queryService.execute(this.$route.params.database_id, { statement: this.sql }, this.timestamp, 0, 1) .then(async (subset) => { - this.$toast.success(this.$t('success.subset.create')) + const toast = useToastInstance() + toast.success(this.$t('success.subset.create')) await this.$router.push(`/database/${this.$route.params.database_id}/subset/${subset.id}/data`) this.loadingQuery = false }) - .catch((error) => { - this.$toast.error(this.$t(error.message)) + .catch(({code}) => { + const toast = useToastInstance() + toast.error(this.$t(code)) this.loadingQuery = false }) }, @@ -520,12 +522,14 @@ export default { .then(async (view) => { this.resultId = view.id this.cacheStore.reloadDatabase() - this.$toast.success(this.$t('success.view.create')) + const toast = useToastInstance() + toast.success(this.$t('success.view.create')) await this.$router.push(`/database/${this.$route.params.database_id}/view/${view.id}/data`) this.loadingQuery = false }) - .catch((error) => { - this.$toast.error(this.$t(error.code)) + .catch(({code}) => { + const toast = useToastInstance() + toast.error(this.$t(code)) this.loadingQuery = false }) }, @@ -536,7 +540,8 @@ export default { const queryService = useQueryService() const { error, reason, column, raw, formatted } = queryService.build(this.table.internal_name, this.select, this.clauses) if (error) { - this.$toast.error(this.$t('error.query.' + reason) + ' ' + column) + const toast = useToastInstance() + toast.error(this.$t('error.query.' + reason) + ' ' + column) return } this.query.raw = raw diff --git a/dbrepo-ui/components/subset/Results.vue b/dbrepo-ui/components/subset/Results.vue index c1e700faef7050b89c6e10e4d711c2dcb2399533..ed6f7448334ae631d400e354832947e9d095c0fa 100644 --- a/dbrepo-ui/components/subset/Results.vue +++ b/dbrepo-ui/components/subset/Results.vue @@ -19,12 +19,6 @@ export default { type: String, default: () => 'query' /* query or view */ }, - view: { - type: Object, - default: () => { - return {} - } - }, loading: { type: Boolean, default: () => { @@ -58,15 +52,6 @@ export default { if (this.result.headers.length !== 0) { return this.result.headers } - if (this.type === 'view' && this.view && this.view.columns) { - return this.view.columns.map((c) => { - return { - title: c.alias ? c.alias : c.internal_name, - value: c.alias ? c.alias : c.internal_name, - sortable: false - } - }) - } return [] } }, @@ -110,7 +95,8 @@ export default { this.loadingExecute = false }) .catch(({code}) => { - this.$toast.error(this.$t(code)) + const toast = useToastInstance() + toast.error(this.$t(code)) this.loadingExecute = false }) .finally(() => { @@ -125,7 +111,8 @@ export default { this.loadingExecute = false }) .catch(({code}) => { - this.$toast.error(this.$t(code)) + const toast = useToastInstance() + toast.error(this.$t(code)) this.loadingExecute = false }) .finally(() => { @@ -146,7 +133,8 @@ export default { this.loadingCount = false }) .catch(({code}) => { - this.$toast.error(this.$t(code)) + const toast = useToastInstance() + toast.error(this.$t(code)) this.loadingCount = false }) .finally(() => { @@ -160,7 +148,8 @@ export default { this.loadingCount = false }) .catch(({code}) => { - this.$toast.error(this.$t(code)) + const toast = useToastInstance() + toast.error(this.$t(code)) this.loadingCount = false }) .finally(() => { diff --git a/dbrepo-ui/components/subset/SubsetList.vue b/dbrepo-ui/components/subset/SubsetList.vue index 1a0150f4d6ca0817ac773fbd3160f6032ee91c11..94c1bff1e82f0932f86e0aff7ebd3bac9d74a539 100644 --- a/dbrepo-ui/components/subset/SubsetList.vue +++ b/dbrepo-ui/components/subset/SubsetList.vue @@ -1,5 +1,10 @@ <template> <div> + <v-card + v-if="!loadingSubsets && queries.length === 0" + variant="flat" + rounded="0" + :text="$t('pages.database.subpages.subsets.empty')" /> <v-card variant="flat" rounded="0"> @@ -8,10 +13,6 @@ lines="two"> <Loading /> </v-list-item> - <v-list-item - v-if="!loadingSubsets && queries.length === 0" - lines="two" - :title="$t('pages.database.subpages.subsets.empty')" /> <div v-for="(item, i) in queries" :key="`q-${i}`"> @@ -79,8 +80,9 @@ export default { .then((queries) => { this.queries = queries }) - .catch((error) => { - this.$toast.error(this.$t(error.code)) + .catch(({code}) => { + const toast = useToastInstance() + toast.error(this.$t(code)) this.loadingSubsets = false }) .finally(() => { diff --git a/dbrepo-ui/components/table/BlobUpload.vue b/dbrepo-ui/components/table/BlobUpload.vue index 67d1ffd4d472877c548e374cb7c9c47e72a24045..d0b1ceb49713e01a19c7b6b80f42bf92bbf47467 100644 --- a/dbrepo-ui/components/table/BlobUpload.vue +++ b/dbrepo-ui/components/table/BlobUpload.vue @@ -39,8 +39,9 @@ export default { this.value = filename this.$emit('blob', { column: this.column, s3key: filename }) }) - .catch((error) => { - this.$toast.error(this.$t(error.code)) + .catch(({code}) => { + const toast = useToastInstance() + toast.error(this.$t(code)) }) } } diff --git a/dbrepo-ui/components/dialogs/TimeTravel.vue b/dbrepo-ui/components/table/TableHistory.vue similarity index 86% rename from dbrepo-ui/components/dialogs/TimeTravel.vue rename to dbrepo-ui/components/table/TableHistory.vue index 12f4228503c61b61561e367986a3ef34521e6a14..dd3dad66e2961b59f5591a586150e88fa2c00ff6 100644 --- a/dbrepo-ui/components/dialogs/TimeTravel.vue +++ b/dbrepo-ui/components/table/TableHistory.vue @@ -54,7 +54,7 @@ <script> import { Bar } from 'vue-chartjs' import { format } from 'date-fns' -import { useCacheStore } from '@/stores/cache' +import { useCacheStore } from '~/stores/cache.js' import { Chart as ChartJS, Title, Tooltip, BarElement, CategoryScale, LinearScale, LogarithmicScale } from 'chart.js' ChartJS.register(Title, Tooltip, BarElement, CategoryScale, LinearScale, LogarithmicScale) @@ -153,23 +153,19 @@ export default { this.datetime = this.chartData.labels[idx] console.debug('date time', this.datetime, 'idx', idx) }, - async loadHistory () { - try { - this.loading = true - const tableService = useTableService() - this.history = await tableService.history(this.table.database_id, this.table.id) - // this.chartData.labels = history.map(d => format(new Date(d.timestamp), 'dd.MM.yyyy HH:mm:ss')) - // this.chartData.datasets = [{ - // // backgroundColor: 'red', - // data: history.map(d => d.total) - // }] - this.totalChanges = history.length - console.debug('history', this.chartData) - } catch (err) { - this.error = true - console.error('failed to load table history', err) - } - this.loading = false + loadHistory () { + this.loading = true + const tableService = useTableService() + tableService.history(this.table.database_id, this.table.id) + .then((history) => { + this.loading = false + this.history = history + }) + .catch(({message}) => { + const toast = useToastInstance() + toast.error(message) + this.loading = false + }) } } } diff --git a/dbrepo-ui/components/table/TableImport.vue b/dbrepo-ui/components/table/TableImport.vue index 92ddba0ecd9973829c8fef238d3b1174b40abcee..3688c4d9e3b4603b3be6929c86ec28b115b31af5 100644 --- a/dbrepo-ui/components/table/TableImport.vue +++ b/dbrepo-ui/components/table/TableImport.vue @@ -401,7 +401,8 @@ export default { const tableService = useTableService() tableService.importCsv(this.$route.params.database_id, this.tableId, this.tableImport) .then(() => { - this.$toast.success(this.$t('success.import.dataset')) + const toast = useToastInstance() + toast.success(this.$t('success.import.dataset')) this.cacheStore.reloadDatabase() tableService.getCount(this.$route.params.database_id, this.tableId, null) .then((rowCount) => { @@ -410,9 +411,9 @@ export default { this.step = this.stepStart + 2 this.loading = false }) - .catch((error) => { - console.error('Failed to import csv', error) - this.$toast.error(this.$t('error.import.dataset')) + .catch(() => { + const toast = useToastInstance() + toast.error(this.$t('error.import.dataset')) this.loading = false }) .finally(() => { @@ -425,11 +426,13 @@ export default { const uploadService = useUploadService() return uploadService.create(this.previousFile) .then((s3key) => { - this.$toast.success(this.$t('success.upload.dataset')) + const toast = useToastInstance() + toast.success(this.$t('success.upload.dataset')) this.analyse(s3key) }) .catch(() => { - this.$toast.error(this.$t('error.upload.dataset')) + const toast = useToastInstance() + toast.error(this.$t('error.upload.dataset')) this.loading = false }) }, @@ -462,12 +465,14 @@ export default { this.suggestedAnalyseLineTerminator = line_termination this.tableImport.location = filename this.step = this.stepStart + 2 - this.$toast.success(this.$t('success.analyse.dataset')) + const toast = useToastInstance() + toast.success(this.$t('success.analyse.dataset')) this.$emit('analyse', {columns: this.columns, filename, line_termination}) this.loading = false }) .catch(({code}) => { - this.$toast.error(this.$t(code)) + const toast = useToastInstance() + toast.error(this.$t(code)) this.loading = false }) } diff --git a/dbrepo-ui/components/table/TableSchema.vue b/dbrepo-ui/components/table/TableSchema.vue index 07485c8690b54ba47fdae0ad75e7eeb4f8b5dd0a..1cc172858c9302b43dd1bbad5ea311fc5898dbd2 100644 --- a/dbrepo-ui/components/table/TableSchema.vue +++ b/dbrepo-ui/components/table/TableSchema.vue @@ -1,15 +1,19 @@ <template> <div> - <v-alert - v-if="needsSequence" - class="mb-6" - border="start" - :text="$t('validation.schema.primary-key')" - color="info" /> <v-form ref="form" v-model="valid" :disabled="disabled"> + <v-row> + <v-col md="8"> + <v-alert + v-if="needsSequence" + class="mb-6" + border="start" + :text="$t('validation.schema.primary-key')" + color="info" /> + </v-col> + </v-row> <v-row v-for="(c, idx) in columns" :key="`r-${idx}`" diff --git a/dbrepo-ui/components/view/ViewToolbar.vue b/dbrepo-ui/components/view/ViewToolbar.vue index bf415031b767d4688602d9aa3d0f3535c6f4f011..21125764983e9f7f79bf8dd6ec5f522a3bff7d49 100644 --- a/dbrepo-ui/components/view/ViewToolbar.vue +++ b/dbrepo-ui/components/view/ViewToolbar.vue @@ -1,44 +1,43 @@ <template> - <div v-if="view"> - <v-toolbar flat> - <v-btn - class="mr-2" - size="small" - icon="mdi-arrow-left" - :to="`/database/${$route.params.database_id}/view`" /> - <v-toolbar-title - :text="title" /> - <v-spacer /> - <v-btn - v-if="canDeleteView" - prepend-icon="mdi-delete" - class="mr-2" - variant="flat" - color="error" - :text="$vuetify.display.lgAndUp ? $t('navigation.delete') : ''" - :loading="loadingDelete" - @click="deleteView" /> - <v-btn - v-if="canCreatePid" - prepend-icon="mdi-content-save-outline" - variant="flat" - color="primary" - :text="($vuetify.display.lgAndUp ? $t('toolbars.view.pid.xl') + ' ' : '') + $t('toolbars.view.pid.permanent')" - :to="`/database/${$route.params.database_id}/view/${$route.params.view_id}/persist`" /> - <template v-slot:extension> - <v-tabs - v-model="tab" - color="primary"> - <v-tab - :text="$t('navigation.info')" - :to="`/database/${$route.params.database_id}/view/${$route.params.view_id}/info`" /> - <v-tab - :text="$t('navigation.data')" - :to="`/database/${$route.params.database_id}/view/${$route.params.view_id}/data`" /> - </v-tabs> - </template> - </v-toolbar> - </div> + <v-toolbar flat> + <v-btn + class="mr-2" + size="small" + icon="mdi-arrow-left" + :to="`/database/${$route.params.database_id}/view`" /> + <v-toolbar-title + v-if="view" + :text="title" /> + <v-spacer /> + <v-btn + v-if="canDeleteView" + prepend-icon="mdi-delete" + class="mr-2" + variant="flat" + color="error" + :text="$vuetify.display.lgAndUp ? $t('navigation.delete') : ''" + :loading="loadingDelete" + @click="deleteView" /> + <v-btn + v-if="canCreatePid" + prepend-icon="mdi-content-save-outline" + variant="flat" + color="primary" + :text="($vuetify.display.lgAndUp ? $t('toolbars.view.pid.xl') + ' ' : '') + $t('toolbars.view.pid.permanent')" + :to="`/database/${$route.params.database_id}/view/${$route.params.view_id}/persist`" /> + <template v-slot:extension> + <v-tabs + v-model="tab" + color="primary"> + <v-tab + :text="$t('navigation.info')" + :to="`/database/${$route.params.database_id}/view/${$route.params.view_id}/info`" /> + <v-tab + :text="$t('navigation.data')" + :to="`/database/${$route.params.database_id}/view/${$route.params.view_id}/data`" /> + </v-tabs> + </template> + </v-toolbar> </template> <script> @@ -123,12 +122,14 @@ export default { const viewService = useViewService() viewService.remove(this.$route.params.database_id, this.$route.params.view_id) .then(() => { - this.$toast.success(this.$t('success.view.delete')) + const toast = useToastInstance() + toast.success(this.$t('success.view.delete')) this.cacheStore.reloadDatabase() this.$router.push(`/database/${this.$route.params.database_id}/view`) }) - .catch((error) => { - this.$toast.error(this.$t(error.code)) + .catch(({code, message}) => { + const toast = useToastInstance() + toast.error(this.$t(code) + ": " + message) }) .finally(() => { this.loadingDelete = false diff --git a/dbrepo-ui/composables/database-service.ts b/dbrepo-ui/composables/database-service.ts index 6a4e283f8d9fb9d04b00c040bb7d769886ee3a70..3890477822cf58a5b0d375b4c45df87931039a52 100644 --- a/dbrepo-ui/composables/database-service.ts +++ b/dbrepo-ui/composables/database-service.ts @@ -60,7 +60,7 @@ export const useDatabaseService = (): any => { resolve(count); }) .catch((error) => { - console.error('Failed to find databases', error); + console.error('Failed to find databases count', error); reject(axiosErrorToApiError(error)); }); }); @@ -72,7 +72,7 @@ export const useDatabaseService = (): any => { return new Promise<Date>((resolve, reject) => { axios.head<Date>('/api/database') .then((response) => { - const date: Date = Date(response.headers['Date']) + const date: Date = new Date(response.headers['Date']) console.info(`Found ${date} server time`); resolve(date); }) @@ -85,7 +85,7 @@ export const useDatabaseService = (): any => { async function findOne(id: number): Promise<DatabaseDto | null> { const axios = useAxiosInstance(); - console.debug('find databases with id', id); + console.debug('find database with id', id); return new Promise((resolve, reject) => { axios.get<DatabaseDto>(`/api/database/${id}`) .then((response) => { @@ -93,7 +93,7 @@ export const useDatabaseService = (): any => { resolve(response.data); }) .catch((error) => { - console.error('Failed to find databases', error); + console.error('Failed to find database', error); reject(axiosErrorToApiError(error)); }); }); diff --git a/dbrepo-ui/composables/table-service.ts b/dbrepo-ui/composables/table-service.ts index 393c540f83739ec59ede4c8a6a9bb278f6fd25d4..96be0537d07b3990ab638acafc724442ae5f7735 100644 --- a/dbrepo-ui/composables/table-service.ts +++ b/dbrepo-ui/composables/table-service.ts @@ -69,6 +69,7 @@ export const useTableService = (): any => { async function getData(databaseId: number, tableId: number, page: number, size: number, timestamp: Date): Promise<QueryResultDto> { const axios = useAxiosInstance() + console.debug('====>', mapFilter(timestamp, page, size)) console.debug('get data for table with id', tableId, 'in database with id', databaseId); return new Promise<QueryResultDto>((resolve, reject) => { axios.get<QueryResultDto>(`/api/database/${databaseId}/table/${tableId}/data`, { params: mapFilter(timestamp, page, size), timeout: 30_000 }) @@ -191,7 +192,7 @@ export const useTableService = (): any => { const axios = useAxiosInstance() console.debug('suggest semantic entities for table column with id', columnId, 'of table with id', tableId, 'of database with id', databaseId) return new Promise<TableColumnEntityDto[]>((resolve, reject) => { - axios.get<TableColumnEntityDto[]>(`/api/semantic/database/${databaseId}/table/${tableId}/column/${columnId}`, {timeout: 10000}) + axios.get<TableColumnEntityDto[]>(`/api/database/${databaseId}/table/${tableId}/column/${columnId}/suggest`, {timeout: 10000}) .then((response) => { console.info('Suggested semantic entities for table column with id', columnId, 'of table with id', tableId, 'of database with id', databaseId) resolve(response.data) @@ -248,10 +249,10 @@ export const useTableService = (): any => { } function mapFilter(timestamp: Date | null, page: number | null, size: number | null) { - if (!timestamp) { + if (timestamp === null) { return {page, size} } - if (!page || !size) { + if (page === null || size === null) { return {timestamp} } return {timestamp, page, size} diff --git a/dbrepo-ui/composables/toast-instance.ts b/dbrepo-ui/composables/toast-instance.ts new file mode 100644 index 0000000000000000000000000000000000000000..bea71258e6dfcdc4b465800e7f56918bcc723aa5 --- /dev/null +++ b/dbrepo-ui/composables/toast-instance.ts @@ -0,0 +1,39 @@ +import {type ToastPluginApi, type ToastProps, useToast} from 'vue-toast-notification'; + +const props: ToastProps = { + position: 'top-right', + duration: 6000, + dismissible: false /* allow copy of error message */ +} + +export const useToastInstance = () => { + function error(message: string): void { + const toast: ToastPluginApi = useToast(props); + if (document) { + toast.error(message) + } + } + + function success(message: string): void { + const toast: ToastPluginApi = useToast(props); + if (document) { + toast.success(message) + } + } + + function info(message: string): void { + const toast: ToastPluginApi = useToast(props); + if (document) { + toast.info(message) + } + } + + function warning(message: string): void { + const toast: ToastPluginApi = useToast(props); + if (document) { + toast.warning(message) + } + } + + return {error, success, info, warning} +}; diff --git a/dbrepo-ui/locales/de-AT.json b/dbrepo-ui/locales/de-AT.json index 15c2664f0f67c97852d58596a27cd6084da2c659..263dbe62fc5ccdbd36d70a549bd8a433122c78ec 100644 --- a/dbrepo-ui/locales/de-AT.json +++ b/dbrepo-ui/locales/de-AT.json @@ -88,12 +88,12 @@ }, "publication-year": { "label": "Erscheinungsjahr", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "titles": { "title": { "label": "Titel", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "type": { "label": "Typ", @@ -116,15 +116,15 @@ "subtitle": "Haben Sie bereits einen DOI für diesen Datensatz?", "label": "Geben Sie hier Ihren bestehenden DOI an", "hint": "Ein DOI ermöglicht die einfache und eindeutige Zitierung Ihres Uploads. ", - "mint": "Nach dem Speichern wird ein PID erstellt." + "mint": "Nach dem Speichern wird ein PID erstellt" }, "doi": { - "mint": "Nach dem Speichern wird ein DOI erstellt." + "mint": "Nach dem Speichern wird ein DOI erstellt" }, "descriptions": { "description": { "label": "Beschreibung", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "type": { "label": "Typ", @@ -146,14 +146,14 @@ "title": "Veröffentlichungsinformationen", "subtitle": "Der Name der Entität, die die Ressource hält, archiviert, veröffentlicht, druckt, verteilt, freigibt, herausgibt oder produziert. ", "label": "Herausgeber", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "related-identifiers": { "title": "Verwandter Bezeichner", "subtitle": "Bezeichner verwandter Ressourcen. ", "identifier": { "label": "Kennung", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "type": { "label": "Typ", @@ -179,7 +179,7 @@ }, "language": { "title": "Sprache", - "subtitle": "Die primäre Sprache des Datensatzes.", + "subtitle": "Die primäre Sprache des Datensatzes", "language": { "label": "Sprache", "hint": "" @@ -187,14 +187,14 @@ }, "funders": { "title": "Finanzierungsreferenz", - "subtitle": "Informationen zur finanziellen Unterstützung (Finanzierung) für den zu registrierenden Datensatz.", + "subtitle": "Informationen zur finanziellen Unterstützung (Finanzierung) für den zu registrierenden Datensatz", "identifier": { "label": "Kennung des Geldgebers", - "hint": "Verwenden Sie eine Namenskennung, ausgedrückt als URL von ORCID*, ROR*, DOI*, ISNI, GND (Schemata mit * unterstützen den automatischen Metadatenabruf)." + "hint": "Verwenden Sie eine Namenskennung, ausgedrückt als URL von ORCID*, ROR*, DOI*, ISNI, GND (Schemata mit * unterstützen den automatischen Metadatenabruf)" }, "name": { "label": "Name des Geldgebers", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "award-number": { "label": "Auszeichnungsnummer", @@ -212,10 +212,10 @@ } }, "creators": { - "subtitle": "Die wichtigsten Forscher, die an der Erstellung der Daten beteiligt waren, in der Reihenfolge ihrer Priorität.", + "subtitle": "Die wichtigsten Forscher, die an der Erstellung der Daten beteiligt waren, in der Reihenfolge ihrer Priorität", "identifier": { "label": "Namensbezeichner", - "hint": "Verwenden Sie eine Namenskennung, ausgedrückt als URL von ORCID*, ROR*, DOI*, ISNI, GND (Schemata mit * unterstützen den automatischen Metadatenabruf)." + "hint": "Verwenden Sie eine Namenskennung, ausgedrückt als URL von ORCID*, ROR*, DOI*, ISNI, GND (Schemata mit * unterstützen den automatischen Metadatenabruf)" }, "insert": { "text": "Füge mich ein" @@ -239,11 +239,11 @@ }, "name": { "label": "Name", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "affiliation-identifier": { "label": "Zugehörigkeitskennung", - "hint": "Verwenden Sie eine Zugehörigkeitskennung, ausgedrückt als URL von ORCID*, ROR*, DOI*, ISNI, GND (Schemata mit * unterstützen den automatischen Metadatenabruf)." + "hint": "Verwenden Sie eine Zugehörigkeitskennung, ausgedrückt als URL von ORCID*, ROR*, DOI*, ISNI, GND (Schemata mit * unterstützen den automatischen Metadatenabruf)" }, "affiliation": { "label": "Zugehörigkeitsname", @@ -253,7 +253,7 @@ }, "summary": { "title": "Zusammenfassung", - "subtitle": "Details zur Kennung, die zur Identifizierung dieses Datensatzes erstellt wird.", + "subtitle": "Details zur Kennung, die zur Identifizierung dieses Datensatzes erstellt wird", "record": "Der Bezeichner beschreibt", "publisher": "Herausgeber", "license": "Lizenz", @@ -287,8 +287,8 @@ "secure": "sicher", "insecure": "unsicher", "permissions": { - "write": "Sie können in diese Tabelle schreiben.", - "read": "Sie können den gesamten Inhalt dieser Tabelle lesen." + "write": "Sie können in diese Tabelle schreiben", + "read": "Sie können den gesamten Inhalt dieser Tabelle lesen" } }, "protocol": { @@ -330,7 +330,7 @@ }, "generated": { "label": "Vorschau des Tabellennamens", - "hint": "Schreibgeschützt." + "hint": "Schreibgeschützt" }, "description": { "label": "Beschreibung", @@ -385,7 +385,7 @@ "summary": { "title": "Zusammenfassung", "prefix": "Importiert", - "suffix": "Zeilen aus dem Datensatz." + "suffix": "Zeilen aus dem Datensatz" }, "analyse": { "text": "Hochladen und analysieren" @@ -398,7 +398,7 @@ }, "name": { "label": "Tabellenname", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "description": { "label": "Tabellenbeschreibung", @@ -406,22 +406,23 @@ }, "summary": { "prefix": "Tabelle mit Namen erstellt", - "suffix": "und importierter Datensatz erfolgreich." + "suffix": "und importierter Datensatz erfolgreich" } }, "drop": { "title": "Tabelle Löschen", "warning": { "prefix": "Diese Aktion kann nicht rückgängig gemacht werden! ", - "suffix": "unten, wenn Sie es wirklich mit allen gespeicherten Daten löschen möchten." + "suffix": "unten, wenn Sie es wirklich mit allen gespeicherten Daten löschen möchten" }, "name": { "label": "Tabellenname", - "hint": "Erforderlich." + "hint": "Erforderlich" } }, "schema": { "title": "System Versioniert", + "subtitle": "Tabellenbeschränkungen", "bullet": "●", "assign": "Zuordnen", "remove": { @@ -453,14 +454,14 @@ }, "name": { "label": "Name", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "add": { "text": "Spalte hinzufügen" }, "type": { "label": "Typ", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "size": { "label": "Größe" @@ -496,23 +497,23 @@ }, "summary": { "title": "Zusammenfassung", - "text": "Tabelle mit internem Namen erfolgreich erstellt:" + "text": "Tabelle mit internem Namen erfolgreich erstellt" } }, "semantics": { - "title": "Semantische Instanz für Tabellenspalte zuweisen:", - "subtitle": "Semantische Instanzen helfen Maschinen dabei, den richtigen Kontext Ihres Datensatzes zu ermitteln.", + "title": "Semantische Instanz für Tabellenspalte zuweisen", + "subtitle": "Semantische Instanzen helfen Maschinen dabei, den richtigen Kontext Ihres Datensatzes zu ermitteln", "recommended": "Empfohlene semantische Instanzen", "bullet": "●", "info": "Die folgenden Ontologien fragen automatisch die Felder rdfs:label ab und speichern sie für diese Spalte. ", "uri": { "label": "Semantischer Instanz-URI", - "hint": "Dieser URI kann automatisch aufgelöst werden." + "hint": "Dieser URI kann automatisch aufgelöst werden" } }, "versioning": { "title": "Geschichte", - "subtitle": "Wählen Sie einen Zeitstempel aus, um die Daten für diese bestimmte Tageszeit anzuzeigen.", + "subtitle": "Wählen Sie einen Zeitstempel aus, um die Daten für diese bestimmte Tageszeit anzuzeigen", "chart": { "title": "Datenereignisse", "ylabel": "# Veranstaltungen", @@ -527,22 +528,22 @@ }, "data": { "auto": { - "hint": "Der Wert wird automatisch durch eine Sequenz generiert." + "hint": "Der Wert wird automatisch durch eine Sequenz generiert" }, "primary-key": { - "hint": "Der Wert ist ein Primärschlüssel." + "hint": "Der Wert ist ein Primärschlüssel" }, "format": { - "hint": "Der Wert muss folgendes Format haben:" + "hint": "Der Wert muss folgendes Format haben" }, "required": { "hint": "Erforderlich. " }, "float": { - "max": "max.", - "min": "Mindest.", - "before": "Ziffer(n) vor dem Punkt.", - "after": "Ziffer(n) nach dem Punkt." + "max": "max", + "min": "Mindest", + "before": "Ziffer(n) vor dem Punkt", + "after": "Ziffer(n) nach dem Punkt" } } } @@ -582,7 +583,7 @@ "subpages": { "access": { "title": "Datenbankzugriff", - "subtitle": "Übersicht über Benutzer mit ihrem Zugriff auf die Datenbank.", + "subtitle": "Übersicht über Benutzer mit ihrem Zugriff auf die Datenbank", "read": "Sie können alle Inhalte lesen", "write-own": "Sie können eigene Tabellen schreiben und alle Inhalte lesen", "write-all": "Sie können eigene Tabellen schreiben und alle Inhalte lesen", @@ -602,7 +603,7 @@ }, "create": { "title": "Datenbank erstellen", - "subtitle": "Wählen Sie einen aussagekräftigen Datenbanknamen und eine Datenbank-Engine.", + "subtitle": "Wählen Sie einen aussagekräftigen Datenbanknamen und eine Datenbank-Engine", "name": { "label": "Name", "hint": "Erforderlich. ", @@ -610,7 +611,7 @@ }, "engine": { "label": "Motor", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "submit": { "text": "Erstellen" @@ -636,7 +637,7 @@ }, "settings": { "title": "Einstellungen", - "subtitle": "Das Bild wird in einem Feld mit den maximalen Abmessungen 200x200 Pixel angezeigt.", + "subtitle": "Das Bild wird in einem Feld mit den maximalen Abmessungen 200x200 Pixel angezeigt", "image": { "label": "Teaser-Bild", "hint": "max. " @@ -649,16 +650,16 @@ }, "scheme": { "title": "Schema", - "subtitle": "Aktualisiert die Metadaten im Datenbankschema, um systemversionierte Tabellen und Ansichten in der Benutzeroberfläche anzuzeigen.", + "subtitle": "Aktualisiert die Metadaten im Datenbankschema, um systemversionierte Tabellen und Ansichten in der Benutzeroberfläche anzuzeigen", "submit": { "text": "Aktualisieren" } }, "ownership": { "title": "Eigentum", - "subtitle": "Benutzer, der Eigentümer dieser Datenbank ist.", + "subtitle": "Benutzer, der Eigentümer dieser Datenbank ist", "label": "Datenbankbesitzer", - "hint": "Erforderlich.", + "hint": "Erforderlich", "submit": { "text": "Überweisen" } @@ -668,7 +669,7 @@ "subtitle": "Private Datenbanken verbergen die Daten, während Metadaten weiterhin sichtbar sind. ", "visibility": { "label": "Datenbanksichtbarkeit", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "submit": { "text": "Ändern" @@ -681,19 +682,19 @@ "name": "Melden Sie sich an", "email": { "label": "E-Mail-Adresse", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "username": { "label": "Nutzername", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "password": { "label": "Passwort", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "confirm": { "label": "Bestätige das Passwort", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "submit": { "label": "Einreichen" @@ -703,11 +704,11 @@ "name": "Anmeldung", "username": { "label": "Nutzername", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "password": { "label": "Passwort", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "submit": { "label": "Einreichen" @@ -720,7 +721,7 @@ "subpages": { "info": { "title": "Information", - "subtitle": "Allgemeine Benutzermetadaten.", + "subtitle": "Allgemeine Benutzermetadaten", "id": { "label": "ID" }, @@ -754,7 +755,7 @@ }, "theme": { "title": "Theme", - "subtitle": "Aktualisieren Sie das Benutzerdesign, wenn Sie angemeldet sind.", + "subtitle": "Aktualisieren Sie das Benutzerdesign, wenn Sie angemeldet sind", "label": "Thema", "dark": "Dunkel", "dark-contrast": "Dunkel – hoher Kontrast", @@ -770,14 +771,14 @@ "subpages": { "authentication": { "title": "Benutzer-Passwort", - "subtitle": "Aktualisieren Sie das Benutzerkennwort, das für die Basisauthentifizierung bei allen Schnittstellen verwendet wird.", + "subtitle": "Aktualisieren Sie das Benutzerkennwort, das für die Basisauthentifizierung bei allen Schnittstellen verwendet wird", "password": { "label": "Passwort", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "confirm": { "label": "Bestätige das Passwort", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "submit": { "text": "Aktualisieren" @@ -786,7 +787,7 @@ "developer": { "token": { "title": "Token-Informationen", - "subtitle": "Sehen Sie sich Ihre Token-Geheimnisse zu Debugging-Zwecken an.", + "subtitle": "Sehen Sie sich Ihre Token-Geheimnisse zu Debugging-Zwecken an", "expiry": "Läuft ab", "access": { "label": "Zugangstoken" @@ -805,11 +806,11 @@ "title": "Wartungsmeldung", "type": { "label": "Typ", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "message": { "label": "Nachricht", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "start": { "label": "Zeitstempel starten" @@ -840,6 +841,9 @@ "info": "Info", "data": "Daten" }, + "name": { + "title": "Name" + }, "query": { "title": "Abfrage" }, @@ -857,19 +861,19 @@ "title": "Ansicht erstellen", "name": { "label": "Name", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "table": { "label": "Datentabelle", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "columns": { "label": "Datenspalten", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "visibility": { "label": "Datensichtbarkeit", - "warn": "Nur Personen mit mindestens Leserechten können die Daten einsehen.", + "warn": "Nur Personen mit mindestens Leserechten können die Daten einsehen", "hint": "Erforderlich. " } } @@ -887,7 +891,7 @@ "title": "Abfrage" }, "query-hash": { - "prefix": "sha256:", + "prefix": "sha256", "title": "Abfrage-Hash" }, "executed": { @@ -906,14 +910,14 @@ "subpages": { "create": { "title": "Teilmenge erstellen", - "generated": "Die folgende Abfrage wird ausgeführt (schreibgeschützt):", - "subtitle": "Die folgende Abfrage wird ausgeführt:", + "generated": "Die folgende Abfrage wird ausgeführt (schreibgeschützt)", + "subtitle": "Die folgende Abfrage wird ausgeführt", "simple": { "text": "Einfach" }, "expert": { "text": "Experte", - "warn": "Von der Verwendung von Kommentaren, Aggregationsfunktionen und den folgenden Vorgängen wird abgeraten:" + "warn": "Von der Verwendung von Kommentaren, Aggregationsfunktionen und den folgenden Vorgängen wird abgeraten" }, "name": { "label": "" @@ -922,15 +926,15 @@ "text": "Filter hinzufügen", "column": { "label": "Spalte", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "operator": { "label": "Operator", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "value": { "label": "Wert", - "hint": "Erforderlich." + "hint": "Erforderlich" }, "remove": { "text": "Entfernen" @@ -973,7 +977,7 @@ "hint": "" }, "publication-range": { - "hint": "Geben Sie Ihren benutzerdefinierten Veröffentlichungsjahrbereich an." + "hint": "Geben Sie Ihren benutzerdefinierten Veröffentlichungsjahrbereich an" }, "start-year": { "label": "Startjahr", @@ -984,7 +988,7 @@ "hint": "" }, "concept-unit": { - "hint": "Wenn Sie ein KONZEPT und eine EINHEIT auswählen, können Sie unabhängig von der Maßeinheit spaltenübergreifend suchen." + "hint": "Wenn Sie ein KONZEPT und eine EINHEIT auswählen, können Sie unabhängig von der Maßeinheit spaltenübergreifend suchen" }, "concept": { "label": "Konzept", @@ -1027,213 +1031,220 @@ }, "error": { "access": { - "missing": "Der Zugriff in der Metadatendatenbank konnte nicht gefunden werden." + "missing": "Der Zugriff in der Metadatendatenbank konnte nicht gefunden werden" }, "axios": { - "connection": "Es konnte keine Verbindung hergestellt werden.", - "timeout": "Zeitüberschreitung der Verbindung." + "connection": "Es konnte keine Verbindung hergestellt werden", + "timeout": "Zeitüberschreitung der Verbindung" }, "concept": { - "missing": "Das Konzept konnte in der Metadatendatenbank nicht gefunden werden." + "missing": "Das Konzept konnte in der Metadatendatenbank nicht gefunden werden" }, "container": { - "exists": "Der Container ist bereits in der Metadatendatenbank vorhanden.", - "missing": "Der Container konnte in der Metadatendatenbank nicht gefunden werden." + "exists": "Der Container ist bereits in der Metadatendatenbank vorhanden", + "missing": "Der Container konnte in der Metadatendatenbank nicht gefunden werden" }, "data": { - "invalid": "Die Kommunikation mit dem Datendienst ist fehlgeschlagen.", - "connection": "Es konnte keine Verbindung zum Datendienst hergestellt werden.", - "value": "Spaltenwert konnte nicht festgelegt werden:", - "drift": "Die Uhr Ihres Browsers ist nicht mit UTC synchronisiert und scheint um Folgendes eingestellt zu sein:" + "invalid": "Die Kommunikation mit dem Datendienst ist fehlgeschlagen", + "connection": "Es konnte keine Verbindung zum Datendienst hergestellt werden", + "value": "Spaltenwert konnte nicht festgelegt werden", + "drift": "Die Uhr Ihres Browsers ist nicht mit UTC synchronisiert und scheint um Folgendes eingestellt zu sein" }, "database": { - "connection": "Es konnte keine Verbindung zur Datenbank hergestellt werden.", - "invalid": "Aktion in der Datenbank konnte nicht ausgeführt werden.", + "connection": "Es konnte keine Verbindung zur Datenbank hergestellt werden", + "invalid": "Aktion in der Datenbank konnte nicht ausgeführt werden", "querystore": "Die Abfrage konnte nicht in den Abfragespeicher eingefügt werden", - "missing": "Die Datenbank konnte nicht in der Metadatendatenbank gefunden werden.", - "create": "Es konnte keine Verbindung zum Metadatendienst hergestellt werden." + "missing": "Die Datenbank konnte nicht in der Metadatendatenbank gefunden werden", + "create": "Es konnte keine Verbindung zum Metadatendienst hergestellt werden" }, "doi": { - "missing": "DOI konnte in der Metadatendatenbank nicht gefunden werden." + "missing": "DOI konnte in der Metadatendatenbank nicht gefunden werden" }, "exchange": { - "missing": "Im Broker-Service konnte keine Börse gefunden werden." + "missing": "Im Broker-Service konnte keine Börse gefunden werden" }, "semantic": { - "filter": "Die semantische Entität konnte im Metadatendienst nicht gefiltert werden.", - "missing": "Die semantische Entität konnte im Metadatendienst nicht gefunden werden." + "filter": "Die semantische Entität konnte im Metadatendienst nicht gefiltert werden", + "missing": "Die semantische Entität konnte im Metadatendienst nicht gefunden werden" }, "storage": { - "missing": "Datensatz im Speicherdienst konnte nicht gefunden werden.", - "invalid": "Es konnte keine Verbindung zum Speicherdienst hergestellt werden." + "missing": "Datensatz im Speicherdienst konnte nicht gefunden werden", + "invalid": "Es konnte keine Verbindung zum Speicherdienst hergestellt werden" }, "identifier": { - "format": "Die Kennung konnte im Metadatendienst nicht in das angeforderte Format umgewandelt werden.", - "missing": "Die Kennung konnte in der Metadatendatenbank nicht gefunden werden.", - "unsupported": "Es konnten keine Metadaten von einem nicht unterstützten Metadatenanbieter gefunden werden.", + "format": "Die Kennung konnte im Metadatendienst nicht in das angeforderte Format umgewandelt werden", + "missing": "Die Kennung konnte in der Metadatendatenbank nicht gefunden werden", + "unsupported": "Es konnten keine Metadaten von einem nicht unterstützten Metadatenanbieter gefunden werden", "form": "Bitte geben Sie im Formular alle erforderlichen Werte ein" }, "image": { - "exists": "Das Bild ist bereits in der Metadatendatenbank vorhanden.", - "missing": "Das Bild konnte nicht in der Metadatendatenbank gefunden werden.", - "invalid": "Bildmetadaten sind fehlerhaft." + "exists": "Das Bild ist bereits in der Metadatendatenbank vorhanden", + "missing": "Das Bild konnte nicht in der Metadatendatenbank gefunden werden", + "invalid": "Bildmetadaten sind fehlerhaft" }, "license": { - "missing": "Die Lizenz konnte in der Metadatendatenbank nicht gefunden werden." + "missing": "Die Lizenz konnte in der Metadatendatenbank nicht gefunden werden" }, "request": { - "invalid": "Die Anforderungsnutzlast wurde vom Metadatendienst abgelehnt.", - "forbidden": "Anfrage ist unzulässig, Rollen oder Authentifizierung fehlen.", - "pagination": "Die Anfrage enthält ungültige Paginierungsinformationen.", - "sort": "Die Anfrage enthält ungültige Sortierinformationen." + "invalid": "Die Anforderungsnutzlast wurde vom Metadatendienst abgelehnt", + "forbidden": "Anfrage ist unzulässig, Rollen oder Authentifizierung fehlen", + "pagination": "Die Anfrage enthält ungültige Paginierungsinformationen", + "sort": "Die Anfrage enthält ungültige Sortierinformationen" }, "message": { - "missing": "Die Nachricht konnte in der Metadatendatenbank nicht gefunden werden." + "missing": "Die Nachricht konnte in der Metadatendatenbank nicht gefunden werden" }, "ontology": { - "missing": "Die Ontologie konnte in der Metadatendatenbank nicht gefunden werden." + "missing": "Die Ontologie konnte in der Metadatendatenbank nicht gefunden werden" }, "orcid": { - "missing": "ORCID konnte im Metadatenanbieter nicht gefunden werden." + "missing": "ORCID konnte im Metadatenanbieter nicht gefunden werden" }, "query": { - "missing": "Die Abfrage konnte im Datendienst nicht gefunden werden.", - "invalid": "Die Abfrage ist ungültig (enthält beispielsweise verbotene Schlüsselwörter).", - "type.exists": "Abfrage konnte nicht erstellt werden: kein solcher Spaltentyp:", - "type.build": "Abfrage konnte nicht erstellt werden: Derzeit gibt es keine Abfrageerstellungsunterstützung für den Spaltentyp:", - "column.exists": "Abfrage konnte nicht erstellt werden: In den Datenspalten fehlt die Spalte mit dem Namen:" + "missing": "Die Abfrage konnte im Datendienst nicht gefunden werden", + "invalid": "Die Abfrage ist ungültig", + "type.exists": "Abfrage konnte nicht erstellt werden: kein solcher Spaltentyp", + "type.build": "Abfrage konnte nicht erstellt werden: Derzeit gibt es keine Abfrageerstellungsunterstützung für den Spaltentyp", + "column.exists": "Abfrage konnte nicht erstellt werden: In den Datenspalten fehlt die Spalte mit dem Namen" }, "store": { - "invalid": "Der Abfragespeicher in der Datenbank konnte nicht erstellt werden.", - "clean": "Der Abfragespeicher in der Datenbank konnte nicht durchsucht werden.", - "insert": "Die Abfrage konnte nicht in den Abfragespeicher der Datenbank eingefügt werden.", - "persist": "Die Abfrage konnte nicht im Abfragespeicher der Datenbank gespeichert werden." + "invalid": "Der Abfragespeicher in der Datenbank konnte nicht erstellt werden", + "clean": "Der Abfragespeicher in der Datenbank konnte nicht durchsucht werden", + "insert": "Die Abfrage konnte nicht in den Abfragespeicher der Datenbank eingefügt werden", + "persist": "Die Abfrage konnte nicht im Abfragespeicher der Datenbank gespeichert werden" }, "metadata": { - "privileged": "Das Abrufen privilegierter Metadaten im Datendienst ist fehlgeschlagen.", - "connection": "Es konnte keine Verbindung zum Metadatendienst hergestellt werden.", - "invalid": "Es konnten keine Authentifizierungsmetadaten im Datendienst abgerufen werden." + "privileged": "Das Abrufen privilegierter Metadaten im Datendienst ist fehlgeschlagen", + "connection": "Es konnte keine Verbindung zum Metadatendienst hergestellt werden", + "invalid": "Es konnten keine Authentifizierungsmetadaten im Datendienst abgerufen werden" }, "sidecar": { - "export": "Der Datensatz konnte nicht in den Datenbank-Sidecar exportiert werden.", - "import": "Der Datensatz konnte nicht aus dem Datenbank-Sidecar importiert werden." + "export": "Der Datensatz konnte nicht in den Datenbank-Sidecar exportiert werden", + "import": "Der Datensatz konnte nicht aus dem Datenbank-Sidecar importiert werden" }, "queue": { - "missing": "Die Warteschlange im Broker-Dienst konnte nicht gefunden werden." + "missing": "Die Warteschlange im Broker-Dienst konnte nicht gefunden werden" }, "ror": { - "missing": "ROR konnte im Metadatenanbieter nicht gefunden werden." + "missing": "ROR konnte im Metadatenanbieter nicht gefunden werden" }, "import": { - "dataset": "Der Datensatz konnte nicht importiert werden." + "dataset": "Der Datensatz konnte nicht importiert werden" }, "upload": { - "dataset": "Der Datensatz konnte nicht hochgeladen werden." + "dataset": "Der Datensatz konnte nicht hochgeladen werden" }, "schema": { - "id": "Die Spalte „id“ muss ein Primärschlüssel sein.", - "view": "Ansichtsschema konnte nicht zugeordnet werden.", - "table": "Tabellenschema konnte nicht zugeordnet werden." + "id": "Die Spalte „id“ muss ein Primärschlüssel sein", + "view": "Ansichtsschema konnte nicht zugeordnet werden", + "table": "Tabellenschema konnte nicht zugeordnet werden" }, "user": { - "exists": "Benutzer mit Benutzername ist in der Authentifizierungsdatenbank vorhanden.", - "missing": "Benutzer konnte in der Authentifizierungsdatenbank nicht gefunden werden.", - "credentials": "Ungültige Benutzername und Passwort Kombination.", - "email-exists": "Das Konto mit dieser E-Mail-Adresse existiert bereits.", - "setup": "Bitte ändern Sie Ihr Passwort." + "exists": "Benutzer mit Benutzername ist in der Authentifizierungsdatenbank vorhanden", + "missing": "Benutzer konnte in der Authentifizierungsdatenbank nicht gefunden werden", + "credentials": "Ungültige Benutzername und Passwort Kombination", + "email-exists": "Das Konto mit dieser E-Mail-Adresse existiert bereits", + "setup": "Bitte ändern Sie Ihr Passwort" }, "search": { - "connection": "Es konnte keine Verbindung zum Suchdienst hergestellt werden.", - "invalid": "Ungültige Suchanfrage." + "connection": "Es konnte keine Verbindung zum Suchdienst hergestellt werden", + "invalid": "Ungültige Suchanfrage" }, "semantics": { - "timeout": "Semantikvorschlag fehlgeschlagen: Zeitüberschreitung bei der Anfrage.", - "uri": "Der semantische URI ist fehlerhaft." + "timeout": "Semantikvorschlag fehlgeschlagen: Zeitüberschreitung bei der Anfrage", + "uri": "Der semantische URI ist fehlerhaft" }, "subset": { - "format": "Die Teilmenge konnte nicht dem angeforderten Format zugeordnet werden." + "format": "Die Teilmenge konnte nicht dem angeforderten Format zugeordnet werden" }, "pagination": { - "malformed": "Ungültige Paginierungsanforderung." + "malformed": "Ungültige Paginierungsanforderung" }, "table": { - "missing": "Die Tabelle konnte in der Metadatendatenbank nicht gefunden werden.", - "exists": "Die Tabelle mit diesem Namen existiert bereits.", - "invalid": "Die Spalten im Datendienst konnten nicht analysiert werden.", - "malformed": "Eintrag konnte nicht eingefügt werden:", - "create": "Tabelle konnte nicht erstellt werden:", - "connection": "Das Laden der Tabellendaten ist fehlgeschlagen, da die Datenbank nicht erreichbar ist." + "missing": "Die Tabelle konnte in der Metadatendatenbank nicht gefunden werden", + "exists": "Die Tabelle mit diesem Namen existiert bereits", + "invalid": "Die Spalten im Datendienst konnten nicht analysiert werden", + "malformed": "Eintrag konnte nicht eingefügt werden", + "create": "Tabelle konnte nicht erstellt werden", + "connection": "Das Laden der Tabellendaten ist fehlgeschlagen, da die Datenbank nicht erreichbar ist" }, "unit": { - "missing": "Die semantische Einheit konnte in der Metadatendatenbank nicht gefunden werden." + "missing": "Die semantische Einheit konnte in der Metadatendatenbank nicht gefunden werden" }, "view": { - "create": "Ansicht konnte nicht erstellt werden:", - "missing": "Die Ansicht konnte in der Metadatendatenbank nicht gefunden werden.", - "invalid": "Die Ansichtsabfrage konnte den Spalten im Datendienst nicht zugeordnet werden." + "create": "Ansicht konnte nicht erstellt werden", + "missing": "Die Ansicht konnte in der Metadatendatenbank nicht gefunden werden", + "invalid": "Die Ansichtsabfrage konnte den Spalten im Datendienst nicht zugeordnet werden" } }, "success": { - "signup": "Konto erfolgreich erstellt.", + "signup": "Konto erfolgreich erstellt", "clipboard": { - "user": "Benutzer-ID erfolgreich kopiert." + "user": "Benutzer-ID erfolgreich kopiert" }, "query": { "build": "Abfrage konnte nicht erstellt werden: Spalte nicht gefunden", "fatal": "Abfragen mit diesem Schema können derzeit nicht über die Benutzeroberfläche erstellt werden" }, "import": { - "dataset": "Datensatz erfolgreich importiert." + "dataset": "Datensatz erfolgreich importiert" }, "upload": { - "dataset": "Datensatz erfolgreich hochgeladen.", - "blob": "Datei erfolgreich hochgeladen." + "dataset": "Datensatz erfolgreich hochgeladen", + "blob": "Datei erfolgreich hochgeladen" }, "analyse": { - "dataset": "Datensatz erfolgreich analysiert." + "dataset": "Datensatz erfolgreich analysiert" }, "access": { - "created": "Zugriff erfolgreich bereitgestellt.", - "modified": "Zugriff erfolgreich geändert.", - "revoked": "Zugriff erfolgreich widerrufen." + "created": "Zugriff erfolgreich bereitgestellt", + "modified": "Zugriff erfolgreich geändert", + "revoked": "Zugriff erfolgreich widerrufen" }, "data": { - "add": "Dateneingabe erfolgreich hinzugefügt.", - "update": "Dateneingabe erfolgreich aktualisiert." + "add": "Dateneingabe erfolgreich hinzugefügt", + "update": "Dateneingabe erfolgreich aktualisiert" }, "table": { - "created": "Tabelle erfolgreich erstellt.", - "semantics": "Semantische Instanz erfolgreich zugewiesen." + "created": "Tabelle erfolgreich erstellt", + "semantics": "Semantische Instanz erfolgreich zugewiesen" + }, + "schema": { + "tables": "Die Metadaten der Datenbanktabellen wurden erfolgreich aktualisiert", + "views": "Metadaten der Datenbankansichten wurden erfolgreich aktualisiert" }, "schema": { "tables": "Die Metadaten der Datenbanktabellen wurden erfolgreich aktualisiert.", "views": "Metadaten der Datenbankansichten wurden erfolgreich aktualisiert." }, "database": { - "upload": "Datenbankbild erfolgreich hochgeladen.", - "transfer": "Der Datenbankeigentümer wurde erfolgreich übertragen.", + "upload": "Datenbankbild erfolgreich hochgeladen", + "transfer": "Der Datenbankeigentümer wurde erfolgreich übertragen", + "visibility": "Die Datenbanksichtbarkeit wurde erfolgreich aktualisiert", "image": { - "update": "Datenbankbild erfolgreich aktualisiert.", - "remove": "Datenbankbild erfolgreich entfernt." + "update": "Datenbankbild erfolgreich aktualisiert", + "remove": "Datenbankbild erfolgreich entfernt" } }, "pid": { - "saved": "Kennung erfolgreich gespeichert.", - "created": "Kennung erfolgreich erstellt.", - "published": "Identifikator erfolgreich veröffentlicht.", - "updated": "Kennung erfolgreich aktualisiert.", - "deleted": "Kennung erfolgreich gelöscht." + "saved": "Kennung erfolgreich gespeichert", + "created": "Kennung erfolgreich erstellt", + "published": "Identifikator erfolgreich veröffentlicht", + "updated": "Kennung erfolgreich aktualisiert", + "deleted": "Kennung erfolgreich gelöscht" }, "user": { - "info": "Benutzerinformationen erfolgreich aktualisiert.", - "theme": "Benutzerthema erfolgreich aktualisiert." + "info": "Benutzerinformationen erfolgreich aktualisiert", + "theme": "Benutzerthema erfolgreich aktualisiert", + "password": "Benutzerkennwort erfolgreich aktualisiert", + "login": "Erfolgreich angemeldet" }, "view": { - "create": "Ansicht erfolgreich erstellt.", - "delete": "Ansicht erfolgreich gelöscht." + "create": "Ansicht erfolgreich erstellt", + "delete": "Ansicht erfolgreich gelöscht" }, "subset": { - "create": "Teilmenge erfolgreich erstellt." + "create": "Teilmenge erfolgreich erstellt" } }, "toolbars": { @@ -1245,7 +1256,7 @@ "semantic": { "register": { "title": "Registrieren Sie die Ontologie", - "subtitle": "Registrieren Sie einen neuen Ontologie-Endpunkt." + "subtitle": "Registrieren Sie einen neuen Ontologie-Endpunkt" }, "ontologies": { "title": "Ontologien", @@ -1263,6 +1274,7 @@ "public": "Öffentlich", "private": "Privat", "current": "Aktuelle Daten", + "history": "Historische Daten", "create": { "text": "Datenbank" }, @@ -1326,7 +1338,7 @@ }, "search": { "fuzzy": { - "placeholder": "Suchen ..." + "placeholder": "Suchen .." }, "result": "Ergebnis", "results": "Ergebnisse" @@ -1368,7 +1380,7 @@ "tuple": "Eintrag", "download": "Herunterladen", "version": "Geschichte", - "subtitle": "Stellen Sie Daten bereit, die direkt in den Datensatz eingefügt werden sollen." + "subtitle": "Stellen Sie Daten bereit, die direkt in den Datensatz eingefügt werden sollen" } } }, @@ -1383,7 +1395,7 @@ "month": "Ungültiger Monat", "schema": { "id": "Die Spalte muss als Primärschlüssel deklariert werden", - "primary-key": "Wir erstellen eine Spalte mit dem Namen „id“ mit einer automatisch ansteigenden Sequenz, die bei 1 beginnt. Bitte geben Sie eine Spalte mit Primärschlüssel an, wenn Sie dieses Verhalten nicht wünschen." + "primary-key": "Wir erstellen eine Spalte mit dem Namen „id“ mit einer automatisch ansteigenden Sequenz, die bei 1 beginnt. Bitte geben Sie eine Spalte mit Primärschlüssel an, wenn Sie dieses Verhalten nicht wünschen" }, "uri": { "pattern": "Ungültiger URI", diff --git a/dbrepo-ui/locales/en-US.json b/dbrepo-ui/locales/en-US.json index 227ae506c244552c0139582bba97f58cdce60188..a14d7292831b1f2e81009be3d39f9051b99c6b8d 100644 --- a/dbrepo-ui/locales/en-US.json +++ b/dbrepo-ui/locales/en-US.json @@ -88,12 +88,12 @@ }, "publication-year": { "label": "Publication Year", - "hint": "Required." + "hint": "Required" }, "titles": { "title": { "label": "Title", - "hint": "Required." + "hint": "Required" }, "type": { "label": "Type", @@ -103,7 +103,7 @@ "label": "Language", "hint": "" }, - "subtitle": "A name or title by which a resource is known. May be the title of a dataset.", + "subtitle": "A name or title by which a resource is known. May be the title of a dataset", "remove": { "text": "Remove" }, @@ -116,15 +116,15 @@ "subtitle": "Do you already have a DOI for this dataset?", "label": "Provide your existing DOI here", "hint": "A DOI allows your upload to be easily and unambiguously cited. Example: 10.1234/foo.bar", - "mint": "A PID will be minted after saving." + "mint": "A PID will be minted after saving" }, "doi": { - "mint": "A DOI will be created after saving." + "mint": "A DOI will be created after saving" }, "descriptions": { "description": { "label": "Description", - "hint": "Required." + "hint": "Required" }, "type": { "label": "Type", @@ -134,7 +134,7 @@ "label": "Language", "hint": "" }, - "subtitle": "All additional information. May be used for technical information or detailed information associated with a dataset.", + "subtitle": "All additional information. May be used for technical information or detailed information associated with a dataset", "remove": { "text": "Remove" }, @@ -144,16 +144,16 @@ }, "publisher": { "title": "Publication Information", - "subtitle": "The name of the entity that holds, archives, publishes, prints, distributes, releases, issues, or produces the resource. This property will be used to formulate the citation, so consider the prominence of the role.", + "subtitle": "The name of the entity that holds, archives, publishes, prints, distributes, releases, issues, or produces the resource. This property will be used to formulate the citation, so consider the prominence of the role", "label": "Publisher", - "hint": "Required." + "hint": "Required" }, "related-identifiers": { "title": "Related Identifier", - "subtitle": "Identifiers of related resources. These must be globally unique identifiers.", + "subtitle": "Identifiers of related resources. These must be globally unique identifiers", "identifier": { "label": "Identifier", - "hint": "Required." + "hint": "Required" }, "type": { "label": "Type", @@ -172,14 +172,14 @@ }, "licenses": { "title": "License", - "subtitle": "Identifiers of related resources. These must be globally unique identifiers.", + "subtitle": "Identifiers of related resources. These must be globally unique identifiers", "license": { "label": "License" } }, "language": { "title": "Language", - "subtitle": "The primary language of the dataset.", + "subtitle": "The primary language of the dataset", "language": { "label": "Language", "hint": "" @@ -187,14 +187,14 @@ }, "funders": { "title": "Funding Reference", - "subtitle": "Information about financial support (funding) for the dataset being registered.", + "subtitle": "Information about financial support (funding) for the dataset being registered", "identifier": { "label": "Funder Identifier", "hint": "Use a name identifier expressed as URL from ORCID*, ROR*, DOI*, ISNI, GND (schemes with * support automatic metadata retrieval)" }, "name": { "label": "Funder Name", - "hint": "Required." + "hint": "Required" }, "award-number": { "label": "Award Number", @@ -212,7 +212,7 @@ } }, "creators": { - "subtitle": "The main researchers involved in producing the data, in priority order.", + "subtitle": "The main researchers involved in producing the data, in priority order", "identifier": { "label": "Name Identifier", "hint": "Use a name identifier expressed as URL from ORCID*, ROR*, DOI*, ISNI, GND (schemes with * support automatic metadata retrieval)" @@ -239,7 +239,7 @@ }, "name": { "label": "Name", - "hint": "Required." + "hint": "Required" }, "affiliation-identifier": { "label": "Affiliation Identifier", @@ -253,7 +253,7 @@ }, "summary": { "title": "Summary", - "subtitle": "Details of the identifier that will be created to identify this record.", + "subtitle": "Details of the identifier that will be created to identify this record", "record": "The identifier describes", "publisher": "Publisher", "license": "License", @@ -287,8 +287,8 @@ "secure": "secure", "insecure": "insecure", "permissions": { - "write": "You can write to this table.", - "read": "You can read all contents of this table." + "write": "You can write to this table", + "read": "You can read all contents of this table" } }, "protocol": { @@ -322,32 +322,32 @@ }, "dataset": { "title": "Dataset Structure", - "warn": "The dataset schema does not match the target table schema. You can still force the import but it is not recommended." + "warn": "The dataset schema does not match the target table schema. You can still force the import but it is not recommended" }, "name": { "label": "Name", - "hint": "Required. Maximum length is 64 characters." + "hint": "Required. Maximum length is 64 characters" }, "generated": { "label": "Preview Table Name", - "hint": "Readonly." + "hint": "Readonly" }, "description": { "label": "Description", - "hint": "Optional. Short and concise description of the data." + "hint": "Optional. Short and concise description of the data" }, "separator": { "label": "Column Separator", - "hint": "Optional. Character that separates the columns.", + "hint": "Optional. Character that separates the columns", "warn": { "prefix": "We analysed your .csv/.tsv dataset and found that the separator you provided", "middle": "is not correct, the separator", - "suffix": "is more likely to be correct. It is advised to change the separator above." + "suffix": "is more likely to be correct. It is advised to change the separator above" } }, "skip": { "label": "Skip Rows", - "hint": "Optional. Number of rows to skip, e.g. when the first one contains header and no data." + "hint": "Optional. Number of rows to skip, e.g. when the first one contains header and no data" }, "quote": { "label": "Quote Encoding", @@ -355,11 +355,11 @@ }, "terminator": { "label": "Line Termination Encoding", - "hint": "Optional. Character that terminates the newlines.", + "hint": "Optional. Character that terminates the newlines", "warn": { "prefix": "We analysed your .csv/.tsv dataset and found that the line termination encoding you provided", "middle": "is not correct, the line termination encoding", - "suffix": "is more likely to be correct. It is advised to change the line termination encoding above." + "suffix": "is more likely to be correct. It is advised to change the line termination encoding above" } }, "null": { @@ -368,16 +368,16 @@ }, "true": { "label": "True Encoding", - "hint": "Optional. Character sequence that represents boolean true, e.g. 1, true, yes." + "hint": "Optional. Character sequence that represents boolean true, e.g. 1, true, yes" }, "false": { "label": "False Encoding", - "hint": "Optional. Character sequence that represents boolean false, e.g. 0, false, no." + "hint": "Optional. Character sequence that represents boolean false, e.g. 0, false, no" }, "file": { "title": "Dataset Upload", "label": "Dataset File", - "hint": "Required. Needs to be in .csv/.tsv file format." + "hint": "Required. Needs to be in .csv/.tsv file format" }, "preview": { "title": "Preview" @@ -385,7 +385,7 @@ "summary": { "title": "Summary", "prefix": "Imported", - "suffix": "rows from dataset." + "suffix": "rows from dataset" }, "analyse": { "text": "Upload & Analyse" @@ -398,7 +398,7 @@ }, "name": { "label": "Table Name", - "hint": "Required." + "hint": "Required" }, "description": { "label": "Table Description", @@ -406,22 +406,23 @@ }, "summary": { "prefix": "Created table with name", - "suffix": "and imported dataset successfully." + "suffix": "and imported dataset successfully" } }, "drop": { "title": "Drop table", "warning": { "prefix": "This action cannot be undone! Type the table name", - "suffix": "below if you really want to drop it with all stored data." + "suffix": "below if you really want to drop it with all stored data" }, "name": { "label": "Table Name", - "hint": "Required." + "hint": "Required" } }, "schema": { "title": "System Versioned", + "subtitle": "Table Constraints", "bullet": "●", "assign": "Assign", "remove": { @@ -453,14 +454,14 @@ }, "name": { "label": "Name", - "hint": "Required." + "hint": "Required" }, "add": { "text": "Add Column" }, "type": { "label": "Type", - "hint": "Required." + "hint": "Required" }, "size": { "label": "Size" @@ -496,23 +497,23 @@ }, "summary": { "title": "Summary", - "text": "Successfully created table with internal name:" + "text": "Successfully created table with internal name" } }, "semantics": { - "title": "Assign semantic instance for table column:", - "subtitle": "Semantic instances help machines to get the proper context of your dataset.", + "title": "Assign semantic instance for table column", + "subtitle": "Semantic instances help machines to get the proper context of your dataset", "recommended": "Recommended semantic instances", "bullet": "●", - "info": "The following ontologies automatically will query the fields rdfs:label and store it for this column. You can still use other URIs that are not matching these ontologies, the URI will be displayed instead.", + "info": "The following ontologies automatically will query the fields rdfs:label and store it for this column. You can still use other URIs that are not matching these ontologies, the URI will be displayed instead", "uri": { "label": "Semantic Instance URI", - "hint": "This URI can be automatically resolved." + "hint": "This URI can be automatically resolved" } }, "versioning": { "title": "History", - "subtitle": "Select a timestamp to view the data for this specific time of day.", + "subtitle": "Select a timestamp to view the data for this specific time of day", "chart": { "title": "Data Events", "ylabel": "# Events", @@ -527,22 +528,22 @@ }, "data": { "auto": { - "hint": "Value is automatically generated by a sequence." + "hint": "Value is automatically generated by a sequence" }, "primary-key": { - "hint": "Value is a primary key." + "hint": "Value is a primary key" }, "format": { - "hint": "Value must be in format:" + "hint": "Value must be in format" }, "required": { "hint": "Required. " }, "float": { - "max": "max.", - "min": "min.", - "before": "digit(s) before the dot.", - "after": "digit(s) after the dot." + "max": "max", + "min": "min", + "before": "digit(s) before the dot", + "after": "digit(s) after the dot" } } } @@ -582,7 +583,7 @@ "subpages": { "access": { "title": "Database Access", - "subtitle": "Overview on users with their access to the database.", + "subtitle": "Overview on users with their access to the database", "read": "You can read all contents", "write-own": "You can write own tables and read all contents", "write-all": "You can write own tables and read all contents", @@ -602,7 +603,7 @@ }, "create": { "title": "Create Database", - "subtitle": "Choose an expressive database name and select a database engine.", + "subtitle": "Choose an expressive database name and select a database engine", "name": { "label": "Name", "hint": "Required. The internal database name will be lowercase alphanumeric, others will be replaced with _", @@ -610,7 +611,7 @@ }, "engine": { "label": "Engine", - "hint": "Required." + "hint": "Required" }, "submit": { "text": "Create" @@ -636,7 +637,7 @@ }, "settings": { "title": "Settings", - "subtitle": "The image will be displayed in a box with maximum dimensions 200x200 pixels.", + "subtitle": "The image will be displayed in a box with maximum dimensions 200x200 pixels", "image": { "label": "Teaser Image", "hint": "max. 1MB file size" @@ -649,26 +650,26 @@ }, "scheme": { "title": "Schema", - "subtitle": "Update the metadata on the database schema to display system-versioned tables and views in the UI.", + "subtitle": "Update the metadata on the database schema to display system-versioned tables and views in the UI", "submit": { "text": "Refresh" } }, "ownership": { "title": "Ownership", - "subtitle": "User who has ownership over this database.", + "subtitle": "User who has ownership over this database", "label": "Database Owner", - "hint": "Required.", + "hint": "Required", "submit": { "text": "Transfer" } }, "visibility": { "title": "Visibility", - "subtitle": "Private databases hide the data while metadata is still visible. Public databases are fully transparent.", + "subtitle": "Private databases hide the data while metadata is still visible. Public databases are fully transparent", "visibility": { "label": "Database Visibility", - "hint": "Required." + "hint": "Required" }, "submit": { "text": "Modify" @@ -681,19 +682,19 @@ "name": "Signup", "email": { "label": "E-Mail Address", - "hint": "Required." + "hint": "Required" }, "username": { "label": "Username", - "hint": "Required." + "hint": "Required" }, "password": { "label": "Password", - "hint": "Required." + "hint": "Required" }, "confirm": { "label": "Confirm Password", - "hint": "Required." + "hint": "Required" }, "submit": { "label": "Submit" @@ -703,11 +704,11 @@ "name": "Login", "username": { "label": "Username", - "hint": "Required." + "hint": "Required" }, "password": { "label": "Password", - "hint": "Required." + "hint": "Required" }, "submit": { "label": "Submit" @@ -720,7 +721,7 @@ "subpages": { "info": { "title": "Information", - "subtitle": "General user metadata.", + "subtitle": "General user metadata", "id": { "label": "ID" }, @@ -754,7 +755,7 @@ }, "theme": { "title": "Theme", - "subtitle": "Update the user theme when logged in.", + "subtitle": "Update the user theme when logged in", "label": "Theme", "dark": "Dark", "dark-contrast": "Dark - High Contrast", @@ -770,14 +771,14 @@ "subpages": { "authentication": { "title": "User Password", - "subtitle": "Update the user password used for basic authentication with all interfaces.", + "subtitle": "Update the user password used for basic authentication with all interfaces", "password": { "label": "Password", - "hint": "Required." + "hint": "Required" }, "confirm": { "label": "Confirm Password", - "hint": "Required." + "hint": "Required" }, "submit": { "text": "Update" @@ -786,7 +787,7 @@ "developer": { "token": { "title": "Token Information", - "subtitle": "View your token secrets for debugging purposes.", + "subtitle": "View your token secrets for debugging purposes", "expiry": "Expires", "access": { "label": "Access Token" @@ -805,11 +806,11 @@ "title": "Maintenance Message", "type": { "label": "Type", - "hint": "Required." + "hint": "Required" }, "message": { "label": "Message", - "hint": "Required." + "hint": "Required" }, "start": { "label": "Start Timestamp" @@ -840,8 +841,11 @@ "info": "Info", "data": "Data" }, + "name": { + "title": "Name" + }, "query": { - "title": "Query" + "title": "Statement" }, "creator": { "title": "Creator" @@ -857,20 +861,20 @@ "title": "Create View", "name": { "label": "Name", - "hint": "Required." + "hint": "Required" }, "table": { "label": "Data Table", - "hint": "Required." + "hint": "Required" }, "columns": { "label": "Data Columns", - "hint": "Required." + "hint": "Required" }, "visibility": { "label": "Data Visibility", - "warn": "Only people with at least read access can view the data.", - "hint": "Required. When private, the view metadata will still be public but the data will only be visible to people with at least read access to this database." + "warn": "Only people with at least read access can view the data", + "hint": "Required. When private, the view metadata will still be public but the data will only be visible to people with at least read access to this database" } } } @@ -887,7 +891,7 @@ "title": "Query" }, "query-hash": { - "prefix": "sha256:", + "prefix": "sha256", "title": "Query Hash" }, "executed": { @@ -906,14 +910,14 @@ "subpages": { "create": { "title": "Create Subset", - "generated": "The following query will be executed (readonly):", - "subtitle": "The following query will be executed:", + "generated": "The following query will be executed (readonly)", + "subtitle": "The following query will be executed", "simple": { "text": "Simple" }, "expert": { "text": "Expert", - "warn": "It is not recommended to use comments, aggregation functions and the following operations:" + "warn": "It is not recommended to use comments, aggregation functions and the following operations" }, "name": { "label": "" @@ -922,15 +926,15 @@ "text": "Add Filter", "column": { "label": "Column", - "hint": "Required." + "hint": "Required" }, "operator": { "label": "Operator", - "hint": "Required." + "hint": "Required" }, "value": { "label": "Value", - "hint": "Required." + "hint": "Required" }, "remove": { "text": "Remove" @@ -973,7 +977,7 @@ "hint": "" }, "publication-range": { - "hint": "Specify your custom publication year range." + "hint": "Specify your custom publication year range" }, "start-year": { "label": "Start Year", @@ -984,7 +988,7 @@ "hint": "" }, "concept-unit": { - "hint": "If you select a CONCEPT and UNIT, you can search across columns regardless of their unit of measurement." + "hint": "If you select a CONCEPT and UNIT, you can search across columns regardless of their unit of measurement" }, "concept": { "label": "Concept", @@ -1027,213 +1031,220 @@ }, "error": { "access": { - "missing": "Failed to find access in metadata database." + "missing": "Failed to find access in metadata database" }, "axios": { - "connection": "Failed to establish connection.", - "timeout": "Connection timed out." + "connection": "Failed to establish connection", + "timeout": "Connection timed out" }, "concept": { - "missing": "Failed to find concept in metadata database." + "missing": "Failed to find concept in metadata database" }, "container": { - "exists": "Container already exists in metadata database.", - "missing": "Failed to find container in metadata database." + "exists": "Container already exists in metadata database", + "missing": "Failed to find container in metadata database" }, "data": { - "invalid": "Failed to communicate with data service.", - "connection": "Failed to establish connection to data service.", - "value": "Failed to set column value:", - "drift": "Your browser clock is not synchronized with UTC and seems to be off by:" + "invalid": "Failed to communicate with data service", + "connection": "Failed to establish connection to data service", + "value": "Failed to set column value", + "drift": "Your browser clock is not synchronized with UTC and seems to be off by" }, "database": { - "connection": "Failed to establis connection to the database.", - "invalid": "Failed to perform action in database.", + "connection": "Failed to establis connection to the database", + "invalid": "Failed to perform action in database", "querystore": "Failed to insert query into query store", - "missing": "Failed to find database in metadata database.", - "create": "Failed to establish connection with metadata service." + "missing": "Failed to find database in metadata database", + "create": "Failed to establish connection with metadata service" }, "doi": { - "missing": "Failed to find DOI in metadata database." + "missing": "Failed to find DOI in metadata database" }, "exchange": { - "missing": "Failed to find exchange in broker service." + "missing": "Failed to find exchange in broker service" }, "semantic": { - "filter": "Failed to filter semantic entity in metadata service.", - "missing": "Failed to find semantic entity in metadata service." + "filter": "Failed to filter semantic entity in metadata service", + "missing": "Failed to find semantic entity in metadata service" }, "storage": { - "missing": "Failed to find dataset in storage service.", - "invalid": "Failed to establish connection with storage service." + "missing": "Failed to find dataset in storage service", + "invalid": "Failed to establish connection with storage service" }, "identifier": { - "format": "Failed to transform identifier into the requested format in metadata service.", - "missing": "Failed to find identifier in metadata database.", - "unsupported": "Failed to find metadata from unsupported metadata provider.", + "format": "Failed to transform identifier into the requested format in metadata service", + "missing": "Failed to find identifier in metadata database", + "unsupported": "Failed to find metadata from unsupported metadata provider", "form": "Please provide all required values in the form" }, "image": { - "exists": "Image already exists in metadata database.", - "missing": "Failed to find image in metadata database.", - "invalid": "Image metadata is malformed." + "exists": "Image already exists in metadata database", + "missing": "Failed to find image in metadata database", + "invalid": "Image metadata is malformed" }, "license": { - "missing": "Failed to find license in metadata database." + "missing": "Failed to find license in metadata database" }, "request": { - "invalid": "Request payload was rejected by the metadata service.", - "forbidden": "Request is forbidden, roles or authentication missing.", - "pagination": "Request contains invalid pagination information.", - "sort": "Request contains invalid sort information." + "invalid": "Request payload was rejected by the metadata service", + "forbidden": "Request is forbidden, roles or authentication missing", + "pagination": "Request contains invalid pagination information", + "sort": "Request contains invalid sort information" }, "message": { - "missing": "Failed to find message in metadata database." + "missing": "Failed to find message in metadata database" }, "ontology": { - "missing": "Failed to find ontology in metadata database." + "missing": "Failed to find ontology in metadata database" }, "orcid": { - "missing": "Failed to find ORCID in metadata provider." + "missing": "Failed to find ORCID in metadata provider" }, "query": { - "missing": "Failed to find query in data service.", - "invalid": "Query is invalid (e.g. contains forbidden keywords).", - "type.exists": "Failed to build query: no such column type:", - "type.build": "Failed to build query: currently no query build support for column type:", - "column.exists": "Failed to build query: data columns are missing column with name:" + "missing": "Failed to find query in data service", + "invalid": "Query is invalid", + "type.exists": "Failed to build query: no such column type", + "type.build": "Failed to build query: currently no query build support for column type", + "column.exists": "Failed to build query: data columns are missing column with name" }, "store": { - "invalid": "Failed to create query store in the database.", - "clean": "Failed to sweep query store in the database.", - "insert": "Failed to insert query into database query store.", - "persist": "Failed to persist query in the database query store." + "invalid": "Failed to create query store in the database", + "clean": "Failed to sweep query store in the database", + "insert": "Failed to insert query into database query store", + "persist": "Failed to persist query in the database query store" }, "metadata": { - "privileged": "Failed to fetch privileged metadata in the data service.", - "connection": "Failed to establish connection to the metadata service.", - "invalid": "Failed to obtain authentication metadata in the data service." + "privileged": "Failed to fetch privileged metadata in the data service", + "connection": "Failed to establish connection to the metadata service", + "invalid": "Failed to obtain authentication metadata in the data service" }, "sidecar": { - "export": "Failed to export dataset to the database sidecar.", - "import": "Failed to import dataset from the database sidecar." + "export": "Failed to export dataset to the database sidecar", + "import": "Failed to import dataset from the database sidecar" }, "queue": { - "missing": "Failed to find queue in broker service." + "missing": "Failed to find queue in broker service" }, "ror": { - "missing": "Failed to find ROR in metadata provider." + "missing": "Failed to find ROR in metadata provider" }, "import": { - "dataset": "Failed to import dataset." + "dataset": "Failed to import dataset" }, "upload": { - "dataset": "Failed to upload dataset." + "dataset": "Failed to upload dataset" }, "schema": { - "id": "Column \"id\" must be a primary key.", - "view": "Failed to map view schema.", - "table": "Failed to map table schema." + "id": "Column \"id\" must be a primary key", + "view": "Failed to map view schema", + "table": "Failed to map table schema" }, "user": { - "exists": "User with username exists in auth database.", - "missing": "Failed to find user in auth database.", - "credentials": "Invalid username/password combination.", - "email-exists": "Account with this e-mail exists already.", - "setup": "Please change your password." + "exists": "User with username exists in auth database", + "missing": "Failed to find user in auth database", + "credentials": "Invalid username/password combination", + "email-exists": "Account with this e-mail exists already", + "setup": "Please change your password" }, "search": { - "connection": "Failed to establish connection to the search service.", - "invalid": "Malformed search request." + "connection": "Failed to establish connection to the search service", + "invalid": "Malformed search request" }, "semantics": { - "timeout": "Failed to suggest semantics: request timed out.", - "uri": "Semantic URI is malformed." + "timeout": "Failed to suggest semantics: request timed out", + "uri": "Semantic URI is malformed" }, "subset": { - "format": "Failed to map subset into requested format." + "format": "Failed to map subset into requested format" }, "pagination": { - "malformed": "Invalid pagination request." + "malformed": "Invalid pagination request" }, "table": { - "missing": "Failed to find table in metadata database.", - "exists": "Table with this name exists already.", - "invalid": "Failed to parse columns in the data service.", - "malformed": "Failed to insert entry:", - "create": "Failed to create table:", - "connection": "Failed to load table data because database is not reachable." + "missing": "Failed to find table in metadata database", + "exists": "Table with this name exists already", + "invalid": "Failed to parse columns in the data service", + "malformed": "Failed to insert entry", + "create": "Failed to create table", + "connection": "Failed to load table data because database is not reachable" }, "unit": { - "missing": "Failed to find semantic unit in metadata database." + "missing": "Failed to find semantic unit in metadata database" }, "view": { - "create": "Failed to create view:", - "missing": "Failed to find view in metadata database.", - "invalid": "Failed to map view query to columns in data service." + "create": "Failed to create view", + "missing": "Failed to find view in metadata database", + "invalid": "Failed to map view query to columns in data service" } }, "success": { - "signup": "Successfully created account.", + "signup": "Successfully created account", "clipboard": { - "user": "Successfully copied user id." + "user": "Successfully copied user id" }, "query": { "build": "Failed to build query: column not found", "fatal": "Query with this schema is not buildable through the UI at the moment" }, "import": { - "dataset": "Successfully imported dataset." + "dataset": "Successfully imported dataset" }, "upload": { - "dataset": "Successfully uploaded dataset.", - "blob": "Successfully uploaded file." + "dataset": "Successfully uploaded dataset", + "blob": "Successfully uploaded file" }, "analyse": { - "dataset": "Successfully analysed dataset." + "dataset": "Successfully analysed dataset" }, "access": { - "created": "Successfully provisioned access.", - "modified": "Successfully modified access.", - "revoked": "Successfully revoked access." + "created": "Successfully provisioned access", + "modified": "Successfully modified access", + "revoked": "Successfully revoked access" }, "data": { - "add": "Successfully added data entry.", - "update": "Successfully updated data entry." + "add": "Successfully added data entry", + "update": "Successfully updated data entry" }, "table": { - "created": "Successfully created table.", - "semantics": "Successfully assigned semantic instance." + "created": "Successfully created table", + "semantics": "Successfully assigned semantic instance" + }, + "schema": { + "tables": "Successfully refreshed database tables metadata", + "views": "Successfully refreshed database views metadata" }, "schema": { "tables": "Successfully refreshed database tables metadata.", "views": "Successfully refreshed database views metadata." }, "database": { - "upload": "Successfully uploaded database image.", - "transfer": "Successfully transferred the database owner.", + "upload": "Successfully uploaded database image", + "transfer": "Successfully transferred the database owner", + "visibility": "Successfully updated the database visibility", "image": { - "update": "Successfully updated database image.", - "remove": "Successfully removed database image." + "update": "Successfully updated database image", + "remove": "Successfully removed database image" } }, "pid": { - "saved": "Successfully saved identifier.", - "created": "Successfully created identifier.", - "published": "Successfully published identifier.", - "updated": "Successfully updated identifier.", - "deleted": "Successfully deleted identifier." + "saved": "Successfully saved identifier", + "created": "Successfully created identifier", + "published": "Successfully published identifier", + "updated": "Successfully updated identifier", + "deleted": "Successfully deleted identifier" }, "user": { - "info": "Successfully updated user information.", - "theme": "Successfully updated user theme." + "info": "Successfully updated user information", + "theme": "Successfully updated user theme", + "password": "Successfully updated user password", + "login": "Successfully logged in" }, "view": { - "create": "Successfully created view.", - "delete": "Successfully deleted view." + "create": "Successfully created view", + "delete": "Successfully deleted view" }, "subset": { - "create": "Successfully created subset." + "create": "Successfully created subset" } }, "toolbars": { @@ -1245,7 +1256,7 @@ "semantic": { "register": { "title": "Register Ontology", - "subtitle": "Register a new ontology endpoint." + "subtitle": "Register a new ontology endpoint" }, "ontologies": { "title": "Ontologies", @@ -1263,6 +1274,7 @@ "public": "Public", "private": "Private", "current": "Current Data", + "history": "Historic Data", "create": { "text": "Database" }, @@ -1326,7 +1338,7 @@ }, "search": { "fuzzy": { - "placeholder": "Search ..." + "placeholder": "Search .." }, "result": "Result", "results": "Results" @@ -1368,7 +1380,7 @@ "tuple": "Entry", "download": "Download", "version": "History", - "subtitle": "Provide data to be directly inserted into the dataset." + "subtitle": "Provide data to be directly inserted into the dataset" } } }, @@ -1383,7 +1395,7 @@ "month": "Invalid month", "schema": { "id": "Column needs to be declared as primary key", - "primary-key": "We create a column named id with a auto-increasing sequence starting at 1. Please specify a column with primary key if you don't want this behavior." + "primary-key": "We create a column named id with a auto-increasing sequence starting at 1. Please specify a column with primary key if you don't want this behavior" }, "uri": { "pattern": "Invalid URI", diff --git a/dbrepo-ui/nuxt.config.ts b/dbrepo-ui/nuxt.config.ts index f2d9df53a35f8d411378851457ffc139251f2903..7dbf4914d2f76a75282017a38c93fb1e0a6607eb 100644 --- a/dbrepo-ui/nuxt.config.ts +++ b/dbrepo-ui/nuxt.config.ts @@ -127,7 +127,7 @@ export default defineNuxtConfig({ storage: 'localStorage' }, i18n: { - lazy: true, + lazy: false, langDir: 'locales', strategy: 'no_prefix', defaultLocale: 'de', diff --git a/dbrepo-ui/package.json b/dbrepo-ui/package.json index 64feac40f11b24794b051c15f460dd19ea897ca9..2bbe6696bc2e59845e4d1d30194a860923f2760d 100644 --- a/dbrepo-ui/package.json +++ b/dbrepo-ui/package.json @@ -13,6 +13,8 @@ "dependencies": { "@fontsource/open-sans": "^5.0.24", "@mdi/font": "^7.4.47", + "@nuxtjs/robots": "^3.0.0", + "@nuxtjs/sitemap": "^5.2.0", "@pinia/nuxt": "^0.5.1", "ace-builds": "^1.32.6", "axios": "^1.6.7", diff --git a/dbrepo-ui/pages/database/[database_id]/settings.vue b/dbrepo-ui/pages/database/[database_id]/settings.vue index 296f639caeb813897b1cb1a08906509af4740a14..558f152fef73cdb22eda4c505eb3d7cb3f6ae153 100644 --- a/dbrepo-ui/pages/database/[database_id]/settings.vue +++ b/dbrepo-ui/pages/database/[database_id]/settings.vue @@ -418,7 +418,8 @@ export default { const databaseService = useDatabaseService() databaseService.updateVisibility(this.$route.params.database_id, this.modifyVisibility) .then((database) => { - this.$toast.success('Successfully updated the database visibility') + const toast = useToastInstance() + toast.success('success.database.visibility') this.cacheStore.setDatabase(database) }) .catch(() => { @@ -434,7 +435,8 @@ export default { uploadService.create(this.fileModel[0]) .then((s3key) => { console.debug('uploaded image', s3key) - this.$toast.success(this.$t('success.database.upload')) + const toast = useToastInstance() + toast.success(this.$t('success.database.upload')) this.modifyImage.key = s3key this.loadingUpload = false }) @@ -448,12 +450,14 @@ export default { databaseService.updateImage(this.$route.params.database_id, this.modifyImage) .then(() => { this.cacheStore.reloadDatabase() - this.$toast.success(this.$t('success.database.image.update')) + const toast = useToastInstance() + toast.success(this.$t('success.database.image.update')) this.modifyImage.key = null this.loadingImage = false }) .catch(() => { - this.$toast.error('Failed to modify image') + const toast = useToastInstance() + toast.error('Failed to modify image') this.loadingImage = false }) .finally(() => { @@ -466,11 +470,13 @@ export default { databaseService.updateImage(this.$route.params.database_id, { key: null }) .then(() => { this.cacheStore.reloadDatabase() - this.$toast.success(this.$t('success.database.image.remove')) + const toast = useToastInstance() + toast.success(this.$t('success.database.image.remove')) this.loadingDeleteImage = false }) - .catch(() => { - this.$toast.error('Failed to delete image') + .catch(({code}) => { + const toast = useToastInstance() + toast.error(this.$t(code)) this.loadingDeleteImage = false }) .finally(() => { @@ -482,7 +488,8 @@ export default { const databaseService = useDatabaseService() databaseService.updateOwner(this.$route.params.database_id, this.modifyOwner.id) .then(() => { - this.$toast.success(this.$t('success.database.transfer')) + const toast = useToastInstance() + toast.success(this.$t('success.database.transfer')) location.reload() }) .catch(() => { @@ -497,20 +504,24 @@ export default { const databaseService = useDatabaseService() databaseService.refreshTablesMetadata(this.$route.params.database_id) .then(() => { - this.$toast.success(this.$t('success.schema.tables')) + const toast = useToastInstance() + toast.success(this.$t('success.schema.tables')) databaseService.refreshViewsMetadata(this.$route.params.database_id) .then(() => { - this.$toast.success(this.$t('success.schema.views')) + const toast = useToastInstance() + toast.success(this.$t('success.schema.views')) this.cacheStore.reloadDatabase() this.loadingSchema = false }) .catch(({code}) => { - this.$toast.error(this.$t(code)) + const toast = useToastInstance() + toast.error(this.$t(code)) this.loadingSchema = false }) }) .catch(({code}) => { - this.$toast.error(this.$t(code)) + const toast = useToastInstance() + toast.error(this.$t(code)) this.loadingSchema = false }) }, diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue index 7484989fa34ae4edc38036fe03639b0cfbf46144..27191e2a606f838a78956854b18352f93c503e9c 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue @@ -54,7 +54,9 @@ @click.stop="pick" /> </v-toolbar> <TimeDrift /> - <v-card tile> + <v-card + elevation="0" + tile> <v-card v-if="error" variant="flat"> @@ -86,7 +88,7 @@ v-model="pickVersionDialog" max-width="640" @close="closeVersion"> - <TimeTravel + <TableHistory ref="timeTravel" @close="pickVersion" /> </v-dialog> @@ -115,7 +117,7 @@ </template> <script> -import TimeTravel from '@/components/dialogs/TimeTravel.vue' +import TableHistory from '@/components/table/TableHistory.vue' import TimeDrift from '@/components/TimeDrift.vue' import TableToolbar from '@/components/table/TableToolbar.vue' import {formatTimestampUTC, formatDateUTC, formatTimestamp} from '@/utils' @@ -128,7 +130,7 @@ export default { components: { BlobDownload, EditTuple, - TimeTravel, + TableHistory, TableToolbar, TimeDrift }, @@ -326,12 +328,14 @@ export default { const tupleService = useTupleService() wait.push(tupleService.remove(this.$route.params.database_id, this.$route.params.table_id, { keys: constraints }) .catch(({message}) => { - this.$toast.error(message) + const toast = useToastInstance() + toast.error(message) })) } Promise.all(wait) .then(() => { - this.$toast.success(`Deleted ${this.selection.length} row(s)`) + const toast = useToastInstance() + toast.success(`Deleted ${this.selection.length} row(s)`) this.$emit('modified', { success: true, action: 'delete' }) this.selection = [] this.reload() @@ -351,8 +355,9 @@ export default { document.body.appendChild(link) link.click() }) - .catch((error) => { - this.$toast.error(this.$t(error.code)) + .catch(({code}) => { + const toast = useToastInstance() + toast.error(this.$t(code)) this.downloadLoading = false }) .finally(() => { @@ -399,7 +404,7 @@ export default { return } try { - this.headers = [{ value: 'selection', title: '', sortable: false }] + this.headers = [] this.table.columns.map((c) => { return { value: c.internal_name, @@ -409,8 +414,9 @@ export default { }).forEach(header => this.headers.push(header)) this.dateColumns = this.table.columns.filter(c => (c.column_type === 'date' || c.column_type === 'timestamp')) console.debug('date columns are', this.dateColumns) - } catch (error) { - this.$toast.error(this.$t(error.code)) + } catch ({code}) { + const toast = useToastInstance() + toast.error(this.$t(code)) } this.loading = false }, @@ -442,8 +448,9 @@ export default { }) this.loadingData = false }) - .catch((error) => { - this.$toast.error(this.$t(error.code)) + .catch(({code, message}) => { + const toast = useToastInstance() + toast.error(this.$t(code) + ": " + message) this.error = true this.loadingData = false }) @@ -456,8 +463,9 @@ export default { this.total = count this.loadingCount = false }) - .catch((error) => { - this.$toast.error(this.$t(error.code)) + .catch(({code, message}) => { + const toast = useToastInstance() + toast.error(this.$t(code) + ": " + message) this.loadingCount = false }) }, diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue index 4af6ba09d796889ec81b2a960b0682847fc24f68..3a821a730b50c6292f603b67c8b666add18aaa08 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue @@ -78,7 +78,7 @@ variant="flat" rounded="0" tile - :title="$t('pages.table.subpages.schema.title')"> + :title="$t('pages.table.subpages.schema.subtitle')"> <v-card-text> <v-container> <ul> @@ -87,12 +87,7 @@ (<i v-text="primaryKeysColumns" />) </li> <li v-for="(foreignKey, i) in table.constraints.foreign_keys" :key="`fk-${i}`"> - <strong>FOREIGN KEY</strong> - <span v-text="foreignKey.name" /> - (<i v-text="foreignKeyColumns(foreignKey)" />) - <strong>REFERENCES</strong> - <a :href="`/database/${database.id}/table/${foreignKey.referenced_table.id}/schema`" v-text="foreignKeyReferencedTable(foreignKey)" /> - (<i v-text="foreignKeyReferencedColumns(foreignKey)" />) + <strong>FOREIGN KEY</strong> <span v-text="foreignKey.name" /> (<i v-text="foreignKeyColumns(foreignKey)" />) <strong>REFERENCES</strong> <a :href="`/database/${database.id}/table/${foreignKey.referenced_table.id}/schema`" v-text="foreignKeyReferencedTable(foreignKey)" /> (<i v-text="foreignKeyReferencedColumns(foreignKey)" />) </li> <li v-for="(uniqueConstraint, i) in table.constraints.uniques" :key="`uk-${i}`"> <strong>UNIQUE INDEX</strong> @@ -193,7 +188,7 @@ export default { return this.userStore.getRoles }, primaryKeysColumns () { - return this.table.constraints.primary_key.join(', ') + return this.table.constraints.primary_key.map(pk => pk.column.internal_name).join(', ') }, canAssignSemanticInformation () { if (!this.user) { @@ -252,7 +247,8 @@ export default { const { success } = event console.debug('closed dialog', event) if (success) { - this.$toast.success(this.$t('success.table.semantics')) + const toast = useToastInstance() + toast.success(this.$t('success.table.semantics')) this.cacheStore.reloadTable() } this.dialogSemantic = false @@ -261,7 +257,7 @@ export default { if (!foreignKey) { return null } - return foreignKey.columns.map(c => c.internal_name).join(',') + return foreignKey.references.map(r => r.column.internal_name).join(',') }, foreignKeyReferencedTable (foreignKey) { if (!foreignKey) { @@ -273,7 +269,7 @@ export default { if (!foreignKey) { return null } - return foreignKey.referenced_columns.map(c => c.internal_name).join(',') + return foreignKey.references.map(r => r.referenced_column.internal_name).join(',') }, uniqueColumns (uniqueConstraint) { if (!uniqueConstraint) { diff --git a/dbrepo-ui/pages/database/[database_id]/table/create.vue b/dbrepo-ui/pages/database/[database_id]/table/create.vue index 496c3ec3cb589e6655e15e0b280f995f5e35f789..52af4ad304db37b7884c746447a1f0629fd0fa8e 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/create.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/create.vue @@ -113,7 +113,7 @@ <v-container v-if="table"> <v-row dense> - <v-col> + <v-col md="8"> <v-alert border="start" color="success" @@ -260,8 +260,9 @@ export default { this.cacheStore.reloadDatabase() this.table = table }) - .catch((error) => { - this.$toast.error(this.$t(error.code)) + .catch(({code}) => { + const toast = useToastInstance() + toast.error(this.$t(code)) this.loading = false }) .finally(() => { diff --git a/dbrepo-ui/pages/database/[database_id]/table/import.vue b/dbrepo-ui/pages/database/[database_id]/table/import.vue index 5eb02f7f8ea693e28f232706275612ad1d1a7625..724205c7ba1934dfcbe4c4e3b4a88659e47f77b6 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/import.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/import.vue @@ -327,7 +327,8 @@ export default { }) .catch((error) => { console.error('Failed to create table', error) - this.$toast.error(this.$t(error.code)) + const toast = useToastInstance() + toast.error(this.$t(error.code)) this.loading = false reject(error) }) @@ -342,12 +343,14 @@ export default { tableService.importCsv(this.$route.params.database_id, table.id, this.tableImport) .then(() => { this.step = 5 - this.$toast.success(this.$t('success.import.dataset')) + const toast = useToastInstance() + toast.success(this.$t('success.import.dataset')) this.cacheStore.reloadDatabase() }) - .catch((error) => { - console.error('Failed to import csv', error) - this.$toast.error(this.$t(error.code)) + .catch(({code}) => { + console.error('Failed to import csv') + const toast = useToastInstance() + toast.error(this.$t(code)) this.loading = false }) .finally(() => { diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue index 783ad566378a9b91acee508ee93e81489a107074..03464f5dbba66d89312f7b1c4a55332c79af161a 100644 --- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue +++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue @@ -1,6 +1,7 @@ <template> - <div v-if="view"> - <ViewToolbar /> + <div> + <ViewToolbar + v-if="view" /> <v-toolbar color="secondary" :title="$t('toolbars.database.current')" @@ -19,7 +20,6 @@ id="query-results" ref="queryResults" type="view" - :view="view" class="mt-0 mb-0" /> </v-card> <v-breadcrumbs :items="items" class="pa-0 mt-2" /> @@ -76,15 +76,12 @@ export default { } }, mounted () { - if (!this.view) { - return - } this.reload() }, methods: { reload () { - this.$refs.queryResults.reExecute(this.view.id) - this.$refs.queryResults.reExecuteCount(this.view.id) + this.$refs.queryResults.reExecute(Number(this.$route.params.view_id)) + this.$refs.queryResults.reExecuteCount(Number(this.$route.params.view_id)) } } } diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue index 44211b6eacebb09a27e72b1236742f984ebde666..3ec97f2bdaec1109edc16f1bedf0ee22b07a1f52 100644 --- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue +++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue @@ -1,10 +1,10 @@ <template> - <div - v-if="view"> + <div> <ViewToolbar /> <v-window v-model="tab"> - <v-window-item> + <v-window-item + v-if="view"> <v-card variant="flat"> <Summary v-if="hasIdentifier" @@ -25,6 +25,10 @@ <v-list v-if="view" dense> + <v-list-item + :title="$t('pages.view.name.title')"> + {{ view.internal_name }} + </v-list-item> <v-list-item :title="$t('pages.view.query.title')"> <pre>{{ view.query }}</pre> diff --git a/dbrepo-ui/pages/login.vue b/dbrepo-ui/pages/login.vue index 5ce0c31a81b1ad63be7dbfcdcd3413a40c496bdf..38c2ce139e10816a89555d7b25fdf658073f5ded 100644 --- a/dbrepo-ui/pages/login.vue +++ b/dbrepo-ui/pages/login.vue @@ -116,6 +116,8 @@ export default { const userId = userService.tokenToUserId(data.access_token) userService.findOne(userId) .then((user) => { + const toast = useToastInstance() + toast.success(this.$t('success.user.login')) switch (user.attributes.theme) { case 'dark': this.$vuetify.theme.global.name = 'tuwThemeDark' @@ -133,13 +135,14 @@ export default { this.userStore.setUser(user) this.$router.push('/database') }) - .catch(error => { - this.$toast.error(this.$t(error.code)) + .catch(({code}) => { + const toast = useToastInstance() + toast.error(this.$t(code)) }) }) - .catch((error) => { - console.error('Failed to login', error) - this.$toast.error(this.$t(error.code)) + .catch(({code}) => { + const toast = useToastInstance() + toast.error(this.$t(code)) this.loading = false }) .finally(() => { diff --git a/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue b/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue index ee1d19d985a3f8b7f7fb56fc6778f5e07c280776..41cfa20426c6d51a12f656ef7cd40bc0dff45405 100644 --- a/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue +++ b/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue @@ -182,7 +182,8 @@ export default { .then(() => { this.loadOntology() // this.$store.dispatch('reloadOntologies') - this.$toast.success('Successfully update ontology!') + const toast = useToastInstance() + toast.success('Successfully update ontology!') }) .catch(() => { this.loading = false diff --git a/dbrepo-ui/pages/signup.vue b/dbrepo-ui/pages/signup.vue index aa944e5d9fa0ab04bdbff72070ea7ab913c777f8..9d84f5c0df8a36b3b56590e42903058895bccb0e 100644 --- a/dbrepo-ui/pages/signup.vue +++ b/dbrepo-ui/pages/signup.vue @@ -117,12 +117,14 @@ export default { const userService = useUserService() userService.create(this.createAccount) .then(() => { - this.$toast.success(this.$t('success.signup')) + const toast = useToastInstance() + toast.success(this.$t('success.signup')) this.$router.push('/login') this.loading = false }) - .catch((error) => { - this.$toast.error(this.$t(error.code)) + .catch(({code}) => { + const toast = useToastInstance() + toast.error(this.$t(code)) this.loading = false }) .finally(() => { @@ -136,8 +138,9 @@ export default { .then((users) => { this.usernames = users.map(u => u.username) }) - .catch((error) => { - this.$toast.error(this.$t(error.code)) + .catch(({code}) => { + const toast = useToastInstance() + toast.error(this.$t(code)) this.loadingUsers = false }) .finally(() => { diff --git a/dbrepo-ui/pages/user/authentication.vue b/dbrepo-ui/pages/user/authentication.vue index 35fec2fa71d9402757ad43076e3c1a88c7e8ad0a..a40fef51e5e8f6b690beffa65d605110384f1c7b 100644 --- a/dbrepo-ui/pages/user/authentication.vue +++ b/dbrepo-ui/pages/user/authentication.vue @@ -114,7 +114,8 @@ export default { const userService = useUserService() userService.updatePassword(this.user.id, this.password) .then(() => { - this.$toast.success('Successfully changed the password') + const toast = useToastInstance() + toast.success('success.user.password') this.loadingUpdate = false }) .catch(() => { diff --git a/dbrepo-ui/pages/user/info.vue b/dbrepo-ui/pages/user/info.vue index 3a085b6008a2362e5dd4c596a7e697fb9cdc3288..3501818ca0408474e81a9038f15a84d61fb662ff 100644 --- a/dbrepo-ui/pages/user/info.vue +++ b/dbrepo-ui/pages/user/info.vue @@ -219,7 +219,8 @@ export default { userService.update(this.user.id, payload) .then((user) => { console.info('Updated user information') - this.$toast.success(this.$t('success.user.info')) + const toast = useToastInstance() + toast.success(this.$t('success.user.info')) this.userStore.setUser(user) /* language */ this.userStore.setLocale(this.model.language) @@ -286,7 +287,8 @@ export default { }, copy () { navigator.clipboard.writeText(this.model.id) - this.$toast.success(this.$t('success.clipboard.user')) + const toast = useToastInstance() + toast.success(this.$t('success.clipboard.user')) } } } diff --git a/dbrepo-ui/stores/cache.js b/dbrepo-ui/stores/cache.js index bb89295ec5534fb82c3c435737af5baf023994fe..087ae4e9b936330b43d3002b076ea431c95c7420 100644 --- a/dbrepo-ui/stores/cache.js +++ b/dbrepo-ui/stores/cache.js @@ -30,25 +30,33 @@ export const useCacheStore = defineStore('cache', { const messageService = useMessageService() messageService.findAll('active') .then(messages => this.messages = messages) - .catch(() => {}) + .catch((error) => { + console.error('Failed to reload messages', error) + }) }, reloadOntologies () { const ontologyService = useOntologyService() ontologyService.findAll() .then(ontologies => this.ontologies = ontologies) - .catch(() => {}) + .catch((error) => { + console.error('Failed to reload ontologies', error) + }) }, reloadDatabase () { const databaseService = useDatabaseService() databaseService.findOne(this.database.id) .then(database => this.database = database) - .catch(() => {}) + .catch((error) => { + console.error('Failed to reload database', error) + }) }, reloadTable () { const tableService = useTableService() tableService.findOne(this.table.database_id, this.table.id) .then(table => this.table = table) - .catch(() => {}) + .catch((error) => { + console.error('Failed to reload table', error) + }) }, setRouteDatabase (databaseId) { if (!databaseId) { @@ -58,7 +66,9 @@ export const useCacheStore = defineStore('cache', { const databaseService = useDatabaseService() databaseService.findOne(databaseId) .then(database => this.database = database) - .catch(() => {}) + .catch((error) => { + console.error('Failed to set route database', error) + }) }, setRouteTable (databaseId, tableId) { if (!databaseId || !tableId) { @@ -68,7 +78,9 @@ export const useCacheStore = defineStore('cache', { const tableService = useTableService() tableService.findOne(databaseId, tableId) .then(table => this.table = table) - .catch(() => {}) + .catch((error) => { + console.error('Failed to set route table', error) + }) } }, }) diff --git a/docker-compose.yml b/docker-compose.yml index da0d6a27ea28a19be313f36be686d43116df87d8..415c754090cad7fea2799123465f5421a04cc827 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -115,14 +115,15 @@ services: volumes: - "${SHARED_VOLUME:-/tmp}:/tmp" environment: - ADMIN_MAIL: "${ADMIN_MAIL:-noreply@localhost}" + ADMIN_EMAIL: "${ADMIN_EMAIL:-noreply@localhost}" ADMIN_PASSWORD: "${ADMIN_PASSWORD:-admin}" ADMIN_USERNAME: "${ADMIN_USERNAME:-admin}" + ANALYSE_SERVICE_ENDPOINT: "${ANALYSE_SERVICE_ENDPOINT:-http://gateway-service}" AUTH_SERVICE_ADMIN: ${AUTH_SERVICE_ADMIN:-fda} AUTH_SERVICE_ADMIN_PASSWORD: ${AUTH_SERVICE_ADMIN_PASSWORD:-fda} AUTH_SERVICE_CLIENT: ${AUTH_SERVICE_CLIENT:-dbrepo-client} AUTH_SERVICE_CLIENT_SECRET: ${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG} - AUTH_SERVICE_ENDPOINT: ${AUTH_SERVICE_ENDPOINT:-http://auth-service:8080} + AUTH_SERVICE_ENDPOINT: ${AUTH_SERVICE_ENDPOINT:-http://gateway-service/api/auth} BASE_URL: "${BASE_URL:-http://localhost}" BROKER_EXCHANGE_NAME: ${BROKER_EXCHANGE_NAME:-dbrepo} BROKER_QUEUE_NAME: ${BROKER_QUEUE_NAME:-dbrepo} @@ -134,10 +135,8 @@ services: BROKER_VIRTUALHOST: "${BROKER_VIRTUALHOST:-dbrepo}" DATA_SERVICE_ENDPOINT: ${DATA_SERVICE_ENDPOINT:-http://data-service:8080} DELETED_RECORD: "${DELETED_RECORD:-persistent}" - GATEWAY_SERVICE_ENDPOINT: ${GATEWAY_SERVICE_ENDPOINT:-http://gateway-service} GRANULARITY: "${GRANULARITY:-YYYY-MM-DDThh:mm:ssZ}" JWT_PUBKEY: "${JWT_PUBKEY:-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB}" -# LOG_LEVEL: ${LOG_LEVEL:-info} LOG_LEVEL: trace METADATA_DB: "${METADATA_DB:-dbrepo}" METADATA_HOST: "${METADATA_HOST:-metadata-db}" @@ -146,7 +145,7 @@ services: METADATA_PASSWORD: "${METADATA_PASSWORD:-dbrepo}" PID_BASE: ${PID_BASE:-http://localhost/pid/} REPOSITORY_NAME: "${REPOSITORY_NAME:-Database Repository}" - SEARCH_SERVICE_ENDPOINT: "${SEARCH_SERVICE_ENDPOINT:-http://search-service:8080}" + SEARCH_SERVICE_ENDPOINT: "${SEARCH_SERVICE_ENDPOINT:-http://gateway-service}" S3_ACCESS_KEY_ID: "${S3_ACCESS_KEY_ID:-seaweedfsadmin}" S3_ENDPOINT: "${S3_ENDPOINT:-http://storage-service:9000}" S3_EXPORT_BUCKET: "${S3_EXPORT_BUCKET:-dbrepo-download}" @@ -154,7 +153,7 @@ services: S3_SECRET_ACCESS_KEY: "${S3_SECRET_ACCESS_KEY:-seaweedfsadmin}" SPARQL_CONNECTION_TIMEOUT: "${SPARQL_CONNECTION_TIMEOUT:-10000}" healthcheck: - test: wget -qO- localhost:8080/actuator/health/readiness | grep -q "UP" || exit 1 + test: curl -sSL localhost:8080/actuator/health/liveness | grep 'UP' || exit 1 interval: 10s timeout: 5s retries: 12 @@ -399,6 +398,8 @@ services: volumes: - ./dbrepo-storage-service/s3_config.json:/app/s3_config.json - storage-service-data:/data + ports: + - "9000:9000" healthcheck: test: echo "cluster.check" | weed shell | grep "checking master.*ok" || exit 1 interval: 10s @@ -477,11 +478,11 @@ services: BROKER_VIRTUALHOST: "${BROKER_VIRTUALHOST:-dbrepo}" CONNECTION_TIMEOUT: ${CONNECTION_TIMEOUT:-60000} EXCHANGE_NAME: ${EXCHANGE_NAME:-dbrepo} - GATEWAY_SERVICE_ENDPOINT: ${GATEWAY_SERVICE_ENDPOINT:-http://gateway-service} + METADATA_SERVICE_ENDPOINT: ${METADATA_SERVICE_ENDPOINT:-http://gateway-service} GRANT_DEFAULT_READ: "${GRANT_DEFAULT_READ:-SELECT}" GRANT_DEFAULT_WRITE: "${GRANT_DEFAULT_WRITE:-SELECT, CREATE, CREATE VIEW, CREATE ROUTINE, CREATE TEMPORARY TABLES, LOCK TABLES, INDEX, TRIGGER, INSERT, UPDATE, DELETE}" JWT_PUBKEY: "${JWT_PUBKEY:-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB}" - LOG_LEVEL: ${LOG_LEVEL:-info} + LOG_LEVEL: ${LOG_LEVEL:-trace} MIN_CONCURRENT_CONSUMERS: ${MIN_CONCURRENT_CONSUMERS:-1} MAX_CONCURRENT_CONSUMERS: ${MAX_CONCURRENT_CONSUMERS:-5} QUEUE_NAME: ${QUEUE_NAME:-dbrepo} @@ -494,7 +495,7 @@ services: S3_IMPORT_BUCKET: "${S3_IMPORT_BUCKET:-dbrepo-upload}" S3_SECRET_ACCESS_KEY: "${S3_SECRET_ACCESS_KEY:-seaweedfsadmin}" healthcheck: - test: wget -qO- localhost:8080/actuator/health/readiness | grep -q "UP" || exit 1 + test: curl -sSL localhost:8080/actuator/health/liveness | grep 'UP' || exit 1 interval: 10s timeout: 5s retries: 12 diff --git a/helm/dbrepo/Makefile b/helm/dbrepo/Makefile deleted file mode 100644 index b89c9b4decd70764a400405af0ff4ccf69b66e61..0000000000000000000000000000000000000000 --- a/helm/dbrepo/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -.PHONY: all -all: - -.PHONY: build -build: ## Generate Helm values schema JSON - #helm package --sign --key 'Martin Weise' . --keyring ~/.gnupg/mweise.gpg --destination ./build - helm schema -input ./values.yaml - readme-generator-for-helm --readme README.md --values values.yaml diff --git a/helm/dbrepo/README.md b/helm/dbrepo/README.md index f7c43ba5dbd6f123cb701d9928415fda931e01de..01f699d9e1841eef85f4889248eef4c83bf4d49c 100644 --- a/helm/dbrepo/README.md +++ b/helm/dbrepo/README.md @@ -145,6 +145,7 @@ The command removes all the Kubernetes components associated with the chart and | Name | Description | Value | | ----------------------------- | ----------------------------------------------------- | ------------------------------- | | `analyseservice.enabled` | Enable the Broker Service. | `true` | +| `analyseservice.endpoint` | The url of the endpoint. | `http://analyse-service` | | `analyseservice.s3.endpoint` | The S3-capable endpoint the microservice connects to. | `http://storageservice-s3:9000` | | `analyseservice.replicaCount` | The number of replicas. | `2` | @@ -153,6 +154,7 @@ The command removes all the Kubernetes components associated with the chart and | Name | Description | Value | | ------------------------------------------ | --------------------------------------------------------------------- | ------------------------------- | | `metadataservice.enabled` | Enable the Metadata Service. | `true` | +| `metadataservice.endpoint` | The Metadata Service endpoint. | `http://metadata-service` | | `metadataservice.admin.email` | The OAI-PMH exposed admin e-mail. | `noreply@example.com` | | `metadataservice.deletedRecord` | The OAI-PMH exposed delete policy. | `permanent` | | `metadataservice.repositoryName` | The OAI-PMH exposed repository name. | `Database Repository` | diff --git a/helm/dbrepo/templates/data-secret.yaml b/helm/dbrepo/templates/data-secret.yaml index b5307a23d95df9abcf06868646ddc8ac85c80e70..7797626672d1976564fcc8404f8f7651a4054120 100644 --- a/helm/dbrepo/templates/data-secret.yaml +++ b/helm/dbrepo/templates/data-secret.yaml @@ -31,6 +31,7 @@ stringData: DEFAULT_TIMESTAMP_FORMAT_ID: "{{ .Values.dataservice.default.timestamp }}" JWT_PUBKEY: "{{ .Values.authservice.jwt.pubkey }}" LOG_LEVEL: "{{ ternary "debug" "info" .Values.dataservice.image.debug }}" + METADATA_SERVICE_ENDPOINT: "{{ .Values.metadataservice.endpoint }}" MIN_CONCURRENT_CONSUMERS: "{{ .Values.dataservice.consumerConcurrentMin }}" MAX_CONCURRENT_CONSUMERS: "{{ .Values.dataservice.consumerConcurrentMax }}" REQUEUE_REJECTED: "{{ .Values.dataservice.requeueRejected }}" diff --git a/helm/dbrepo/templates/metadata-configmap.yaml b/helm/dbrepo/templates/metadata-configmap.yaml index 88c761643a70da48cd6032f3225ceb5459543052..4bb2eb136b557c0a44f3a9fb77d8d6a023ab67ea 100644 --- a/helm/dbrepo/templates/metadata-configmap.yaml +++ b/helm/dbrepo/templates/metadata-configmap.yaml @@ -13,11 +13,10 @@ data: BEGIN; INSERT INTO `mdb_containers` (name, internal_name, image_id, host, port, sidecar_host, sidecar_port, privileged_username, privileged_password) VALUES ('MariaDB Galera 11.1.3', 'mariadb_11_1_3', 1, 'data-db', 3306, 'data-db', 80, 'root', 'dbrepo'); - INSERT INTO `mdb_banner_messages` (type, message) - VALUES ('INFO', 'You are currently working on our test environment. Any data upload to this system may be deleted.'); COMMIT; 01-setup-schema.sql: | BEGIN; + CREATE TABLE IF NOT EXISTS `mdb_users` ( id character varying(36) NOT NULL, @@ -138,13 +137,13 @@ data: CREATE TABLE IF NOT EXISTS `mdb_tables` ( - ID bigint NOT NULL AUTO_INCREMENT, - tDBID bigint NOT NULL, - internal_name character varying(255) NOT NULL, - queue_name character varying(255) NOT NULL, - routing_key character varying(255), - tName VARCHAR(50), - tDescription TEXT, + ID bigint NOT NULL AUTO_INCREMENT, + tDBID bigint NOT NULL, + tName VARCHAR(64) NOT NULL, + internal_name VARCHAR(64) NOT NULL, + queue_name VARCHAR(255) NOT NULL, + routing_key VARCHAR(255), + tDescription VARCHAR(2048), num_rows BIGINT, data_length BIGINT, max_data_length BIGINT, @@ -156,12 +155,13 @@ data: element_true VARCHAR(50), element_false VARCHAR(50), Version TEXT, - created timestamp NOT NULL DEFAULT NOW(), - versioned boolean not null default true, - created_by character varying(36) NOT NULL, - owned_by character varying(36) NOT NULL, + created timestamp NOT NULL DEFAULT NOW(), + versioned boolean not null default true, + created_by character varying(36) NOT NULL, + owned_by character varying(36) NOT NULL, last_modified timestamp, PRIMARY KEY (ID), + UNIQUE (tDBID, internal_name), FOREIGN KEY (tDBID) REFERENCES mdb_databases (id), FOREIGN KEY (created_by) REFERENCES mdb_users (id), FOREIGN KEY (owned_by) REFERENCES mdb_users (id) @@ -169,25 +169,26 @@ data: CREATE TABLE IF NOT EXISTS `mdb_columns` ( - ID BIGINT NOT NULL AUTO_INCREMENT, - tID BIGINT NOT NULL, + ID BIGINT NOT NULL AUTO_INCREMENT, + tID BIGINT NOT NULL, dfID BIGINT, - cName VARCHAR(100), - internal_name VARCHAR(100) NOT NULL, + cName VARCHAR(64), + internal_name VARCHAR(64) NOT NULL, Datatype ENUM ('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR'), - length BIGINT NULL, - ordinal_position INTEGER NOT NULL, - index_length BIGINT NULL, + length BIGINT NULL, + ordinal_position INTEGER NOT NULL, + index_length BIGINT NULL, + description VARCHAR(2048), size BIGINT, d BIGINT, - auto_generated BOOLEAN DEFAULT false, - is_null_allowed BOOLEAN NOT NULL DEFAULT true, - val_min NUMERIC NULL, - val_max NUMERIC NULL, - mean NUMERIC NULL, - median NUMERIC NULL, - std_dev Numeric NULL, - created timestamp NOT NULL DEFAULT NOW(), + auto_generated BOOLEAN DEFAULT false, + is_null_allowed BOOLEAN NOT NULL DEFAULT true, + val_min NUMERIC NULL, + val_max NUMERIC NULL, + mean NUMERIC NULL, + median NUMERIC NULL, + std_dev Numeric NULL, + created timestamp NOT NULL DEFAULT NOW(), last_modified timestamp, FOREIGN KEY (tID) REFERENCES mdb_tables (ID) ON DELETE CASCADE, PRIMARY KEY (ID) @@ -344,8 +345,8 @@ data: ( id bigint NOT NULL AUTO_INCREMENT, vdbid bigint NOT NULL, - vName VARCHAR(255) NOT NULL, - internal_name VARCHAR(255) NOT NULL, + vName VARCHAR(64) NOT NULL, + internal_name VARCHAR(64) NOT NULL, Query TEXT NOT NULL, query_hash VARCHAR(255) NOT NULL, Public BOOLEAN NOT NULL, @@ -387,14 +388,19 @@ data: CREATE TABLE IF NOT EXISTS `mdb_view_columns` ( - id BIGINT NOT NULL AUTO_INCREMENT, - cid BIGINT NOT NULL, - vid BIGINT NOT NULL, - alias VARCHAR(100), - ordinal_position INTEGER, + id BIGINT NOT NULL AUTO_INCREMENT, + view_id BIGINT NOT NULL, + dfID BIGINT, + name VARCHAR(64), + internal_name VARCHAR(64) NOT NULL, + column_type ENUM ('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR'), + ordinal_position INTEGER NOT NULL, + size BIGINT, + d BIGINT, + auto_generated BOOLEAN DEFAULT false, + is_null_allowed BOOLEAN NOT NULL DEFAULT true, PRIMARY KEY (id), - FOREIGN KEY (vid) REFERENCES mdb_view (id), - FOREIGN KEY (cid) REFERENCES mdb_columns (ID) + FOREIGN KEY (view_id) REFERENCES mdb_view (id) ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_identifiers` @@ -503,18 +509,6 @@ data: FOREIGN KEY (pid) REFERENCES mdb_identifiers (id) ) WITH SYSTEM VERSIONING; - CREATE TABLE IF NOT EXISTS `mdb_feed` - ( - fDBID bigint, - fID bigint, - fUserId character varying(36) not null, - fDataID bigint REFERENCES mdb_data (ID), - created timestamp NOT NULL DEFAULT NOW(), - PRIMARY KEY (fDBID, fID, fUserId, fDataID), - FOREIGN KEY (fDBID, fID) REFERENCES mdb_tables (tDBID, ID), - FOREIGN KEY (fUserId) REFERENCES mdb_users (id) - ) WITH SYSTEM VERSIONING; - CREATE TABLE IF NOT EXISTS `mdb_update` ( uUserID character varying(255) NOT NULL, diff --git a/helm/dbrepo/templates/metadata-secret.yaml b/helm/dbrepo/templates/metadata-secret.yaml index db8328b7a8e313b7e2110be1d29045136df3b8e7..3beda17fc57fe12ecb06021e3b81fe47e6a067f0 100644 --- a/helm/dbrepo/templates/metadata-secret.yaml +++ b/helm/dbrepo/templates/metadata-secret.yaml @@ -7,8 +7,9 @@ metadata: namespace: {{ .Values.namespace }} stringData: ADMIN_EMAIL: "{{ .Values.metadataservice.admin.email }}" - ADMIN_USERNAME: "{{ .Values.admin.username }}" ADMIN_PASSWORD: "{{ .Values.admin.password }}" + ADMIN_USERNAME: "{{ .Values.admin.username }}" + ANALYSE_SERVICE_ENDPOINT: "{{ .Values.analyseservice.endpoint }}" AUTH_SERVICE_ADMIN: "{{ .Values.authservice.auth.adminUser }}" AUTH_SERVICE_ADMIN_PASSWORD: "{{ .Values.authservice.auth.adminPassword }}" AUTH_SERVICE_CLIENT: "{{ .Values.authservice.client.id }}" @@ -29,7 +30,6 @@ stringData: DATACITE_USERNAME: "{{ .Values.metadataservice.datacite.username }}" DATACITE_PASSWORD: "{{ .Values.metadataservice.datacite.password }}" DELETED_RECORD: "{{ .Values.metadataservice.deletedRecord }}" - GATEWAY_SERVICE_ENDPOINT: "{{ .Values.gateway }}" GRANULARITY: "{{ .Values.metadataservice.granularity }}" JWT_PUBKEY: "{{ .Values.authservice.jwt.pubkey }}" LOG_LEVEL: "{{ ternary "trace" "info" .Values.metadataservice.image.debug }}" diff --git a/helm/dbrepo/values.yaml b/helm/dbrepo/values.yaml index d15d46c305eaa829415e181694d18ccd0279f429..dc8cd7bdbaa7533296664612d77635ed7fe0d07c 100644 --- a/helm/dbrepo/values.yaml +++ b/helm/dbrepo/values.yaml @@ -173,12 +173,13 @@ datadb: service: extraPorts: - name: "sidecar" - port: 80 + port: 8080 targetPort: 8080 protocol: TCP sidecars: - name: sidecar image: s210.dl.hpc.tuwien.ac.at/dbrepo/data-db-sidecar:1.4.4 + imagePullPolicy: Always securityContext: runAsUser: 1001 runAsGroup: 0 @@ -430,6 +431,7 @@ brokerservice: ## @param analyseservice.enabled Enable the Broker Service. ## @skip analyseservice.image +## @param analyseservice.endpoint The url of the endpoint. ## @param analyseservice.s3.endpoint The S3-capable endpoint the microservice connects to. ## @param analyseservice.replicaCount The number of replicas. ## @@ -439,6 +441,7 @@ analyseservice: name: s210.dl.hpc.tuwien.ac.at/dbrepo/analyse-service:1.4.4 pullPolicy: Always debug: false + endpoint: http://analyse-service s3: endpoint: http://storageservice-s3:9000 replicaCount: 2 @@ -447,6 +450,7 @@ analyseservice: ## @param metadataservice.enabled Enable the Metadata Service. ## @skip metadataservice.image +## @param metadataservice.endpoint The Metadata Service endpoint. ## @param metadataservice.admin.email The OAI-PMH exposed admin e-mail. ## @param metadataservice.deletedRecord The OAI-PMH exposed delete policy. ## @param metadataservice.repositoryName The OAI-PMH exposed repository name. @@ -469,6 +473,7 @@ metadataservice: name: s210.dl.hpc.tuwien.ac.at/dbrepo/metadata-service:1.4.4 pullPolicy: Always debug: false + endpoint: http://metadata-service admin: email: noreply@example.com deletedRecord: permanent diff --git a/install.sh b/install.sh index eeba0c1d45db41b70408d78a1b3851ed51ae6ce4..9850ccd35eaae4c71032655bbe72e97892aba0f1 100644 --- a/install.sh +++ b/install.sh @@ -58,7 +58,7 @@ fi # environment echo "[🚀] Gathering environment ..." mkdir -p ./dist -curl -sSL -o ./docker-compose.yml "https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/release-${VERSION}/docker-compose.prod.yml" +curl -sSL -o ./docker-compose.yml "https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/release-${VERSION}/.docker/docker-compose.yml" curl -sSL -o ./dist/2_setup-data.sql "https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/release-${VERSION}/dbrepo-metadata-db/2_setup-data.sql" curl -sSL -o ./dist/rabbitmq.conf "https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/release-${VERSION}/dbrepo-broker-service/rabbitmq.conf" curl -sSL -o ./dist/enabled_plugins "https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/release-${VERSION}/dbrepo-broker-service/enabled_plugins" diff --git a/lib/python/.gitignore b/lib/python/.gitignore index 1a92852ebd1ba1f7692ad8f3e2ad7b09ff304c71..46916e3e91c948d297fa8fda068bc1b123d9aced 100644 --- a/lib/python/.gitignore +++ b/lib/python/.gitignore @@ -6,6 +6,9 @@ dist/ dbrepo.egg-info/ build/ +# debug +debug.py + # secrets .pypirc diff --git a/lib/python/Makefile b/lib/python/Makefile index f8f7215b3839eba5dd547603bb1725fa08f9156b..7c79a178bfd875327542c07e6bbdd0353a068b19 100644 --- a/lib/python/Makefile +++ b/lib/python/Makefile @@ -1,11 +1,8 @@ -all: +all: build install clean: rm -rf ./python/dist/* ./docs/build/* ./dist/* -install: - pipenv install - docs: clean sphinx-apidoc -o ./docs/source ./dbrepo sphinx-build -M html ./docs/ ./docs/build/ @@ -16,8 +13,14 @@ check: build: clean python3 -m build --sdist . python3 -m build --wheel . + +install: cp ./dist/dbrepo-* ../../dbrepo-analyse-service/lib/ + (cd ../../dbrepo-analyse-service && pipenv lock) cp ./dist/dbrepo-* ../../dbrepo-search-service/lib/ + (cd ../../dbrepo-search-service && pipenv lock) + cp ./dist/dbrepo-* ../../../dpm2024/lib/ + (cd ../../../dpm2024 && pipenv lock) deploy: build python3 -m twine upload --config-file ~/.pypirc --verbose --repository pypi ./dist/dbrepo-* diff --git a/lib/python/Pipfile.lock b/lib/python/Pipfile.lock index 554a33747d2a6ae6e9e80a30b90228bdf4d98ad2..953bcf20f326a8e1fc3c313683f09d546271f963 100644 --- a/lib/python/Pipfile.lock +++ b/lib/python/Pipfile.lock @@ -18,85 +18,85 @@ "default": { "aiohttp": { "hashes": [ - "sha256:017a21b0df49039c8f46ca0971b3a7fdc1f56741ab1240cb90ca408049766168", - "sha256:039df344b45ae0b34ac885ab5b53940b174530d4dd8a14ed8b0e2155b9dddccb", - "sha256:055ce4f74b82551678291473f66dc9fb9048a50d8324278751926ff0ae7715e5", - "sha256:06a9b2c8837d9a94fae16c6223acc14b4dfdff216ab9b7202e07a9a09541168f", - "sha256:07b837ef0d2f252f96009e9b8435ec1fef68ef8b1461933253d318748ec1acdc", - "sha256:0ed621426d961df79aa3b963ac7af0d40392956ffa9be022024cd16297b30c8c", - "sha256:0fa43c32d1643f518491d9d3a730f85f5bbaedcbd7fbcae27435bb8b7a061b29", - "sha256:1f5a71d25cd8106eab05f8704cd9167b6e5187bcdf8f090a66c6d88b634802b4", - "sha256:1f5cd333fcf7590a18334c90f8c9147c837a6ec8a178e88d90a9b96ea03194cc", - "sha256:27468897f628c627230dba07ec65dc8d0db566923c48f29e084ce382119802bc", - "sha256:298abd678033b8571995650ccee753d9458dfa0377be4dba91e4491da3f2be63", - "sha256:2c895a656dd7e061b2fd6bb77d971cc38f2afc277229ce7dd3552de8313a483e", - "sha256:361a1026c9dd4aba0109e4040e2aecf9884f5cfe1b1b1bd3d09419c205e2e53d", - "sha256:363afe77cfcbe3a36353d8ea133e904b108feea505aa4792dad6585a8192c55a", - "sha256:38a19bc3b686ad55804ae931012f78f7a534cce165d089a2059f658f6c91fa60", - "sha256:38f307b41e0bea3294a9a2a87833191e4bcf89bb0365e83a8be3a58b31fb7f38", - "sha256:3e59c23c52765951b69ec45ddbbc9403a8761ee6f57253250c6e1536cacc758b", - "sha256:4b4af9f25b49a7be47c0972139e59ec0e8285c371049df1a63b6ca81fdd216a2", - "sha256:504b6981675ace64c28bf4a05a508af5cde526e36492c98916127f5a02354d53", - "sha256:50fca156d718f8ced687a373f9e140c1bb765ca16e3d6f4fe116e3df7c05b2c5", - "sha256:522a11c934ea660ff8953eda090dcd2154d367dec1ae3c540aff9f8a5c109ab4", - "sha256:52df73f14ed99cee84865b95a3d9e044f226320a87af208f068ecc33e0c35b96", - "sha256:595f105710293e76b9dc09f52e0dd896bd064a79346234b521f6b968ffdd8e58", - "sha256:59c26c95975f26e662ca78fdf543d4eeaef70e533a672b4113dd888bd2423caa", - "sha256:5bce0dc147ca85caa5d33debc4f4d65e8e8b5c97c7f9f660f215fa74fc49a321", - "sha256:5eafe2c065df5401ba06821b9a054d9cb2848867f3c59801b5d07a0be3a380ae", - "sha256:5ed3e046ea7b14938112ccd53d91c1539af3e6679b222f9469981e3dac7ba1ce", - "sha256:5fe9ce6c09668063b8447f85d43b8d1c4e5d3d7e92c63173e6180b2ac5d46dd8", - "sha256:648056db9a9fa565d3fa851880f99f45e3f9a771dd3ff3bb0c048ea83fb28194", - "sha256:69361bfdca5468c0488d7017b9b1e5ce769d40b46a9f4a2eed26b78619e9396c", - "sha256:6b0e029353361f1746bac2e4cc19b32f972ec03f0f943b390c4ab3371840aabf", - "sha256:6b88f9386ff1ad91ace19d2a1c0225896e28815ee09fc6a8932fded8cda97c3d", - "sha256:770d015888c2a598b377bd2f663adfd947d78c0124cfe7b959e1ef39f5b13869", - "sha256:7943c414d3a8d9235f5f15c22ace69787c140c80b718dcd57caaade95f7cd93b", - "sha256:7cf5c9458e1e90e3c390c2639f1017a0379a99a94fdfad3a1fd966a2874bba52", - "sha256:7f46acd6a194287b7e41e87957bfe2ad1ad88318d447caf5b090012f2c5bb528", - "sha256:82e6aa28dd46374f72093eda8bcd142f7771ee1eb9d1e223ff0fa7177a96b4a5", - "sha256:835a55b7ca49468aaaac0b217092dfdff370e6c215c9224c52f30daaa735c1c1", - "sha256:84871a243359bb42c12728f04d181a389718710129b36b6aad0fc4655a7647d4", - "sha256:8aacb477dc26797ee089721536a292a664846489c49d3ef9725f992449eda5a8", - "sha256:8e2c45c208c62e955e8256949eb225bd8b66a4c9b6865729a786f2aa79b72e9d", - "sha256:90842933e5d1ff760fae6caca4b2b3edba53ba8f4b71e95dacf2818a2aca06f7", - "sha256:938a9653e1e0c592053f815f7028e41a3062e902095e5a7dc84617c87267ebd5", - "sha256:939677b61f9d72a4fa2a042a5eee2a99a24001a67c13da113b2e30396567db54", - "sha256:9d3c9b50f19704552f23b4eaea1fc082fdd82c63429a6506446cbd8737823da3", - "sha256:a6fe5571784af92b6bc2fda8d1925cccdf24642d49546d3144948a6a1ed58ca5", - "sha256:a78ed8a53a1221393d9637c01870248a6f4ea5b214a59a92a36f18151739452c", - "sha256:ab40e6251c3873d86ea9b30a1ac6d7478c09277b32e14745d0d3c6e76e3c7e29", - "sha256:abf151955990d23f84205286938796c55ff11bbfb4ccfada8c9c83ae6b3c89a3", - "sha256:acef0899fea7492145d2bbaaaec7b345c87753168589cc7faf0afec9afe9b747", - "sha256:b40670ec7e2156d8e57f70aec34a7216407848dfe6c693ef131ddf6e76feb672", - "sha256:b791a3143681a520c0a17e26ae7465f1b6f99461a28019d1a2f425236e6eedb5", - "sha256:b955ed993491f1a5da7f92e98d5dad3c1e14dc175f74517c4e610b1f2456fb11", - "sha256:ba39e9c8627edc56544c8628cc180d88605df3892beeb2b94c9bc857774848ca", - "sha256:bca77a198bb6e69795ef2f09a5f4c12758487f83f33d63acde5f0d4919815768", - "sha256:c3452ea726c76e92f3b9fae4b34a151981a9ec0a4847a627c43d71a15ac32aa6", - "sha256:c46956ed82961e31557b6857a5ca153c67e5476972e5f7190015018760938da2", - "sha256:c7c8b816c2b5af5c8a436df44ca08258fc1a13b449393a91484225fcb7545533", - "sha256:cd73265a9e5ea618014802ab01babf1940cecb90c9762d8b9e7d2cc1e1969ec6", - "sha256:dad46e6f620574b3b4801c68255492e0159d1712271cc99d8bdf35f2043ec266", - "sha256:dc9b311743a78043b26ffaeeb9715dc360335e5517832f5a8e339f8a43581e4d", - "sha256:df822ee7feaaeffb99c1a9e5e608800bd8eda6e5f18f5cfb0dc7eeb2eaa6bbec", - "sha256:e083c285857b78ee21a96ba1eb1b5339733c3563f72980728ca2b08b53826ca5", - "sha256:e5e46b578c0e9db71d04c4b506a2121c0cb371dd89af17a0586ff6769d4c58c1", - "sha256:e99abf0bba688259a496f966211c49a514e65afa9b3073a1fcee08856e04425b", - "sha256:ee43080e75fc92bf36219926c8e6de497f9b247301bbf88c5c7593d931426679", - "sha256:f033d80bc6283092613882dfe40419c6a6a1527e04fc69350e87a9df02bbc283", - "sha256:f1088fa100bf46e7b398ffd9904f4808a0612e1d966b4aa43baa535d1b6341eb", - "sha256:f56455b0c2c7cc3b0c584815264461d07b177f903a04481dfc33e08a89f0c26b", - "sha256:f59dfe57bb1ec82ac0698ebfcdb7bcd0e99c255bd637ff613760d5f33e7c81b3", - "sha256:f7217af2e14da0856e082e96ff637f14ae45c10a5714b63c77f26d8884cf1051", - "sha256:f734e38fd8666f53da904c52a23ce517f1b07722118d750405af7e4123933511", - "sha256:f95511dd5d0e05fd9728bac4096319f80615aaef4acbecb35a990afebe953b0e", - "sha256:fdd215b7b7fd4a53994f238d0f46b7ba4ac4c0adb12452beee724ddd0743ae5d", - "sha256:feeb18a801aacb098220e2c3eea59a512362eb408d4afd0c242044c33ad6d542", - "sha256:ff30218887e62209942f91ac1be902cc80cddb86bf00fbc6783b7a43b2bea26f" + "sha256:0605cc2c0088fcaae79f01c913a38611ad09ba68ff482402d3410bf59039bfb8", + "sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c", + "sha256:0cbf56238f4bbf49dab8c2dc2e6b1b68502b1e88d335bea59b3f5b9f4c001475", + "sha256:1732102949ff6087589408d76cd6dea656b93c896b011ecafff418c9661dc4ed", + "sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf", + "sha256:239f975589a944eeb1bad26b8b140a59a3a320067fb3cd10b75c3092405a1372", + "sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81", + "sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f", + "sha256:38d80498e2e169bc61418ff36170e0aad0cd268da8b38a17c4cf29d254a8b3f1", + "sha256:3916c8692dbd9d55c523374a3b8213e628424d19116ac4308e434dbf6d95bbdd", + "sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a", + "sha256:3b7b30258348082826d274504fbc7c849959f1989d86c29bc355107accec6cfb", + "sha256:3fcb4046d2904378e3aeea1df51f697b0467f2aac55d232c87ba162709478c46", + "sha256:4109adee842b90671f1b689901b948f347325045c15f46b39797ae1bf17019de", + "sha256:4558e5012ee03d2638c681e156461d37b7a113fe13970d438d95d10173d25f78", + "sha256:45731330e754f5811c314901cebdf19dd776a44b31927fa4b4dbecab9e457b0c", + "sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771", + "sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb", + "sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430", + "sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233", + "sha256:52c27110f3862a1afbcb2af4281fc9fdc40327fa286c4625dfee247c3ba90156", + "sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9", + "sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59", + "sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888", + "sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c", + "sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c", + "sha256:6380c039ec52866c06d69b5c7aad5478b24ed11696f0e72f6b807cfb261453da", + "sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424", + "sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2", + "sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb", + "sha256:694d828b5c41255e54bc2dddb51a9f5150b4eefa9886e38b52605a05d96566e8", + "sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a", + "sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10", + "sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0", + "sha256:7b179eea70833c8dee51ec42f3b4097bd6370892fa93f510f76762105568cf09", + "sha256:7f64cbd44443e80094309875d4f9c71d0401e966d191c3d469cde4642bc2e031", + "sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4", + "sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3", + "sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa", + "sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a", + "sha256:8b4f72fbb66279624bfe83fd5eb6aea0022dad8eec62b71e7bf63ee1caadeafe", + "sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a", + "sha256:8cf142aa6c1a751fcb364158fd710b8a9be874b81889c2bd13aa8893197455e2", + "sha256:8d1964eb7617907c792ca00b341b5ec3e01ae8c280825deadbbd678447b127e1", + "sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323", + "sha256:9c69e77370cce2d6df5d12b4e12bdcca60c47ba13d1cbbc8645dd005a20b738b", + "sha256:9dbc053ac75ccc63dc3a3cc547b98c7258ec35a215a92bd9f983e0aac95d3d5b", + "sha256:9e3a1ae66e3d0c17cf65c08968a5ee3180c5a95920ec2731f53343fac9bad106", + "sha256:a6ea1a5b409a85477fd8e5ee6ad8f0e40bf2844c270955e09360418cfd09abac", + "sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6", + "sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832", + "sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75", + "sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6", + "sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d", + "sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72", + "sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db", + "sha256:c6021d296318cb6f9414b48e6a439a7f5d1f665464da507e8ff640848ee2a58a", + "sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da", + "sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678", + "sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b", + "sha256:cd2adf5c87ff6d8b277814a28a535b59e20bfea40a101db6b3bdca7e9926bc24", + "sha256:d1469f228cd9ffddd396d9948b8c9cd8022b6d1bf1e40c6f25b0fb90b4f893ed", + "sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f", + "sha256:d5ab8e1f6bee051a4bf6195e38a5c13e5e161cb7bad83d8854524798bd9fcd6e", + "sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58", + "sha256:da22dab31d7180f8c3ac7c7635f3bcd53808f374f6aa333fe0b0b9e14b01f91a", + "sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342", + "sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558", + "sha256:e9a3d838441bebcf5cf442700e3963f58b5c33f015341f9ea86dcd7d503c07e2", + "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551", + "sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595", + "sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee", + "sha256:f3c2890ca8c59ee683fd09adf32321a40fe1cf164e3387799efb2acebf090c11", + "sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d", + "sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7", + "sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f" ], "markers": "python_version >= '3.8'", - "version": "==3.9.3" + "version": "==3.9.5" }, "aiosignal": { "hashes": [ @@ -108,11 +108,11 @@ }, "annotated-types": { "hashes": [ - "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43", - "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d" + "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", + "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" ], "markers": "python_version >= '3.8'", - "version": "==0.6.0" + "version": "==0.7.0" }, "attrs": { "hashes": [ @@ -124,11 +124,11 @@ }, "certifi": { "hashes": [ - "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", - "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" + "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", + "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" ], "markers": "python_version >= '3.6'", - "version": "==2024.2.2" + "version": "==2024.6.2" }, "charset-normalizer": { "hashes": [ @@ -311,11 +311,11 @@ }, "idna": { "hashes": [ - "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", - "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", + "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" ], "markers": "python_version >= '3.5'", - "version": "==3.6" + "version": "==3.7" }, "multidict": { "hashes": [ @@ -457,39 +457,38 @@ }, "pandas": { "hashes": [ - "sha256:04f6ec3baec203c13e3f8b139fb0f9f86cd8c0b94603ae3ae8ce9a422e9f5bee", - "sha256:06cf591dbaefb6da9de8472535b185cba556d0ce2e6ed28e21d919704fef1a9e", - "sha256:0ab90f87093c13f3e8fa45b48ba9f39181046e8f3317d3aadb2fffbb1b978572", - "sha256:0f573ab277252ed9aaf38240f3b54cfc90fff8e5cab70411ee1d03f5d51f3944", - "sha256:101d0eb9c5361aa0146f500773395a03839a5e6ecde4d4b6ced88b7e5a1a6403", - "sha256:11940e9e3056576ac3244baef2fedade891977bcc1cb7e5cc8f8cc7d603edc89", - "sha256:1ba21b1d5c0e43416218db63037dbe1a01fc101dc6e6024bcad08123e48004ab", - "sha256:4aa1d8707812a658debf03824016bf5ea0d516afdea29b7dc14cf687bc4d4ec6", - "sha256:4acf681325ee1c7f950d058b05a820441075b0dd9a2adf5c4835b9bc056bf4fb", - "sha256:53680dc9b2519cbf609c62db3ed7c0b499077c7fefda564e330286e619ff0dd9", - "sha256:739cc70eaf17d57608639e74d63387b0d8594ce02f69e7a0b046f117974b3019", - "sha256:76f27a809cda87e07f192f001d11adc2b930e93a2b0c4a236fde5429527423be", - "sha256:7d2ed41c319c9fb4fd454fe25372028dfa417aacb9790f68171b2e3f06eae8cd", - "sha256:88ecb5c01bb9ca927ebc4098136038519aa5d66b44671861ffab754cae75102c", - "sha256:8df8612be9cd1c7797c93e1c5df861b2ddda0b48b08f2c3eaa0702cf88fb5f88", - "sha256:94e714a1cca63e4f5939cdce5f29ba8d415d85166be3441165edd427dc9f6bc0", - "sha256:9bd8a40f47080825af4317d0340c656744f2bfdb6819f818e6ba3cd24c0e1397", - "sha256:9d1265545f579edf3f8f0cb6f89f234f5e44ba725a34d86535b1a1d38decbccc", - "sha256:a935a90a76c44fe170d01e90a3594beef9e9a6220021acfb26053d01426f7dc2", - "sha256:af5d3c00557d657c8773ef9ee702c61dd13b9d7426794c9dfeb1dc4a0bf0ebc7", - "sha256:c2ce852e1cf2509a69e98358e8458775f89599566ac3775e70419b98615f4b06", - "sha256:c38ce92cb22a4bea4e3929429aa1067a454dcc9c335799af93ba9be21b6beb51", - "sha256:c391f594aae2fd9f679d419e9a4d5ba4bce5bb13f6a989195656e7dc4b95c8f0", - "sha256:c70e00c2d894cb230e5c15e4b1e1e6b2b478e09cf27cc593a11ef955b9ecc81a", - "sha256:df0c37ebd19e11d089ceba66eba59a168242fc6b7155cba4ffffa6eccdfb8f16", - "sha256:e97fbb5387c69209f134893abc788a6486dbf2f9e511070ca05eed4b930b1b02", - "sha256:f02a3a6c83df4026e55b63c1f06476c9aa3ed6af3d89b4f04ea656ccdaaaa359", - "sha256:f821213d48f4ab353d20ebc24e4faf94ba40d76680642fb7ce2ea31a3ad94f9b", - "sha256:f9d3558d263073ed95e46f4650becff0c5e1ffe0fc3a015de3c79283dfbdb3df" + "sha256:001910ad31abc7bf06f49dcc903755d2f7f3a9186c0c040b827e522e9cef0863", + "sha256:0ca6377b8fca51815f382bd0b697a0814c8bda55115678cbc94c30aacbb6eff2", + "sha256:0cace394b6ea70c01ca1595f839cf193df35d1575986e484ad35c4aeae7266c1", + "sha256:1cb51fe389360f3b5a4d57dbd2848a5f033350336ca3b340d1c53a1fad33bcad", + "sha256:2925720037f06e89af896c70bca73459d7e6a4be96f9de79e2d440bd499fe0db", + "sha256:3e374f59e440d4ab45ca2fffde54b81ac3834cf5ae2cdfa69c90bc03bde04d76", + "sha256:40ae1dffb3967a52203105a077415a86044a2bea011b5f321c6aa64b379a3f51", + "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32", + "sha256:4abfe0be0d7221be4f12552995e58723c7422c80a659da13ca382697de830c08", + "sha256:58b84b91b0b9f4bafac2a0ac55002280c094dfc6402402332c0913a59654ab2b", + "sha256:640cef9aa381b60e296db324337a554aeeb883ead99dc8f6c18e81a93942f5f4", + "sha256:66b479b0bd07204e37583c191535505410daa8df638fd8e75ae1b383851fe921", + "sha256:696039430f7a562b74fa45f540aca068ea85fa34c244d0deee539cb6d70aa288", + "sha256:6d2123dc9ad6a814bcdea0f099885276b31b24f7edf40f6cdbc0912672e22eee", + "sha256:8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0", + "sha256:873d13d177501a28b2756375d59816c365e42ed8417b41665f346289adc68d24", + "sha256:8e5a0b00e1e56a842f922e7fae8ae4077aee4af0acb5ae3622bd4b4c30aedf99", + "sha256:8e90497254aacacbc4ea6ae5e7a8cd75629d6ad2b30025a4a8b09aa4faf55151", + "sha256:9057e6aa78a584bc93a13f0a9bf7e753a5e9770a30b4d758b8d5f2a62a9433cd", + "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce", + "sha256:92fd6b027924a7e178ac202cfbe25e53368db90d56872d20ffae94b96c7acc57", + "sha256:9dfde2a0ddef507a631dc9dc4af6a9489d5e2e740e226ad426a05cabfbd7c8ef", + "sha256:9e79019aba43cb4fda9e4d983f8e88ca0373adbb697ae9c6c43093218de28b54", + "sha256:a77e9d1c386196879aa5eb712e77461aaee433e54c68cf253053a73b7e49c33a", + "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238", + "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23", + "sha256:ddf818e4e6c7c6f4f7c8a12709696d193976b591cc7dc50588d3d1a6b5dc8772", + "sha256:e9b79011ff7a0f4b1d6da6a61aa1aa604fb312d6647de5bad20013682d1429ce", + "sha256:eee3a87076c0756de40b05c5e9a6069c035ba43e8dd71c379e68cab2c20f16ad" ], "index": "pypi", - "markers": "python_version >= '3.9'", - "version": "==2.2.1" + "version": "==2.2.2" }, "pika": { "hashes": [ @@ -497,102 +496,100 @@ "sha256:b2a327ddddf8570b4965b3576ac77091b850262d34ce8c1d8cb4e4146aa4145f" ], "index": "pypi", - "markers": "python_version >= '3.7'", "version": "==1.3.2" }, "pydantic": { "hashes": [ - "sha256:b1704e0847db01817624a6b86766967f552dd9dbf3afba4004409f908dcc84e6", - "sha256:cc46fce86607580867bdc3361ad462bab9c222ef042d3da86f2fb333e1d916c5" + "sha256:c46c76a40bb1296728d7a8b99aa73dd70a48c3510111ff290034f860c99c419e", + "sha256:ea91b002777bf643bb20dd717c028ec43216b24a6001a280f83877fd2655d0b4" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==2.6.4" + "version": "==2.7.3" }, "pydantic-core": { "hashes": [ - "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a", - "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed", - "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979", - "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff", - "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5", - "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45", - "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340", - "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad", - "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23", - "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6", - "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7", - "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241", - "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda", - "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187", - "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba", - "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c", - "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2", - "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c", - "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132", - "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf", - "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972", - "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db", - "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade", - "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4", - "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8", - "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f", - "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9", - "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48", - "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec", - "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d", - "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9", - "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb", - "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4", - "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89", - "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c", - "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9", - "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da", - "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac", - "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b", - "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf", - "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e", - "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137", - "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1", - "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b", - "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8", - "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e", - "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053", - "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01", - "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe", - "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd", - "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805", - "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183", - "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8", - "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99", - "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820", - "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074", - "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256", - "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8", - "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975", - "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad", - "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e", - "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca", - "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df", - "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b", - "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a", - "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a", - "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721", - "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a", - "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f", - "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2", - "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97", - "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6", - "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed", - "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc", - "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1", - "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe", - "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120", - "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f", - "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a" + "sha256:01dd777215e2aa86dfd664daed5957704b769e726626393438f9c87690ce78c3", + "sha256:0eb2a4f660fcd8e2b1c90ad566db2b98d7f3f4717c64fe0a83e0adb39766d5b8", + "sha256:0fbbdc827fe5e42e4d196c746b890b3d72876bdbf160b0eafe9f0334525119c8", + "sha256:123c3cec203e3f5ac7b000bd82235f1a3eced8665b63d18be751f115588fea30", + "sha256:14601cdb733d741b8958224030e2bfe21a4a881fb3dd6fbb21f071cabd48fa0a", + "sha256:18f469a3d2a2fdafe99296a87e8a4c37748b5080a26b806a707f25a902c040a8", + "sha256:19894b95aacfa98e7cb093cd7881a0c76f55731efad31073db4521e2b6ff5b7d", + "sha256:1b4de2e51bbcb61fdebd0ab86ef28062704f62c82bbf4addc4e37fa4b00b7cbc", + "sha256:1d886dc848e60cb7666f771e406acae54ab279b9f1e4143babc9c2258213daa2", + "sha256:1f4d26ceb5eb9eed4af91bebeae4b06c3fb28966ca3a8fb765208cf6b51102ab", + "sha256:21a5e440dbe315ab9825fcd459b8814bb92b27c974cbc23c3e8baa2b76890077", + "sha256:293afe532740370aba8c060882f7d26cfd00c94cae32fd2e212a3a6e3b7bc15e", + "sha256:2f5966897e5461f818e136b8451d0551a2e77259eb0f73a837027b47dc95dab9", + "sha256:2fd41f6eff4c20778d717af1cc50eca52f5afe7805ee530a4fbd0bae284f16e9", + "sha256:2fdf2156aa3d017fddf8aea5adfba9f777db1d6022d392b682d2a8329e087cef", + "sha256:3c40d4eaad41f78e3bbda31b89edc46a3f3dc6e171bf0ecf097ff7a0ffff7cb1", + "sha256:43d447dd2ae072a0065389092a231283f62d960030ecd27565672bd40746c507", + "sha256:44a688331d4a4e2129140a8118479443bd6f1905231138971372fcde37e43528", + "sha256:44c7486a4228413c317952e9d89598bcdfb06399735e49e0f8df643e1ccd0558", + "sha256:44cd83ab6a51da80fb5adbd9560e26018e2ac7826f9626bc06ca3dc074cd198b", + "sha256:46387e38bd641b3ee5ce247563b60c5ca098da9c56c75c157a05eaa0933ed154", + "sha256:4701b19f7e3a06ea655513f7938de6f108123bf7c86bbebb1196eb9bd35cf724", + "sha256:4748321b5078216070b151d5271ef3e7cc905ab170bbfd27d5c83ee3ec436695", + "sha256:4b06beb3b3f1479d32befd1f3079cc47b34fa2da62457cdf6c963393340b56e9", + "sha256:4d0dcc59664fcb8974b356fe0a18a672d6d7cf9f54746c05f43275fc48636851", + "sha256:4e99bc050fe65c450344421017f98298a97cefc18c53bb2f7b3531eb39bc7805", + "sha256:509daade3b8649f80d4e5ff21aa5673e4ebe58590b25fe42fac5f0f52c6f034a", + "sha256:51991a89639a912c17bef4b45c87bd83593aee0437d8102556af4885811d59f5", + "sha256:53db086f9f6ab2b4061958d9c276d1dbe3690e8dd727d6abf2321d6cce37fa94", + "sha256:564d7922e4b13a16b98772441879fcdcbe82ff50daa622d681dd682175ea918c", + "sha256:574d92eac874f7f4db0ca653514d823a0d22e2354359d0759e3f6a406db5d55d", + "sha256:578e24f761f3b425834f297b9935e1ce2e30f51400964ce4801002435a1b41ef", + "sha256:59ff3e89f4eaf14050c8022011862df275b552caef8082e37b542b066ce1ff26", + "sha256:5f09baa656c904807e832cf9cce799c6460c450c4ad80803517032da0cd062e2", + "sha256:6891a2ae0e8692679c07728819b6e2b822fb30ca7445f67bbf6509b25a96332c", + "sha256:6a750aec7bf431517a9fd78cb93c97b9b0c496090fee84a47a0d23668976b4b0", + "sha256:6f5c4d41b2771c730ea1c34e458e781b18cc668d194958e0112455fff4e402b2", + "sha256:77450e6d20016ec41f43ca4a6c63e9fdde03f0ae3fe90e7c27bdbeaece8b1ed4", + "sha256:81b5efb2f126454586d0f40c4d834010979cb80785173d1586df845a632e4e6d", + "sha256:823be1deb01793da05ecb0484d6c9e20baebb39bd42b5d72636ae9cf8350dbd2", + "sha256:834b5230b5dfc0c1ec37b2fda433b271cbbc0e507560b5d1588e2cc1148cf1ce", + "sha256:847a35c4d58721c5dc3dba599878ebbdfd96784f3fb8bb2c356e123bdcd73f34", + "sha256:86110d7e1907ab36691f80b33eb2da87d780f4739ae773e5fc83fb272f88825f", + "sha256:8951eee36c57cd128f779e641e21eb40bc5073eb28b2d23f33eb0ef14ffb3f5d", + "sha256:8a7164fe2005d03c64fd3b85649891cd4953a8de53107940bf272500ba8a788b", + "sha256:8b8bab4c97248095ae0c4455b5a1cd1cdd96e4e4769306ab19dda135ea4cdb07", + "sha256:90afc12421df2b1b4dcc975f814e21bc1754640d502a2fbcc6d41e77af5ec312", + "sha256:938cb21650855054dc54dfd9120a851c974f95450f00683399006aa6e8abb057", + "sha256:942ba11e7dfb66dc70f9ae66b33452f51ac7bb90676da39a7345e99ffb55402d", + "sha256:972658f4a72d02b8abfa2581d92d59f59897d2e9f7e708fdabe922f9087773af", + "sha256:97736815b9cc893b2b7f663628e63f436018b75f44854c8027040e05230eeddb", + "sha256:98906207f29bc2c459ff64fa007afd10a8c8ac080f7e4d5beff4c97086a3dabd", + "sha256:99457f184ad90235cfe8461c4d70ab7dd2680e28821c29eca00252ba90308c78", + "sha256:a0d829524aaefdebccb869eed855e2d04c21d2d7479b6cada7ace5448416597b", + "sha256:a2fdd81edd64342c85ac7cf2753ccae0b79bf2dfa063785503cb85a7d3593223", + "sha256:a55b5b16c839df1070bc113c1f7f94a0af4433fcfa1b41799ce7606e5c79ce0a", + "sha256:a642295cd0c8df1b86fc3dced1d067874c353a188dc8e0f744626d49e9aa51c4", + "sha256:ab86ce7c8f9bea87b9d12c7f0af71102acbf5ecbc66c17796cff45dae54ef9a5", + "sha256:abc267fa9837245cc28ea6929f19fa335f3dc330a35d2e45509b6566dc18be23", + "sha256:ae1d6df168efb88d7d522664693607b80b4080be6750c913eefb77e34c12c71a", + "sha256:b2ebef0e0b4454320274f5e83a41844c63438fdc874ea40a8b5b4ecb7693f1c4", + "sha256:b48ece5bde2e768197a2d0f6e925f9d7e3e826f0ad2271120f8144a9db18d5c8", + "sha256:b7cdf28938ac6b8b49ae5e92f2735056a7ba99c9b110a474473fd71185c1af5d", + "sha256:bb4462bd43c2460774914b8525f79b00f8f407c945d50881568f294c1d9b4443", + "sha256:bc4ff9805858bd54d1a20efff925ccd89c9d2e7cf4986144b30802bf78091c3e", + "sha256:c1322d7dd74713dcc157a2b7898a564ab091ca6c58302d5c7b4c07296e3fd00f", + "sha256:c67598100338d5d985db1b3d21f3619ef392e185e71b8d52bceacc4a7771ea7e", + "sha256:ca26a1e73c48cfc54c4a76ff78df3727b9d9f4ccc8dbee4ae3f73306a591676d", + "sha256:d323a01da91851a4f17bf592faf46149c9169d68430b3146dcba2bb5e5719abc", + "sha256:dc1803ac5c32ec324c5261c7209e8f8ce88e83254c4e1aebdc8b0a39f9ddb443", + "sha256:e00a3f196329e08e43d99b79b286d60ce46bed10f2280d25a1718399457e06be", + "sha256:e85637bc8fe81ddb73fda9e56bab24560bdddfa98aa64f87aaa4e4b6730c23d2", + "sha256:e858ac0a25074ba4bce653f9b5d0a85b7456eaddadc0ce82d3878c22489fa4ee", + "sha256:eae237477a873ab46e8dd748e515c72c0c804fb380fbe6c85533c7de51f23a8f", + "sha256:ebef0dd9bf9b812bf75bda96743f2a6c5734a02092ae7f721c048d156d5fabae", + "sha256:ec3beeada09ff865c344ff3bc2f427f5e6c26401cc6113d77e372c3fdac73864", + "sha256:f76d0ad001edd426b92233d45c746fd08f467d56100fd8f30e9ace4b005266e4", + "sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951", + "sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc" ], "markers": "python_version >= '3.8'", - "version": "==2.16.3" + "version": "==2.18.4" }, "python-dateutil": { "hashes": [ @@ -611,12 +608,11 @@ }, "requests": { "hashes": [ - "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", - "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==2.31.0" + "version": "==2.32.3" }, "six": { "hashes": [ @@ -640,16 +636,15 @@ "sha256:024d3d1745120098a85635e42242039ca6b1bc787f561ec974fffb45fc775c1b" ], "index": "pypi", - "markers": "python_full_version >= '3.5.3'", "version": "==1.0.3" }, "typing-extensions": { "hashes": [ - "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", - "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" + "sha256:6024b58b69089e5a89c347397254e35f1bf02a907728ec7fee9bf0fe837d203a", + "sha256:915f5e35ff76f56588223f15fdd5938f9a1cf9195c0de25130c627e4d597f6d1" ], "markers": "python_version >= '3.8'", - "version": "==4.11.0" + "version": "==4.12.1" }, "tzdata": { "hashes": [ @@ -775,19 +770,19 @@ }, "babel": { "hashes": [ - "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363", - "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287" + "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb", + "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413" ], - "markers": "python_version >= '3.7'", - "version": "==2.14.0" + "markers": "python_version >= '3.8'", + "version": "==2.15.0" }, "backports.tarfile": { "hashes": [ - "sha256:2688f159c21afd56a07b75f01306f9f52c79aebcc5f4a117fb8fbb4445352c75", - "sha256:bcd36290d9684beb524d3fe74f4a2db056824c47746583f090b8e55daf0776e4" + "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34", + "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991" ], "markers": "python_version < '3.12'", - "version": "==1.0.0" + "version": "==1.2.0" }, "beautifulsoup4": { "hashes": [ @@ -803,16 +798,15 @@ "sha256:75e10f767a433d9a86e50d83f418e83efc18ede923ee5ff7df93b6cb0306c5d4" ], "index": "pypi", - "markers": "python_version >= '3.8'", "version": "==1.2.1" }, "certifi": { "hashes": [ - "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", - "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" + "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", + "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" ], "markers": "python_version >= '3.6'", - "version": "==2024.2.2" + "version": "==2024.6.2" }, "cffi": { "hashes": [ @@ -970,125 +964,123 @@ }, "coverage": { "hashes": [ - "sha256:00838a35b882694afda09f85e469c96367daa3f3f2b097d846a7216993d37f4c", - "sha256:0513b9508b93da4e1716744ef6ebc507aff016ba115ffe8ecff744d1322a7b63", - "sha256:09c3255458533cb76ef55da8cc49ffab9e33f083739c8bd4f58e79fecfe288f7", - "sha256:09ef9199ed6653989ebbcaacc9b62b514bb63ea2f90256e71fea3ed74bd8ff6f", - "sha256:09fa497a8ab37784fbb20ab699c246053ac294d13fc7eb40ec007a5043ec91f8", - "sha256:0f9f50e7ef2a71e2fae92774c99170eb8304e3fdf9c8c3c7ae9bab3e7229c5cf", - "sha256:137eb07173141545e07403cca94ab625cc1cc6bc4c1e97b6e3846270e7e1fea0", - "sha256:1f384c3cc76aeedce208643697fb3e8437604b512255de6d18dae3f27655a384", - "sha256:201bef2eea65e0e9c56343115ba3814e896afe6d36ffd37bab783261db430f76", - "sha256:38dd60d7bf242c4ed5b38e094baf6401faa114fc09e9e6632374388a404f98e7", - "sha256:3b799445b9f7ee8bf299cfaed6f5b226c0037b74886a4e11515e569b36fe310d", - "sha256:3ea79bb50e805cd6ac058dfa3b5c8f6c040cb87fe83de10845857f5535d1db70", - "sha256:40209e141059b9370a2657c9b15607815359ab3ef9918f0196b6fccce8d3230f", - "sha256:41c9c5f3de16b903b610d09650e5e27adbfa7f500302718c9ffd1c12cf9d6818", - "sha256:54eb8d1bf7cacfbf2a3186019bcf01d11c666bd495ed18717162f7eb1e9dd00b", - "sha256:598825b51b81c808cb6f078dcb972f96af96b078faa47af7dfcdf282835baa8d", - "sha256:5fc1de20b2d4a061b3df27ab9b7c7111e9a710f10dc2b84d33a4ab25065994ec", - "sha256:623512f8ba53c422fcfb2ce68362c97945095b864cda94a92edbaf5994201083", - "sha256:690db6517f09336559dc0b5f55342df62370a48f5469fabf502db2c6d1cffcd2", - "sha256:69eb372f7e2ece89f14751fbcbe470295d73ed41ecd37ca36ed2eb47512a6ab9", - "sha256:73bfb9c09951125d06ee473bed216e2c3742f530fc5acc1383883125de76d9cd", - "sha256:742a76a12aa45b44d236815d282b03cfb1de3b4323f3e4ec933acfae08e54ade", - "sha256:7c95949560050d04d46b919301826525597f07b33beba6187d04fa64d47ac82e", - "sha256:8130a2aa2acb8788e0b56938786c33c7c98562697bf9f4c7d6e8e5e3a0501e4a", - "sha256:8a2b2b78c78293782fd3767d53e6474582f62443d0504b1554370bde86cc8227", - "sha256:8ce1415194b4a6bd0cdcc3a1dfbf58b63f910dcb7330fe15bdff542c56949f87", - "sha256:9ca28a302acb19b6af89e90f33ee3e1906961f94b54ea37de6737b7ca9d8827c", - "sha256:a4cdc86d54b5da0df6d3d3a2f0b710949286094c3a6700c21e9015932b81447e", - "sha256:aa5b1c1bfc28384f1f53b69a023d789f72b2e0ab1b3787aae16992a7ca21056c", - "sha256:aadacf9a2f407a4688d700e4ebab33a7e2e408f2ca04dbf4aef17585389eff3e", - "sha256:ae71e7ddb7a413dd60052e90528f2f65270aad4b509563af6d03d53e979feafd", - "sha256:b14706df8b2de49869ae03a5ccbc211f4041750cd4a66f698df89d44f4bd30ec", - "sha256:b1a93009cb80730c9bca5d6d4665494b725b6e8e157c1cb7f2db5b4b122ea562", - "sha256:b2991665420a803495e0b90a79233c1433d6ed77ef282e8e152a324bbbc5e0c8", - "sha256:b2c5edc4ac10a7ef6605a966c58929ec6c1bd0917fb8c15cb3363f65aa40e677", - "sha256:b4d33f418f46362995f1e9d4f3a35a1b6322cb959c31d88ae56b0298e1c22357", - "sha256:b91cbc4b195444e7e258ba27ac33769c41b94967919f10037e6355e998af255c", - "sha256:c74880fc64d4958159fbd537a091d2a585448a8f8508bf248d72112723974cbd", - "sha256:c901df83d097649e257e803be22592aedfd5182f07b3cc87d640bbb9afd50f49", - "sha256:cac99918c7bba15302a2d81f0312c08054a3359eaa1929c7e4b26ebe41e9b286", - "sha256:cc4f1358cb0c78edef3ed237ef2c86056206bb8d9140e73b6b89fbcfcbdd40e1", - "sha256:ccd341521be3d1b3daeb41960ae94a5e87abe2f46f17224ba5d6f2b8398016cf", - "sha256:ce4b94265ca988c3f8e479e741693d143026632672e3ff924f25fab50518dd51", - "sha256:cf271892d13e43bc2b51e6908ec9a6a5094a4df1d8af0bfc360088ee6c684409", - "sha256:d5ae728ff3b5401cc320d792866987e7e7e880e6ebd24433b70a33b643bb0384", - "sha256:d71eec7d83298f1af3326ce0ff1d0ea83c7cb98f72b577097f9083b20bdaf05e", - "sha256:d898fe162d26929b5960e4e138651f7427048e72c853607f2b200909794ed978", - "sha256:d89d7b2974cae412400e88f35d86af72208e1ede1a541954af5d944a8ba46c57", - "sha256:dfa8fe35a0bb90382837b238fff375de15f0dcdb9ae68ff85f7a63649c98527e", - "sha256:e0be5efd5127542ef31f165de269f77560d6cdef525fffa446de6f7e9186cfb2", - "sha256:fdfafb32984684eb03c2d83e1e51f64f0906b11e64482df3c5db936ce3839d48", - "sha256:ff7687ca3d7028d8a5f0ebae95a6e4827c5616b31a4ee1192bdfde697db110d4" + "sha256:015eddc5ccd5364dcb902eaecf9515636806fa1e0d5bef5769d06d0f31b54523", + "sha256:04aefca5190d1dc7a53a4c1a5a7f8568811306d7a8ee231c42fb69215571944f", + "sha256:05ac5f60faa0c704c0f7e6a5cbfd6f02101ed05e0aee4d2822637a9e672c998d", + "sha256:0bbddc54bbacfc09b3edaec644d4ac90c08ee8ed4844b0f86227dcda2d428fcb", + "sha256:1d2a830ade66d3563bb61d1e3c77c8def97b30ed91e166c67d0632c018f380f0", + "sha256:239a4e75e09c2b12ea478d28815acf83334d32e722e7433471fbf641c606344c", + "sha256:244f509f126dc71369393ce5fea17c0592c40ee44e607b6d855e9c4ac57aac98", + "sha256:25a5caf742c6195e08002d3b6c2dd6947e50efc5fc2c2205f61ecb47592d2d83", + "sha256:296a7d9bbc598e8744c00f7a6cecf1da9b30ae9ad51c566291ff1314e6cbbed8", + "sha256:2e079c9ec772fedbade9d7ebc36202a1d9ef7291bc9b3a024ca395c4d52853d7", + "sha256:33ca90a0eb29225f195e30684ba4a6db05dbef03c2ccd50b9077714c48153cac", + "sha256:33fc65740267222fc02975c061eb7167185fef4cc8f2770267ee8bf7d6a42f84", + "sha256:341dd8f61c26337c37988345ca5c8ccabeff33093a26953a1ac72e7d0103c4fb", + "sha256:34d6d21d8795a97b14d503dcaf74226ae51eb1f2bd41015d3ef332a24d0a17b3", + "sha256:3538d8fb1ee9bdd2e2692b3b18c22bb1c19ffbefd06880f5ac496e42d7bb3884", + "sha256:38a3b98dae8a7c9057bd91fbf3415c05e700a5114c5f1b5b0ea5f8f429ba6614", + "sha256:3d5a67f0da401e105753d474369ab034c7bae51a4c31c77d94030d59e41df5bd", + "sha256:50084d3516aa263791198913a17354bd1dc627d3c1639209640b9cac3fef5807", + "sha256:55f689f846661e3f26efa535071775d0483388a1ccfab899df72924805e9e7cd", + "sha256:5bc5a8c87714b0c67cfeb4c7caa82b2d71e8864d1a46aa990b5588fa953673b8", + "sha256:62bda40da1e68898186f274f832ef3e759ce929da9a9fd9fcf265956de269dbc", + "sha256:705f3d7c2b098c40f5b81790a5fedb274113373d4d1a69e65f8b68b0cc26f6db", + "sha256:75e3f4e86804023e991096b29e147e635f5e2568f77883a1e6eed74512659ab0", + "sha256:7b2a19e13dfb5c8e145c7a6ea959485ee8e2204699903c88c7d25283584bfc08", + "sha256:7cec2af81f9e7569280822be68bd57e51b86d42e59ea30d10ebdbb22d2cb7232", + "sha256:8383a6c8cefba1b7cecc0149415046b6fc38836295bc4c84e820872eb5478b3d", + "sha256:8c836309931839cca658a78a888dab9676b5c988d0dd34ca247f5f3e679f4e7a", + "sha256:8e317953bb4c074c06c798a11dbdd2cf9979dbcaa8ccc0fa4701d80042d4ebf1", + "sha256:923b7b1c717bd0f0f92d862d1ff51d9b2b55dbbd133e05680204465f454bb286", + "sha256:990fb20b32990b2ce2c5f974c3e738c9358b2735bc05075d50a6f36721b8f303", + "sha256:9aad68c3f2566dfae84bf46295a79e79d904e1c21ccfc66de88cd446f8686341", + "sha256:a5812840d1d00eafae6585aba38021f90a705a25b8216ec7f66aebe5b619fb84", + "sha256:a6519d917abb15e12380406d721e37613e2a67d166f9fb7e5a8ce0375744cd45", + "sha256:ab0b028165eea880af12f66086694768f2c3139b2c31ad5e032c8edbafca6ffc", + "sha256:aea7da970f1feccf48be7335f8b2ca64baf9b589d79e05b9397a06696ce1a1ec", + "sha256:b1196e13c45e327d6cd0b6e471530a1882f1017eb83c6229fc613cd1a11b53cd", + "sha256:b368e1aee1b9b75757942d44d7598dcd22a9dbb126affcbba82d15917f0cc155", + "sha256:bde997cac85fcac227b27d4fb2c7608a2c5f6558469b0eb704c5726ae49e1c52", + "sha256:c4c2872b3c91f9baa836147ca33650dc5c172e9273c808c3c3199c75490e709d", + "sha256:c59d2ad092dc0551d9f79d9d44d005c945ba95832a6798f98f9216ede3d5f485", + "sha256:d1da0a2e3b37b745a2b2a678a4c796462cf753aebf94edcc87dcc6b8641eae31", + "sha256:d8b7339180d00de83e930358223c617cc343dd08e1aa5ec7b06c3a121aec4e1d", + "sha256:dd4b3355b01273a56b20c219e74e7549e14370b31a4ffe42706a8cda91f19f6d", + "sha256:e08c470c2eb01977d221fd87495b44867a56d4d594f43739a8028f8646a51e0d", + "sha256:f5102a92855d518b0996eb197772f5ac2a527c0ec617124ad5242a3af5e25f85", + "sha256:f542287b1489c7a860d43a7d8883e27ca62ab84ca53c965d11dac1d3a1fab7ce", + "sha256:f78300789a708ac1f17e134593f577407d52d0417305435b134805c4fb135adb", + "sha256:f81bc26d609bf0fbc622c7122ba6307993c83c795d2d6f6f6fd8c000a770d974", + "sha256:f836c174c3a7f639bded48ec913f348c4761cbf49de4a20a956d3431a7c9cb24", + "sha256:fa21a04112c59ad54f69d80e376f7f9d0f5f9123ab87ecd18fbb9ec3a2beed56", + "sha256:fcf7d1d6f5da887ca04302db8e0e0cf56ce9a5e05f202720e49b3e8157ddb9a9", + "sha256:fd27d8b49e574e50caa65196d908f80e4dff64d7e592d0c59788b45aad7e8b35" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==7.4.4" + "version": "==7.5.3" }, "cryptography": { "hashes": [ - "sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee", - "sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576", - "sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d", - "sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30", - "sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413", - "sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb", - "sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da", - "sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4", - "sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd", - "sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc", - "sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8", - "sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1", - "sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc", - "sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e", - "sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8", - "sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940", - "sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400", - "sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7", - "sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16", - "sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278", - "sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74", - "sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec", - "sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1", - "sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2", - "sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c", - "sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922", - "sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a", - "sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6", - "sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1", - "sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e", - "sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac", - "sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7" + "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad", + "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583", + "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b", + "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c", + "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1", + "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648", + "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949", + "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba", + "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c", + "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9", + "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d", + "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c", + "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e", + "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2", + "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d", + "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7", + "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70", + "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2", + "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7", + "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14", + "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe", + "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e", + "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71", + "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961", + "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7", + "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c", + "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28", + "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842", + "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902", + "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801", + "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a", + "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e" ], "markers": "python_version >= '3.7'", - "version": "==42.0.5" + "version": "==42.0.8" }, "docutils": { "hashes": [ - "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6", - "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b" + "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", + "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2" ], - "markers": "python_version >= '3.7'", - "version": "==0.20.1" + "markers": "python_version >= '3.9'", + "version": "==0.21.2" }, "furo": { "hashes": [ - "sha256:3548be2cef45a32f8cdc0272d415fcb3e5fa6a0eb4ddfe21df3ecf1fe45a13cf", - "sha256:4d6b2fe3f10a6e36eb9cc24c1e7beb38d7a23fc7b3c382867503b7fcac8a1e02" + "sha256:490a00d08c0a37ecc90de03ae9227e8eb5d6f7f750edf9807f398a2bdf2358de", + "sha256:81f205a6605ebccbb883350432b4831c0196dd3d1bc92f61e1f459045b3d2b0b" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==2024.1.29" + "version": "==2024.5.6" }, "idna": { "hashes": [ - "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", - "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", + "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" ], "markers": "python_version >= '3.5'", - "version": "==3.6" + "version": "==3.7" }, "imagesize": { "hashes": [ @@ -1132,11 +1124,11 @@ }, "jaraco.functools": { "hashes": [ - "sha256:c279cb24c93d694ef7270f970d499cab4d3813f4e08273f95398651a634f0925", - "sha256:daf276ddf234bea897ef14f43c4e1bf9eefeac7b7a82a4dd69228ac20acff68d" + "sha256:3b24ccb921d6b593bdceb56ce14799204f473976e2a9d4b15b04d0f2c2326664", + "sha256:d33fa765374c0611b52f8b3a795f8900869aa88c84769d4d1746cd68fb28c3e8" ], "markers": "python_version >= '3.8'", - "version": "==4.0.0" + "version": "==4.0.1" }, "jeepney": { "hashes": [ @@ -1148,19 +1140,19 @@ }, "jinja2": { "hashes": [ - "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa", - "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90" + "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", + "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d" ], "markers": "python_version >= '3.7'", - "version": "==3.1.3" + "version": "==3.1.4" }, "keyring": { "hashes": [ - "sha256:26fc12e6a329d61d24aa47b22a7c5c3f35753df7d8f2860973cf94f4e1fb3427", - "sha256:7230ea690525133f6ad536a9b5def74a4bd52642abe594761028fc044d7c7893" + "sha256:2458681cdefc0dbc0b7eb6cf75d0b98e59f9ad9b2d4edd319d18f68bdca95e50", + "sha256:daaffd42dbda25ddafb1ad5fec4024e5bbcfe424597ca1ca452b299861e49f1b" ], "markers": "python_version >= '3.8'", - "version": "==25.1.0" + "version": "==25.2.1" }, "markdown-it-py": { "hashes": [ @@ -1283,19 +1275,19 @@ }, "pkginfo": { "hashes": [ - "sha256:5df73835398d10db79f8eecd5cd86b1f6d29317589ea70796994d49399af6297", - "sha256:889a6da2ed7ffc58ab5b900d888ddce90bce912f2d2de1dc1c26f4cb9fe65097" + "sha256:6d4998d1cd42c297af72cc0eab5f5bab1d356fb8a55b828fa914173f8bc1ba05", + "sha256:dba885aa82e31e80d615119874384923f4e011c2a39b0c4b7104359e36cb7087" ], - "markers": "python_version >= '3.6'", - "version": "==1.10.0" + "markers": "python_version >= '3.8'", + "version": "==1.11.0" }, "pluggy": { "hashes": [ - "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981", - "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be" + "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", + "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" ], "markers": "python_version >= '3.8'", - "version": "==1.4.0" + "version": "==1.5.0" }, "pycparser": { "hashes": [ @@ -1307,28 +1299,27 @@ }, "pygments": { "hashes": [ - "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c", - "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367" + "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", + "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a" ], - "markers": "python_version >= '3.7'", - "version": "==2.17.2" + "markers": "python_version >= '3.8'", + "version": "==2.18.0" }, "pyproject-hooks": { "hashes": [ - "sha256:283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8", - "sha256:f271b298b97f5955d53fb12b72c1fb1948c22c1a6b70b315c54cedaca0264ef5" + "sha256:4b37730834edbd6bd37f26ece6b44802fb1c1ee2ece0e54ddff8bfc06db86965", + "sha256:7ceeefe9aec63a1064c18d939bdc3adf2d8aa1988a510afec15151578b232aa2" ], "markers": "python_version >= '3.7'", - "version": "==1.0.0" + "version": "==1.1.0" }, "pytest": { "hashes": [ - "sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7", - "sha256:ac978141a75948948817d360297b7aae0fcb9d6ff6bc9ec6d514b85d5a65c044" + "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343", + "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==8.1.1" + "version": "==8.2.2" }, "readme-renderer": { "hashes": [ @@ -1340,12 +1331,11 @@ }, "requests": { "hashes": [ - "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", - "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==2.31.0" + "version": "==2.32.3" }, "requests-mock": { "hashes": [ @@ -1353,7 +1343,6 @@ "sha256:e9e12e333b525156e82a3c852f22016b9158220d2f47454de9cae8a77d371401" ], "index": "pypi", - "markers": "python_version >= '3.5'", "version": "==1.12.1" }, "requests-toolbelt": { @@ -1390,12 +1379,11 @@ }, "setuptools": { "hashes": [ - "sha256:0ff4183f8f42cd8fa3acea16c45205521a4ef28f73c6391d8a25e92893134f2e", - "sha256:c21c49fb1042386df081cb5d86759792ab89efca84cf114889191cd09aacc80c" + "sha256:54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4", + "sha256:f211a66637b8fa059bb28183da127d4e86396c991a942b028c6650d4319c3fd0" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==69.2.0" + "version": "==70.0.0" }, "snowballstemmer": { "hashes": [ @@ -1414,11 +1402,11 @@ }, "sphinx": { "hashes": [ - "sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560", - "sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5" + "sha256:413f75440be4cacf328f580b4274ada4565fb2187d696a84970c23f77b64d8c3", + "sha256:a4a7db75ed37531c05002d56ed6948d4c42f473a36f46e1382b0bd76ca9627bc" ], "markers": "python_version >= '3.9'", - "version": "==7.2.6" + "version": "==7.3.7" }, "sphinx-basic-ng": { "hashes": [ @@ -1478,12 +1466,11 @@ }, "twine": { "hashes": [ - "sha256:89b0cc7d370a4b66421cc6102f269aa910fe0f1861c124f573cf2ddedbc10cf4", - "sha256:a262933de0b484c53408f9edae2e7821c1c45a3314ff2df9bdd343aa7ab8edc0" + "sha256:4d74770c88c4fcaf8134d2a6a9d863e40f08255ff7d8e2acb3cbbd57d25f6e9d", + "sha256:fe1d814395bfe50cfbe27783cb74efe93abeac3f66deaeb6c8390e4e92bacb43" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==5.0.0" + "version": "==5.1.0" }, "urllib3": { "hashes": [ @@ -1495,11 +1482,11 @@ }, "zipp": { "hashes": [ - "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b", - "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715" + "sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19", + "sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c" ], "markers": "python_version >= '3.8'", - "version": "==3.18.1" + "version": "==3.19.2" } } } diff --git a/lib/python/dbrepo/RestClient.py b/lib/python/dbrepo/RestClient.py index 25f20858a97ef379bdedfa9ccda41f8b566d9560..0a03fd669bd8b8a2834b42fb59b8456a4b7edabf 100644 --- a/lib/python/dbrepo/RestClient.py +++ b/lib/python/dbrepo/RestClient.py @@ -48,7 +48,7 @@ class RestClient: def _wrapper(self, method: str, url: str, params: [(str,)] = None, payload=None, headers: dict = None, force_auth: bool = False, stream: bool = False) -> requests.Response: - if force_auth and (self.username is None or self.password is None): + if force_auth and (self.username is None and self.password is None): raise AuthenticationError(f"Failed to perform request: authentication required") url = f'{self.endpoint}{url}' logging.debug(f'method: {method}') @@ -60,15 +60,20 @@ class RestClient: logging.debug(f'secure: {self.secure}') if headers is not None: logging.debug(f'headers: {headers}') + else: + headers = dict() + logging.debug(f'no headers set') if payload is not None: - logging.debug(f'payload: {payload}') - payload = payload.model_dump_json() - if self.username is not None and self.password is not None: - logging.debug(f'username: {self.username}, password: (hidden)') - return requests.request(method=method, url=url, auth=(self.username, self.password), verify=self.secure, - json=payload, headers=headers, params=params, stream=stream) - return requests.request(method=method, url=url, verify=self.secure, json=payload, headers=headers, - params=params, stream=stream) + payload = payload.model_dump() + auth = None + if self.username is None and self.password is not None: + headers["Authorization"] = f"Bearer {self.password}" + logging.debug(f'configured for oidc/bearer auth') + elif self.username is not None and self.password is not None: + auth = (self.username, self.password) + logging.debug(f'configured for basic auth: username={self.username}, password=(hidden)') + return requests.request(method=method, url=url, auth=auth, verify=self.secure, + json=payload, headers=headers, params=params, stream=stream) def upload(self, file_path: str) -> str: """ @@ -86,6 +91,31 @@ class RestClient: raise UploadError(f'Failed to upload the file to {self.endpoint}') return filename + def get_jwt_auth(self, username: str = None, password: str = None) -> JwtAuth: + """ + Obtains a JWT auth object from the Auth Service containing e.g. the access token and refresh token. + + :param username: The username used to authenticate with the Auth Service. Optional. Default: username from the `RestClient` constructor. + :param password: The password used to authenticate with the Auth Service. Optional. Default: password from the `RestClient` constructor. + + :returns: JWT auth object from the Auth Service, if successful. + + :raises ForbiddenError: If something went wrong with the authentication. + :raises ResponseCodeError: If something went wrong with the authentication. + """ + if username is None: + username = self.username + if password is None: + password = self.password + url = f'{self.endpoint}/api/user/token' + response = requests.post(url=url, json=dict({"username": username, "password": password})) + if response.status_code == 202: + body = response.json() + return JwtAuth.model_validate(body) + if response.status_code == 403: + raise ForbiddenError(f'Failed to get JWT auth') + raise ResponseCodeError(f'Failed to get JWT auth: response code: {response.status_code} is not 202 (ACCEPTED)') + def whoami(self) -> str | None: """ Print the username. @@ -98,7 +128,7 @@ class RestClient: logging.info(f"No username set!") return None - def get_users(self) -> List[User]: + def get_users(self) -> List[UserBrief]: """ Get all users. @@ -110,7 +140,7 @@ class RestClient: response = self._wrapper(method="get", url=url) if response.status_code == 200: body = response.json() - return TypeAdapter(List[User]).validate_python(body) + return TypeAdapter(List[UserBrief]).validate_python(body) raise ResponseCodeError(f'Failed to find users: response code: {response.status_code} is not 200 (OK)') def get_user(self, user_id: str) -> User: @@ -165,12 +195,14 @@ class RestClient: raise ResponseCodeError( f'Failed to create user: response code: {response.status_code} is not 201 (CREATED)') - def update_user(self, user_id: str, firstname: str = None, lastname: str = None, affiliation: str = None, - orcid: str = None) -> User: + def update_user(self, user_id: str, theme: str, language: str, firstname: str = None, lastname: str = None, + affiliation: str = None, orcid: str = None) -> User: """ Updates a user with given user id. :param user_id: The user id of the user that should be updated. + :param theme: The user theme. One of "light", "dark", "light-contrast", "dark-contrast". + :param language: The user language localization. One of "en", "de". :param firstname: The updated given name. Optional. :param lastname: The updated family name. Optional. :param affiliation: The updated affiliation identifier. Optional. @@ -184,8 +216,8 @@ class RestClient: """ url = f'/api/user/{user_id}' response = self._wrapper(method="put", url=url, force_auth=True, - payload=UpdateUser(firstname=firstname, lastname=lastname, affiliation=affiliation, - orcid=orcid)) + payload=UpdateUser(theme=theme, language=language, firstname=firstname, + lastname=lastname, affiliation=affiliation, orcid=orcid)) if response.status_code == 202: body = response.json() return User.model_validate(body) @@ -200,35 +232,6 @@ class RestClient: raise ResponseCodeError( f'Failed to update user: response code: {response.status_code} is not 202 (ACCEPTED)') - def update_user_theme(self, user_id: str, theme: str) -> User: - """ - Updates the theme of a user with given user id. - - :param user_id: The user id of the user that should be updated. - :param theme: The updated user theme name. - - :returns: The user, if successful. - - :raises ResponseCodeError: If something went wrong with the update. - :raises ForbiddenError: If the action is not allowed. - :raises NotExistsError: If theuser does not exist. - """ - url = f'/api/user/{user_id}/theme' - response = self._wrapper(method="put", url=url, force_auth=True, payload=UpdateUserTheme(theme=theme)) - if response.status_code == 202: - body = response.json() - return User.model_validate(body) - if response.status_code == 400: - raise ResponseCodeError(f'Failed to update user theme: invalid values') - if response.status_code == 403: - raise ForbiddenError(f'Failed to update user password: not allowed') - if response.status_code == 404: - raise NotExistsError(f'Failed to update user theme: user not found') - if response.status_code == 405: - raise ResponseCodeError(f'Failed to update user theme: foreign user') - raise ResponseCodeError( - f'Failed to update user theme: response code: {response.status_code} is not 202 (ACCEPTED)') - def update_user_password(self, user_id: str, password: str) -> User: """ Updates the password of a user with given user id. @@ -436,7 +439,7 @@ class RestClient: :raises NameExistsError: If a table with this name already exists. :raises ForbiddenError: If the action is not allowed. :raises MalformedError: If the payload is rejected by the service. - :raises NotExistsError: If thecontainer does not exist. + :raises NotExistsError: If the container does not exist. """ url = f'/api/database/{database_id}/table' response = self._wrapper(method="post", url=url, force_auth=True, @@ -456,7 +459,7 @@ class RestClient: raise ResponseCodeError( f'Failed to create table: response code: {response.status_code} is not 201 (CREATED)') - def get_tables(self, database_id: int) -> List[Table]: + def get_tables(self, database_id: int) -> List[TableBrief]: """ Get all tables. @@ -470,7 +473,7 @@ class RestClient: response = self._wrapper(method="get", url=url) if response.status_code == 200: body = response.json() - return TypeAdapter(List[Table]).validate_python(body) + return TypeAdapter(List[TableBrief]).validate_python(body) raise ResponseCodeError(f'Failed to find tables: response code: {response.status_code} is not 200 (OK)') def get_table(self, database_id: int, table_id: int) -> Table: @@ -755,7 +758,7 @@ class RestClient: """ url = f'/api/database/{database_id}/table/{table_id}/data' response = self._wrapper(method="post", url=url, force_auth=True, payload=CreateData(data=data)) - if response.status_code == 202: + if response.status_code == 201: return if response.status_code == 400 or response.status_code == 410: raise MalformedError(f'Failed to insert table data: service rejected malformed payload') @@ -764,12 +767,12 @@ class RestClient: if response.status_code == 404: raise NotExistsError(f'Failed to insert table data: not found') raise ResponseCodeError( - f'Failed to insert table data: response code: {response.status_code} is not 202 (ACCEPTED)') + f'Failed to insert table data: response code: {response.status_code} is not 201 (CREATED)') def import_table_data(self, database_id: int, table_id: int, separator: str, file_path: str, - quote: str = None, skip_lines: int = None, false_encoding: str = None, + quote: str = None, skip_lines: int = 0, false_encoding: str = None, true_encoding: str = None, null_encoding: str = None, - line_encoding: str = None) -> None: + line_encoding: str = "\r\n") -> None: """ Import a csv dataset from a file into a table in a database with given database id and table id. @@ -778,10 +781,10 @@ class RestClient: :param separator: The csv column separator. :param file_path: The path of the file that is imported on the storage service. :param quote: The column data quotation character. Optional. - :param skip_lines: The number of lines to skip. Optional. + :param skip_lines: The number of lines to skip. Optional. Default: 0. :param false_encoding: The encoding of boolean false. Optional. :param true_encoding: The encoding of boolean true. Optional. - :param null_encoding: The encoding of null. Optional. Default: empty string "". + :param null_encoding: The encoding of null. Optional. :param line_encoding: The encoding of the line termination. Optional. Default: CR (Windows). :raises ResponseCodeError: If something went wrong with the insert. @@ -789,7 +792,7 @@ class RestClient: :raises NotExistsError: If the table does not exist. :raises MalformedError: If the payload is rejected by the service (e.g. LOB data could not be imported). """ - client = UploadClient(endpoint=self.endpoint) + client = UploadClient(endpoint=f"{self.endpoint}/api/upload/files") filename = client.upload(file_path=file_path) url = f'/api/database/{database_id}/table/{table_id}/data/import' response = self._wrapper(method="post", url=url, force_auth=True, @@ -829,7 +832,7 @@ class RestClient: :raises NotExistsError: If the file was not found by the Analyse Service. """ if upload: - client = UploadClient(endpoint=self.endpoint) + client = UploadClient(endpoint=f"{self.endpoint}/api/upload/files") filename = client.upload(file_path=file_path) else: filename = file_path @@ -867,7 +870,7 @@ class RestClient: :raises NotExistsError: If the file was not found by the Analyse Service. """ if upload: - client = UploadClient(endpoint=self.endpoint) + client = UploadClient(endpoint=f"{self.endpoint}/api/upload/files") filename = client.upload(file_path=file_path) else: filename = file_path diff --git a/lib/python/dbrepo/api/dto.py b/lib/python/dbrepo/api/dto.py index 27256c63985dbf1801612cef461cb6a4541b8030..5eae072f35610faf5315d7145544556036dfe7eb 100644 --- a/lib/python/dbrepo/api/dto.py +++ b/lib/python/dbrepo/api/dto.py @@ -4,7 +4,7 @@ from dataclasses import field from enum import Enum import datetime from typing import List, Optional, Any, Annotated -from pydantic import BaseModel, ConfigDict, PlainSerializer +from pydantic import BaseModel, ConfigDict, PlainSerializer, Field Timestamp = Annotated[ datetime.datetime, PlainSerializer(lambda v: v.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z', return_type=str) @@ -19,6 +19,18 @@ class ImageDate(BaseModel): created_at: Timestamp +class JwtAuth(BaseModel): + access_token: str + refresh_token: str + id_token: str + expires_in: int + refresh_expires_in: int + not_before_policy: int = Field(alias='not-before-policy') + scope: str + session_state: str + token_type: str + + class Image(BaseModel): id: int registry: str @@ -51,6 +63,8 @@ class CreateUser(BaseModel): class UpdateUser(BaseModel): + theme: str + language: str firstname: Optional[str] = None lastname: Optional[str] = None affiliation: Optional[str] = None @@ -60,11 +74,11 @@ class UpdateUser(BaseModel): class UserBrief(BaseModel): id: str username: str - name: str - orcid: str - qualified_name: str - given_name: str - family_name: str + name: Optional[str] = None + orcid: Optional[str] = None + qualified_name: Optional[str] = None + given_name: Optional[str] = None + family_name: Optional[str] = None class Container(BaseModel): @@ -103,12 +117,12 @@ class ColumnBrief(BaseModel): class TableBrief(BaseModel): id: int + database_id: int name: str - description: str - owner: UserBrief - columns: List[ColumnBrief] + description: Optional[str] internal_name: str is_versioned: bool + owner: UserBrief class UserAttributes(BaseModel): @@ -135,16 +149,6 @@ class UpdateUserPassword(BaseModel): password: str -class UserBrief(BaseModel): - id: str - username: str - name: Optional[str] = None - orcid: Optional[str] = None - qualified_name: Optional[str] = None - given_name: Optional[str] = None - family_name: Optional[str] = None - - class AccessType(str, Enum): """ Enumeration of database access. @@ -499,8 +503,9 @@ class CreateTable(BaseModel): class CreateTableColumn(BaseModel): name: str type: ColumnType - primary_key: bool null_allowed: bool + concept_uri: Optional[str] = None + unit_uri: Optional[str] = None index_length: Optional[int] = None size: Optional[int] = None d: Optional[int] = None @@ -512,6 +517,7 @@ class CreateTableColumn(BaseModel): class CreateTableConstraints(BaseModel): uniques: List[List[str]] = field(default_factory=list) checks: List[str] = field(default_factory=list) + primary_key: List[str] = field(default_factory=list) foreign_keys: List[CreateForeignKey] = field(default_factory=list) @@ -946,7 +952,12 @@ class Table(BaseModel): class TableMinimal(BaseModel): id: int database_id: int - name: str + + +class ColumnMinimal(BaseModel): + id: int + table_id: int + database_id: int class Database(BaseModel): @@ -971,30 +982,59 @@ class Database(BaseModel): class Unique(BaseModel): - uid: int + id: int table: TableMinimal - columns: List[Column] + columns: List[ColumnMinimal] + + +class ForeignKeyReference(BaseModel): + id: int + foreign_key: ForeignKeyMinimal + column: ColumnMinimal + referenced_column: ColumnMinimal + + +class ReferenceType(str, Enum): + """ + Enumeration of reference types. + """ + RESTRICT = "restrict" + CASCADE = "cascade" + SET_NULL = "set_null" + NO_ACTION = "no_action" + SET_DEFAULT = "set_default" + + +class ForeignKeyMinimal(BaseModel): + id: int class ForeignKey(BaseModel): + id: int name: str - columns: List[Column] + references: List[ForeignKeyReference] + table: TableMinimal referenced_table: TableMinimal - referenced_columns: List[Column] - on_update: Optional[str] = None - on_delete: Optional[str] = None + on_update: Optional[ReferenceType] = None + on_delete: Optional[ReferenceType] = None class CreateForeignKey(BaseModel): - columns: List[Column] - referenced_table: Table - referenced_columns: List[Column] - on_update: Optional[str] = None - on_delete: Optional[str] = None + columns: List[str] + referenced_table: str + referenced_columns: List[str] + on_update: Optional[ReferenceType] = None + on_delete: Optional[ReferenceType] = None + + +class PrimaryKey(BaseModel): + id: int + table: TableMinimal + column: ColumnMinimal class Constraints(BaseModel): uniques: List[Unique] foreign_keys: List[ForeignKey] checks: List[str] - primary_key: List[str] + primary_key: List[PrimaryKey] diff --git a/lib/python/tests/test_analyse.py b/lib/python/tests/test_unit_analyse.py similarity index 94% rename from lib/python/tests/test_analyse.py rename to lib/python/tests/test_unit_analyse.py index a4668fedc500dbd8c6ebebf9edb6f3885156f5eb..a26d7aa8441fd716640ca1d71c65a26f45f154ff 100644 --- a/lib/python/tests/test_analyse.py +++ b/lib/python/tests/test_unit_analyse.py @@ -7,7 +7,7 @@ from dbrepo.RestClient import RestClient from dbrepo.api.dto import KeyAnalysis -class AnalyseTest(unittest.TestCase): +class AnalyseUnitTest(unittest.TestCase): def test_analyse_keys_succeeds(self): with requests_mock.Mocker() as mock: diff --git a/lib/python/tests/test_container.py b/lib/python/tests/test_unit_container.py similarity index 99% rename from lib/python/tests/test_container.py rename to lib/python/tests/test_unit_container.py index e9988f19ca9dd1567d48295c7c4e3184acc30b83..8f3297879ada5fcf416cc8afc508d059cf28c95d 100644 --- a/lib/python/tests/test_container.py +++ b/lib/python/tests/test_unit_container.py @@ -10,7 +10,7 @@ from dbrepo.api.exceptions import ResponseCodeError, NotExistsError from dbrepo.api.dto import ImageDate -class ContainerTest(unittest.TestCase): +class ContainerUnitTest(unittest.TestCase): def test_get_containers_empty_succeeds(self): with requests_mock.Mocker() as mock: diff --git a/lib/python/tests/test_database.py b/lib/python/tests/test_unit_database.py similarity index 96% rename from lib/python/tests/test_database.py rename to lib/python/tests/test_unit_database.py index 017a17445ab4a7e4eb0e56002f1a444da0208118..cb0bb19a702233cc3b573c028bd4fe1589e54fa3 100644 --- a/lib/python/tests/test_database.py +++ b/lib/python/tests/test_unit_database.py @@ -12,7 +12,7 @@ from dbrepo.api.exceptions import ResponseCodeError, NotExistsError, ForbiddenEr from dbrepo.api.dto import ImageDate -class DatabaseTest(unittest.TestCase): +class DatabaseUnitTest(unittest.TestCase): def test_get_databases_empty_succeeds(self): with requests_mock.Mocker() as mock: @@ -531,8 +531,7 @@ class DatabaseTest(unittest.TestCase): mock.delete('/api/database/1/access/abdbf897-e599-4e5a-a3f0-7529884ea011', status_code=202) # test client = RestClient(username="a", password="b") - response = client.delete_database_access(database_id=1, - user_id='abdbf897-e599-4e5a-a3f0-7529884ea011') + client.delete_database_access(database_id=1, user_id='abdbf897-e599-4e5a-a3f0-7529884ea011') def test_delete_database_access_malformed_fails(self): with requests_mock.Mocker() as mock: @@ -541,8 +540,7 @@ class DatabaseTest(unittest.TestCase): # test try: client = RestClient(username="a", password="b") - response = client.delete_database_access(database_id=1, - user_id='abdbf897-e599-4e5a-a3f0-7529884ea011') + client.delete_database_access(database_id=1, user_id='abdbf897-e599-4e5a-a3f0-7529884ea011') except MalformedError: pass @@ -553,8 +551,7 @@ class DatabaseTest(unittest.TestCase): # test try: client = RestClient(username="a", password="b") - response = client.delete_database_access(database_id=1, - user_id='abdbf897-e599-4e5a-a3f0-7529884ea011') + client.delete_database_access(database_id=1, user_id='abdbf897-e599-4e5a-a3f0-7529884ea011') except ForbiddenError: pass @@ -565,8 +562,7 @@ class DatabaseTest(unittest.TestCase): # test try: client = RestClient(username="a", password="b") - response = client.delete_database_access(database_id=1, - user_id='abdbf897-e599-4e5a-a3f0-7529884ea011') + client.delete_database_access(database_id=1, user_id='abdbf897-e599-4e5a-a3f0-7529884ea011') except NotExistsError: pass @@ -576,8 +572,7 @@ class DatabaseTest(unittest.TestCase): mock.delete('/api/database/1/access/abdbf897-e599-4e5a-a3f0-7529884ea011', status_code=404) # test try: - response = RestClient().delete_database_access(database_id=1, - user_id='abdbf897-e599-4e5a-a3f0-7529884ea011') + RestClient().delete_database_access(database_id=1, user_id='abdbf897-e599-4e5a-a3f0-7529884ea011') except AuthenticationError: pass diff --git a/lib/python/tests/test_identifier.py b/lib/python/tests/test_unit_identifier.py similarity index 99% rename from lib/python/tests/test_identifier.py rename to lib/python/tests/test_unit_identifier.py index ec63b3c3051d793706e091dedaa59b6e0d16fca7..b64816731d4dcae28d87b38f1e4ef43ae25cf439 100644 --- a/lib/python/tests/test_identifier.py +++ b/lib/python/tests/test_unit_identifier.py @@ -13,7 +13,7 @@ from dbrepo.api.exceptions import MalformedError, ForbiddenError, NotExistsError AuthenticationError -class IdentifierTest(unittest.TestCase): +class IdentifierUnitTest(unittest.TestCase): def test_create_identifier_succeeds(self): with requests_mock.Mocker() as mock: diff --git a/lib/python/tests/test_license.py b/lib/python/tests/test_unit_license.py similarity index 96% rename from lib/python/tests/test_license.py rename to lib/python/tests/test_unit_license.py index bddb99213a0c675afef3937f20ef96f3362d0d32..2efb613c42f66dbac6908cfbc75e1054a16c1268 100644 --- a/lib/python/tests/test_license.py +++ b/lib/python/tests/test_unit_license.py @@ -7,7 +7,7 @@ from dbrepo.RestClient import RestClient from dbrepo.api.dto import License -class DatabaseTest(unittest.TestCase): +class DatabaseUnitTest(unittest.TestCase): def test_get_licenses_empty_succeeds(self): with requests_mock.Mocker() as mock: diff --git a/lib/python/tests/test_query.py b/lib/python/tests/test_unit_query.py similarity index 99% rename from lib/python/tests/test_query.py rename to lib/python/tests/test_unit_query.py index d876401809b37c4aa65cdd90552eb1fc6ac21d13..1a6109dc2b85e00e668eca0691dc36f9205ccc89 100644 --- a/lib/python/tests/test_query.py +++ b/lib/python/tests/test_unit_query.py @@ -13,7 +13,7 @@ from dbrepo.api.exceptions import MalformedError, NotExistsError, ForbiddenError MetadataConsistencyError, AuthenticationError -class QueryTest(unittest.TestCase): +class QueryUnitTest(unittest.TestCase): def test_execute_query_succeeds(self): with requests_mock.Mocker() as mock: diff --git a/lib/python/tests/test_rest_client.py b/lib/python/tests/test_unit_rest_client.py similarity index 97% rename from lib/python/tests/test_rest_client.py rename to lib/python/tests/test_unit_rest_client.py index 64dd3d0032877244b2d5d927b87740945d909d60..ca425683816d4a76a1dff452420e38c364750111 100644 --- a/lib/python/tests/test_rest_client.py +++ b/lib/python/tests/test_unit_rest_client.py @@ -4,7 +4,7 @@ from unittest import TestCase, mock, main from dbrepo.RestClient import RestClient -class DatabaseTest(TestCase): +class DatabaseUnitTest(TestCase): def test_constructor_succeeds(self): # test diff --git a/lib/python/tests/test_table.py b/lib/python/tests/test_unit_table.py similarity index 93% rename from lib/python/tests/test_table.py rename to lib/python/tests/test_unit_table.py index 4839f4ffe152bd4f61f8a572c987b8bb123f980b..5dff01582ec536a116e4a996e60e9236c765db52 100644 --- a/lib/python/tests/test_table.py +++ b/lib/python/tests/test_unit_table.py @@ -8,12 +8,12 @@ from dbrepo.RestClient import RestClient from pandas import DataFrame from dbrepo.api.dto import Table, CreateTableConstraints, UserAttributes, User, Column, Constraints, ColumnType, Result, \ - Concept, Unit, TableStatistics, ColumnStatistic + Concept, Unit, TableStatistics, ColumnStatistic, PrimaryKey, TableMinimal, ColumnMinimal, TableBrief, UserBrief from dbrepo.api.exceptions import MalformedError, ForbiddenError, NotExistsError, NameExistsError, QueryStoreError, \ AuthenticationError -class TableTest(unittest.TestCase): +class TableUnitTest(unittest.TestCase): def test_create_table_succeeds(self): exp = Table(id=2, @@ -31,7 +31,13 @@ class TableTest(unittest.TestCase): queue_name='test', routing_key='dbrepo.test_database_1234.test', is_public=True, - constraints=Constraints(primary_key=["ID"], uniques=[], foreign_keys=[], checks=[]), + constraints=Constraints(uniques=[], + foreign_keys=[], + checks=[], + primary_key=[PrimaryKey(id=1, + table=TableMinimal(id=2, database_id=1), + column=ColumnMinimal(id=1, table_id=2, + database_id=1))]), columns=[Column(id=1, name="ID", database_id=1, @@ -120,32 +126,14 @@ class TableTest(unittest.TestCase): def test_get_tables_succeeds(self): with requests_mock.Mocker() as mock: - exp = [Table(id=2, - name="Test", - description="Test Table", - database_id=1, - internal_name="test", - creator=User(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise', - attributes=UserAttributes(theme='light')), - owner=User(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise', - attributes=UserAttributes(theme='light')), - created=datetime.datetime(2024, 1, 1, 0, 0, 0, 0, datetime.timezone.utc), - is_versioned=True, - created_by='8638c043-5145-4be8-a3e4-4b79991b0a16', - queue_name='test', - routing_key='dbrepo.test_database_1234.test', - is_public=True, - constraints=Constraints(primary_key=["ID"], uniques=[], foreign_keys=[], checks=[]), - columns=[Column(id=1, - name="ID", - database_id=1, - table_id=2, - internal_name="id", - auto_generated=True, - is_primary_key=True, - column_type=ColumnType.BIGINT, - is_public=True, - is_null_allowed=False)])] + exp = [TableBrief(id=2, + name="Test", + description="Test Table", + database_id=1, + internal_name="test", + owner=UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise', + attributes=UserAttributes(theme='light')), + is_versioned=True)] # mock mock.get('/api/database/1/table', json=[exp[0].model_dump()]) # test @@ -169,7 +157,13 @@ class TableTest(unittest.TestCase): queue_name='test', routing_key='dbrepo.test_database_1234.test', is_public=True, - constraints=Constraints(primary_key=["ID"], uniques=[], foreign_keys=[], checks=[]), + constraints=Constraints(uniques=[], + foreign_keys=[], + checks=[], + primary_key=[PrimaryKey(id=1, + table=TableMinimal(id=2, database_id=1), + column=ColumnMinimal(id=1, table_id=2, + database_id=1))]), columns=[Column(id=1, name="ID", database_id=1, @@ -362,7 +356,7 @@ class TableTest(unittest.TestCase): def test_create_table_data_succeeds(self): with requests_mock.Mocker() as mock: # mock - mock.post('/api/database/1/table/9/data', status_code=202) + mock.post('/api/database/1/table/9/data', status_code=201) # test client = RestClient(username="a", password="b") client.create_table_data(database_id=1, table_id=9, diff --git a/lib/python/tests/test_user.py b/lib/python/tests/test_unit_user.py similarity index 79% rename from lib/python/tests/test_user.py rename to lib/python/tests/test_unit_user.py index 67698a8fd58b811f58a89a7ba9d1c5245f2f242c..08133fa6f02318a585ce0bcdb7f328072ba860de 100644 --- a/lib/python/tests/test_user.py +++ b/lib/python/tests/test_unit_user.py @@ -8,7 +8,7 @@ from dbrepo.api.exceptions import ResponseCodeError, UsernameExistsError, EmailE ForbiddenError, AuthenticationError -class UserTest(unittest.TestCase): +class UserUnitTest(unittest.TestCase): def test_whoami_fails(self): username = RestClient().whoami() @@ -143,7 +143,8 @@ class UserTest(unittest.TestCase): json=exp.model_dump()) # test client = RestClient(username="a", password="b") - response = client.update_user(user_id='8638c043-5145-4be8-a3e4-4b79991b0a16', firstname='Martin') + response = client.update_user(user_id='8638c043-5145-4be8-a3e4-4b79991b0a16', firstname='Martin', + language='en', theme='light') self.assertEqual(exp, response) def test_update_user_not_allowed_fails(self): @@ -153,7 +154,8 @@ class UserTest(unittest.TestCase): # test try: client = RestClient(username="a", password="b") - response = client.update_user(user_id='8638c043-5145-4be8-a3e4-4b79991b0a16', firstname='Martin') + response = client.update_user(user_id='8638c043-5145-4be8-a3e4-4b79991b0a16', firstname='Martin', + language='en', theme='light') except ForbiddenError as e: pass @@ -164,7 +166,8 @@ class UserTest(unittest.TestCase): # test try: client = RestClient(username="a", password="b") - response = client.update_user(user_id='8638c043-5145-4be8-a3e4-4b79991b0a16', firstname='Martin') + response = client.update_user(user_id='8638c043-5145-4be8-a3e4-4b79991b0a16', firstname='Martin', + language='en', theme='light') except NotExistsError as e: pass @@ -175,7 +178,8 @@ class UserTest(unittest.TestCase): # test try: client = RestClient(username="a", password="b") - response = client.update_user(user_id='8638c043-5145-4be8-a3e4-4b79991b0a16', firstname='Martin') + response = client.update_user(user_id='8638c043-5145-4be8-a3e4-4b79991b0a16', firstname='Martin', + language='en', theme='light') except ForbiddenError as e: pass @@ -185,62 +189,8 @@ class UserTest(unittest.TestCase): mock.put('http://gateway-service/api/user/8638c043-5145-4be8-a3e4-4b79991b0a16', status_code=405) # test try: - response = RestClient().update_user(user_id='8638c043-5145-4be8-a3e4-4b79991b0a16', firstname='Martin') - except AuthenticationError as e: - pass - - def test_update_user_theme_succeeds(self): - with requests_mock.Mocker() as mock: - exp = User(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise', given_name='Martin', - attributes=UserAttributes(theme='dark')) - # mock - mock.put('http://gateway-service/api/user/8638c043-5145-4be8-a3e4-4b79991b0a16/theme', status_code=202, - json=exp.model_dump()) - # test - client = RestClient(username="a", password="b") - response = client.update_user_theme(user_id='8638c043-5145-4be8-a3e4-4b79991b0a16', theme='dark') - self.assertEqual(exp, response) - - def test_update_user_theme_not_allowed_fails(self): - with requests_mock.Mocker() as mock: - # mock - mock.put('http://gateway-service/api/user/8638c043-5145-4be8-a3e4-4b79991b0a16/theme', status_code=403) - # test - try: - client = RestClient(username="a", password="b") - response = client.update_user_theme(user_id='8638c043-5145-4be8-a3e4-4b79991b0a16', theme='dark') - except ForbiddenError as e: - pass - - def test_update_user_theme_not_found_fails(self): - with requests_mock.Mocker() as mock: - # mock - mock.put('http://gateway-service/api/user/8638c043-5145-4be8-a3e4-4b79991b0a16/theme', status_code=404) - # test - try: - client = RestClient(username="a", password="b") - response = client.update_user_theme(user_id='8638c043-5145-4be8-a3e4-4b79991b0a16', theme='dark') - except NotExistsError as e: - pass - - def test_update_user_theme_foreign_fails(self): - with requests_mock.Mocker() as mock: - # mock - mock.put('http://gateway-service/api/user/8638c043-5145-4be8-a3e4-4b79991b0a16/theme', status_code=405) - # test - try: - client = RestClient(username="a", password="b") - response = client.update_user_theme(user_id='8638c043-5145-4be8-a3e4-4b79991b0a16', theme='dark') - except ResponseCodeError as e: - pass - - def test_update_user_theme_not_auth_fails(self): - with requests_mock.Mocker() as mock: - # mock - mock.put('http://gateway-service/api/user/8638c043-5145-4be8-a3e4-4b79991b0a16/theme', status_code=405) - # test - try: - response = RestClient().update_user_theme(user_id='8638c043-5145-4be8-a3e4-4b79991b0a16', theme='dark') + response = RestClient().update_user(user_id='8638c043-5145-4be8-a3e4-4b79991b0a16', firstname='Martin', + language='en', theme='light') except AuthenticationError as e: pass diff --git a/lib/python/tests/test_view.py b/lib/python/tests/test_unit_view.py similarity index 93% rename from lib/python/tests/test_view.py rename to lib/python/tests/test_unit_view.py index 2a61cab89ee2a4a0fa1778c598da27e00ea9910b..476f0473700ed79f9af1faaa4da7291517c117ca 100644 --- a/lib/python/tests/test_view.py +++ b/lib/python/tests/test_unit_view.py @@ -7,11 +7,11 @@ import datetime from dbrepo.RestClient import RestClient from pandas import DataFrame -from dbrepo.api.dto import UserAttributes, User, View, Result +from dbrepo.api.dto import UserAttributes, User, View, Result, ViewColumn, ColumnType from dbrepo.api.exceptions import ForbiddenError, NotExistsError, MalformedError, AuthenticationError -class ViewTest(unittest.TestCase): +class ViewUnitTest(unittest.TestCase): def test_get_views_empty_succeeds(self): with requests_mock.Mocker() as mock: @@ -33,6 +33,8 @@ class ViewTest(unittest.TestCase): creator=User(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise', attributes=UserAttributes(theme='light')), is_public=True, + columns=[ViewColumn(id=1, name="id", internal_name="id", database_id=1, auto_generated=False, + column_type=ColumnType.BIGINT, is_public=True, is_null_allowed=False)], created=datetime.datetime(2024, 1, 1, 0, 0, 0, 0, datetime.timezone.utc), last_modified=datetime.datetime(2024, 1, 1, 0, 0, 0, 0, datetime.timezone.utc), identifiers=[])] @@ -74,6 +76,8 @@ class ViewTest(unittest.TestCase): creator=User(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise', attributes=UserAttributes(theme='light')), is_public=True, + columns=[ViewColumn(id=1, name="id", internal_name="id", database_id=1, auto_generated=False, + column_type=ColumnType.BIGINT, is_public=True, is_null_allowed=False)], created=datetime.datetime(2024, 1, 1, 0, 0, 0, 0, datetime.timezone.utc), last_modified=datetime.datetime(2024, 1, 1, 0, 0, 0, 0, datetime.timezone.utc), identifiers=[]) @@ -115,6 +119,8 @@ class ViewTest(unittest.TestCase): creator=User(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise', attributes=UserAttributes(theme='light')), is_public=True, + columns=[ViewColumn(id=1, name="id", internal_name="id", database_id=1, auto_generated=False, + column_type=ColumnType.BIGINT, is_public=True, is_null_allowed=False)], created=datetime.datetime(2024, 1, 1, 0, 0, 0, 0, datetime.timezone.utc), last_modified=datetime.datetime(2024, 1, 1, 0, 0, 0, 0, datetime.timezone.utc), identifiers=[]) diff --git a/make/gen.mk b/make/gen.mk index e6fceaf2ba3e40a0dc496f885448916a3eb3c766..14206d66334bed074579ad2bab7ef4642e8f914c 100644 --- a/make/gen.mk +++ b/make/gen.mk @@ -10,6 +10,12 @@ gen-swagger-doc-fe: build-images ## Generate Swagger documentation and fetch. bash .docs/.swagger/swagger-generate.sh bash .docs/.swagger/swagger-site.sh docker compose down + openapi-merge-cli --config .docs/.swagger/openapi-merge.json + +.PHONY: gen-helm-doc +gen-helm-doc: build-helm ## Generate Helm documentation and schema + helm schema -input ./helm/dbrepo/values.yaml + readme-generator-for-helm --readme ./helm/dbrepo/README.md --values ./helm/dbrepo/values.yaml .PHONY: gen-dbrepo-doc gen-docs-doc: ## Generate DBRepo documentation. diff --git a/make/rel.mk b/make/rel.mk index bf73c6bb8ecb239525a49a1e5dcbec731f1dd0db..c06bb234334f0f55fc0bcf4ab3a6becf04825a63 100644 --- a/make/rel.mk +++ b/make/rel.mk @@ -2,50 +2,28 @@ .PHONY: tag-images tag-images: build-images ## Tag the docker images. - docker tag dbrepo-analyse-service:latest "${REPOSITORY_1_URL}/analyse-service:${APP_VERSION}" - docker tag dbrepo-analyse-service:latest "${REPOSITORY_2_URL}/analyse-service:${APP_VERSION}" - docker tag dbrepo-auth-service:latest "${REPOSITORY_1_URL}/auth-service:${APP_VERSION}" - docker tag dbrepo-auth-service:latest "${REPOSITORY_2_URL}/auth-service:${APP_VERSION}" - docker tag dbrepo-metadata-db:latest "${REPOSITORY_1_URL}/metadata-db:${APP_VERSION}" - docker tag dbrepo-metadata-db:latest "${REPOSITORY_2_URL}/metadata-db:${APP_VERSION}" - docker tag dbrepo-ui:latest "${REPOSITORY_1_URL}/ui:${APP_VERSION}" - docker tag dbrepo-ui:latest "${REPOSITORY_2_URL}/ui:${APP_VERSION}" - docker tag dbrepo-data-service:latest "${REPOSITORY_1_URL}/data-service:${APP_VERSION}" - docker tag dbrepo-data-service:latest "${REPOSITORY_2_URL}/data-service:${APP_VERSION}" - docker tag dbrepo-metadata-service:latest "${REPOSITORY_1_URL}/metadata-service:${APP_VERSION}" - docker tag dbrepo-metadata-service:latest "${REPOSITORY_2_URL}/metadata-service:${APP_VERSION}" - docker tag dbrepo-search-db:latest "${REPOSITORY_1_URL}/search-db:${APP_VERSION}" - docker tag dbrepo-search-db:latest "${REPOSITORY_2_URL}/search-db:${APP_VERSION}" - docker tag dbrepo-data-db-sidecar:latest "${REPOSITORY_1_URL}/data-db-sidecar:${APP_VERSION}" - docker tag dbrepo-data-db-sidecar:latest "${REPOSITORY_2_URL}/data-db-sidecar:${APP_VERSION}" - docker tag dbrepo-search-service:latest "${REPOSITORY_1_URL}/search-service:${APP_VERSION}" - docker tag dbrepo-search-service:latest "${REPOSITORY_2_URL}/search-service:${APP_VERSION}" - docker tag dbrepo-search-service-init:latest "${REPOSITORY_1_URL}/search-service-init:${APP_VERSION}" - docker tag dbrepo-search-service-init:latest "${REPOSITORY_2_URL}/search-service-init:${APP_VERSION}" - docker tag dbrepo-storage-service-init:latest "${REPOSITORY_1_URL}/storage-service-init:${APP_VERSION}" - docker tag dbrepo-storage-service-init:latest "${REPOSITORY_2_URL}/storage-service-init:${APP_VERSION}" + docker tag dbrepo-analyse-service:latest "${REPOSITORY_URL}/analyse-service:${APP_VERSION}" + docker tag dbrepo-auth-service:latest "${REPOSITORY_URL}/auth-service:${APP_VERSION}" + docker tag dbrepo-metadata-db:latest "${REPOSITORY_URL}/metadata-db:${APP_VERSION}" + docker tag dbrepo-ui:latest "${REPOSITORY_URL}/ui:${APP_VERSION}" + docker tag dbrepo-data-service:latest "${REPOSITORY_URL}/data-service:${APP_VERSION}" + docker tag dbrepo-metadata-service:latest "${REPOSITORY_URL}/metadata-service:${APP_VERSION}" + docker tag dbrepo-search-db:latest "${REPOSITORY_URL}/search-db:${APP_VERSION}" + docker tag dbrepo-data-db-sidecar:latest "${REPOSITORY_URL}/data-db-sidecar:${APP_VERSION}" + docker tag dbrepo-search-service:latest "${REPOSITORY_URL}/search-service:${APP_VERSION}" + docker tag dbrepo-search-service-init:latest "${REPOSITORY_URL}/search-service-init:${APP_VERSION}" + docker tag dbrepo-storage-service-init:latest "${REPOSITORY_URL}/storage-service-init:${APP_VERSION}" .PHONY: release-images release-images: tag-images ## Release the docker images. - docker push "${REPOSITORY_1_URL}/analyse-service:${APP_VERSION}" - docker push "${REPOSITORY_2_URL}/analyse-service:${APP_VERSION}" - docker push "${REPOSITORY_1_URL}/auth-service:${APP_VERSION}" - docker push "${REPOSITORY_2_URL}/auth-service:${APP_VERSION}" - docker push "${REPOSITORY_1_URL}/metadata-db:${APP_VERSION}" - docker push "${REPOSITORY_2_URL}/metadata-db:${APP_VERSION}" - docker push "${REPOSITORY_1_URL}/ui:${APP_VERSION}" - docker push "${REPOSITORY_2_URL}/ui:${APP_VERSION}" - docker push "${REPOSITORY_1_URL}/data-service:${APP_VERSION}" - docker push "${REPOSITORY_2_URL}/data-service:${APP_VERSION}" - docker push "${REPOSITORY_1_URL}/search-db:${APP_VERSION}" - docker push "${REPOSITORY_2_URL}/search-db:${APP_VERSION}" - docker push "${REPOSITORY_1_URL}/data-db-sidecar:${APP_VERSION}" - docker push "${REPOSITORY_2_URL}/data-db-sidecar:${APP_VERSION}" - docker push "${REPOSITORY_1_URL}/metadata-service:${APP_VERSION}" - docker push "${REPOSITORY_2_URL}/metadata-service:${APP_VERSION}" - docker push "${REPOSITORY_1_URL}/search-service:${APP_VERSION}" - docker push "${REPOSITORY_2_URL}/search-service:${APP_VERSION}" - docker push "${REPOSITORY_1_URL}/search-service-init:${APP_VERSION}" - docker push "${REPOSITORY_2_URL}/search-service-init:${APP_VERSION}" - docker push "${REPOSITORY_1_URL}/storage-service-init:${APP_VERSION}" - docker push "${REPOSITORY_2_URL}/storage-service-init:${APP_VERSION}" + docker push "${REPOSITORY_URL}/analyse-service:${APP_VERSION}" + docker push "${REPOSITORY_URL}/auth-service:${APP_VERSION}" + docker push "${REPOSITORY_URL}/metadata-db:${APP_VERSION}" + docker push "${REPOSITORY_URL}/ui:${APP_VERSION}" + docker push "${REPOSITORY_URL}/data-service:${APP_VERSION}" + docker push "${REPOSITORY_URL}/search-db:${APP_VERSION}" + docker push "${REPOSITORY_URL}/data-db-sidecar:${APP_VERSION}" + docker push "${REPOSITORY_URL}/metadata-service:${APP_VERSION}" + docker push "${REPOSITORY_URL}/search-service:${APP_VERSION}" + docker push "${REPOSITORY_URL}/search-service-init:${APP_VERSION}" + docker push "${REPOSITORY_URL}/storage-service-init:${APP_VERSION}" diff --git a/mkdocs.yml b/mkdocs.yml index 3911589ff5880616420b466e4a7b04fbed73123d..1455b24f4e3fd6bfb20e5f0f855ce7cdb1d9e82f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -45,6 +45,7 @@ nav: - Customization: api/ui.md - Examples: - COVID-19 Tweets: examples/covid19.md + - Hazardous Materials: examples/hazard.md - Influenza Monitoring: examples/influenza.md - Manufacturing Data: examples/manufacturing.md - Power Usage: examples/power.md diff --git a/values.schema.json b/values.schema.json new file mode 100644 index 0000000000000000000000000000000000000000..2cc52abfed3216d26a5e140292c82ffc2e023a8f --- /dev/null +++ b/values.schema.json @@ -0,0 +1,1459 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "admin": { + "properties": { + "password": { + "type": "string" + }, + "username": { + "type": "string" + } + }, + "type": "object" + }, + "analyseservice": { + "properties": { + "enabled": { + "type": "boolean" + }, + "endpoint": { + "type": "string" + }, + "image": { + "properties": { + "debug": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "pullPolicy": { + "type": "string" + } + }, + "type": "object" + }, + "replicaCount": { + "type": "integer" + }, + "s3": { + "properties": { + "endpoint": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "authservice": { + "properties": { + "auth": { + "properties": { + "adminPassword": { + "type": "string" + }, + "adminUser": { + "type": "string" + } + }, + "type": "object" + }, + "client": { + "properties": { + "id": { + "type": "string" + }, + "secret": { + "type": "string" + } + }, + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "endpoint": { + "type": "string" + }, + "extraEnvVarsCM": { + "type": "string" + }, + "extraStartupArgs": { + "type": "string" + }, + "extraVolumeMounts": { + "items": { + "properties": { + "mountPath": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "extraVolumes": { + "items": { + "properties": { + "configMap": { + "properties": { + "name": { + "type": "string" + } + }, + "type": "object" + }, + "name": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "fullnameOverride": { + "type": "string" + }, + "image": { + "properties": { + "debug": { + "type": "boolean" + } + }, + "type": "object" + }, + "jwt": { + "properties": { + "pubkey": { + "type": "string" + } + }, + "type": "object" + }, + "metrics": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "postgresql": { + "properties": { + "auth": { + "properties": { + "postgresPassword": { + "type": "string" + } + }, + "type": "object" + }, + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "replicaCount": { + "type": "integer" + }, + "tls": { + "properties": { + "enabled": { + "type": "boolean" + }, + "existingSecret": { + "type": "string" + }, + "usePem": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "brokerservice": { + "properties": { + "auth": { + "properties": { + "password": { + "type": "string" + }, + "tls": { + "properties": { + "enabled": { + "type": "boolean" + }, + "existingSecret": { + "type": "string" + }, + "failIfNoPeerCert": { + "type": "boolean" + }, + "sslOptionsVerify": { + "type": "boolean" + } + }, + "type": "object" + }, + "username": { + "type": "string" + } + }, + "type": "object" + }, + "connectionTimeout": { + "type": "integer" + }, + "enabled": { + "type": "boolean" + }, + "endpoint": { + "type": "string" + }, + "exchangeName": { + "type": "string" + }, + "extraConfiguration": { + "type": "string" + }, + "extraPlugins": { + "type": "string" + }, + "extraVolumes": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "secret": { + "properties": { + "secretName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "fullnameOverride": { + "type": "string" + }, + "host": { + "type": "string" + }, + "image": { + "properties": { + "debug": { + "type": "boolean" + } + }, + "type": "object" + }, + "loadDefinition": { + "properties": { + "enabled": { + "type": "boolean" + }, + "existingSecret": { + "type": "string" + } + }, + "type": "object" + }, + "persistence": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "port": { + "type": "integer" + }, + "queueName": { + "type": "string" + }, + "replicaCount": { + "type": "integer" + }, + "routingKey": { + "type": "string" + }, + "service": { + "properties": { + "managerPortEnabled": { + "type": "boolean" + }, + "type": { + "type": "string" + } + }, + "type": "object" + }, + "virtualHost": { + "type": "string" + } + }, + "type": "object" + }, + "clusterDomain": { + "type": "string" + }, + "datadb": { + "properties": { + "enabled": { + "type": "boolean" + }, + "extraFlags": { + "type": "string" + }, + "extraVolumeMounts": { + "items": { + "properties": { + "mountPath": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "extraVolumes": { + "items": { + "properties": { + "emptyDir": { + "properties": {}, + "type": "object" + }, + "name": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "fullnameOverride": { + "type": "string" + }, + "galera": { + "properties": { + "mariabackup": { + "properties": { + "password": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "image": { + "properties": { + "debug": { + "type": "boolean" + } + }, + "type": "object" + }, + "metrics": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "persistence": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "replicaCount": { + "type": "integer" + }, + "rootUser": { + "properties": { + "password": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + }, + "service": { + "properties": { + "extraPorts": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "protocol": { + "type": "string" + }, + "targetPort": { + "type": "integer" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "sidecars": { + "items": { + "properties": { + "envFrom": { + "items": { + "properties": { + "secretRef": { + "properties": { + "name": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "image": { + "type": "string" + }, + "imagePullPolicy": { + "type": "string" + }, + "livenessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + } + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "ports": { + "items": { + "properties": { + "containerPort": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "protocol": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "readinessProbe": { + "properties": { + "exec": { + "properties": { + "command": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "initialDelaySeconds": { + "type": "integer" + }, + "periodSeconds": { + "type": "integer" + } + }, + "type": "object" + }, + "securityContext": { + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean" + }, + "capabilities": { + "properties": { + "drop": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + }, + "runAsGroup": { + "type": "integer" + }, + "runAsNonRoot": { + "type": "boolean" + }, + "runAsUser": { + "type": "integer" + }, + "seccompProfile": { + "properties": { + "type": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "volumeMounts": { + "items": { + "properties": { + "mountPath": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "dataservice": { + "properties": { + "consumerConcurrentMax": { + "type": "integer" + }, + "consumerConcurrentMin": { + "type": "integer" + }, + "default": { + "properties": { + "date": { + "type": "integer" + }, + "time": { + "type": "integer" + }, + "timestamp": { + "type": "integer" + } + }, + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "endpoint": { + "type": "string" + }, + "grant": { + "properties": { + "read": { + "type": "string" + }, + "write": { + "type": "string" + } + }, + "type": "object" + }, + "image": { + "properties": { + "debug": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "pullPolicy": { + "type": "string" + } + }, + "type": "object" + }, + "replicaCount": { + "type": "integer" + }, + "requeueRejected": { + "type": "boolean" + }, + "s3": { + "properties": { + "auth": { + "properties": { + "password": { + "type": "string" + }, + "username": { + "type": "string" + } + }, + "type": "object" + }, + "bucket": { + "properties": { + "export": { + "type": "string" + }, + "import": { + "type": "string" + } + }, + "type": "object" + }, + "endpoint": { + "type": "string" + }, + "filePath": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "gateway": { + "type": "string" + }, + "hostname": { + "type": "string" + }, + "ingress": { + "properties": { + "annotations": { + "properties": { + "basic": { + "properties": {}, + "type": "object" + }, + "rewriteApi": { + "properties": { + "nginx.ingress.kubernetes.io/rewrite-target": { + "type": "string" + }, + "nginx.ingress.kubernetes.io/use-regex": { + "type": "string" + } + }, + "type": "object" + }, + "rewritePid": { + "properties": { + "nginx.ingress.kubernetes.io/rewrite-target": { + "type": "string" + }, + "nginx.ingress.kubernetes.io/use-regex": { + "type": "string" + } + }, + "type": "object" + }, + "rewriteRoot": { + "properties": { + "nginx.ingress.kubernetes.io/rewrite-target": { + "type": "string" + }, + "nginx.ingress.kubernetes.io/use-regex": { + "type": "string" + } + }, + "type": "object" + }, + "rewriteRootSecure": { + "properties": { + "nginx.ingress.kubernetes.io/backend-protocol": { + "type": "string" + }, + "nginx.ingress.kubernetes.io/force-ssl-redirect": { + "type": "string" + }, + "nginx.ingress.kubernetes.io/rewrite-target": { + "type": "string" + }, + "nginx.ingress.kubernetes.io/use-regex": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "className": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "tls": { + "properties": { + "enabled": { + "type": "boolean" + }, + "secretName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "metadatadb": { + "properties": { + "db": { + "properties": { + "name": { + "type": "string" + } + }, + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "extraInitDbScripts": { + "properties": {}, + "type": "object" + }, + "fullnameOverride": { + "type": "string" + }, + "galera": { + "properties": { + "mariabackup": { + "properties": { + "password": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "host": { + "type": "string" + }, + "image": { + "properties": { + "debug": { + "type": "boolean" + } + }, + "type": "object" + }, + "initdbScriptsConfigMap": { + "type": "string" + }, + "jdbcExtraArgs": { + "type": "string" + }, + "metrics": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "persistence": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "replicaCount": { + "type": "integer" + }, + "rootUser": { + "properties": { + "password": { + "type": "string" + }, + "user": { + "type": "string" + } + }, + "type": "object" + }, + "service": { + "properties": { + "annotations": { + "properties": {}, + "type": "object" + }, + "loadBalancerIP": { + "type": "string" + }, + "loadBalancerSourceRanges": { + "type": "array" + }, + "type": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "metadataservice": { + "properties": { + "admin": { + "properties": { + "email": { + "type": "string" + } + }, + "type": "object" + }, + "datacite": { + "properties": { + "enabled": { + "type": "boolean" + }, + "password": { + "type": "string" + }, + "prefix": { + "type": "string" + }, + "url": { + "type": "string" + }, + "username": { + "type": "string" + } + }, + "type": "object" + }, + "deletedRecord": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "endpoint": { + "type": "string" + }, + "granularity": { + "type": "string" + }, + "image": { + "properties": { + "debug": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "pullPolicy": { + "type": "string" + } + }, + "type": "object" + }, + "replicaCount": { + "type": "integer" + }, + "repositoryName": { + "type": "string" + }, + "s3": { + "properties": { + "auth": { + "properties": { + "password": { + "type": "string" + }, + "username": { + "type": "string" + } + }, + "type": "object" + }, + "bucket": { + "properties": { + "export": { + "type": "string" + }, + "import": { + "type": "string" + } + }, + "type": "object" + }, + "endpoint": { + "type": "string" + } + }, + "type": "object" + }, + "sparql": { + "properties": { + "connectionTimeout": { + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "namespace": { + "type": "string" + }, + "searchdb": { + "properties": { + "clusterName": { + "type": "string" + }, + "config": { + "properties": { + "opensearch.yml": { + "type": "string" + } + }, + "type": "object" + }, + "enabled": { + "type": "boolean" + }, + "extraEnvs": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "extraVolumeMounts": { + "items": { + "properties": { + "mountPath": { + "type": "string" + }, + "name": { + "type": "string" + }, + "readOnly": { + "type": "boolean" + } + }, + "type": "object" + }, + "type": "array" + }, + "extraVolumes": { + "items": { + "properties": { + "name": { + "type": "string" + }, + "secret": { + "properties": { + "secretName": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "fullnameOverride": { + "type": "string" + }, + "host": { + "type": "string" + }, + "masterService": { + "type": "string" + }, + "password": { + "type": "string" + }, + "persistence": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "port": { + "type": "integer" + }, + "protocol": { + "type": "string" + }, + "replicas": { + "type": "integer" + }, + "service": { + "properties": { + "annotations": { + "properties": {}, + "type": "object" + }, + "loadBalancerSourceRanges": { + "type": "array" + }, + "type": { + "type": "string" + } + }, + "type": "object" + }, + "sysctlInit": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "username": { + "type": "string" + } + }, + "type": "object" + }, + "searchservice": { + "properties": { + "enabled": { + "type": "boolean" + }, + "endpoint": { + "type": "string" + }, + "image": { + "properties": { + "debug": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "pullPolicy": { + "type": "string" + } + }, + "type": "object" + }, + "init": { + "properties": { + "image": { + "properties": { + "name": { + "type": "string" + }, + "pullPolicy": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "replicaCount": { + "type": "integer" + } + }, + "type": "object" + }, + "storageservice": { + "properties": { + "enabled": { + "type": "boolean" + }, + "filer": { + "properties": { + "enablePVC": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "replicas": { + "type": "integer" + }, + "s3": { + "properties": { + "allowEmptyFolder": { + "type": "boolean" + }, + "enableAuth": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "existingConfigSecret": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "skipAuthSecretCreation": { + "type": "boolean" + } + }, + "type": "object" + }, + "storage": { + "type": "string" + } + }, + "type": "object" + }, + "init": { + "properties": { + "image": { + "type": "string" + }, + "pullPolicy": { + "type": "string" + } + }, + "type": "object" + }, + "master": { + "properties": { + "enabled": { + "type": "boolean" + } + }, + "type": "object" + }, + "s3": { + "properties": { + "auth": { + "properties": { + "password": { + "type": "string" + }, + "username": { + "type": "string" + } + }, + "type": "object" + }, + "bucket": { + "properties": { + "export": { + "type": "string" + }, + "import": { + "type": "string" + } + }, + "type": "object" + }, + "enableAuth": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "existingConfigSecret": { + "type": "string" + }, + "metricsPort": { + "type": "integer" + }, + "port": { + "type": "integer" + }, + "replicas": { + "type": "integer" + }, + "skipAuthSecretCreation": { + "type": "boolean" + } + }, + "type": "object" + }, + "volume": { + "properties": { + "enabled": { + "type": "boolean" + }, + "replicas": { + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "strategyType": { + "type": "string" + }, + "ui": { + "properties": { + "enabled": { + "type": "boolean" + }, + "extraVolumeMounts": { + "type": "array" + }, + "extraVolumes": { + "type": "array" + }, + "image": { + "properties": { + "debug": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "pullPolicy": { + "type": "string" + } + }, + "type": "object" + }, + "public": { + "properties": { + "api": { + "properties": { + "client": { + "type": "string" + }, + "server": { + "type": "string" + } + }, + "type": "object" + }, + "broker": { + "properties": { + "extra": { + "type": "string" + }, + "host": { + "type": "string" + }, + "port": { + "properties": { + "5671": { + "type": "boolean" + }, + "5672": { + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "database": { + "properties": { + "extra": { + "type": "string" + } + }, + "type": "object" + }, + "doi": { + "properties": { + "enabled": { + "type": "boolean" + }, + "endpoint": { + "type": "string" + } + }, + "type": "object" + }, + "icon": { + "type": "string" + }, + "links": { + "properties": { + "keycloak": { + "properties": { + "href": { + "type": "string" + }, + "text": { + "type": "string" + } + }, + "type": "object" + }, + "rabbitmq": { + "properties": { + "href": { + "type": "string" + }, + "text": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "logo": { + "type": "string" + }, + "pid": { + "properties": { + "default": { + "properties": { + "publisher": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "title": { + "type": "string" + }, + "touch": { + "type": "string" + } + }, + "type": "object" + }, + "replicaCount": { + "type": "integer" + } + }, + "type": "object" + }, + "uploadservice": { + "properties": { + "containerArgs": { + "items": { + "type": "string" + }, + "type": "array" + }, + "enabled": { + "type": "boolean" + }, + "envFrom": { + "items": { + "properties": { + "secretRef": { + "properties": { + "name": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "fullnameOverride": { + "type": "string" + }, + "image": { + "properties": { + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + }, + "type": "object" + }, + "replicaCount": { + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" +}