diff --git a/.docs/system-services-authentication.md b/.docs/system-services-authentication.md index 64bc61120d1ca7c6e79cdcf8a85ad6d7fb7de390..a1d25539fa3bcc8732a5e4c49517c27d27e1404b 100644 --- a/.docs/system-services-authentication.md +++ b/.docs/system-services-authentication.md @@ -91,6 +91,7 @@ public ResponseEntity<DatabaseBriefDto> create(@NotNull Long containerId, | `find-tables` | Can list a specific table in a database | | `list-tables` | Can list all tables | | `modify-table-column-semantics` | Can modify the column semantics of a specific column | +| `delete-table` | Can delete tables owned by the user in a database | ### Default Query Handling @@ -168,9 +169,9 @@ public ResponseEntity<DatabaseBriefDto> create(@NotNull Long containerId, ### Escalated Table Handling -| Name | Description | -|----------------|--------------------------------------| -| `delete-table` | Can delete any table in any database | +| Name | Description | +|------------------------|--------------------------------------| +| `delete-foreign-table` | Can delete any table in any database | ### Escalated Query Handling diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f0feb7e23396e18bc323014992004a7b03bfbad1..13d9a94dd11fad3a7a5229f80494eeb072608d1e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -439,8 +439,8 @@ release-latest: script: - "ifconfig eth0 mtu 1450 up" - "apk add make" - - echo "$CI_REGISTRY_PASSWORD" | docker login --username "$CI_REGISTRY_USER" --password-stdin docker.io - - echo "$AZURE_PASSWORD" | docker login --username "$AZURE_USERNAME" --password-stdin dbrepo.azurecr.io + - echo "$CI_REGISTRY_PASSWORD" | docker login --username "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY_URL + - echo "$CI_REGISTRY2_PASSWORD" | docker login --username "$CI_REGISTRY2_USER" --password-stdin $CI_REGISTRY2_URL - TAG=latest make release release-version: @@ -458,8 +458,8 @@ release-version: script: - "ifconfig eth0 mtu 1450 up" - "apk add make" - - echo "$CI_REGISTRY_PASSWORD" | docker login --username "$CI_REGISTRY_USER" --password-stdin docker.io - - echo "$AZURE_PASSWORD" | docker login --username "$AZURE_USERNAME" --password-stdin dbrepo.azurecr.io + - echo "$CI_REGISTRY_PASSWORD" | docker login --username "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY_URL + - echo "$CI_REGISTRY2_PASSWORD" | docker login --username "$CI_REGISTRY2_USER" --password-stdin $CI_REGISTRY2_URL - "TAG=1.3 make release" build-api-latest: diff --git a/Makefile b/Makefile index 5bc096951bef0feccda2bcad8a95d7f120769393..0a9d7b3c934935a7ab23e2679b48f8c2806816c5 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,8 @@ TAG ?= latest TRIVY_VERSION ?= v0.41.0 -AZURE_REPO ?= dbrepo.azurecr.io +REPOSITORY_URL ?= docker.io/dbrepo +REPOSITORY2_URL ?= s210.dl.hpc.tuwien.ac.at/dbrepo all: build @@ -46,102 +47,102 @@ build-clients: tag: tag-analyse-service tag-authentication-service tag-metadata-db tag-ui tag-metadata-service tag-data-service tag-mirror-service tag-log-service tag-search-db tag-search-db-init tag-search-service tag-data-db-sidecar tag-analyse-service: - docker tag dbrepo-analyse-service:latest "dbrepo/analyse-service:${TAG}" - docker tag dbrepo-analyse-service:latest "${AZURE_REPO}/dbrepo/analyse-service:${TAG}" + docker tag dbrepo-analyse-service:latest "${REPOSITORY_URL}/analyse-service:${TAG}" + docker tag dbrepo-analyse-service:latest "${REPOSITORY2_URL}/analyse-service:${TAG}" tag-authentication-service: - docker tag dbrepo-authentication-service:latest "dbrepo/authentication-service:${TAG}" - docker tag dbrepo-authentication-service:latest "${AZURE_REPO}/dbrepo/authentication-service:${TAG}" + docker tag dbrepo-authentication-service:latest "${REPOSITORY_URL}/authentication-service:${TAG}" + docker tag dbrepo-authentication-service:latest "${REPOSITORY2_URL}/authentication-service:${TAG}" tag-metadata-db: - docker tag dbrepo-metadata-db:latest "dbrepo/metadata-db:${TAG}" - docker tag dbrepo-metadata-db:latest "${AZURE_REPO}/dbrepo/metadata-db:${TAG}" + docker tag dbrepo-metadata-db:latest "${REPOSITORY_URL}/metadata-db:${TAG}" + docker tag dbrepo-metadata-db:latest "${REPOSITORY2_URL}/metadata-db:${TAG}" tag-ui: - docker tag dbrepo-ui:latest "dbrepo/ui:${TAG}" - docker tag dbrepo-ui:latest "${AZURE_REPO}/dbrepo/ui:${TAG}" + docker tag dbrepo-ui:latest "${REPOSITORY_URL}/ui:${TAG}" + docker tag dbrepo-ui:latest "${REPOSITORY2_URL}/ui:${TAG}" tag-data-service: - docker tag dbrepo-data-service:latest "dbrepo/data-service:${TAG}" - docker tag dbrepo-data-service:latest "${AZURE_REPO}/dbrepo/data-service:${TAG}" + docker tag dbrepo-data-service:latest "${REPOSITORY_URL}/data-service:${TAG}" + docker tag dbrepo-data-service:latest "${REPOSITORY2_URL}/data-service:${TAG}" tag-mirror-service: - docker tag dbrepo-mirror-service:latest "dbrepo/mirror-service:${TAG}" - docker tag dbrepo-mirror-service:latest "${AZURE_REPO}/dbrepo/mirror-service:${TAG}" + docker tag dbrepo-mirror-service:latest "${REPOSITORY_URL}/mirror-service:${TAG}" + docker tag dbrepo-mirror-service:latest "${REPOSITORY2_URL}/mirror-service:${TAG}" tag-metadata-service: - docker tag dbrepo-metadata-service:latest "dbrepo/metadata-service:${TAG}" - docker tag dbrepo-metadata-service:latest "${AZURE_REPO}/dbrepo/metadata-service:${TAG}" + docker tag dbrepo-metadata-service:latest "${REPOSITORY_URL}/metadata-service:${TAG}" + docker tag dbrepo-metadata-service:latest "${REPOSITORY2_URL}/metadata-service:${TAG}" tag-search-db: - docker tag dbrepo-search-db:latest "dbrepo/search-db:${TAG}" - docker tag dbrepo-search-db:latest "${AZURE_REPO}/dbrepo/search-db:${TAG}" + docker tag dbrepo-search-db:latest "${REPOSITORY_URL}/search-db:${TAG}" + docker tag dbrepo-search-db:latest "${REPOSITORY2_URL}/search-db:${TAG}" tag-data-db-sidecar: - docker tag dbrepo-data-db-sidecar:latest "dbrepo/data-db-sidecar:${TAG}" - docker tag dbrepo-data-db-sidecar:latest "${AZURE_REPO}/dbrepo/data-db-sidecar:${TAG}" + docker tag dbrepo-data-db-sidecar:latest "${REPOSITORY_URL}/data-db-sidecar:${TAG}" + docker tag dbrepo-data-db-sidecar:latest "${REPOSITORY2_URL}/data-db-sidecar:${TAG}" tag-search-db-init: - docker tag dbrepo-search-db-init:latest "dbrepo/search-db-init:${TAG}" - docker tag dbrepo-search-db-init:latest "${AZURE_REPO}/dbrepo/search-db-init:${TAG}" + docker tag dbrepo-search-db-init:latest "${REPOSITORY_URL}/search-db-init:${TAG}" + docker tag dbrepo-search-db-init:latest "${REPOSITORY2_URL}/search-db-init:${TAG}" tag-log-service: - docker tag dbrepo-log-service:latest "dbrepo/log-service:${TAG}" - docker tag dbrepo-log-service:latest "${AZURE_REPO}/dbrepo/log-service:${TAG}" + docker tag dbrepo-log-service:latest "${REPOSITORY_URL}/log-service:${TAG}" + docker tag dbrepo-log-service:latest "${REPOSITORY2_URL}/log-service:${TAG}" tag-search-service: - docker tag dbrepo-search-service:latest "dbrepo/search-service:${TAG}" - docker tag dbrepo-search-service:latest "${AZURE_REPO}/dbrepo/search-service:${TAG}" + docker tag dbrepo-search-service:latest "${REPOSITORY_URL}/search-service:${TAG}" + docker tag dbrepo-search-service:latest "${REPOSITORY2_URL}/search-service:${TAG}" release: build-docker tag release-analyse-service release-authentication-service release-metadata-db release-ui release-metadata-service release-data-service release-log-service release-search-db release-mirror-service release-search-db-init release-search-service release-data-db-sidecar release-analyse-service: tag-analyse-service - docker push "dbrepo/analyse-service:${TAG}" - docker push "${AZURE_REPO}/dbrepo/analyse-service:${TAG}" + docker push "${REPOSITORY_URL}/analyse-service:${TAG}" + docker push "${REPOSITORY2_URL}/analyse-service:${TAG}" release-authentication-service: tag-authentication-service - docker push "dbrepo/authentication-service:${TAG}" - docker push "${AZURE_REPO}/dbrepo/authentication-service:${TAG}" + docker push "${REPOSITORY_URL}/authentication-service:${TAG}" + docker push "${REPOSITORY2_URL}/authentication-service:${TAG}" release-metadata-db: tag-metadata-db - docker push "dbrepo/metadata-db:${TAG}" - docker push "${AZURE_REPO}/dbrepo/metadata-db:${TAG}" + docker push "${REPOSITORY_URL}/metadata-db:${TAG}" + docker push "${REPOSITORY2_URL}/metadata-db:${TAG}" release-ui: tag-ui - docker push "dbrepo/ui:${TAG}" - docker push "${AZURE_REPO}/dbrepo/ui:${TAG}" + docker push "${REPOSITORY_URL}/ui:${TAG}" + docker push "${REPOSITORY2_URL}/ui:${TAG}" release-data-service: tag-data-service - docker push "dbrepo/data-service:${TAG}" - docker push "${AZURE_REPO}/dbrepo/data-service:${TAG}" + docker push "${REPOSITORY_URL}/data-service:${TAG}" + docker push "${REPOSITORY2_URL}/data-service:${TAG}" release-mirror-service: tag-mirror-service - docker push "dbrepo/mirror-service:${TAG}" - docker push "${AZURE_REPO}/dbrepo/mirror-service:${TAG}" + docker push "${REPOSITORY_URL}/mirror-service:${TAG}" + docker push "${REPOSITORY2_URL}/mirror-service:${TAG}" release-search-db: tag-search-db - docker push "dbrepo/search-db:${TAG}" - docker push "${AZURE_REPO}/dbrepo/search-db:${TAG}" + docker push "${REPOSITORY_URL}/search-db:${TAG}" + docker push "${REPOSITORY2_URL}/search-db:${TAG}" release-search-db-init: tag-search-db-init - docker push "dbrepo/search-db-init:${TAG}" - docker push "${AZURE_REPO}/dbrepo/search-db-init:${TAG}" + docker push "${REPOSITORY_URL}/search-db-init:${TAG}" + docker push "${REPOSITORY2_URL}/search-db-init:${TAG}" release-data-db-sidecar: tag-data-db-sidecar - docker push "dbrepo/data-db-sidecar:${TAG}" - docker push "${AZURE_REPO}/dbrepo/data-db-sidecar:${TAG}" + docker push "${REPOSITORY_URL}/data-db-sidecar:${TAG}" + docker push "${REPOSITORY2_URL}/data-db-sidecar:${TAG}" release-metadata-service: tag-metadata-service - docker push "dbrepo/metadata-service:${TAG}" - docker push "${AZURE_REPO}/dbrepo/metadata-service:${TAG}" + docker push "${REPOSITORY_URL}/metadata-service:${TAG}" + docker push "${REPOSITORY2_URL}/metadata-service:${TAG}" release-log-service: tag-log-service - docker push "dbrepo/log-service:${TAG}" - docker push "${AZURE_REPO}/dbrepo/log-service:${TAG}" + docker push "${REPOSITORY_URL}/log-service:${TAG}" + docker push "${REPOSITORY2_URL}/log-service:${TAG}" release-search-service: tag-search-service - docker push "dbrepo/search-service:${TAG}" - docker push "${AZURE_REPO}/dbrepo/search-service:${TAG}" + docker push "${REPOSITORY_URL}/search-service:${TAG}" + docker push "${REPOSITORY2_URL}/search-service:${TAG}" test-backend: test-metadata-service test-analyse-service test-data-service test-mirror-service diff --git a/dbrepo-analyse-service/Dockerfile b/dbrepo-analyse-service/Dockerfile index 0b5718ea3faa29aafcc840f3964824f4a3d081f3..52912bdcebd58f7d51e7f8f8a59f1195a42e76ff 100644 --- a/dbrepo-analyse-service/Dockerfile +++ b/dbrepo-analyse-service/Dockerfile @@ -13,6 +13,7 @@ ENV FLASK_RUN_HOST=0.0.0.0 ENV PORT_APP=5000 ENV FLASK_ENV=production ENV HOSTNAME=analyse-service +ENV LOG_LEVEL=INFO ENV S3_STORAGE_ENDPOINT="http://storage-service:9000" ENV S3_ACCESS_KEY_ID="minioadmin" ENV S3_SECRET_ACCESS_KEY="minioadmin" diff --git a/dbrepo-analyse-service/app.py b/dbrepo-analyse-service/app.py index d3b9dc36169030dbf837c0a458c8657707bcb830..e917b10cfe0d292d7a98240406cddaec05581b6b 100644 --- a/dbrepo-analyse-service/app.py +++ b/dbrepo-analyse-service/app.py @@ -1,3 +1,4 @@ +import os from _csv import Error from flask import Flask, request, Response @@ -11,7 +12,9 @@ from flasgger import LazyJSONEncoder from gevent.pywsgi import WSGIServer from prometheus_flask_exporter import PrometheusMetrics -logging.basicConfig(level=logging.DEBUG) +log_level = os.getenv('LOG_LEVEL', 'INFO') + +logging.basicConfig(level=logging.getLevelName(log_level)) from logging.config import dictConfig @@ -26,7 +29,7 @@ dictConfig({ 'formatter': 'default' }}, 'root': { - 'level': 'INFO', + 'level': log_level, 'handlers': ['wsgi'] } }) diff --git a/dbrepo-authentication-service/dbrepo-realm.json b/dbrepo-authentication-service/dbrepo-realm.json index 88b4fbec0040e351caef5e6dc211c07cbc60af1a..dbd6c6cc5b928ee4f571673495a38ac79e26c433 100644 --- a/dbrepo-authentication-service/dbrepo-realm.json +++ b/dbrepo-authentication-service/dbrepo-realm.json @@ -5,10 +5,10 @@ "defaultSignatureAlgorithm" : "RS256", "revokeRefreshToken" : false, "refreshTokenMaxReuse" : 1, - "accessTokenLifespan" : 720, + "accessTokenLifespan" : 86400, "accessTokenLifespanForImplicitFlow" : 900, - "ssoSessionIdleTimeout" : 1296000, - "ssoSessionMaxLifespan" : 1296000, + "ssoSessionIdleTimeout" : 1800, + "ssoSessionMaxLifespan" : 36000, "ssoSessionIdleTimeoutRememberMe" : 0, "ssoSessionMaxLifespanRememberMe" : 0, "offlineSessionIdleTimeout" : 2592000, @@ -126,7 +126,7 @@ "description" : "${default-table-handling}", "composite" : true, "composites" : { - "realm" : [ "modify-table-column-semantics", "list-tables", "find-table", "create-table" ] + "realm" : [ "modify-table-column-semantics", "list-tables", "find-table", "create-table", "delete-table" ] }, "clientRole" : false, "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", @@ -577,6 +577,14 @@ "clientRole" : false, "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", "attributes" : { } + }, { + "id" : "6a0bb740-4448-49be-aee8-6dd183325be5", + "name" : "delete-foreign-table", + "description" : "${delete-foreign-table}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } }, { "id" : "7f3652c7-3073-4566-ab63-25385495ebc3", "name" : "modify-database-visibility", @@ -714,7 +722,7 @@ "description" : "${escalated-table-handling}", "composite" : true, "composites" : { - "realm" : [ "delete-table" ] + "realm" : [ "delete-foreign-table" ] }, "clientRole" : false, "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", @@ -1054,7 +1062,7 @@ "otpPolicyLookAheadWindow" : 1, "otpPolicyPeriod" : 30, "otpPolicyCodeReusable" : false, - "otpSupportedApplications" : [ "totpAppFreeOTPName", "totpAppMicrosoftAuthenticatorName", "totpAppGoogleName" ], + "otpSupportedApplications" : [ "totpAppGoogleName", "totpAppFreeOTPName", "totpAppMicrosoftAuthenticatorName" ], "webAuthnPolicyRpEntityName" : "keycloak", "webAuthnPolicySignatureAlgorithms" : [ "ES256" ], "webAuthnPolicyRpId" : "", @@ -2027,7 +2035,7 @@ "subType" : "anonymous", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper", "saml-user-property-mapper", "oidc-address-mapper", "oidc-usermodel-property-mapper", "oidc-full-name-mapper" ] + "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper" ] } }, { "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1", @@ -2053,11 +2061,11 @@ "subType" : "authenticated", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "saml-user-attribute-mapper", "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper", "saml-user-property-mapper", "saml-role-list-mapper", "oidc-usermodel-property-mapper", "oidc-full-name-mapper" ] + "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper", "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper" ] } } ], "org.keycloak.userprofile.UserProfileProvider" : [ { - "id" : "5da93330-911b-44c9-b971-5176ed5ce1f9", + "id" : "7970b87f-f28b-4085-8612-43281968f118", "providerId" : "declarative-user-profile", "subComponents" : { }, "config" : { } @@ -2111,7 +2119,7 @@ "internationalizationEnabled" : false, "supportedLocales" : [ ], "authenticationFlows" : [ { - "id" : "136de2cd-39b0-451f-9b5b-0596a6e703ba", + "id" : "7b9f9c3b-0636-406b-8ac3-c7259ef423d3", "alias" : "Account verification options", "description" : "Method with which to verity the existing account", "providerId" : "basic-flow", @@ -2133,7 +2141,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "6d041452-0e17-4c2f-8dc1-077ae4bc0d15", + "id" : "70be7410-8823-4c0f-aa70-39d9d0e1c7f2", "alias" : "Authentication Options", "description" : "Authentication options.", "providerId" : "basic-flow", @@ -2162,7 +2170,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "a124f3c8-73e9-4ba9-bebc-8282aa0fad62", + "id" : "c3bfd9c1-1e61-4789-9797-7e28867ac15b", "alias" : "Browser - Conditional OTP", "description" : "Flow to determine if the OTP is required for the authentication", "providerId" : "basic-flow", @@ -2184,7 +2192,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "b989868b-effd-494b-90ce-72311208cd07", + "id" : "ba6106ab-6fca-43b3-a170-c1db8352fc69", "alias" : "Direct Grant - Conditional OTP", "description" : "Flow to determine if the OTP is required for the authentication", "providerId" : "basic-flow", @@ -2206,7 +2214,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "3a1986ff-77b5-43ee-8ea5-e83ce4c0b052", + "id" : "bd04da6b-71b0-42d0-a279-4402b7cf35cf", "alias" : "First broker login - Conditional OTP", "description" : "Flow to determine if the OTP is required for the authentication", "providerId" : "basic-flow", @@ -2228,7 +2236,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "8ef32e4a-384c-4a0f-9ef5-6b6c6dd67e23", + "id" : "2016d479-271f-4dfd-88c3-50635d1d27ea", "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", @@ -2250,7 +2258,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "b800468d-d6f4-4e01-a143-f3b9a24767dd", + "id" : "3294bcec-0829-405e-bc34-897eb5ecbf62", "alias" : "Reset - Conditional OTP", "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", "providerId" : "basic-flow", @@ -2272,7 +2280,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "1a25e553-ebc5-407a-b432-ffdeea36907d", + "id" : "cdc002be-a391-4853-8c40-8eef726dcfb6", "alias" : "User creation or linking", "description" : "Flow for the existing/non-existing user alternatives", "providerId" : "basic-flow", @@ -2295,7 +2303,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "b799d43f-e8f4-4d6a-93e9-39f73e42e22a", + "id" : "11e9d0a5-743f-44fe-ab9f-59f3e730e20a", "alias" : "Verify Existing Account by Re-authentication", "description" : "Reauthentication of existing account", "providerId" : "basic-flow", @@ -2317,7 +2325,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "6f1b9b5f-3d09-4b2e-ba42-237ca174f393", + "id" : "c5ea7e5c-c07d-48c5-ba99-4e84ed167bee", "alias" : "browser", "description" : "browser based authentication", "providerId" : "basic-flow", @@ -2353,7 +2361,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "2eddb88f-3c4c-4d2f-99ba-f2cba595b94a", + "id" : "e18342ad-98d9-4411-bf59-30e07cf65f98", "alias" : "clients", "description" : "Base authentication for clients", "providerId" : "client-flow", @@ -2389,7 +2397,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "509dd5c3-ef75-45be-8cad-6328eef3c94e", + "id" : "ca97318e-8587-43b4-919b-5c65e2a074f3", "alias" : "direct grant", "description" : "OpenID Connect Resource Owner Grant", "providerId" : "basic-flow", @@ -2418,7 +2426,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "995b881c-71d0-4ac1-be36-ce7cf7a9779d", + "id" : "7f523ba5-6d6b-4a65-9ba0-107b5c3afe7a", "alias" : "docker auth", "description" : "Used by Docker clients to authenticate against the IDP", "providerId" : "basic-flow", @@ -2433,7 +2441,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "2c18ddd1-e304-4e7e-98f5-25f8abba945d", + "id" : "c72a0c74-0dc4-45dc-8b62-a77bc42d805c", "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", @@ -2456,7 +2464,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "7abb16cf-310d-465f-93ef-34349ffc42fb", + "id" : "5939da5a-b299-49b7-8c07-c45e13d995db", "alias" : "forms", "description" : "Username, password, otp and other auth forms.", "providerId" : "basic-flow", @@ -2478,7 +2486,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "c01ab73b-0bc7-4047-98a3-502f98e6cc74", + "id" : "6a0341db-eec8-4962-bb04-4b8a43dced2a", "alias" : "http challenge", "description" : "An authentication flow based on challenge-response HTTP Authentication Schemes", "providerId" : "basic-flow", @@ -2500,7 +2508,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "9270fad3-c2da-4d20-9d8d-c55c3bace9fc", + "id" : "525006c3-c676-4bfb-83cf-79faeafe0183", "alias" : "registration", "description" : "registration flow", "providerId" : "basic-flow", @@ -2516,7 +2524,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "1c8a94b0-eb77-4201-aa7f-4411da843ba1", + "id" : "65e9d76b-d180-47e6-ad1b-dddea414668f", "alias" : "registration form", "description" : "registration form", "providerId" : "form-flow", @@ -2552,7 +2560,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "28b08679-329a-4555-a0a0-7396e398e5bb", + "id" : "feb110ed-e018-43ba-8989-0b17a3a20de3", "alias" : "reset credentials", "description" : "Reset credentials for a user if they forgot their password or something", "providerId" : "basic-flow", @@ -2588,7 +2596,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "3e3a0a50-0850-4f48-b315-dcd9340b1c2a", + "id" : "15efa29f-2140-4e3b-803e-64d79906c18b", "alias" : "saml ecp", "description" : "SAML ECP Profile Authentication Flow", "providerId" : "basic-flow", @@ -2604,13 +2612,13 @@ } ] } ], "authenticatorConfig" : [ { - "id" : "2e6a1507-6515-4d2a-8462-a2517df9d1da", + "id" : "2c135401-6244-41b0-8c49-648f38b5e1bd", "alias" : "create unique user config", "config" : { "require.password.update.after.registration" : "false" } }, { - "id" : "4b0c01c1-aa00-432c-a9c6-640881e71fb6", + "id" : "39d00721-0854-4ff7-9f5c-7f6fa71ae37a", "alias" : "review profile config", "config" : { "update.profile.on.first.login" : "missing" diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java index 1d61a1108d8ceba8c2eaabaee35a6f1efcfd98d3..dea7c9258442eec08b7a2a72ad24f29bb7d2b96f 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java @@ -33,7 +33,7 @@ public class MariaDbContainerConfig { public static synchronized CustomMariaDBContainer getInstance() { if (instance == null) { - instance = new CustomMariaDBContainer(BaseTest.IMAGE_1_NAME + ":" + BaseTest.IMAGE_1_VERSION); + instance = new CustomMariaDBContainer("mariadb:11.1.3"); instance.withImagePullPolicy(PullPolicy.alwaysPull()); instance.addFixedExposedPort(BaseTest.CONTAINER_1_PORT, BaseTest.IMAGE_1_PORT); instance.withUsername(BaseTest.CONTAINER_1_PRIVILEGED_USERNAME); diff --git a/dbrepo-metadata-db/setup-schema.sql b/dbrepo-metadata-db/setup-schema.sql index 972216ac0c6c2d28f654e3ea41febbbe7adf1c13..0b3a6c132db85e7454de153332c318d13cee2d6f 100644 --- a/dbrepo-metadata-db/setup-schema.sql +++ b/dbrepo-metadata-db/setup-schema.sql @@ -167,7 +167,7 @@ CREATE TABLE IF NOT EXISTS `mdb_columns` std_dev Numeric NULL, created timestamp NOT NULL DEFAULT NOW(), last_modified timestamp, - FOREIGN KEY (tID) REFERENCES mdb_tables (ID), + FOREIGN KEY (tID) REFERENCES mdb_tables (ID) ON DELETE CASCADE, PRIMARY KEY (ID) ) WITH SYSTEM VERSIONING; @@ -221,7 +221,7 @@ CREATE TABLE IF NOT EXISTS `mdb_constraints_foreign_key` on_delete VARCHAR(50) NULL, position INT NULL, PRIMARY KEY (fkid), - FOREIGN KEY (tid) REFERENCES mdb_tables (id), + FOREIGN KEY (tid) REFERENCES mdb_tables (id) ON DELETE CASCADE, FOREIGN KEY (rtid) REFERENCES mdb_tables (id) ) WITH SYSTEM VERSIONING; @@ -243,7 +243,7 @@ CREATE TABLE IF NOT EXISTS `mdb_constraints_unique` tid BIGINT NOT NULL, position INT NULL, PRIMARY KEY (uid), - FOREIGN KEY (tid) REFERENCES mdb_tables (id) + FOREIGN KEY (tid) REFERENCES mdb_tables (id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS `mdb_constraints_unique_columns` @@ -253,7 +253,7 @@ CREATE TABLE IF NOT EXISTS `mdb_constraints_unique_columns` cid BIGINT NOT NULL, PRIMARY KEY (id), FOREIGN KEY (uid) REFERENCES mdb_constraints_unique (uid), - FOREIGN KEY (cid) REFERENCES mdb_columns (id) + FOREIGN KEY (cid) REFERENCES mdb_columns (id) ON DELETE CASCADE ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_constraints_checks` @@ -262,7 +262,7 @@ CREATE TABLE IF NOT EXISTS `mdb_constraints_checks` tid BIGINT NOT NULL, checks VARCHAR(255) NOT NULL, PRIMARY KEY (id), - FOREIGN KEY (tid) REFERENCES mdb_tables (id) + FOREIGN KEY (tid) REFERENCES mdb_tables (id) ON DELETE CASCADE ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_concepts` diff --git a/dbrepo-metadata-db/setup-schema_local.sql b/dbrepo-metadata-db/setup-schema_local.sql index 1c144e31e35cb22bd09702ae683050454b66337d..4b35338875b707d7a951461bd54314017e573d16 100644 --- a/dbrepo-metadata-db/setup-schema_local.sql +++ b/dbrepo-metadata-db/setup-schema_local.sql @@ -2,6 +2,6 @@ BEGIN; INSERT INTO `mdb_containers` (name, internal_name, image_id, host, port, sidecar_host, sidecar_port, privileged_username, privileged_password) -VALUES ('MariaDB 11.1.3', 'mariadb_11_1_3', 1, 'data-db', 3306, 'data-db-sidecar', 3305, 'root', 'dbrepo'); +VALUES ('MariaDB Galera 11.1.3', 'mariadb_11_1_3', 1, 'data-db', 3306, 'data-db-sidecar', 3305, 'root', 'dbrepo'); COMMIT; diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AccessDeniedException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AccessDeniedException.java index 84169f32e08a9580d23b3590bb7a5691dcfe3975..a13b3f6016bfb60fb5b23c47ffb320e43c0f8165 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AccessDeniedException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AccessDeniedException.java @@ -13,7 +13,7 @@ public class AccessDeniedException extends IOException { } public AccessDeniedException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public AccessDeniedException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AmqpException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AmqpException.java index da70a16dd326cb81616e6f25a27b59151d57f33c..68da501b06ebb5c8009dad4179ea3d39e6bbe56a 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AmqpException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/AmqpException.java @@ -11,7 +11,7 @@ public class AmqpException extends Exception { } public AmqpException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public AmqpException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ArbitraryPrimaryKeysException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ArbitraryPrimaryKeysException.java index 0b644444233b141d76b0c4bd321c1bf50ed6880c..68bdb7647042cf0927640df62324fdca99456819 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ArbitraryPrimaryKeysException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ArbitraryPrimaryKeysException.java @@ -11,7 +11,7 @@ public class ArbitraryPrimaryKeysException extends Exception { } public ArbitraryPrimaryKeysException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public ArbitraryPrimaryKeysException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BannerMessageNotFoundException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BannerMessageNotFoundException.java index e4587b14539c329f409be25e5e67b2651771be88..75693577cbeae6499f65faa5e4e32ca29a613a71 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BannerMessageNotFoundException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BannerMessageNotFoundException.java @@ -11,7 +11,7 @@ public class BannerMessageNotFoundException extends Exception { } public BannerMessageNotFoundException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public BannerMessageNotFoundException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerMalformedException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerMalformedException.java index 975982aeac0f57b8bb5abfa1067e3483d25acb91..a448be46065f1568d7efb69839e98aa3805ae7cc 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerMalformedException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerMalformedException.java @@ -13,7 +13,7 @@ public class BrokerMalformedException extends IOException { } public BrokerMalformedException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public BrokerMalformedException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerRemoteException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerRemoteException.java index 922462d2ee95b4cfea228b64cab7f80e40fa7661..0d3a1b988b7e389b73c5c69f5474c8ae0afa27f7 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerRemoteException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerRemoteException.java @@ -11,7 +11,7 @@ public class BrokerRemoteException extends Exception { } public BrokerRemoteException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public BrokerRemoteException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerVirtualHostGrantException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerVirtualHostGrantException.java index 43c9b928a6250d8db190bfc5104557ac659fb594..4e06e3f843bc46561b5dc733d9f93093571f416d 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerVirtualHostGrantException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerVirtualHostGrantException.java @@ -11,7 +11,7 @@ public class BrokerVirtualHostGrantException extends Exception { } public BrokerVirtualHostGrantException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public BrokerVirtualHostGrantException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerVirtualHostModificationException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerVirtualHostModificationException.java index a9fda0c9d43ffc61ff5205c5f4eabf0ebadd32f0..5f7420d056bf5ea2712d5d3c7523af803e8d50d8 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerVirtualHostModificationException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/BrokerVirtualHostModificationException.java @@ -11,7 +11,7 @@ public class BrokerVirtualHostModificationException extends Exception { } public BrokerVirtualHostModificationException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public BrokerVirtualHostModificationException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ColumnParseException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ColumnParseException.java index c0c1e109de740d33646d7b91bb1a68ebabdc7616..8b81d044522ccf054c6f611314f5b042e811472d 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ColumnParseException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ColumnParseException.java @@ -11,7 +11,7 @@ public class ColumnParseException extends Exception { } public ColumnParseException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public ColumnParseException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ConceptNotFoundException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ConceptNotFoundException.java index f85cd6846a63acdd0e93d3828fcff57781b979bf..490b3c78dc2f48b2c9f61d16dd3c074e9e178aad 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ConceptNotFoundException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ConceptNotFoundException.java @@ -11,7 +11,7 @@ public class ConceptNotFoundException extends Exception { } public ConceptNotFoundException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public ConceptNotFoundException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ContainerNotFoundException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ContainerNotFoundException.java index 85d49d4cb34b20b15fdc1441c69cbab0fe0a34f3..40fc0dd4e17db6dcd9f8aa09d73e4fc91bf5d921 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ContainerNotFoundException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ContainerNotFoundException.java @@ -11,7 +11,7 @@ public class ContainerNotFoundException extends Exception { } public ContainerNotFoundException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public ContainerNotFoundException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ContainerStillRunningException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ContainerStillRunningException.java index 0eeceada67c3de08ffdf717b9cea24df0fc30d0a..7799caa84fd8b0b1c7f16cae86980c48b2c7aec1 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ContainerStillRunningException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ContainerStillRunningException.java @@ -10,12 +10,12 @@ public class ContainerStillRunningException extends Exception { super(msg); } - public ContainerStillRunningException(String msg, Throwable e) { - super(msg, e); + public ContainerStillRunningException(String msg, Throwable thr) { + super(msg + ": " + thr.getLocalizedMessage(), thr); } - public ContainerStillRunningException(Throwable e) { - super(e); + public ContainerStillRunningException(Throwable thr) { + super(thr); } } diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DataDbSidecarException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DataDbSidecarException.java index 036b23f6314fd6e230ca98b1ef8c08138a3f49e0..7258ad17555dc07e5f2896feee5e96d2c9ff8627 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DataDbSidecarException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DataDbSidecarException.java @@ -13,7 +13,7 @@ public class DataDbSidecarException extends IOException { } public DataDbSidecarException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public DataDbSidecarException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DataProcessingException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DataProcessingException.java index 873eb5d2820bebea680f55ad94d9350c88f77905..fd86efc2b2d2b2e211e3d12c236225c03afbdc44 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DataProcessingException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DataProcessingException.java @@ -11,7 +11,7 @@ public class DataProcessingException extends Exception { } public DataProcessingException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public DataProcessingException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseConnectionException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseConnectionException.java index 1296c643711ff9ed7bcaea35789201156c239ee8..a1d8dc0d26e3dfbe3a8ef67731e66f2f30f4b935 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseConnectionException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseConnectionException.java @@ -11,7 +11,7 @@ public class DatabaseConnectionException extends Exception { } public DatabaseConnectionException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public DatabaseConnectionException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseMalformedException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseMalformedException.java index 1775380783119b43ab6a716d4a152be9298ca4fa..1f9b8295c743efd358ca2781a66edf5663b19a82 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseMalformedException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseMalformedException.java @@ -13,7 +13,7 @@ public class DatabaseMalformedException extends IOException { } public DatabaseMalformedException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public DatabaseMalformedException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseNameExistsException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseNameExistsException.java index 68e194813806a1a5f3ecd8c36983e6e6a798acfc..86926b70167aa46aed6bdd234909fef38ea6808b 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseNameExistsException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseNameExistsException.java @@ -13,7 +13,7 @@ public class DatabaseNameExistsException extends IOException { } public DatabaseNameExistsException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public DatabaseNameExistsException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseNotFoundException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseNotFoundException.java index 3c22d6ea357d69865bba2e827209426ec78a6d11..d3c463cd9a5daf336f74d1cecbdb9d731f51f969 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseNotFoundException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DatabaseNotFoundException.java @@ -11,7 +11,7 @@ public class DatabaseNotFoundException extends Exception { } public DatabaseNotFoundException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public DatabaseNotFoundException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DoiNotFoundException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DoiNotFoundException.java index 4530e1e9967f91f1d86ae4b3eff347ee0e28c224..dc03edf81e473b266843cec7607533ece0e5371c 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DoiNotFoundException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/DoiNotFoundException.java @@ -11,7 +11,7 @@ public class DoiNotFoundException extends Exception { } public DoiNotFoundException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public DoiNotFoundException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ExchangeNotFoundException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ExchangeNotFoundException.java index fdaa0e3cfd64758d1f31ec8991e2312de00814b1..8b6620fed5bcb6cd520a512764f81269fee6359c 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ExchangeNotFoundException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ExchangeNotFoundException.java @@ -11,7 +11,7 @@ public class ExchangeNotFoundException extends Exception { } public ExchangeNotFoundException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public ExchangeNotFoundException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/FileStorageException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/FileStorageException.java index 21968a6e680f88e85ec1406936dc973c20c5c09b..9ec3f4f0df7a4019cffb14d32e1ccb6d1b6a9609 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/FileStorageException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/FileStorageException.java @@ -11,7 +11,7 @@ public class FileStorageException extends Exception { } public FileStorageException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public FileStorageException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/FilterBadRequestException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/FilterBadRequestException.java index 7364f797a3f48666b6836f7f2154fb48d32dad68..3fb79090130824b40f734928343cd4cb42e38a81 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/FilterBadRequestException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/FilterBadRequestException.java @@ -11,7 +11,7 @@ public class FilterBadRequestException extends Exception { } public FilterBadRequestException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public FilterBadRequestException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/HeaderInvalidException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/HeaderInvalidException.java index 87b7da4e97813da498f3ce6e8fd9b8584fb72ea2..ca6e829d3b9b41c0b5e571b58c6250677be5cba3 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/HeaderInvalidException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/HeaderInvalidException.java @@ -11,7 +11,7 @@ public class HeaderInvalidException extends Exception { } public HeaderInvalidException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public HeaderInvalidException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierAlreadyExistsException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierAlreadyExistsException.java index e913485aad24e30b1fc67cf4d493b7233a02c33f..706eeac06d4db44295d052e8439f4f112e01c084 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierAlreadyExistsException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierAlreadyExistsException.java @@ -11,7 +11,7 @@ public class IdentifierAlreadyExistsException extends Exception { } public IdentifierAlreadyExistsException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public IdentifierAlreadyExistsException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierAlreadyPublishedException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierAlreadyPublishedException.java index fefe477205e7fd431997e35b94d2ccba0e4bbd54..e8c23984b2390b9f6c527dca7cd9f12254ba9908 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierAlreadyPublishedException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierAlreadyPublishedException.java @@ -11,7 +11,7 @@ public class IdentifierAlreadyPublishedException extends Exception { } public IdentifierAlreadyPublishedException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public IdentifierAlreadyPublishedException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierNotFoundException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierNotFoundException.java index 9a844d7651439a897041f060709c242e3dbf9332..c4c2ead188086d6193041934cb9eb06aeae209b2 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierNotFoundException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierNotFoundException.java @@ -11,7 +11,7 @@ public class IdentifierNotFoundException extends Exception { } public IdentifierNotFoundException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public IdentifierNotFoundException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierPublishingNotAllowedException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierPublishingNotAllowedException.java index b2748cb9a71fee96982605c4833c3edf11f8d012..9623c55919f126c7a0b11ae05c68e8330b319be3 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierPublishingNotAllowedException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierPublishingNotAllowedException.java @@ -11,7 +11,7 @@ public class IdentifierPublishingNotAllowedException extends Exception { } public IdentifierPublishingNotAllowedException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public IdentifierPublishingNotAllowedException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierRequestException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierRequestException.java index ef20713d6f95170564908c42707cdea075cd3197..3999c47bc93ab0cfedd5d5ce2ba2d955dd91dc20 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierRequestException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierRequestException.java @@ -11,7 +11,7 @@ public class IdentifierRequestException extends Exception { } public IdentifierRequestException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public IdentifierRequestException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierUpdateBadFormException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierUpdateBadFormException.java index 884a5d4bc5e0c3edf69eb98833405fd073f1582d..b71955e757a84bc7c001a0995c015e76f69d1e47 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierUpdateBadFormException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/IdentifierUpdateBadFormException.java @@ -11,7 +11,7 @@ public class IdentifierUpdateBadFormException extends Exception { } public IdentifierUpdateBadFormException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public IdentifierUpdateBadFormException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageAlreadyExistsException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageAlreadyExistsException.java index 9b52af25ff35893279889643ba06f7ae8db242c8..ff6d236fc40e30b90b2b011679599e88d0916e25 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageAlreadyExistsException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageAlreadyExistsException.java @@ -10,12 +10,12 @@ public class ImageAlreadyExistsException extends Exception { super(msg); } - public ImageAlreadyExistsException(String msg, Throwable e) { - super(msg, e); + public ImageAlreadyExistsException(String msg, Throwable thr) { + super(msg + ": " + thr.getLocalizedMessage(), thr); } - public ImageAlreadyExistsException(Throwable e) { - super(e); + public ImageAlreadyExistsException(Throwable thr) { + super(thr); } } \ No newline at end of file diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageInvalidException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageInvalidException.java index 5cfc720a4ca3f6c236f58380fae9c520591bde8f..93a7a30912de66767c6270def780399a7e7c9e19 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageInvalidException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageInvalidException.java @@ -10,12 +10,12 @@ public class ImageInvalidException extends Exception { super(msg); } - public ImageInvalidException(String msg, Throwable e) { - super(msg, e); + public ImageInvalidException(String msg, Throwable thr) { + super(msg + ": " + thr.getLocalizedMessage(), thr); } - public ImageInvalidException(Throwable e) { - super(e); + public ImageInvalidException(Throwable thr) { + super(thr); } } \ No newline at end of file diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageNotSupportedException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageNotSupportedException.java index 1d293e03e5be0ba929f933187d1cbab9bb42a446..c37d2d07a441ed950ac6e3a0ed898478f7fc8e1f 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageNotSupportedException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ImageNotSupportedException.java @@ -11,7 +11,7 @@ public class ImageNotSupportedException extends Exception { } public ImageNotSupportedException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public ImageNotSupportedException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/InvalidPrefixException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/InvalidPrefixException.java index d14264a53c75c5b36143aeb1747082d30d2670f3..0a51bf42b0b2186e5e9c9a448bdf0041701ae1a6 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/InvalidPrefixException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/InvalidPrefixException.java @@ -11,7 +11,7 @@ public class InvalidPrefixException extends Exception { } public InvalidPrefixException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public InvalidPrefixException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/KeycloakRemoteException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/KeycloakRemoteException.java index 6616739278b0b02b8160d09e94c87f304f809628..f4898eba1e0be444043186e7eabf21fabf7add06 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/KeycloakRemoteException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/KeycloakRemoteException.java @@ -11,7 +11,7 @@ public class KeycloakRemoteException extends Exception { } public KeycloakRemoteException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public KeycloakRemoteException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/NotAllowedException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/NotAllowedException.java index b1521fe9402ed022ac69d33f48b704b643fc62da..f7bc6f69f7244da3f892d8f0bec02ed76be6e05b 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/NotAllowedException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/NotAllowedException.java @@ -11,7 +11,7 @@ public class NotAllowedException extends Exception { } public NotAllowedException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public NotAllowedException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/OntologyNotFoundException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/OntologyNotFoundException.java index cb82fc0b9acc02f7e27faa3fa4f4efdeee8d6532..df590e0669d1d08edfee445d102e051529306f68 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/OntologyNotFoundException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/OntologyNotFoundException.java @@ -11,7 +11,7 @@ public class OntologyNotFoundException extends Exception { } public OntologyNotFoundException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public OntologyNotFoundException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/OrcidNotFoundException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/OrcidNotFoundException.java index 0f87985305d93294f1dcbfc1648d3f13a74113de..13414f10e1f89d193512ed23993d4e025edaa281 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/OrcidNotFoundException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/OrcidNotFoundException.java @@ -11,7 +11,7 @@ public class OrcidNotFoundException extends Exception { } public OrcidNotFoundException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public OrcidNotFoundException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/PaginationException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/PaginationException.java index 9d56aec9c2752c2c37e7b31f227950ad94c95ef3..11b8aecc8757f4d3b7a5c776d963101725eb75cc 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/PaginationException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/PaginationException.java @@ -11,7 +11,7 @@ public class PaginationException extends Exception { } public PaginationException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public PaginationException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/PersistenceException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/PersistenceException.java index 92c1d6f4b9ed8fa7ab2e69e6d11871fe9ed176dd..44bf9da7ed2703897ce79acfbb8f6b4a24e8a5ba 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/PersistenceException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/PersistenceException.java @@ -11,7 +11,7 @@ public class PersistenceException extends Exception { } public PersistenceException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public PersistenceException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryAlreadyPersistedException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryAlreadyPersistedException.java index 48d3bb0ad9ec2fb1f7c6b9727f2a3e700291cbc6..4192625527eccc87620e5bb927b5a3ed4963b80f 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryAlreadyPersistedException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryAlreadyPersistedException.java @@ -11,7 +11,7 @@ public class QueryAlreadyPersistedException extends Exception { } public QueryAlreadyPersistedException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public QueryAlreadyPersistedException(Throwable thr) { super(thr); diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryMalformedException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryMalformedException.java index 6d3d2bc052a734dd49bf58e309b063c11f55292a..18fdc50074fe7384465de8fb31b9e2cb55372846 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryMalformedException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryMalformedException.java @@ -11,7 +11,7 @@ public class QueryMalformedException extends Exception { } public QueryMalformedException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public QueryMalformedException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryNotFoundException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryNotFoundException.java index a5e90754898f19f6cce8938d2385f3f9fecd43e4..003a85046b5da45eea6ccf9e8f211d4ed0c227d9 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryNotFoundException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryNotFoundException.java @@ -11,7 +11,7 @@ public class QueryNotFoundException extends Exception { } public QueryNotFoundException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public QueryNotFoundException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStoreException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStoreException.java index d07cd0df4aa239005ecfdefec438d9305dcfa818..388a35a85f10ca0457d0929a4053724b696c64d7 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStoreException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueryStoreException.java @@ -11,7 +11,7 @@ public class QueryStoreException extends Exception { } public QueryStoreException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public QueryStoreException(Throwable thr) { super(thr); diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueueNotFoundException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueueNotFoundException.java index b5c6aed7ffa34baa9b10d7db3b083eb47223b3ff..7ee465aab5baa05fb272c45daa1067525e43c15b 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueueNotFoundException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/QueueNotFoundException.java @@ -11,7 +11,7 @@ public class QueueNotFoundException extends Exception { } public QueueNotFoundException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public QueueNotFoundException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RealmNotFoundException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RealmNotFoundException.java index 1750cfb525c2947f8f13837b5e89ed7ddc46f8fd..1b69a01df8d5b6598e8eaf12a2d74547cf305759 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RealmNotFoundException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RealmNotFoundException.java @@ -11,7 +11,7 @@ public class RealmNotFoundException extends Exception { } public RealmNotFoundException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public RealmNotFoundException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RemoteUnavailableException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RemoteUnavailableException.java index 3f6700d06b277d59ccbf812136faec277261357d..3c2a17743989080140758a016e8900ceac87af7a 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RemoteUnavailableException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RemoteUnavailableException.java @@ -11,7 +11,7 @@ public class RemoteUnavailableException extends Exception { } public RemoteUnavailableException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public RemoteUnavailableException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RoleNotFoundException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RoleNotFoundException.java index 8430d64d76c7a422a6e17752398c491cf6f78cd3..21caf8b8bda96729d77fd3b70a4568c66b56e749 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RoleNotFoundException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RoleNotFoundException.java @@ -11,7 +11,7 @@ public class RoleNotFoundException extends Exception { } public RoleNotFoundException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public RoleNotFoundException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RorNotFoundException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RorNotFoundException.java index e22cad5c36bc4d116c41cffb613a7b3419a9fb79..f6a188e1858eaf1a1b0c2166e40cf02a4011249e 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RorNotFoundException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/RorNotFoundException.java @@ -11,7 +11,7 @@ public class RorNotFoundException extends Exception { } public RorNotFoundException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public RorNotFoundException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SemanticEntityNotFoundException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SemanticEntityNotFoundException.java index 70098f61dacc02ff101b4c99724eb83d4b1c636a..2903da9a48fd101e3b1e1aca237d96f9c83d5f4b 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SemanticEntityNotFoundException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SemanticEntityNotFoundException.java @@ -11,7 +11,7 @@ public class SemanticEntityNotFoundException extends Exception { } public SemanticEntityNotFoundException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public SemanticEntityNotFoundException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SemanticEntityPersistException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SemanticEntityPersistException.java index e33560e942a30c38e1a027c2d1ce1a5a98aa978a..a46ae85be041d29c171fda8278f333c485618c75 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SemanticEntityPersistException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SemanticEntityPersistException.java @@ -11,7 +11,7 @@ public class SemanticEntityPersistException extends Exception { } public SemanticEntityPersistException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public SemanticEntityPersistException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SortException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SortException.java index 7415590ad637461baac4c9bf1d68b7d411054b19..b15e055793aa302bfd39685b6e4ae911009412f7 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SortException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/SortException.java @@ -11,7 +11,7 @@ public class SortException extends Exception { } public SortException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public SortException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableColumnNotFoundException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableColumnNotFoundException.java index e83abd5eef61384fce6292ec2870b76ebcf70481..1de886ca193ae1de15976382ccafe081f5f1301c 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableColumnNotFoundException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableColumnNotFoundException.java @@ -11,7 +11,7 @@ public class TableColumnNotFoundException extends Exception { } public TableColumnNotFoundException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public TableColumnNotFoundException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableMalformedException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableMalformedException.java index fb232e7155d519be931d0aaa1641a576480ca183..d4de12d91bf2647dd082a74c19a5e22819784cf9 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableMalformedException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableMalformedException.java @@ -11,7 +11,7 @@ public class TableMalformedException extends Exception { } public TableMalformedException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public TableMalformedException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableNameExistsException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableNameExistsException.java index e1251f4b5f7eb6889be6cbb21f5085d3f1c0d718..6650c0ac3117720bb6ec0ec097c2ce19aed8367a 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableNameExistsException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableNameExistsException.java @@ -11,7 +11,7 @@ public class TableNameExistsException extends Exception { } public TableNameExistsException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public TableNameExistsException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableNotFoundException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableNotFoundException.java index 89fa3ed467e76998431c2b366bceb83804824f38..57146ca8c6ba2e92ee20ecb2521eb60872355281 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableNotFoundException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TableNotFoundException.java @@ -11,7 +11,7 @@ public class TableNotFoundException extends Exception { } public TableNotFoundException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public TableNotFoundException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TupleDeleteException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TupleDeleteException.java index 87e5e4a483f9dfe38f9563be9a9d275415b5a0d9..55b034c7b39407c890cb91f1717e0060a619664e 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TupleDeleteException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/TupleDeleteException.java @@ -11,7 +11,7 @@ public class TupleDeleteException extends Exception { } public TupleDeleteException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public TupleDeleteException(Throwable thr) { super(thr); diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UnitNotFoundException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UnitNotFoundException.java index 6a5e1ddf6065a0469c1322a2e37a86c46871b328..2d67d3bc5e2b131626dbcca56aa90ff1d75974b6 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UnitNotFoundException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UnitNotFoundException.java @@ -11,7 +11,7 @@ public class UnitNotFoundException extends Exception { } public UnitNotFoundException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public UnitNotFoundException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UriMalformedException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UriMalformedException.java index 92f102fb569beec5c45eb6ed8a2043dabe702610..b8867960749e6ac98b122040851849180671a795 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UriMalformedException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UriMalformedException.java @@ -11,7 +11,7 @@ public class UriMalformedException extends Exception { } public UriMalformedException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public UriMalformedException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UserAttributeNotFoundException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UserAttributeNotFoundException.java index f0d3249868a20ff1211226b4fefd2eade255f3db..2ceb33a0f702fe21702d37ec1e2acc03c6ab8556 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UserAttributeNotFoundException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/UserAttributeNotFoundException.java @@ -11,7 +11,7 @@ public class UserAttributeNotFoundException extends Exception { } public UserAttributeNotFoundException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public UserAttributeNotFoundException(Throwable thr) { diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ViewMalformedException.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ViewMalformedException.java index 5dfdaf170eaccc76da2290673448be19511e4fab..fc96d29c32955a93317387cdf7772569bc791f72 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ViewMalformedException.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/exception/ViewMalformedException.java @@ -11,7 +11,7 @@ public class ViewMalformedException extends Exception { } public ViewMalformedException(String msg, Throwable thr) { - super(msg, thr); + super(msg + ": " + thr.getLocalizedMessage(), thr); } public ViewMalformedException(Throwable thr) { 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 index 1b6214611938d74342ebbcd0645e96c948ee40b0..d5fe384b3475a444aaf7e6497140014d564786a8 100644 --- 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 @@ -307,26 +307,40 @@ public interface TableMapper { /** * Map the table to a drop table query - * TODO for e.g. postgres image * - * @param data The table - * @return The drop table query + * @param connection The connection + * @param data The table that should be dropped. */ - default PreparedStatement tableToDropTableRawQuery(Connection connection, Table data) throws ImageNotSupportedException, QueryMalformedException { + default void tableToDropTableRawQuery(Connection connection, Table data) throws ImageNotSupportedException, QueryMalformedException { if (!data.getDatabase().getContainer().getImage().getName().equals("mariadb")) { log.error("Currently only MariaDB is supported"); throw new ImageNotSupportedException("Currently only MariaDB is supported"); } - final StringBuilder statement = new StringBuilder("DROP TABLE `") + final StringBuilder sequence = new StringBuilder(); + if (data.getColumns().stream().anyMatch(TableColumn::getAutoGenerated)) { + log.debug("table with id {} has sequence generated which needs to be dropped too", data.getId()); + sequence.append("DROP SEQUENCE `") + .append(tableToSequenceName(data)) + .append("`;"); + } + final StringBuilder table = new StringBuilder("DROP TABLE `") + .append(data.getInternalName()) + .append("`;"); + final StringBuilder view = new StringBuilder("DROP VIEW `hs_") .append(data.getInternalName()) .append("`;"); try { - final PreparedStatement pstmt = connection.prepareStatement(statement.toString()); - log.trace("prepared statement {}", statement); - return pstmt; + final Statement statement = connection.createStatement(); + if (!sequence.isEmpty()) { + statement.execute(sequence.toString()); + } + statement.execute(table.toString()); + log.trace("mapped drop table statement {}", table); + statement.execute(view.toString()); + log.trace("mapped drop view statement {}", table); } catch (SQLException e) { - log.error("Failed to prepare statement {}, reason: {}", statement, e.getMessage()); - throw new QueryMalformedException("Failed to prepare statement", e); + log.error("Failed to drop table or sequence: {}", e.getMessage()); + throw new QueryMalformedException("Failed to drop table or sequence", e); } } @@ -439,7 +453,7 @@ public interface TableMapper { log.trace("create table query built with {} columns and system versioning", data.getColumns().size()); try { final Statement statement = connection.createStatement(); - if (sequence.length() > 0) { + if (!sequence.isEmpty()) { log.trace("mapped create sequence statement: {}", sequence); statement.execute(sequence.toString()); } @@ -454,32 +468,28 @@ public interface TableMapper { default String tableCreateDtoToSequenceName(TableCreateDto data) { final String name = "seq_" + nameToInternalName(data.getName()) + "_id"; - log.trace("mapped name {} to internal name {}", data.getName(), name); + log.trace("mapped table name {} to sequence name {}", data.getName(), name); + return name; + } + + default String tableToSequenceName(Table data) { + final String name = "seq_" + data.getInternalName() + "_id"; + log.trace("mapped table to sequence name {}", name); return name; } default PreparedStatement tableToCreateHistoryViewRawQuery(Connection connection, Table data) throws QueryMalformedException { - final StringBuilder statement = new StringBuilder("CREATE VIEW `hs_") + final StringBuilder view = new StringBuilder("CREATE VIEW `hs_") .append(data.getInternalName()) - .append("` AS SELECT * FROM (SELECT "); - final int[] idx = new int[]{0}; - data.getColumns() - .stream() - .filter(c -> Objects.nonNull(c.getIsPrimaryKey())) - .filter(TableColumn::getIsPrimaryKey) - .forEach(c -> statement.append(idx[0]++ > 0 ? "," : "") - .append("`") - .append(c.getInternalName()) - .append("`")); - statement.append(", ROW_START AS inserted_at, IF(ROW_END > NOW(), NULL, ROW_END) AS deleted_at, COUNT(*) as total FROM `") + .append("` AS SELECT * FROM (SELECT ROW_START AS inserted_at, IF(ROW_END > NOW(), NULL, ROW_END) AS deleted_at, COUNT(*) as total FROM `") .append(data.getInternalName()) .append("` FOR SYSTEM_TIME ALL GROUP BY inserted_at, deleted_at ORDER BY deleted_at DESC LIMIT 50) AS v ORDER BY v.inserted_at, v.deleted_at ASC"); try { - final PreparedStatement pstmt = connection.prepareStatement(statement.toString()); - log.trace("prepared create sequence statement {}", statement); + final PreparedStatement pstmt = connection.prepareStatement(view.toString()); + log.trace("prepared create view statement {}", view); return pstmt; } catch (SQLException e) { - log.error("failed to prepare statement {}, reason: {}", statement, e.getMessage()); + log.error("Failed to prepare statement: {}", e.getMessage()); throw new QueryMalformedException("Failed to prepare statement", e); } } diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/mdb/TableRepository.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/mdb/TableRepository.java index 314c23ab0b8b02432a0d98a8622fc8e6f512bfe0..4ee22add4f56a40ea89428b060e1223324ae7bb0 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/mdb/TableRepository.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/mdb/TableRepository.java @@ -26,6 +26,8 @@ public interface TableRepository extends JpaRepository<Table, Long> { */ List<Table> findByDatabaseOrderByCreatedDesc(Database database); + List<Table> findByInternalName(String internalName); + /** * Finds a table with given database and internal name. * 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 10d0ae805ff6e6fbe1303571d469e0e5d35c2fb9..0b0b27c16f6be592debe9f1d5e2d3de77776e8d2 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 @@ -12,6 +12,7 @@ import at.tuwien.mapper.TableMapper; import at.tuwien.service.MessageQueueService; import at.tuwien.service.TableService; import at.tuwien.utils.PrincipalUtil; +import at.tuwien.utils.UserUtil; import at.tuwien.validation.EndpointValidator; import io.micrometer.core.annotation.Timed; import io.micrometer.observation.annotation.Observed; @@ -201,7 +202,7 @@ public class TableEndpoint { @DeleteMapping("/{tableId}") @Transactional - @PreAuthorize("hasAuthority('delete-table')") + @PreAuthorize("hasAuthority('delete-table') or hasAuthority('delete-foreign-table')") @Observed(name = "dbr_table_delete") @Operation(summary = "Delete a table", security = @SecurityRequirement(name = "bearerAuth")) @ApiResponses(value = { @@ -245,8 +246,14 @@ public class TableEndpoint { @NotNull @PathVariable("tableId") Long tableId, @NotNull Principal principal) throws TableNotFoundException, DatabaseNotFoundException, ImageNotSupportedException, - DataProcessingException, ContainerNotFoundException, TableMalformedException, QueryMalformedException { + DataProcessingException, ContainerNotFoundException, TableMalformedException, QueryMalformedException, + NotAllowedException { log.debug("endpoint delete table, databaseId={}, tableId={}, {}", databaseId, tableId, PrincipalUtil.formatForDebug(principal)); + final Table table = tableService.find(databaseId, tableId); + if (!table.getOwner().getUsername().equals(principal.getName()) && !UserUtil.hasRole(principal, "delete-foreign-table")) { + log.error("Failed to delete table: not owned by you"); + throw new NotAllowedException("Failed to delete table: not owned by you"); + } tableService.deleteTable(databaseId, tableId); return ResponseEntity.accepted() .build(); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java index 1d61a1108d8ceba8c2eaabaee35a6f1efcfd98d3..8dcfd93053237604647e5a588ccd9949666fc0bb 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/config/MariaDbContainerConfig.java @@ -1,6 +1,7 @@ package at.tuwien.config; import at.tuwien.test.BaseTest; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.testcontainers.containers.MariaDBContainer; @@ -33,7 +34,7 @@ public class MariaDbContainerConfig { public static synchronized CustomMariaDBContainer getInstance() { if (instance == null) { - instance = new CustomMariaDBContainer(BaseTest.IMAGE_1_NAME + ":" + BaseTest.IMAGE_1_VERSION); + instance = new CustomMariaDBContainer("mariadb:11.1.3"); instance.withImagePullPolicy(PullPolicy.alwaysPull()); instance.addFixedExposedPort(BaseTest.CONTAINER_1_PORT, BaseTest.IMAGE_1_PORT); instance.withUsername(BaseTest.CONTAINER_1_PRIVILEGED_USERNAME); 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 5ee6b057a2cb95b3d968e48d6c39fdc9144e8ec7..21762fad93390459ccf89d2bc87d4542b7ad6b45 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 @@ -321,7 +321,12 @@ public class TableEndpointUnitTest extends BaseUnitTest { @Test @WithMockUser(username = USER_1_USERNAME, authorities = "delete-table") - public void delete_publicHasRoleTableNotFound_fails() { + public void delete_publicHasRoleTableNotFound_fails() throws TableNotFoundException, DatabaseNotFoundException { + + /* mock */ + doThrow(TableNotFoundException.class) + .when(tableService) + .find(DATABASE_3_ID, TABLE_8_ID); /* test */ assertThrows(TableNotFoundException.class, () -> { @@ -331,20 +336,45 @@ public class TableEndpointUnitTest extends BaseUnitTest { @Test @WithMockUser(username = USER_1_USERNAME, authorities = "delete-table") - public void delete_publiceHasRoleDatabaseNotFound_fails() { + public void delete_publicHasRole_succeeds() throws DatabaseNotFoundException, NotAllowedException, + TableNotFoundException, TableMalformedException, QueryMalformedException, ImageNotSupportedException, + ContainerNotFoundException, DataProcessingException { + + /* mock */ + when(tableService.find(DATABASE_3_ID, TABLE_8_ID)) + .thenReturn(TABLE_8); /* test */ - assertThrows(DatabaseNotFoundException.class, () -> { - generic_delete(DATABASE_3_ID, TABLE_8_ID, null, TABLE_8, USER_1_PRINCIPAL); - }); + final ResponseEntity<?> response = generic_delete(DATABASE_3_ID, TABLE_8_ID, DATABASE_3, TABLE_8, USER_1_PRINCIPAL); + assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); } @Test @WithMockUser(username = USER_1_USERNAME, authorities = "delete-table") - public void delete_publicHasRole_succeeds() throws DatabaseNotFoundException, NotAllowedException, TableNotFoundException, TableMalformedException, QueryMalformedException, ImageNotSupportedException, ContainerNotFoundException, DataProcessingException { + public void delete_privateHasRoleForeignTable_fails() throws DatabaseNotFoundException, TableNotFoundException { + + /* mock */ + when(tableService.find(DATABASE_1_ID, TABLE_2_ID)) + .thenReturn(TABLE_2); /* test */ - final ResponseEntity<?> response = generic_delete(DATABASE_3_ID, TABLE_8_ID, DATABASE_3, TABLE_8, USER_1_PRINCIPAL); + assertThrows(NotAllowedException.class, () -> { + generic_delete(DATABASE_1_ID, TABLE_2_ID, DATABASE_1, TABLE_2, USER_1_PRINCIPAL); + }); + } + + @Test + @WithMockUser(username = USER_2_USERNAME, authorities = "delete-foreign-table") + public void delete_privateHasRoleForeignTable_succeeds() throws DatabaseNotFoundException, TableNotFoundException, + NotAllowedException, TableMalformedException, QueryMalformedException, ImageNotSupportedException, + ContainerNotFoundException, DataProcessingException { + + /* mock */ + when(tableService.find(DATABASE_1_ID, TABLE_1_ID)) + .thenReturn(TABLE_1); + + /* test */ + final ResponseEntity<?> response = generic_delete(DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_2_PRINCIPAL); assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); } @@ -515,7 +545,11 @@ public class TableEndpointUnitTest extends BaseUnitTest { @Test @WithMockUser(username = USER_1_USERNAME, authorities = "delete-table") - public void delete_privateHasRoleTableNotFound_fails() { + public void delete_privateHasRoleTableNotFound_fails() throws TableNotFoundException, DatabaseNotFoundException { + + doThrow(TableNotFoundException.class) + .when(tableService) + .find(DATABASE_1_ID, TABLE_1_ID); /* test */ assertThrows(TableNotFoundException.class, () -> { @@ -525,7 +559,11 @@ public class TableEndpointUnitTest extends BaseUnitTest { @Test @WithMockUser(username = USER_1_USERNAME, authorities = "delete-table") - public void delete_privateHasRoleDatabaseNotFound_fails() { + public void delete_privateHasRoleDatabaseNotFound_fails() throws TableNotFoundException, DatabaseNotFoundException { + + /* mock */ + when(tableService.find(DATABASE_1_ID, TABLE_1_ID)) + .thenReturn(TABLE_1); /* test */ assertThrows(DatabaseNotFoundException.class, () -> { @@ -539,6 +577,10 @@ public class TableEndpointUnitTest extends BaseUnitTest { TableNotFoundException, TableMalformedException, QueryMalformedException, ImageNotSupportedException, ContainerNotFoundException, DataProcessingException { + /* mock */ + when(tableService.find(DATABASE_1_ID, TABLE_1_ID)) + .thenReturn(TABLE_1); + /* test */ final ResponseEntity<?> response = generic_delete(DATABASE_1_ID, TABLE_1_ID, DATABASE_1, TABLE_1, USER_1_PRINCIPAL); assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceIntegrationTest.java index d8557922fd1a9bd00ebf9bbfdc9603d7b3720425..d87c4aef51a902751a5aee720c2d383e92518221 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceIntegrationTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceIntegrationTest.java @@ -49,7 +49,7 @@ public class ImageServiceIntegrationTest extends BaseUnitTest { public void create_succeeds() throws ImageAlreadyExistsException { final ImageCreateDto request = ImageCreateDto.builder() .name(IMAGE_1_NAME) - .version("11.1.3") + .version("11.1.4") // new tag .jdbcMethod(IMAGE_1_JDBC) .dialect(IMAGE_1_DIALECT) .driverClass(IMAGE_1_DRIVER) diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationWriteTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationWriteTest.java index c3149bd713ea0fe616724f72468e7d7774dc7417..cf4f5f86edb5f5f0b0f963174d647255ff9c3678 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationWriteTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationWriteTest.java @@ -97,6 +97,9 @@ public class TableServiceIntegrationWriteTest extends BaseUnitTest { databaseRepository.save(DATABASE_1_SIMPLE); tableRepository.save(TABLE_1_SIMPLE); tableRepository.save(TABLE_2_SIMPLE); + /* missing pointers */ + TABLE_1.setConstraints(TABLE_1_CONSTRAINTS); + TABLE_2.setConstraints(TABLE_2_CONSTRAINTS); } @Test diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java index caa127161168b6ab4c7a70c6efb2be6149107592..68525e6729e4852eb4016f5e6a066acbcf8fa1f2 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java @@ -135,12 +135,11 @@ public class ViewServiceIntegrationTest extends BaseUnitTest { assertEquals("7.4", resultSet.get(1).get("mintemp")); assertEquals("0", resultSet.get(1).get("rainfall")); assertEquals("Albury", resultSet.get(1).get("location")); - assertEquals("2008-12-01", resultSet.get(1).get("date")); + assertEquals("2008-12-02", resultSet.get(1).get("date")); assertEquals("12.9", resultSet.get(2).get("mintemp")); assertEquals("0", resultSet.get(2).get("rainfall")); assertEquals("Albury", resultSet.get(2).get("location")); - assertEquals("2008-12-01", resultSet.get(2).get("date")); - /* more result checks omitted */ + assertEquals("2008-12-03", resultSet.get(2).get("date")); } @Test 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 ef99379904afbbbc2bacf1b2c625c0c0a474435a..7b37e4d8b94f6a542401ad22313ca3a0ea5fd321 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 @@ -15,8 +15,8 @@ public interface TableService { /** * Find a table in the metadata database by database-table id tuple * - * @param databaseId The database id. - * @param tableId The table id. + * @param databaseId The database id. + * @param tableId The table id. * @return The database. * @throws DatabaseNotFoundException The database is not found. * @throws TableNotFoundException The table is not found. @@ -33,21 +33,22 @@ public interface TableService { /** * Find the table history. * - * @param databaseId The database id. - * @param tableId The table id. - * @param principal The user principal. + * @param databaseId The database id. + * @param tableId The table id. + * @param principal The user principal. * @return The history as a list, if successful. * @throws QueryMalformedException The query is malformed. * @throws DatabaseNotFoundException The database is not found. * @throws TableNotFoundException The table is not found. */ List<TableHistoryDto> findHistory(Long databaseId, Long tableId, Principal principal) - throws DatabaseNotFoundException, QueryMalformedException, TableNotFoundException, DatabaseConnectionException, QueryStoreException, UserNotFoundException; + throws DatabaseNotFoundException, QueryMalformedException, TableNotFoundException, + DatabaseConnectionException, QueryStoreException, UserNotFoundException; /** * Select all tables from the metadata database. * - * @param databaseId The database id. + * @param databaseId The database id. * @return The list of tables. */ List<Table> findAll(Long databaseId) throws DatabaseNotFoundException; @@ -55,8 +56,8 @@ public interface TableService { /** * Deletes a table for a fiven database-table id pair. * - * @param databaseId The database id. - * @param tableId The table id. + * @param databaseId The database id. + * @param tableId The table id. * @throws TableNotFoundException The table was not found in the metadata database. * @throws DatabaseNotFoundException The database was not found in the metadata database. * @throws ImageNotSupportedException The image is not supported. @@ -70,8 +71,8 @@ public interface TableService { /** * Find a table by database-table id pair * - * @param databaseId The database id. - * @param tableId The table id. + * @param databaseId The database id. + * @param tableId The table id. * @return The table. * @throws TableNotFoundException The table was not found in the metadata database. * @throws DatabaseNotFoundException The database was not found in the metadata database. @@ -83,9 +84,9 @@ public interface TableService { /** * Creates a table for a database id with given schema as data * - * @param databaseId The database id. - * @param createDto The schema (as data). - * @param principal The principal. + * @param databaseId The database id. + * @param createDto The schema (as data). + * @param principal The principal. * @return The created table. * @throws ImageNotSupportedException The image is not supported. * @throws DatabaseNotFoundException The database was not found in the metadata database. @@ -101,10 +102,10 @@ public interface TableService { /** * Updates a table column * - * @param databaseId The database id. - * @param tableId The table id. - * @param columnId The column id. - * @param updateDto The update data containing unit and concept uris. + * @param databaseId The database id. + * @param tableId The table id. + * @param columnId The column id. + * @param updateDto The update data containing unit and concept uris. * @return The updated table column, if successful. * @throws TableNotFoundException The table was not found in the metadata database. * @throws DatabaseNotFoundException The database was not found in the metadata database. 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 4cf3bf7459721e47a0d4c852a19bf8f772f5b96e..16bfa35731097aa91de4d7417bf7cc8b4b6903f3 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 @@ -128,11 +128,10 @@ public class TableServiceImpl extends HibernateConnector implements TableService final ComboPooledDataSource dataSource = getPrivilegedDataSource(database.getContainer().getImage(), database.getContainer(), database); try { final Connection connection = dataSource.getConnection(); - final PreparedStatement preparedStatement = tableMapper.tableToDropTableRawQuery(connection, table); - preparedStatement.executeUpdate(); + tableMapper.tableToDropTableRawQuery(connection, table); } catch (SQLException e) { - log.error("Failed to delete table {}, reason: {}", table, e.getMessage()); - throw new TableMalformedException("Failed to delete table", e); + log.error("Failed to drop table: {}", e.getMessage()); + throw new TableMalformedException("Failed to drop table", e); } finally { dataSource.close(); } @@ -181,7 +180,7 @@ public class TableServiceImpl extends HibernateConnector implements TableService final Connection connection = dataSource.getConnection(); generatedSequence = tableMapper.tableToCreateTableRawQuery(connection, createDto); } catch (Exception e) { - log.error("Failed to create table, reason: {}", e.getMessage()); + log.error("Failed to create table: {}", e.getMessage()); throw new TableMalformedException("Failed to create table", e); } finally { dataSource.close(); 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 c6a049806f2401ac62c3129aa67cb2b4b91b0140..91fc524226b74c251917359c075fb85a73b5fdaf 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 @@ -160,10 +160,10 @@ 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"}; + "list-tables", "create-table", "modify-table-column-semantics", "find-table", "delete-table"}; public final static String[] ESCALATED_TABLE_HANDLING = new String[]{"escalated-table-handling", - "delete-table"}; + "delete-foreign-table"}; public final static String[] DEFAULT_USER_HANDLING = new String[]{"default-user-handling", "modify-user-theme", "modify-user-information"}; @@ -665,7 +665,7 @@ public abstract class BaseTest { public final static Long IMAGE_1_ID = 1L; public final static String IMAGE_1_REGISTRY = "docker.io/library"; public final static String IMAGE_1_NAME = "mariadb"; - public final static String IMAGE_1_VERSION = "10.5"; + public final static String IMAGE_1_VERSION = "11.1.3"; public final static String IMAGE_1_DIALECT = "org.hibernate.dialect.MariaDBDialect"; public final static String IMAGE_1_DRIVER = "org.mariadb.jdbc.Driver"; public final static String IMAGE_1_JDBC = "mariadb"; @@ -1651,6 +1651,7 @@ public abstract class BaseTest { .created(TABLE_1_CREATED) .createdBy(USER_1_ID) .ownedBy(USER_1_ID) + .owner(USER_1) .lastModified(TABLE_1_LAST_MODIFIED) .build(); @@ -1702,6 +1703,7 @@ public abstract class BaseTest { .constraints(null /* TABLE_2_CONSTRAINTS */) .createdBy(USER_2_ID) .ownedBy(USER_2_ID) + .owner(USER_2) .created(TABLE_2_CREATED) .lastModified(TABLE_2_LAST_MODIFIED) .build(); @@ -1754,6 +1756,7 @@ public abstract class BaseTest { .constraints(null /* TABLE_3_CONSTRAINTS */) .createdBy(USER_3_ID) .ownedBy(USER_3_ID) + .owner(USER_3) .created(TABLE_3_CREATED) .lastModified(TABLE_3_LAST_MODIFIED) .build(); @@ -1830,6 +1833,7 @@ public abstract class BaseTest { .constraints(null) /* TABLE_4_CONSTRAINTS */ .createdBy(USER_1_ID) .ownedBy(USER_1_ID) + .owner(USER_1) .build(); public final static Table TABLE_4_SIMPLE = Table.builder() @@ -1882,6 +1886,7 @@ public abstract class BaseTest { .constraints(null) /* TABLE_5_CONSTRAINTS */ .createdBy(USER_1_ID) .ownedBy(USER_1_ID) + .owner(USER_1) .created(TABLE_5_CREATED) .lastModified(TABLE_5_LAST_MODIFIED) .build(); @@ -1932,6 +1937,7 @@ public abstract class BaseTest { .constraints(null) /* TABLE_6_CONSTRAINTS */ .createdBy(USER_1_ID) .ownedBy(USER_1_ID) + .owner(USER_1) .created(TABLE_6_CREATED) .lastModified(TABLE_6_LAST_MODIFIED) .build(); @@ -1979,6 +1985,7 @@ public abstract class BaseTest { .columns(List.of() /* needs to be set in the junit tests */) .createdBy(USER_1_ID) .ownedBy(USER_1_ID) + .owner(USER_1) .created(TABLE_7_CREATED) .lastModified(TABLE_7_LAST_MODIFIED) .build(); @@ -2088,6 +2095,7 @@ public abstract class BaseTest { .columns(List.of() /* needs to be set in the junit tests */) .createdBy(USER_1_ID) .ownedBy(USER_1_ID) + .owner(USER_1) .created(TABLE_8_CREATED) .lastModified(TABLE_8_LAST_MODIFIED) .build(); @@ -3510,7 +3518,10 @@ public abstract class BaseTest { ForeignKeyReference.builder().column(TABLE_1_COLUMNS.get(2)).referencedColumn(TABLE_1_COLUMNS.get(0)).build()) ).build() )) - .uniques(List.of(Unique.builder().columns(List.of(TABLE_1_COLUMNS.get(1))).build())) + .uniques(List.of(Unique.builder().columns(List.of( + TABLE_1_COLUMNS.get(0), + TABLE_1_COLUMNS.get(1) + )).build())) .checks(Set.of("`mintemp` > 0")) .build(); @@ -5280,8 +5291,8 @@ public abstract class BaseTest { public final static Long VIEW_3_CONTAINER_ID = CONTAINER_1_ID; public final static Long VIEW_3_DATABASE_ID = DATABASE_1_ID; public final static Boolean VIEW_3_PUBLIC = false; - public final static String VIEW_3_QUERY = "select w.`mintemp`, w.`rainfall`, w.`location`, m.`date` from `weather_aus` w join `junit2` m on m.`location` = w.`location`"; - public final static String VIEW_3_QUERY_HASH = "297bbacf5bf142028d0f4a1e537db03fd91b0c3be9e66ea2abc13d2984d22824"; + public final static String VIEW_3_QUERY = "select w.`mintemp`, w.`rainfall`, w.`location`, m.`date` from `weather_aus` w join `junit2` m on m.`location` = w.`location` and m.`date` = w.`date`"; + public final static String VIEW_3_QUERY_HASH = "bbbaa56a5206b3dc3e6cf9301b0db9344eb6f19b100c7b88550ffb597a0bd255"; public final static List<TableColumn> VIEW_3_COLUMNS = List.of(TableColumn.builder() .id(COLUMN_1_4_ID) diff --git a/dbrepo-search-service/Dockerfile b/dbrepo-search-service/Dockerfile index 4371d22bd0464d7a680935abd0638e5e2dfb1c2d..1faeae58d0b12caecb23d92a0ae160cf52080157 100644 --- a/dbrepo-search-service/Dockerfile +++ b/dbrepo-search-service/Dockerfile @@ -17,6 +17,12 @@ COPY ./us-yml ./us-yml COPY config.py wsgi.py ./ ENV FLASK_APP=wsgi.py +ENV COLLECTION="['database','table','column','identifier','unit','concept','user','view']" +ENV OPENSEARCH_HOST=localhost +ENV OPENSEARCH_PORT=9200 +ENV OPENSEARCH_USERNAME=admin +ENV OPENSEARCH_PASSWORD=admin +ENV LOG_LEVEL=INFO RUN chown -R alpine:alpine ./ USER alpine diff --git a/dbrepo-search-service/app/__init__.py b/dbrepo-search-service/app/__init__.py index 014b475338d3348e16121bcc75b487129cef5df7..f7554e25da9ab5b36a5157b611980adadbee41fe 100644 --- a/dbrepo-search-service/app/__init__.py +++ b/dbrepo-search-service/app/__init__.py @@ -8,7 +8,9 @@ from opensearchpy import OpenSearch from config import Config from prometheus_flask_exporter import PrometheusMetrics -logging.basicConfig(level=logging.DEBUG) +log_level = os.getenv('LOG_LEVEL', 'INFO') + +logging.basicConfig(level=logging.getLevelName(log_level)) from logging.config import dictConfig @@ -31,7 +33,7 @@ def create_app(config_class=Config): 'formatter': 'simple' # default }}, 'root': { - 'level': 'DEBUG', + 'level': log_level, 'handlers': ['wsgi'] } }) diff --git a/dbrepo-search-service/app/api/routes.py b/dbrepo-search-service/app/api/routes.py index f666637037a2cf5289387de1801194d733d7bffd..8850f57939262043eb8bad141ac78ea6a9f330fe 100644 --- a/dbrepo-search-service/app/api/routes.py +++ b/dbrepo-search-service/app/api/routes.py @@ -2,7 +2,8 @@ """ This file defines the endpoints for the dbrepo-search-service. """ -import logging +import os +from ast import literal_eval from flask import request @@ -11,16 +12,11 @@ from app.api import api_bp from flasgger.utils import swag_from from app.opensearch_client import * import math -from opensearchpy import OpenSearch -host = "localhost" -port = 9200 -auth = ("admin", "admin") -client = OpenSearch( - hosts=[{"host": host, "port": port}], - http_compress=True, # enables gzip compression for request bodies - http_auth=auth, -) +available_indices = literal_eval( + os.getenv("COLLECTION", "['database','table','column','identifier','unit','concept','user','view']")) + +logging.info(f"Available collection loaded as: {available_indices}") def general_filter(index, results): @@ -70,21 +66,10 @@ def get_index(index): :param index: desired index :return: list of the results """ - logging.info('Searching for index: %s', index) - available_indices = [ - "table", - "user", - "database", - "column", - "identifier", - "concept", - "unit", - "view", - ] + logging.info(f'Searching for index: {index}') if index not in available_indices: return { "results": {}, - "status": 404, }, 404 # ToDo: replace with better error handling results = query_index_by_term_opensearch(index, "*", "contains") results = general_filter(index, results) @@ -104,54 +89,54 @@ def get_fields(index): :param index: :return: """ - logging.info('Getting fields for index: %s', index) - available_indices = [ - "table", - "user", - "database", - "column", - "identifier", - "concept", - "unit", - "view", - ] + logging.info(f'Searching for index: {index}') if index not in available_indices: return { "results": {}, - "status": 404, - }, 404 # ToDo: replace with better error handling - fields = [] + }, 404 fields = get_fields_for_index(index) - logging.debug('get fields for index %s resulted in fields: %s', index, fields) + logging.debug(f'get fields for index {index} resulted in {len(fields)} field(s)') return {"fields": fields, "status": 200} @api_bp.route("/api/search", methods=["POST"], endpoint="search_fuzzy_search") -def search(): +def post_fuzzy_search(): """ - Main endpoint for general searching. - - There are three ways of searching: - * if you specify 'search_term' in the request json, all entries that have relevant fields matching the 'search_term' are returned. - No wildcards are allowed, although fuzzy search is enabled (meaning, there are also matches when 1 or two characters differ) - * if you specify 't1' and/or 't2' entries that are newer than timestamp 't1' and entries that are younger than timestamp 't2' are returned. - the timestamp has to have the format YYYY-MM-DD - * if 'field' and 'value' are specified, only entries where the 'field' matches the 'value' are returned. - For example, if the 'field' is 'creator.orcid' and the 'value' is '0000-0002-6778-0887', - only entries created by the person with this specific orcid id are returned. - If there are multiple parameters specified, they are combined via an AND-conjunction, so you can e.g. search for entries that match a certain keyword, - were created in a certain time period, by a specific person. + Main endpoint for fuzzy searching. :return: """ if request.content_type != "application/json": return { - "status": 415, "message": "Unsupported Media Type", "suggested_content_types": ["application/json"], }, 415 req_body = request.json - logging.debug('search request body: %s', req_body) + logging.debug(f"search request body: {req_body}") search_term = req_body.get("search_term") + response = general_search(None, available_indices, search_term, None, None, None) + return response, 200 + + +@api_bp.route("/api/search/<string:index>", methods=["POST"], endpoint="search_general_search") +def post_general_search(index): + """ + Main endpoint for fuzzy searching. + :return: + """ + if request.content_type != "application/json": + return { + "message": "Unsupported Media Type", + "suggested_content_types": ["application/json"], + }, 415 + req_body = request.json + logging.info(f'Searching for index: {index}') + logging.debug(f"search request body: {req_body}") + search_term = req_body.get("search_term") + if index is not None and index not in available_indices: + logging.error(f"Index {index} is not in list of searchable indices: {available_indices}") + return { + "results": {}, + }, 404 t1 = req_body.get("t1") if not str(t1).isdigit(): t1 = None @@ -162,5 +147,5 @@ def search(): if t1 is not None and t2 is not None and "unit.uri" in field_value_pairs and "concept.uri" in field_value_pairs: response = unit_independent_search(t1, t2, field_value_pairs) else: - response = general_search(search_term, t1, t2, field_value_pairs) + response = general_search(index, available_indices, search_term, t1, t2, field_value_pairs) return response, 200 diff --git a/dbrepo-search-service/app/opensearch_client.py b/dbrepo-search-service/app/opensearch_client.py index 01717c6a98f957c2052a22223a2b186429c10f98..d5d5e8f877caafd90c8de12effd7c0fc98ea2f4d 100644 --- a/dbrepo-search-service/app/opensearch_client.py +++ b/dbrepo-search-service/app/opensearch_client.py @@ -7,7 +7,6 @@ import re from flask import current_app from collections.abc import MutableMapping -from omlib.dimension import Dimension from omlib.measure import om from omlib.constants import SI, OM_IDS from omlib.omconstants import OM @@ -117,25 +116,25 @@ def get_fields_for_index(index): return fields_list -def general_search(search_term=None, t1=None, t2=None, fieldValuePairs=None): +def general_search(index=None, indices=[], search_term=None, t1=None, t2=None, field_value_pairs=None): """ Main method for seaching stuff in the opensearch db all parameters are optional - :param search_term: the term you want to search for (no wildcards are allowed) - :param t1: beginn time period - :param t2: end time period - :param field: name of the field you want to look at - :param value: the value the specified field should match - :return: + :param index: The index to be searched. Optional. + :param indices: The available indices to be searched. + :param search_term: The search term. Optional. + :param t1: The start range value. Optional. + :param t2: The end range value. Optional. + :param field_value_pairs: The key-value pair of properties that need to match. Optional. + :return: The object of results and HTTP status code. e.g. { "hits": { "hits": [] } }, 200 """ - logging.info(f"Performing general search") - searchable_indices = ["database", "user", "table", "column", "identifier", "view", "concept", "unit"] - index = searchable_indices queries = [] - if search_term is not None: - logging.debug('query has search_term present') + if search_term is None: + logging.info(f"Performing general search") + else: + logging.info(f"Performing fuzzy search") fuzzy_body = { "query": { "multi_match": { @@ -146,14 +145,16 @@ def general_search(search_term=None, t1=None, t2=None, fieldValuePairs=None): } } } - logging.debug('search body: %s', fuzzy_body) + logging.debug(f'search body: {fuzzy_body}') + index = ','.join(indices) + logging.debug(f'search index: {index}') response = current_app.opensearch_client.search( index=index, body=fuzzy_body ) - response["status"] = 200 + logging.info(f"Found {len(response['hits']['hits'])} result(s)") return response - if fieldValuePairs is not None and len(fieldValuePairs) > 0: + if field_value_pairs is not None and len(field_value_pairs) > 0: logging.debug('query has field_value_pairs present') musts = [] is_range_open_end = False @@ -168,12 +169,8 @@ def general_search(search_term=None, t1=None, t2=None, fieldValuePairs=None): if t1 is not None and t2 is not None: is_range_query = True logging.debug(f"query has start value {t1} and end value {t2} present") - for key, value in fieldValuePairs.items(): + for key, value in field_value_pairs.items(): logging.debug(f"current key={key}, value={value}") - if key == "type" and value in searchable_indices: - logging.debug("search for specific index: %s", value) - index = value - continue # if key in field_list: if re.match(f"{index}\.", key): new_field = key[key.index(".") + 1:len(key)] @@ -242,10 +239,8 @@ def general_search(search_term=None, t1=None, t2=None, fieldValuePairs=None): logging.debug('search body: %s', body) response = current_app.opensearch_client.search( index=index, - body=body + body=json.dumps(body) ) - response["status"] = 200 - # response = [hit["_source"] for hit in response["hits"]["hits"]] return response @@ -271,16 +266,17 @@ def unit_independent_search(t1=None, t2=None, field_value_pairs=None): """ logging.info(f"Performing unit-independent search") searches = [] - response = current_app.opensearch_client.search( - index="column", - body={ - "size": 0, - "aggs": { - "units": { - "terms": {"field": "unit.uri", "size": 500} - } + body = { + "size": 0, + "aggs": { + "units": { + "terms": {"field": "unit.uri", "size": 500} } } + } + response = current_app.opensearch_client.search( + index="column", + body=json.dumps(body) ) unit_uris = [hit["key"] for hit in response["aggregations"]["units"]["buckets"]] logging.debug(f"found {len(unit_uris)} unit(s) in column index") @@ -334,24 +330,17 @@ def unit_independent_search(t1=None, t2=None, field_value_pairs=None): } } }) - # searches.append({'index': 'column'}) - # searches.append({ - # "query": { - # "match_all": {} - # } - # }) logging.debug('searches: %s', searches) body = '' for search in searches: body += '%s \n' % json.dumps(search) responses = current_app.opensearch_client.msearch( - body=body + body=json.dumps(body) ) response = { "hits": { "hits": flatten([hits["hits"]["hits"] for hits in responses["responses"]]) }, - "took": responses["took"], - "status": 200 + "took": responses["took"] } return response diff --git a/dbrepo-ui/api/analyse.service.js b/dbrepo-ui/api/analyse.service.js index a244759d628563e92f0e5666237532c7f9eda7dc..b25b051571f70c5bc3a70fc69f0a19f42d146c7e 100644 --- a/dbrepo-ui/api/analyse.service.js +++ b/dbrepo-ui/api/analyse.service.js @@ -1,5 +1,4 @@ -import Vue from 'vue' -import api from '@/api' +import api, { displayError } from '@/api' class AnalyseService { determineDataTypes (filename, separator) { @@ -15,9 +14,7 @@ class AnalyseService { resolve(analysis) }) .catch((error) => { - const { code, message } = error - console.error('Failed to load analysis', error) - Vue.$toast.error(`[${code}] Failed to load analysis: ${message}`) + displayError('Failed to load analysis', error) reject(error) }) }) diff --git a/dbrepo-ui/api/authentication.service.js b/dbrepo-ui/api/authentication.service.js index 6f5d92d411784a607b52a07688897eafca8dde6f..035a8106202043cdb98f4ac36dc3c063f1d3aefb 100644 --- a/dbrepo-ui/api/authentication.service.js +++ b/dbrepo-ui/api/authentication.service.js @@ -91,19 +91,9 @@ class AuthenticationService { }).catch((error) => { console.error('Failed to authenticate', error) const { response } = error - const { status, data } = response + const { status } = response if (status === 401) { Vue.$toast.error('Invalid username-password combination.') - } else if (data && data.error && data.error === 'invalid_grant') { - store().commit('SET_TOKEN', null) - store().commit('SET_REFRESH_TOKEN', null) - store().commit('SET_ROLES', []) - store().commit('SET_USER', null) - this.$vuetify.theme.dark = false - Vue.$toast.warning('Authentication expired.') - this.$router.push('/login') - } else { - /* ignore */ } reject(error) }) diff --git a/dbrepo-ui/api/container.service.js b/dbrepo-ui/api/container.service.js index 2d6021c89f6bf75e0f15b4a1950faf4d626ab933..168716512cefaa4adbc78f92bbff2d7a94010b3c 100644 --- a/dbrepo-ui/api/container.service.js +++ b/dbrepo-ui/api/container.service.js @@ -1,5 +1,4 @@ -import Vue from 'vue' -import api from '@/api' +import api, { displayError } from '@/api' class ContainerService { findAll (limit = 100) { @@ -11,9 +10,7 @@ class ContainerService { resolve(containers) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to load containers', error) - Vue.$toast.error(`[${code}] Failed to load containers: ${message}`) + displayError('Failed to load container', error) reject(error) }) }) @@ -28,9 +25,7 @@ class ContainerService { resolve(container) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to load container', error) - Vue.$toast.error(`[${code}] Failed to load container: ${message}`) + displayError('Failed to load container', error) reject(error) }) }) @@ -45,9 +40,7 @@ class ContainerService { resolve(image) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to load image', error) - Vue.$toast.error(`[${code}] Failed to load image: ${message}`) + displayError('Failed to load image', error) reject(error) }) }) diff --git a/dbrepo-ui/api/identifier.service.js b/dbrepo-ui/api/identifier.service.js index c377aa03264748308cff834555cf8a5622527660..a214c6d9e7c6a5590bee4ff8fd0be3618ceaf5ce 100644 --- a/dbrepo-ui/api/identifier.service.js +++ b/dbrepo-ui/api/identifier.service.js @@ -1,5 +1,4 @@ -import Vue from 'vue' -import api from '@/api' +import api, { displayError } from '@/api' class IdentifierService { findAll (databaseId, type) { @@ -12,9 +11,7 @@ class IdentifierService { resolve(identifiers) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to load identifiers', error) - Vue.$toast.error(`[${code}] Failed to load identifiers: ${message}`) + displayError('Failed to load identifiers', error) reject(error) }) }) @@ -41,9 +38,7 @@ class IdentifierService { } }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to load identifier metadata', error) - Vue.$toast.error(`[${code}] Failed to load identifier metadata: ${message}`) + displayError('Failed to load identifier', error) reject(error) }) }) @@ -58,9 +53,7 @@ class IdentifierService { resolve(identifier) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to load identifier', error) - Vue.$toast.error(`[${code}] Failed to load identifier: ${message}`) + displayError('Failed to load citation recommendation', error) reject(error) }) }) @@ -75,9 +68,7 @@ class IdentifierService { resolve(identifier) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to create identifier', error) - Vue.$toast.error(`[${code}] Failed to create identifier: ${message}`) + displayError('Failed to create identifier', error) reject(error) }) }) @@ -92,9 +83,7 @@ class IdentifierService { resolve(identifier) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to update identifier', error) - Vue.$toast.error(`[${code}] Failed to update identifier: ${message}`) + displayError('Failed to update identifier', error) reject(error) }) }) @@ -109,9 +98,7 @@ class IdentifierService { resolve(identifier) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to export identifier', error) - Vue.$toast.error(`[${code}] Failed to export identifier: ${message}`) + displayError('Failed to export identifier', error) reject(error) }) }) @@ -122,9 +109,7 @@ class IdentifierService { api.delete(`/api/pid/${pid}`, { headers: { Accept: 'application/json' } }) .then(() => resolve()) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to delete identifier', error) - Vue.$toast.error(`[${code}] Failed to delete identifier: ${message}`) + displayError('Failed to delete identifier', error) reject(error) }) }) diff --git a/dbrepo-ui/api/index.js b/dbrepo-ui/api/index.js index c56e45b3ddd33a95128133fb6966ec9dbd6ca6e6..c562536197686dcdeb8ce7266963fef3003574fa 100644 --- a/dbrepo-ui/api/index.js +++ b/dbrepo-ui/api/index.js @@ -11,15 +11,15 @@ const instance = axios.create({ baseURL: baseUrl }) -function displayError (error, warning) { +function displayError (altMessage, error) { const { code, message } = error.response.data if (code && message) { - console.error(warning, error) - Vue.$toast.error(`[${code}] ${warning}: ${message}`) + console.error(error) + Vue.$toast.error(message) return } - console.error(warning, error) - Vue.$toast.error(`[${error.code}] ${warning}: ${error.message}`) + console.error(altMessage, error) + Vue.$toast.error(`[${error.code}] ${altMessage}: ${error.message}`) } export default instance diff --git a/dbrepo-ui/api/metadata.service.js b/dbrepo-ui/api/metadata.service.js index c49d1d952da0b0865d6c42c3affd35ed737f1c94..9954f9ca91fb3f20f2fc3fcc9bff3e6ffd0bdad6 100644 --- a/dbrepo-ui/api/metadata.service.js +++ b/dbrepo-ui/api/metadata.service.js @@ -1,5 +1,4 @@ -import Vue from 'vue' -import api from '@/api' +import api, { displayError } from '@/api' class MetadataService { findAllMessages () { @@ -11,9 +10,7 @@ class MetadataService { resolve(messages) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to load messages', error) - Vue.$toast.error(`[${code}] Failed to load messages: ${message}`) + displayError('Failed to load maintenance messages', error) reject(error) }) }) @@ -28,9 +25,7 @@ class MetadataService { resolve(messages) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to create message', error) - Vue.$toast.error(`[${code}] Failed to create message: ${message}`) + displayError('Failed to create maintenance message', error) reject(error) }) }) @@ -45,9 +40,7 @@ class MetadataService { resolve(messages) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to find message', error) - Vue.$toast.error(`[${code}] Failed to find message: ${message}`) + displayError('Failed to find maintenance message', error) reject(error) }) }) @@ -62,9 +55,7 @@ class MetadataService { resolve(messages) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to update message', error) - Vue.$toast.error(`[${code}] Failed to update message: ${message}`) + displayError('Failed to update maintenance message', error) reject(error) }) }) @@ -75,9 +66,7 @@ class MetadataService { api.delete(`/api/maintenance/message/${id}`, { headers: { Accept: 'application/json' } }) .then(() => resolve()) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to delete message', error) - Vue.$toast.error(`[${code}] Failed to delete message: ${message}`) + displayError('Failed to delete maintenance message', error) reject(error) }) }) @@ -92,9 +81,7 @@ class MetadataService { resolve(messages) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to load active messages', error) - Vue.$toast.error(`[${code}] Failed to load active messages: ${message}`) + displayError('Failed to load active maintenance messages', error) reject(error) }) }) diff --git a/dbrepo-ui/api/middleware.service.js b/dbrepo-ui/api/middleware.service.js index be56c223bb2fc12365eca24b246fd40262a5d80b..11377428ee1068854619fc90c2db2a992173d8e0 100644 --- a/dbrepo-ui/api/middleware.service.js +++ b/dbrepo-ui/api/middleware.service.js @@ -1,5 +1,5 @@ -import Vue from 'vue' import axios from 'axios' +import { displayError } from '@/api/index' class MiddlewareService { buildQuery (data) { @@ -11,9 +11,7 @@ class MiddlewareService { resolve(file) }) .catch((error) => { - const { code, message } = error - console.error('Failed to build query', error) - Vue.$toast.error(`[${code}] Failed to build query: ${message}`) + displayError('Failed to build query', error) reject(error) }) }) diff --git a/dbrepo-ui/api/query.service.js b/dbrepo-ui/api/query.service.js index 8f8488d6478611c671b62b8bd36fcf36dd92d538..5029b562ae80013b9f8e7a6a6ca9800183eac679 100644 --- a/dbrepo-ui/api/query.service.js +++ b/dbrepo-ui/api/query.service.js @@ -1,5 +1,4 @@ -import Vue from 'vue' -import api from '@/api' +import api, { displayError } from '@/api' class QueryService { findAll (databaseId, persisted) { @@ -11,9 +10,7 @@ class QueryService { resolve(queries) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to load queries', error) - Vue.$toast.error(`[${code}] Failed to load queries: ${message}`) + displayError('Failed to load queries', error) reject(error) }) }) @@ -27,9 +24,7 @@ class QueryService { console.debug('response query', query) resolve(query) }).catch((error) => { - const { code, message } = error.response.data - console.error('Failed to load query', error) - Vue.$toast.error(`[${code}] Failed to load query: ${message}`) + displayError('Failed to load query', error) reject(error) }) }) @@ -44,9 +39,7 @@ class QueryService { resolve(query) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to persist query', error) - Vue.$toast.error(`[${code}] Failed to persist query: ${message}`) + displayError('Failed to persist query', error) reject(error) }) }) @@ -61,9 +54,7 @@ class QueryService { resolve(table) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to import csv to table', error) - Vue.$toast.error(`[${code}] Failed to import csv to table: ${message}`) + displayError('Failed to import csv to table', error) reject(error) }) }) @@ -78,14 +69,7 @@ class QueryService { resolve(tuple) }) .catch((error) => { - const { status } = error - const { code, message } = error.response.data - if (status === 423) { - console.error('Database failed to accept tuple', error) - } else { - console.error('Failed to insert tuple', error) - } - Vue.$toast.error(`[${code}] Failed to insert tuple: ${message}`) + displayError('Failed to insert tuple', error) reject(error) }) }) @@ -100,14 +84,7 @@ class QueryService { resolve(tuple) }) .catch((error) => { - const { status } = error - const { code, message } = error.response.data - if (status === 423) { - console.error('Database failed to accept tuple', error) - } else { - console.error('Failed to update tuple', error) - } - Vue.$toast.error(`[${code}] Failed to update tuple: ${message}`) + displayError('Failed to update tuple', error) reject(error) }) }) @@ -122,9 +99,7 @@ class QueryService { resolve(subset) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to export query', error) - Vue.$toast.error(`[${code}] Failed to export query: ${message}`) + displayError('Failed to export subset', error) reject(error) }) }) @@ -139,9 +114,7 @@ class QueryService { resolve(metadata) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to export metadata', error) - Vue.$toast.error(`[${code}] Failed to export metadata: ${message}`) + displayError('Failed to export metadata', error) reject(error) }) }) @@ -156,9 +129,7 @@ class QueryService { resolve(result) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to execute statement', error) - Vue.$toast.error(`[${code}] Failed to execute statement: ${message}`) + displayError('Failed to execute query', error) reject(error) }) }) @@ -173,9 +144,7 @@ class QueryService { resolve(result) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to re-execute query', error) - Vue.$toast.error(`[${code}] Failed to re-execute query: ${message}`) + displayError('Failed to re-execute query', error) reject(error) }) }) @@ -190,9 +159,7 @@ class QueryService { resolve(count) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to re-execute query count', error) - Vue.$toast.error(`[${code}] Failed to re-execute query count: ${message}`) + displayError('Failed to re-execute query and count results', error) reject(error) }) }) @@ -207,9 +174,7 @@ class QueryService { resolve(result) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to re-execute view', error) - Vue.$toast.error(`[${code}] Failed to re-execute view: ${message}`) + displayError('Failed to re-execute view', error) reject(error) }) }) @@ -224,9 +189,7 @@ class QueryService { resolve(count) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to re-execute view count', error) - Vue.$toast.error(`[${code}] Failed to re-execute view count: ${message}`) + displayError('Failed to re-execute view and count results', error) reject(error) }) }) @@ -241,9 +204,7 @@ class QueryService { resolve(view) }) .catch((error) => { - const { code, message } = error.response.data - console.error('Failed to find view', error) - Vue.$toast.error(`[${code}] Failed to find view: ${message}`) + displayError('Failed to find view', error) reject(error) }) }) diff --git a/dbrepo-ui/api/search.service.js b/dbrepo-ui/api/search.service.js index c531256ee6d678beb258ae944350182ce2cce6aa..b30c79b6fee7a1b419bdc6be3764570f97be6475 100644 --- a/dbrepo-ui/api/search.service.js +++ b/dbrepo-ui/api/search.service.js @@ -1,25 +1,22 @@ -import Vue from 'vue' -import axios from 'axios' +import api, { displayError } from '@/api/index' class SearchService { getFields (type) { return new Promise((resolve, reject) => { - axios.get(`/api/search/${type}/fields`, { headers: { Accept: 'application/json' } }) + api.get(`/api/search/${type}/fields`, { headers: { Accept: 'application/json' } }) .then((response) => { const json = response.data console.debug('fields result', json) resolve(json) }) .catch((error) => { - const { code, message } = error - console.error(`Failed to load ${type} fields`, error) - Vue.$toast.error(`[${code}] Failed to load ${type} fields: ${message}`) + displayError('Failed to load fields', error) reject(error) }) }) } - search (searchData) { + search (index, searchData) { // transform values to what the search API expects let localSearchData = Object.assign({}, searchData) const searchTerm = localSearchData.search_term @@ -36,16 +33,14 @@ class SearchService { field_value_pairs: { ...localSearchData } } return new Promise((resolve, reject) => { - axios.post('/api/search', payload, { headers: { Accept: 'application/json' } }) + api.post(`/api/search${index ? `/${index}` : ''}`, payload, { headers: { Accept: 'application/json' } }) .then((response) => { const { hits } = response.data console.debug('advanced search response', hits.hits) resolve(hits.hits) }) .catch((error) => { - const { code, message } = error - console.error('Failed to load search results', error) - Vue.$toast.error(`[${code}] Failed to load search results: ${message}`) + displayError('Failed to load search results', error) reject(error) }) }) diff --git a/dbrepo-ui/api/semantic.service.js b/dbrepo-ui/api/semantic.service.js index 662106eb5416aa2943c458f3cbcc797e89615e3e..0935727a57640aa119b633596f3e6df8058740b4 100644 --- a/dbrepo-ui/api/semantic.service.js +++ b/dbrepo-ui/api/semantic.service.js @@ -10,7 +10,7 @@ class SemanticService { resolve(ontologies) }) .catch((error) => { - displayError(error, 'Failed to load ontologies') + displayError('Failed to load ontologies', error) reject(error) }) }) @@ -25,7 +25,7 @@ class SemanticService { resolve(concepts) }) .catch((error) => { - displayError(error, 'Failed to load concepts') + displayError('Failed to load concepts', error) reject(error) }) }) @@ -40,7 +40,7 @@ class SemanticService { resolve(concept) }) .catch((error) => { - displayError(error, 'Failed to update concept') + displayError('Failed to update concept', error) reject(error) }) }) @@ -55,7 +55,7 @@ class SemanticService { resolve(units) }) .catch((error) => { - displayError(error, 'Failed to load units') + displayError('Failed to load units', error) reject(error) }) }) @@ -70,7 +70,7 @@ class SemanticService { resolve(unit) }) .catch((error) => { - displayError(error, 'Failed to update unit') + displayError('Failed to update unit', error) reject(error) }) }) @@ -85,7 +85,7 @@ class SemanticService { resolve(ontology) }) .catch((error) => { - displayError(error, 'Failed to find ontology') + displayError('Failed to find ontology', error) reject(error) }) }) @@ -100,7 +100,7 @@ class SemanticService { resolve(ontology) }) .catch((error) => { - displayError(error, 'Failed to register ontology') + displayError('Failed to register ontology', error) reject(error) }) }) @@ -115,7 +115,7 @@ class SemanticService { resolve(ontology) }) .catch((error) => { - displayError(error, 'Failed to update ontology') + displayError('Failed to update ontology', error) reject(error) }) }) @@ -126,7 +126,7 @@ class SemanticService { api.delete(`/api/semantic/ontology/${id}`, { headers: { Accept: 'application/json' } }) .then(() => resolve()) .catch((error) => { - displayError(error, 'Failed to unregister ontology') + displayError('Failed to unregister ontology', error) reject(error) }) }) @@ -141,7 +141,7 @@ class SemanticService { resolve(semantics) }) .catch((error) => { - displayError(error, 'Failed to suggest table column semantic') + displayError('Failed to suggest table column semantic', error) reject(error) }) }) diff --git a/dbrepo-ui/api/table.mapper.js b/dbrepo-ui/api/table.mapper.js index 2f2c69c5529474d1dd7fbe354be6f7895f5b8f92..2150619bf4f65b7c69b75afba724dffe2bc574fd 100644 --- a/dbrepo-ui/api/table.mapper.js +++ b/dbrepo-ui/api/table.mapper.js @@ -39,6 +39,16 @@ class TableMapper { } }) } + + tableNameToInternalName (name) { + return name.toString() + .normalize('NFKD') + .toLowerCase() + .trim() + .replace(/\s+/g, '-') + .replace(/[^\w-]+/g, '') + .replace(/--+/g, '_') + } } export default new TableMapper() diff --git a/dbrepo-ui/api/table.service.js b/dbrepo-ui/api/table.service.js index a438b46aaedf589bb1bc877302157b6b42e4e02b..0b3c7d3d5a0d771df354cbc7732836717392a4a8 100644 --- a/dbrepo-ui/api/table.service.js +++ b/dbrepo-ui/api/table.service.js @@ -41,6 +41,19 @@ class TableService { }) } + findByName (databaseId, name) { + return new Promise((resolve, reject) => { + this.findAll(databaseId) + .then((tables) => { + const filter = tables.filter(t => t.name === name) + if (filter.length === 1) { + resolve(filter[0]) + } + reject(new Error('Failed to find table with name ' + name + ' in database with id ' + databaseId)) + }) + }) + } + updateColumn (databaseId, tableId, columnId, data) { return new Promise((resolve, reject) => { api.put(`/api/database/${databaseId}/table/${tableId}/column/${columnId}`, data, { headers: { Accept: 'application/json' } }) @@ -160,6 +173,22 @@ class TableService { }) } + delete (databaseId, tableId) { + return new Promise((resolve, reject) => { + api.delete(`/api/database/${databaseId}/table/${tableId}`, { headers: { Accept: 'application/json' } }) + .then(() => { + console.info('Deleted table with id', tableId) + resolve() + }) + .catch((error) => { + const { code, message } = error.response.data + console.error('Failed to delete table', error) + Vue.$toast.error(`[${code}] Failed to delete table: ${message}`) + reject(error) + }) + }) + } + deleteTuple (databaseId, tableId, data) { return new Promise((resolve, reject) => { api.delete(`/api/database/${databaseId}/table/${tableId}/data`, { headers: { Accept: 'application/json' }, data }) diff --git a/dbrepo-ui/api/table.utils.js b/dbrepo-ui/api/table.utils.js new file mode 100644 index 0000000000000000000000000000000000000000..5744289e7e94839c2cbf1077a8110c00555f5ec1 --- /dev/null +++ b/dbrepo-ui/api/table.utils.js @@ -0,0 +1,10 @@ +class TableUtils { + isOwner (table, user) { + if (!table || !user) { + return false + } + return table.owner.id === user.id + } +} + +export default new TableUtils() diff --git a/dbrepo-ui/components/TableSchema.vue b/dbrepo-ui/components/TableSchema.vue index d2447f2e277bedb67a13950177532e499915337d..4714f76275fef000439ed373a582883ff861d26f 100644 --- a/dbrepo-ui/components/TableSchema.vue +++ b/dbrepo-ui/components/TableSchema.vue @@ -109,7 +109,7 @@ <v-btn v-if="back" class="mt-10 mr-2 mb-1" @click="stepBack()"> Back </v-btn> - <v-btn color="primary" :loading="localLoading" class="mt-10 mb-1" @click="submit"> + <v-btn color="primary" :loading="loading" class="mt-10 mb-1" @click="submit"> Continue </v-btn> </div> @@ -134,23 +134,11 @@ export default { default () { return false } - }, - error: { - type: Boolean, - default () { - return false - } - }, - loading: { - type: Boolean, - default () { - return false - } } }, data () { return { - localLoading: false, + loading: false, dateFormats: [], valid: true, finished: false, @@ -163,13 +151,7 @@ export default { return this.columns.filter(c => c.primary_key).length === 0 } }, - watch: { - loading () { - this.localLoading = this.loading - } - }, mounted () { - this.localLoading = this.loading this.loadDateFormats() }, methods: { @@ -194,12 +176,12 @@ export default { const database = await DatabaseService.findOne(this.$route.params.database_id) this.dateFormats = database.image.date_formats } finally { - this.localLoading = false + this.loading = false } }, submit () { this.finished = true - this.localLoading = true + this.loading = true this.$emit('close', { success: true }) }, setOthers (column) { diff --git a/dbrepo-ui/components/TableToolbar.vue b/dbrepo-ui/components/TableToolbar.vue index 2cfe2f80ece49ed407c2d4f6cd185cb0bc010869..90720a6ff2914c9da7e0fe3cd752d19f979ef963 100644 --- a/dbrepo-ui/components/TableToolbar.vue +++ b/dbrepo-ui/components/TableToolbar.vue @@ -29,6 +29,9 @@ <v-btn v-if="canImportCsv" class="mb-1" :to="`/database/${$route.params.database_id}/table/${$route.params.table_id}/import`"> <v-icon left>mdi-cloud-upload</v-icon> Import .csv </v-btn> + <v-btn v-if="canDropTable" class="mb-1" color="error" @click="dropTableDialog = true"> + <v-icon left>mdi-delete</v-icon> Drop Table + </v-btn> </v-toolbar-title> </v-toolbar> <v-tabs v-model="tab" color="primary"> @@ -48,6 +51,11 @@ max-width="640"> <EditTuple :columns="table.columns" :tuple="tuple" :edit="edit" @close="close" /> </v-dialog> + <v-dialog + v-model="dropTableDialog" + max-width="640"> + <DropTable @close="closed" /> + </v-dialog> </div> </template> @@ -56,10 +64,13 @@ import EditTuple from '@/components/dialogs/EditTuple' import TableService from '@/api/table.service' import UserUtils from '@/api/user.utils' import DatabaseUtils from '@/api/database.utils' +import TableUtils from '@/api/table.utils' +import DropTable from '@/components/dialogs/DropTable' export default { components: { - EditTuple + EditTuple, + DropTable }, props: { selection: { @@ -76,7 +87,8 @@ export default { loadingDelete: false, error: false, edit: false, - editTupleDialog: false + editTupleDialog: false, + dropTableDialog: false } }, computed: { @@ -131,6 +143,12 @@ export default { } return UserUtils.hasReadAccess(this.access) && this.roles.includes('execute-query') }, + canDropTable () { + if (!this.roles || !this.table) { + return false + } + return TableUtils.isOwner(this.table, this.user) || this.roles.includes('drop-foreign-table') + }, canCreateView () { if (!this.user) { return false @@ -219,6 +237,12 @@ export default { } else { this.$emit('modified', { success: false, action: 'close' }) } + }, + async closed (event) { + console.debug('closed drop table dialog', event) + this.dropTableDialog = false + await this.$store.dispatch('reloadDatabase') + await this.$router.push(`/database/${this.$route.params.database_id}/table`) } } } diff --git a/dbrepo-ui/components/dialogs/DropTable.vue b/dbrepo-ui/components/dialogs/DropTable.vue new file mode 100644 index 0000000000000000000000000000000000000000..0a60a4fb3200f1e72cbd2c89b336b493fb4cfd4e --- /dev/null +++ b/dbrepo-ui/components/dialogs/DropTable.vue @@ -0,0 +1,85 @@ +<template> + <div> + <v-form ref="form" v-model="valid" autocomplete="off" @submit.prevent="submit"> + <v-card> + <v-card-title>Drop table {{ table.internal_name }}</v-card-title> + <v-card-text> + <v-row dense> + <v-col> + This action cannot be undone! Type the table name <code>{{ table.internal_name }}</code> below if you really want to drop it with all stored data. + </v-col> + </v-row> + <v-row dense> + <v-col> + <v-text-field + id="confirm" + v-model="confirm" + name="confirm" + label="Table Name *" + autofocus + required /> + </v-col> + </v-row> + </v-card-text> + <v-card-actions> + <v-spacer /> + <v-btn + class="mb-2" + @click="cancel"> + Cancel + </v-btn> + <v-btn + class="mb-2 mr-1" + color="error" + :loading="loadingDelete" + :disabled="confirm !== table.internal_name" + @click="dropTable"> + Delete + </v-btn> + </v-card-actions> + </v-card> + </v-form> + </div> +</template> + +<script> +import TableService from '@/api/table.service' + +export default { + data () { + return { + confirm: null, + loadingDelete: false, + valid: false + } + }, + computed: { + table () { + return this.$store.state.table + } + }, + methods: { + submit () { + this.$refs.form.validate() + }, + cancel () { + this.$emit('close', { action: 'closed' }) + }, + dropTable () { + if (!this.table.id) { + return + } + this.loadingDelete = true + TableService.delete(this.table.database.id, this.table.id) + .then(() => { + console.info('Deleted table with id ', this.table.id) + this.$toast.success('Successfully deleted table with id ' + this.table.id) + this.$emit('close', { action: 'deleted' }) + }) + .finally(() => { + this.loadingDelete = false + }) + } + } +} +</script> diff --git a/dbrepo-ui/components/search/AdvancedSearch.vue b/dbrepo-ui/components/search/AdvancedSearch.vue index f1cb9faf59d693353a3ec742fb4a0e1b4f05047d..6113cc14ff723ae1720f3f4bec67649537f24c31 100644 --- a/dbrepo-ui/components/search/AdvancedSearch.vue +++ b/dbrepo-ui/components/search/AdvancedSearch.vue @@ -1,12 +1,12 @@ <template> <div> - <v-card flat tile> + <v-card v-if="isAdvancedSearch" flat tile> <v-card-text class="pt-0 pl-4 pb-6 pr-4"> <v-form ref="form" v-model="valid" autocomplete="off" @submit.prevent="submit"> <v-row dense> <v-col cols="3"> <v-select - v-model="advancedSearchData.type" + v-model="index" :items="fieldItems" item-text="name" item-value="value" @@ -141,6 +141,7 @@ import SemanticMapper from '@/api/semantic.mapper' export default { data () { return { + index: 'database', valid: false, loading: false, loadingFields: false, @@ -170,25 +171,27 @@ export default { advancedSearchData: { name: null, internal_name: null, - id: null, - type: 'database' + id: null } } }, computed: { hideFields () { - const selectedOption = this.advancedSearchData.type + const selectedOption = this.index return { hideNameField: selectedOption === 'identifier', hideInternalNameField: ['identifier', 'user', 'concept', 'unit'].includes(selectedOption) } }, isEligibleConceptOrUnitSearch () { - return ['column'].includes(this.advancedSearchData.type) + return ['column'].includes(this.index) + }, + isAdvancedSearch () { + return !this.$route.query.q } }, watch: { - 'advancedSearchData.type': { + index: { handler (newType, oldType) { if (!newType) { return @@ -244,7 +247,7 @@ export default { this.advancedSearchData.t2 = Number(this.advancedSearchData.t2) } this.loading = true - SearchService.search(this.advancedSearchData) + SearchService.search(this.index, this.advancedSearchData) .then((response) => { this.$emit('search-result', response.map(h => h._source)) }) @@ -254,7 +257,6 @@ export default { }, isAdvancedSearchEmpty () { return !( - this.advancedSearchData.type || this.advancedSearchData.id || this.advancedSearchData.name || this.advancedSearchData.internal_name @@ -304,12 +306,12 @@ export default { // Generates a dynamic v-model; It will be attached to the advancedSearchData object if (!item) { return '' } - return `${this.advancedSearchData.type}.${item.attribute_name}` + return `${this.index}.${item.attribute_name}` }, shouldRenderItem (item) { // Checks if item's attribute_name matches any wanted field // The expected response is of a flattened format, so this method must be modified accordingly if the response is changed - return this.dynamicFieldsMap()[this.advancedSearchData.type].includes(item.attribute_name) + return this.dynamicFieldsMap()[this.index].includes(item.attribute_name) }, fetchLicenses () { // Licenses is a nested object in the backend, but without any values. diff --git a/dbrepo-ui/layouts/default.vue b/dbrepo-ui/layouts/default.vue index 496f427136f5434d73c9b472d2c021c6bf004f0c..66d6ee2385368a687a844e5fa85671f313571f88 100644 --- a/dbrepo-ui/layouts/default.vue +++ b/dbrepo-ui/layouts/default.vue @@ -95,6 +95,7 @@ flat single-line hide-details + clearable append-icon="mdi-magnify" :placeholder="$t('search.fuzzy.placeholder', { name: 'vue-i18n' })" @click:append="retrieve" /> @@ -148,7 +149,6 @@ </template> <script> -import AuthenticationService from '@/api/authentication.service' import DatabaseService from '@/api/database.service' import TableService from '@/api/table.service' @@ -171,12 +171,6 @@ export default { availableLocales () { return this.$i18n.locales.filter(i => i.code !== this.$i18n.locale) }, - token () { - return this.$store.state.token - }, - refreshToken () { - return this.$store.state.refreshToken - }, user () { return this.$store.state.user }, @@ -220,13 +214,6 @@ export default { this.$store.commit('SET_LOCALE', this.$i18n.locale) } }, - $route: { - handler () { - if (this.refreshToken) { - AuthenticationService.authenticateToken(this.refreshToken) - } - } - }, '$route.params.database_id': { handler (id, oldId) { if (id !== oldId) { @@ -313,9 +300,6 @@ export default { if (!this.$route.params.database_id) { return } - if (!this.token) { - return - } this.loading = true DatabaseService.checkAccess(this.$route.params.database_id) .then((access) => { 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 8a3df803ef2ba03aef52c1e3d5eec68ca534723e..dde1904cff391ee032c9e67868531cdd74c4627d 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 @@ -8,7 +8,7 @@ </v-toolbar-title> <v-spacer /> <v-toolbar-title> - <v-btn class="mr-2" :loading="downloadLoading" @click.stop="download"> + <v-btn :loading="downloadLoading" @click.stop="download"> <v-icon left>mdi-download</v-icon> Download csv </v-btn> <v-btn @click="pick"> diff --git a/dbrepo-ui/pages/database/_database_id/table/import.vue b/dbrepo-ui/pages/database/_database_id/table/import.vue index a64bcc54f605e3fea0fbec97d47eee6b41451241..ad767f43152c0fc179858d0e422fdaa0e12c398e 100644 --- a/dbrepo-ui/pages/database/_database_id/table/import.vue +++ b/dbrepo-ui/pages/database/_database_id/table/import.vue @@ -183,7 +183,7 @@ Table Schema </v-stepper-step> <v-stepper-content step="4"> - <TableSchema :back="true" :error="error" :loading="loading" :columns="tableCreate.columns" @close="schemaClose" /> + <TableSchema ref="schema" :back="true" :columns="tableCreate.columns" @close="schemaClose" /> </v-stepper-content> <v-stepper-step :complete="step > 5" @@ -251,7 +251,7 @@ export default { required: value => !!value || 'Required' }, dateFormats: [], - tableNames: [], + tables: [], tableCreate: { name: null, description: null, @@ -284,6 +284,9 @@ export default { roles () { return this.$store.state.roles }, + database () { + return this.$store.state.database + }, validTableName () { if (this.tableCreate.name === null) { return true @@ -291,13 +294,13 @@ export default { if (this.tableCreate.name.length < 3) { return true } - return !this.tableNames.includes(this.tableCreate.name.toString() - .normalize('NFKD') - .toLowerCase() - .trim() - .replace(/\s+/g, '-') - .replace(/[^\w-]+/g, '') - .replace(/--+/g, '_')) + if (!this.database || !('tables' in this.database)) { + return false + } + return !this.database + .tables + .map(t => t.internal_name) + .includes(TableMapper.tableNameToInternalName(this.tableCreate.name)) }, canInsertTableData () { if (!this.roles) { @@ -308,7 +311,6 @@ export default { }, mounted () { this.loadDateFormats() - this.listTables() }, methods: { notEmpty, @@ -379,16 +381,6 @@ export default { this.loading = false }) }, - listTables () { - this.loading = true - TableService.findAll(this.$route.params.database_id) - .then((tables) => { - this.tableNames = tables.map(t => t.internal_name) - }) - .finally(() => { - this.loading = false - }) - }, schemaClose (event) { console.debug('schema closed', event) if (!event.success) { @@ -396,7 +388,7 @@ export default { return } this.validStep4 = true - this.createTable() + this.createEmptyTableAndImport() }, async loadDateFormats () { this.loading = true @@ -404,10 +396,10 @@ export default { const database = await DatabaseService.findOne(this.$route.params.database_id) this.dateFormats = database.container.image.date_formats } finally { - this.localLoading = false + this.loading = false } }, - createTable () { + createEmptyTableAndImport () { /* make enum values to array */ const validColumns = this.tableCreate.columns.map((column) => { // validate `id` column: must be a PK @@ -420,6 +412,24 @@ export default { // bail out if there is a problem with one of the columns if (!validColumns.every(Boolean)) { return } const table = TableMapper.tableCreateToTableCreateDto(this.tableCreate) + // check if table already exists (e.g. due to previous fail to import) + TableService.findByName(this.$route.params.database_id, this.tableCreate.name) + .then((table) => { + console.warn('There exists already a table with name', this.tableCreate.name, 'in database: attempt to delete table with id', table.id) + TableService.delete(this.$route.params.database_id, table.id) + .then(() => { + this.$store.dispatch('reloadDatabase') + }) + }) + .catch(() => { + /* ignore, table does not (yet) exist */ + }) + .finally(() => { + // finally create the table and import csv + this.createTableAndImport(table) + }) + }, + createTableAndImport (table) { TableService.create(this.$route.params.database_id, table) .then((table) => { this.newTableId = table.id @@ -429,11 +439,17 @@ export default { await this.$store.dispatch('reloadDatabase') this.step = 5 }) + .catch(() => { + this.$refs.schema.loading = false + }) .finally(() => { this.loading = false }) }) .catch(() => { + this.$refs.schema.loading = false + }) + .finally(() => { this.loading = false }) } diff --git a/dbrepo-ui/pages/search/index.vue b/dbrepo-ui/pages/search/index.vue index e08e4b63b846351c4f5d8ccbbfe484c73350c81e..4f97484d1491271fbdbf119aec8de2617c684ee6 100644 --- a/dbrepo-ui/pages/search/index.vue +++ b/dbrepo-ui/pages/search/index.vue @@ -96,22 +96,22 @@ export default { watch: { '$route.query.q': { handler () { - this.retrieve() + this.generalSearch() } } }, mounted () { if (this.query) { - this.retrieve() + this.generalSearch() } }, methods: { - retrieve () { + generalSearch () { if (this.loading) { return } this.loading = true - SearchService.search({ search_term: this.query }) + SearchService.search(null, { search_term: this.query }) .then((hits) => { this.results = hits.map(h => h._source) }) diff --git a/dbrepo-ui/plugins/axios.js b/dbrepo-ui/plugins/axios.js index 0f67762dbfef1f7e33878dd0eaf91978056b8e60..7d475a29340f3737417862b244f956b338743e6f 100644 --- a/dbrepo-ui/plugins/axios.js +++ b/dbrepo-ui/plugins/axios.js @@ -11,20 +11,26 @@ api.interceptors.request.use((config) => { return config } const { exp } = jwtDecode(token) - if (new Date(exp) <= new Date()) { + let accessTokenExpiryDate = new Date(exp * 1000) + if (accessTokenExpiryDate <= Date.now()) { /* token expired */ + console.warn('access token has expired:', accessTokenExpiryDate) const refreshToken = store().state.refreshToken - const { exp2 } = jwtDecode(refreshToken) - if (new Date(exp2) <= new Date()) { + const refreshTokenExpiryDate = new Date(jwtDecode(refreshToken).exp * 1000) + if (refreshTokenExpiryDate <= Date.now()) { /* refresh token expired */ + console.error('Refresh token expired') store().commit('SET_TOKEN', null) store().commit('SET_REFRESH_TOKEN', null) - console.warn('Refresh token expired') + return config } AuthenticationService.authenticateToken(refreshToken) - .then((authentication) => { - // console.debug('interceptor inject authorization header for url', config.url) - config.headers.Authorization = `Bearer ${authentication.access_token}` + .then((response) => { + accessTokenExpiryDate = new Date(jwtDecode(response.access_token).exp * 1000) + console.info('Successfully requested a new access token') + console.debug('new access token expires:', accessTokenExpiryDate) + console.debug('attach access token to intercepted request:', config.url) + config.headers.Authorization = `Bearer ${response.access_token}` return config }) .finally(() => { diff --git a/dbrepo-ui/plugins/vuex-persist.js b/dbrepo-ui/plugins/vuex-persist.js index e74b481794aad33bac5e27c38e4ecc26582fe864..d9f892c78c1b55ceafe1705ab2c280c6f34d49f6 100644 --- a/dbrepo-ui/plugins/vuex-persist.js +++ b/dbrepo-ui/plugins/vuex-persist.js @@ -4,9 +4,24 @@ export default ({ store }) => { new VuexPersistence({ storage: window.localStorage, reducer: state => ({ + title: state.title, + icon: state.icon, token: state.token, refreshToken: state.refreshToken, - user: state.user + roles: state.roles, + user: state.user, + database: state.database, + table: state.table, + access: state.access, + locale: state.locale, + messages: state.messages, + ontologies: state.ontologies, + clientId: state.clientId, + clientSecret: state.clientSecret, + searchUsername: state.searchUsername, + searchPassword: state.searchPassword, + databaseCount: state.databaseCount, + doiUrl: state.doiUrl }) }).plugin(store) } diff --git a/dbrepo-ui/store/index.js b/dbrepo-ui/store/index.js index b919a18df9b3cd3076efd7f809a8406709147baf..db1da92da93e468f597404e5a2195993d3b1792e 100644 --- a/dbrepo-ui/store/index.js +++ b/dbrepo-ui/store/index.js @@ -10,6 +10,7 @@ Vue.use(Vuex) // https://github.com/hua1995116/webchat/blob/7c6544d3defd41cb7cf68306accea97800858bc3/client/src/store/index.js#L293 const store = new Store({ + // changes to the state information here *NEED* to be manually propagated to @/plugins/vuex-persist.js to be stored in the web-browser state: { title: null, icon: null, @@ -158,7 +159,7 @@ const store = new Store({ logout ({ state, commit }) { commit('SET_TOKEN', null) commit('SET_REFRESH_TOKEN', null) - commit('SET_ROLES', null) + commit('SET_ROLES', []) commit('SET_USER', null) commit('SET_DATABASE', null) commit('SET_ACCESS', null) diff --git a/docker-compose.yml b/docker-compose.yml index 4074c172ab10e56b7d89d75535f807aad4260ea4..6431cb7a414b62fffdac3abe41222b1ce13cf800 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -40,7 +40,7 @@ services: restart: "no" container_name: dbrepo-data-db hostname: data-db - image: docker.io/bitnami/mariadb:11.1.3 + image: docker.io/bitnami/mariadb-galera:11.1.3-debian-11-r0 volumes: - data-db-data:/bitnami/mariadb - "${SHARED_FILESYSTEM:-/tmp}:/tmp" @@ -48,6 +48,7 @@ services: - "3307:3306" environment: MARIADB_ROOT_PASSWORD: "${USER_DB_PASSWORD:-dbrepo}" + MARIADB_GALERA_MARIABACKUP_PASSWORD: "${USER_DB_BACKUP_PASSWORD:-dbrepo}" healthcheck: test: mysqladmin ping --user="${USER_DB_USERNAME:-root}" --password="${USER_DB_PASSWORD:-dbrepo}" --silent interval: 10s