diff --git a/.docker/docker-compose.yml b/.docker/docker-compose.yml index cdeb4e3624f4f6aa78a0e1a1f6c3cfaa3cb33d20..4d33cc34e54ec5818e14827803b14006029e5a4e 100644 --- a/.docker/docker-compose.yml +++ b/.docker/docker-compose.yml @@ -78,23 +78,26 @@ services: restart: "no" container_name: dbrepo-auth-service hostname: auth-service - image: bitnami/keycloak:26.0.0-debian-12-r1 + image: bitnami/keycloak:24.0.5-debian-12-r8 volumes: - ./config/import-realms.sh:/docker-entrypoint-initdb.d/import-realms.sh - ./config/master-realm.json:/opt/keycloak/data/import/master-realm.json - ./config/dbrepo-realm.json:/opt/keycloak/data/import/dbrepo-realm.json + - ./config/create-event-listener.jar:/opt/bitnami/keycloak/providers/create-event-listener.jar ports: - "8080:8080" environment: KEYCLOAK_ENABLE_HTTPS: "false" KEYCLOAK_ENABLE_STATISTICS: "true" - KEYCLOAK_ENABLE_HEALTH_ENDPOINTS: "true" KEYCLOAK_DATABASE_HOST: "auth-db" KEYCLOAK_DATABASE_NAME: "${AUTH_DB_NAME:-keycloak}" KEYCLOAK_DATABASE_USER: "${AUTH_DB_USERNAME:-keycloak}" KEYCLOAK_DATABASE_PASSWORD: "${AUTH_DB_PASSWORD:-dbrepo}" + METADATA_SERVICE_ENDPOINT: "${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080}/api/user" + SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}" + SYSTEM_PASSWORD: "${SYSTEM_PASSWORD:-admin}" healthcheck: - test: curl --head -fsS http://localhost:9000/health/ready + test: curl -fsS http://localhost:8080/realms/master interval: 10s timeout: 5s retries: 12 @@ -109,7 +112,8 @@ services: dbrepo-auth-service-init: init: true restart: "no" - image: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.1 + container_name: dbrepo-auth-service-init + image: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.3 environment: AUTH_SERVICE_ADMIN: ${AUTH_SERVICE_ADMIN:-admin} AUTH_SERVICE_ADMIN_PASSWORD: ${AUTH_SERVICE_ADMIN_PASSWORD:-admin} @@ -130,7 +134,7 @@ services: restart: "no" container_name: dbrepo-metadata-service hostname: metadata-service - image: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.1 + image: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.3 volumes: - "${SHARED_VOLUME:-/tmp}:/tmp" environment: @@ -193,7 +197,7 @@ services: restart: "no" container_name: dbrepo-analyse-service hostname: analyse-service - image: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.6.1 + image: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.6.3 environment: AUTH_SERVICE_CLIENT: ${AUTH_SERVICE_CLIENT:-dbrepo-client} AUTH_SERVICE_CLIENT_SECRET: ${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG} @@ -248,7 +252,7 @@ services: restart: "no" container_name: dbrepo-search-db hostname: search-db - image: registry.datalab.tuwien.ac.at/dbrepo/search-db:1.6.1 + image: registry.datalab.tuwien.ac.at/dbrepo/search-db:1.6.3 healthcheck: test: curl -sSL localhost:9200/_plugins/_security/health | jq .status | grep UP interval: 10s @@ -272,7 +276,7 @@ services: restart: "no" container_name: dbrepo-search-service hostname: search-service - image: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.6.1 + image: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.6.3 environment: AUTH_SERVICE_CLIENT: ${AUTH_SERVICE_CLIENT:-dbrepo-client} AUTH_SERVICE_CLIENT_SECRET: ${AUTH_SERVICE_CLIENT_SECRET:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG} @@ -296,11 +300,15 @@ services: restart: "no" container_name: dbrepo-ui hostname: ui - image: registry.datalab.tuwien.ac.at/dbrepo/ui:1.6.1 + image: registry.datalab.tuwien.ac.at/dbrepo/ui:1.6.3 environment: NUXT_PUBLIC_API_CLIENT: "${BASE_URL:-http://localhost}" - NUXT_PUBLIC_API_SERVER: "${BASE_URL:-http://localhost}" + NUXT_PUBLIC_API_SERVER: "${BASE_URL:-http://gateway-service}" NUXT_PUBLIC_UPLOAD_CLIENT: "${BASE_URL:-http://localhost}/api/upload/files" + NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_ID: "${AUTH_SERVICE_CLIENT:-dbrepo-client}" + NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_SECRET: "${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}" + NUXT_OIDC_PROVIDERS_KEYCLOAK_REDIRECT_URI: "${BASE_URL:-http://localhost}/auth/keycloak/callback" + NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_REDIRECT_URI: "${BASE_URL:-http://localhost}" depends_on: dbrepo-search-service: condition: service_healthy @@ -311,6 +319,8 @@ services: interval: 10s timeout: 5s retries: 12 + extra_hosts: + - "localhost:host-gateway" logging: driver: json-file @@ -365,7 +375,7 @@ services: init: true container_name: dbrepo-search-service-init hostname: search-service-init - image: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.6.1 + image: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.6.3 environment: LOG_LEVEL: ${LOG_LEVEL:-info} METADATA_SERVICE_ENDPOINT: ${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080} @@ -422,7 +432,7 @@ services: restart: "no" container_name: dbrepo-dashboard-service hostname: dashboard-service - image: registry.datalab.tuwien.ac.at/dbrepo/dashboard-service:1.6.1 + image: registry.datalab.tuwien.ac.at/dbrepo/dashboard-service:1.6.3 ports: - "3000:3000" volumes: @@ -449,7 +459,7 @@ services: init: true container_name: dbrepo-storage-service-init hostname: storage-service-init - image: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.6.1 + image: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.6.3 environment: S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID:-seaweedfsadmin} S3_BUCKET: "${S3_BUCKET:-dbrepo}" @@ -479,6 +489,7 @@ services: AWS_ACCESS_KEY_ID: "${S3_ACCESS_KEY_ID:-seaweedfsadmin}" AWS_SECRET_ACCESS_KEY: "${S3_SECRET_ACCESS_KEY:-seaweedfsadmin}" AWS_REGION: "${STORAGE_REGION_NAME:-default}" + METADATA_SERVICE_ENDPOINT: "${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080}" depends_on: dbrepo-storage-service: condition: service_healthy @@ -494,7 +505,7 @@ services: restart: "no" container_name: dbrepo-data-service hostname: data-service - image: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.6.1 + image: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.6.3 volumes: - "${SHARED_VOLUME:-/tmp}:/tmp" environment: diff --git a/.docs/.openapi/api-analyse.yaml b/.docs/.openapi/api-analyse.yaml new file mode 100644 index 0000000000000000000000000000000000000000..25e15521d5474324eab5e43adb8baa0b90312949 --- /dev/null +++ b/.docs/.openapi/api-analyse.yaml @@ -0,0 +1,332 @@ +{ + "components": { + "schemas": { + "AnalysisDto": { + "properties": { + "columns": { + "items": { + "properties": { + "column_name": { + "$ref": "#/components/schemas/ColumnAnalysisDto" + } + } + }, + "type": "array" + }, + "line_termination": { + "example": "\r\n", + "type": "string" + }, + "separator": { + "example": ",", + "type": "string" + } + }, + "type": "object" + }, + "ColumnAnalysisDto": { + "properties": { + "d": { + "example": 4, + "type": "integer" + }, + "dfid": { + "example": null, + "type": "integer" + }, + "enums": { + "example": null, + "properties": { + "type": "string" + }, + "type": "array" + }, + "null_allowed": { + "type": "boolean" + }, + "sets": { + "example": null, + "properties": { + "type": "string" + }, + "type": "array" + }, + "size": { + "example": 10, + "type": "integer" + }, + "type": { + "example": "decimal", + "type": "string" + } + }, + "type": "object" + }, + "ErrorDto": { + "properties": { + "message": { + "example": "Message", + "type": "string" + }, + "success": { + "example": false, + "type": "boolean" + } + }, + "type": "object" + }, + "KeysDto": { + "properties": { + "keys": { + "items": { + "properties": { + "column_name": { + "format": "int64", + "type": "integer" + } + } + }, + "type": "array" + } + }, + "required": [ + "keys" + ], + "type": "object" + } + }, + "securitySchemes": { + "basicAuth": { + "in": "header", + "scheme": "basic", + "type": "http" + }, + "bearerAuth": { + "bearerFormat": "JWT", + "in": "header", + "scheme": "bearer", + "type": "http" + } + } + }, + "externalDocs": { + "description": "Sourcecode Documentation", + "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.5/" + }, + "info": { + "contact": { + "email": "andreas.rauber@tuwien.ac.at", + "name": "Prof. Andreas Rauber" + }, + "description": "Service that analyses data structures", + "license": { + "name": "Apache 2.0", + "url": "https://www.apache.org/licenses/LICENSE-2.0" + }, + "title": "Database Repository Analyse Service API", + "version": "1.5" + }, + "openapi": "3.0.0", + "paths": { + "/api/analyse/datatypes": { + "get": { + "consumes": [ + "application/json" + ], + "description": "Determines MySQL 8 datatypes of a given dataset. Requires role `table-semantic-analyse`.", + "operationId": "analyse_datatypes", + "parameters": [ + { + "example": "filename_s3_key", + "in": "query", + "name": "filename", + "required": true, + "schema": { + "type": "string" + } + }, + { + "example": ",", + "in": "query", + "name": "separator", + "required": true, + "schema": { + "type": "string" + } + }, + { + "example": "false", + "in": "query", + "name": "enum", + "required": false, + "schema": { + "type": "boolean" + } + }, + { + "example": "2.5", + "in": "query", + "name": "enum_tol", + "required": false, + "schema": { + "type": "float" + } + } + ], + "produces": [ + "application/json" + ], + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AnalysisDto" + } + } + }, + "description": "Determined data types successfully" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + }, + "description": "Failed to determine data types" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + }, + "description": "Failed to find file in Storage Service" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + }, + "description": "Unexpected system error" + } + }, + "security": [ + { + "bearerAuth": [] + }, + { + "basicAuth": [] + } + ], + "summary": "Determine datatypes", + "tags": [ + "analyse-endpoint" + ] + } + }, + "/api/analyse/keys": { + "get": { + "consumes": [ + "application/json" + ], + "description": "Determines primary keys of a given dataset. Requires role `table-semantic-analyse`.", + "operationId": "analyse_keys", + "parameters": [ + { + "example": "filename_s3_key", + "in": "query", + "name": "filename", + "required": true, + "schema": { + "type": "string" + } + }, + { + "example": ",", + "in": "query", + "name": "separator", + "required": true, + "schema": { + "type": "string" + } + } + ], + "produces": [ + "application/json" + ], + "responses": { + "202": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/KeysDto" + } + } + }, + "description": "Determined keys successfully" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + }, + "description": "Failed to determine keys" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + }, + "description": "Failed to find file in Storage Service or is empty" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + }, + "description": "Unexpected system error" + } + }, + "security": [ + { + "bearerAuth": [] + }, + { + "basicAuth": [] + } + ], + "summary": "Determine keys", + "tags": [ + "analyse-endpoint" + ] + } + } + }, + "servers": [ + { + "description": "Generated server url", + "url": "http://localhost:5000" + }, + { + "description": "Sandbox", + "url": "https://test.dbrepo.tuwien.ac.at" + } + ] +} diff --git a/.docs/.openapi/api-data.yaml b/.docs/.openapi/api-data.yaml new file mode 100644 index 0000000000000000000000000000000000000000..bd14ba55057657c5a38d47cc29875d41e5cc1e71 --- /dev/null +++ b/.docs/.openapi/api-data.yaml @@ -0,0 +1,1877 @@ +openapi: 3.0.1 +info: + title: Database Repository Data Service API + description: Service that manages the data + contact: + name: Prof. Andreas Rauber + email: andreas.rauber@tuwien.ac.at + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0 + version: 1.6.2 +externalDocs: + description: Sourcecode Documentation + url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6.2/system-services-metadata/ +servers: +- url: http://localhost + description: Development instance +- url: https://test.dbrepo.tuwien.ac.at + description: Staging instance +paths: + /api/database/{databaseId}/view/{viewId}/data: + get: + tags: + - view-endpoint + summary: Get view data + description: "Gets data from a view of a database. For private databases, the\ + \ user needs at least *READ* access to the associated database. Requires role\ + \ `view-database-view-data`." + operationId: getData + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: viewId + in: path + required: true + schema: + type: integer + format: int64 + - name: page + in: query + required: false + schema: + type: integer + format: int64 + - name: size + in: query + required: false + schema: + type: integer + format: int64 + - name: timestamp + in: query + required: false + schema: + type: string + format: date-time + responses: + "503": + description: Failed to establish connection with the metadata service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find view in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "409": + description: View schema could not be mapped + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Request pagination is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Not allowed to retrieve view data + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Retrieved view data + headers: + Access-Control-Expose-Headers: + description: Expose `X-Count` custom header + required: true + style: simple + X-Count: + description: Number of rows + required: true + style: simple + content: + application/json: + schema: + type: string + security: + - basicAuth: [] + - bearerAuth: [] + head: + tags: + - view-endpoint + summary: Get view data + description: "Gets data from a view of a database. For private databases, the\ + \ user needs at least *READ* access to the associated database. Requires role\ + \ `view-database-view-data`." + operationId: getData_1 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: viewId + in: path + required: true + schema: + type: integer + format: int64 + - name: page + in: query + required: false + schema: + type: integer + format: int64 + - name: size + in: query + required: false + schema: + type: integer + format: int64 + - name: timestamp + in: query + required: false + schema: + type: string + format: date-time + responses: + "503": + description: Failed to establish connection with the metadata service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find view in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "409": + description: View schema could not be mapped + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Request pagination is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Not allowed to retrieve view data + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Retrieved view data + headers: + Access-Control-Expose-Headers: + description: Expose `X-Count` custom header + required: true + style: simple + X-Count: + description: Number of rows + required: true + style: simple + content: + application/json: + schema: + type: string + security: + - basicAuth: [] + - bearerAuth: [] + /api/database/{databaseId}/table/{tableId}/data: + get: + tags: + - table-endpoint + summary: Get table data + description: "Gets data from a table with id. For a table in a private database,\ + \ the user needs to have at least *READ* access to the associated database.\ + \ Requests with HTTP method **GET** return the full dataset, requests with\ + \ HTTP method **HEAD** only the number of tuples in the `X-Count` header." + operationId: getData_2 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + - name: timestamp + in: query + required: false + schema: + type: string + format: date-time + - name: page + in: query + required: false + schema: + type: integer + format: int64 + - name: size + in: query + required: false + schema: + type: integer + format: int64 + responses: + "400": + description: Request pagination or table data select query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to establish connection with the metadata service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find table in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Get table data + headers: + Access-Control-Expose-Headers: + description: Expose `X-Count` custom header + required: true + style: simple + X-Count: + description: Number of rows + required: true + style: simple + content: + application/json: + schema: + type: string + "403": + description: Not allowed to get table data + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - basicAuth: [] + - bearerAuth: [] + put: + tags: + - table-endpoint + summary: Update tuple + description: "Updates a data tuple into a table, then the table statistics are\ + \ updated. The user needs to have at least *WRITE_OWN* access to the associated\ + \ database. Requires role `insert-table-data`." + operationId: updateRawTuple + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + - name: Authorization + in: header + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/TupleUpdateDto" + required: true + responses: + "400": + description: Request pagination or table data select query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to establish connection with the metadata service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find table in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Updated table data + "403": + description: Update table data not allowed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - basicAuth: [] + - bearerAuth: [] + post: + tags: + - table-endpoint + summary: Insert tuple + description: "Inserts a data tuple into a table, then the table statistics are\ + \ updated. The user needs to have at least *WRITE_OWN* access to the associated\ + \ database. Requires role `insert-table-data`." + operationId: insertRawTuple + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + - name: Authorization + in: header + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/TupleDto" + required: true + responses: + "404": + description: Failed to find table in metadata database or blob in storage + service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Request pagination or table data select query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "201": + description: Created table data + "503": + description: Failed to establish connection with the metadata service or + storage service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Create table data not allowed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - basicAuth: [] + - bearerAuth: [] + delete: + tags: + - table-endpoint + summary: Delete tuple + description: "Deletes a data tuple into a table, then the table statistics are\ + \ updated. The user needs to have at least *WRITE_OWN* access to the associated\ + \ database. Requires role `delete-table-data`." + operationId: deleteRawTuple + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + - name: Authorization + in: header + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/TupleDeleteDto" + required: true + responses: + "400": + description: Request pagination or table data select query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to establish connection with the metadata service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find table in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Deleted table data + "403": + description: Delete table data not allowed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - basicAuth: [] + - bearerAuth: [] + head: + tags: + - table-endpoint + summary: Get table data + description: "Gets data from a table with id. For a table in a private database,\ + \ the user needs to have at least *READ* access to the associated database.\ + \ Requests with HTTP method **GET** return the full dataset, requests with\ + \ HTTP method **HEAD** only the number of tuples in the `X-Count` header." + operationId: getData_3 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + - name: timestamp + in: query + required: false + schema: + type: string + format: date-time + - name: page + in: query + required: false + schema: + type: integer + format: int64 + - name: size + in: query + required: false + schema: + type: integer + format: int64 + responses: + "400": + description: Request pagination or table data select query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to establish connection with the metadata service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find table in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Get table data + headers: + Access-Control-Expose-Headers: + description: Expose `X-Count` custom header + required: true + style: simple + X-Count: + description: Number of rows + required: true + style: simple + content: + application/json: + schema: + type: string + "403": + description: Not allowed to get table data + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - basicAuth: [] + - bearerAuth: [] + /api/database/{databaseId}/subset/{subsetId}/data: + get: + tags: + - subset-endpoint + summary: Get subset data + description: "Gets data of subset with id. For private databases, the user needs\ + \ at least *READ* access to the associated database. Requests with HTTP method\ + \ **GET** return the subset dataset, requests with HTTP method **HEAD** only\ + \ the number of rows in the subset dataset in the `X-Count` header" + operationId: getData_4 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: subsetId + in: path + required: true + schema: + type: integer + format: int64 + - name: timestamp + in: query + required: false + schema: + type: string + format: date-time + - name: page + in: query + required: false + schema: + type: integer + format: int64 + - name: size + in: query + required: false + schema: + type: integer + format: int64 + responses: + "503": + description: Failed to communicate with database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Retrieved subset data + headers: + Access-Control-Expose-Headers: + description: Reverse proxy exposing of custom headers + required: true + style: simple + X-Count: + description: Number of rows + style: simple + X-Id: + description: The subset id + required: true + style: simple + X-Headers: + description: The list of headers separated by comma + style: simple + content: + application/json: + schema: + type: string + "400": + description: Invalid pagination + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database in metadata database or query in query + store of the data database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Not allowed to retrieve subset data + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + head: + tags: + - subset-endpoint + summary: Get subset data + description: "Gets data of subset with id. For private databases, the user needs\ + \ at least *READ* access to the associated database. Requests with HTTP method\ + \ **GET** return the subset dataset, requests with HTTP method **HEAD** only\ + \ the number of rows in the subset dataset in the `X-Count` header" + operationId: getData_5 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: subsetId + in: path + required: true + schema: + type: integer + format: int64 + - name: timestamp + in: query + required: false + schema: + type: string + format: date-time + - name: page + in: query + required: false + schema: + type: integer + format: int64 + - name: size + in: query + required: false + schema: + type: integer + format: int64 + responses: + "503": + description: Failed to communicate with database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Retrieved subset data + headers: + Access-Control-Expose-Headers: + description: Reverse proxy exposing of custom headers + required: true + style: simple + X-Count: + description: Number of rows + style: simple + X-Id: + description: The subset id + required: true + style: simple + X-Headers: + description: The list of headers separated by comma + style: simple + content: + application/json: + schema: + type: string + "400": + description: Invalid pagination + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database in metadata database or query in query + store of the data database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Not allowed to retrieve subset data + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/subset/{queryId}: + put: + tags: + - subset-endpoint + summary: Persist subset + description: Persists a subset with id. Requires role `persist-query`. + operationId: persist + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: queryId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/QueryPersistDto" + required: true + responses: + "503": + description: Failed to communicate with database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Persisted subset + content: + application/json: + schema: + $ref: "#/components/schemas/QueryDto" + "403": + description: Not allowed to persist subset + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "417": + description: Failed to persist subset + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database in metadata database or query in query + store of the data database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Malformed select query + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/table/{tableId}/data/import: + post: + tags: + - table-endpoint + summary: Import dataset + description: Imports a dataset in a table. Then update the table statistics. + The user needs to have at least *WRITE_OWN* access to the associated database + when importing into a owned table. Otherwise *WRITE_ALL* access in needed. + Requires role `insert-table-data`. + operationId: importDataset + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + - name: Authorization + in: header + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ImportDto" + required: true + responses: + "202": + description: Imported dataset successfully + "503": + description: Failed to establish connection with the metadata service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find table in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Import table dataset not allowed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Dataset and/or query are malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - basicAuth: [] + - bearerAuth: [] + /api/database/{databaseId}/subset: + get: + tags: + - subset-endpoint + summary: Find subsets + description: "Finds subsets in the query store. When the database schema is\ + \ marked as hidden, the user needs to be authorized, have at least read-access\ + \ to the database. The result can be optionally filtered by setting `persisted`.\ + \ When set to *true*, only persisted queries are returned, otherwise only\ + \ non-persisted queries are returned." + operationId: list + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: persisted + in: query + required: false + schema: + type: boolean + responses: + "503": + description: Failed to communicate with database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database in metadata database or query in query + store of the data database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Found subsets + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/QueryDto" + "403": + description: Not allowed to find subsets + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - basicAuth: [] + - bearerAuth: [] + post: + tags: + - subset-endpoint + summary: Create subset + description: Creates a subset in the query store of the data database. Can also + be used without authentication if (and only if) the database is marked as + public (i.e. when `is_public` = `is_schema_public` is set to `true`). Otherwise + at least read access is required. + operationId: create + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: timestamp + in: query + required: false + schema: + type: string + format: date-time + - name: page + in: query + required: false + schema: + type: integer + format: int64 + - name: size + in: query + required: false + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ExecuteStatementDto" + required: true + responses: + "201": + description: Created subset + content: + application/json: + schema: + type: string + "503": + description: Failed to communicate with database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "501": + description: Failed to execute query as it contains non-supported keywords + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Not allowed to find subset + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database in metadata database or query in query + store of the data database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Malformed select query + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "417": + description: Failed to insert query into query store of data database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - basicAuth: [] + - bearerAuth: [] + /api/database/{databaseId}/view/{viewId}/export: + get: + tags: + - view-endpoint + summary: Get view data + description: "Gets data from view with id as downloadable file. For tables in\ + \ private databases, the user needs to have at least *READ* access to the\ + \ associated database." + operationId: exportDataset + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: viewId + in: path + required: true + schema: + type: integer + format: int64 + - name: timestamp + in: query + required: false + schema: + type: string + format: date-time + responses: + "503": + description: Failed to establish connection with the metadata service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Export view data not allowed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find view in metadata database or export dataset + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Exported view data + content: + application/json: + schema: + type: string + format: binary + "400": + description: Request pagination or view data select query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - basicAuth: [] + - bearerAuth: [] + /api/database/{databaseId}/table/{tableId}/history: + get: + tags: + - table-endpoint + summary: Get history + description: "Gets the insert/delete operations history performed. For tables\ + \ in private databases, the user needs to have at least *READ* access to the\ + \ associated database." + operationId: getHistory + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + - name: size + in: query + required: false + schema: + type: integer + format: int64 + responses: + "403": + description: Find table history not allowed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to establish connection with the metadata service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find table history in data database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: "Invalid pagination size request, must be > 0" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Found table history + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/TableHistoryDto" + security: + - basicAuth: [] + - bearerAuth: [] + /api/database/{databaseId}/table/{tableId}/export: + get: + tags: + - table-endpoint + summary: Get table data + description: "Gets data from table with id as downloadable file. For tables\ + \ in private databases, the user needs to have at least *READ* access to the\ + \ associated database." + operationId: exportDataset_1 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + - name: timestamp + in: query + required: false + schema: + type: string + format: date-time + responses: + "400": + description: Request pagination or table data select query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to establish connection with the metadata service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Exported table data + content: + application/json: + schema: + type: string + format: binary + "404": + description: Failed to find table in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Export table data not allowed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - basicAuth: [] + - bearerAuth: [] + /api/database/{databaseId}/subset/{subsetId}: + get: + tags: + - subset-endpoint + summary: Find subset + description: "Finds a subset in the data database. When the database schema\ + \ is marked as hidden, the user needs to be authorized, have at least read-access\ + \ to the database. Requests with HTTP header `Accept=application/json` return\ + \ the metadata, requests with HTTP header `Accept=text/csv` return the data\ + \ as downloadable file." + operationId: findById + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: subsetId + in: path + required: true + schema: + type: integer + format: int64 + - name: Accept + in: header + required: true + schema: + type: string + - name: timestamp + in: query + required: false + schema: + type: string + format: date-time + responses: + "503": + description: Failed to communicate with database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Not allowed to find subset + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "406": + description: Failed to find acceptable representation + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Found subset + content: + application/json: + schema: + $ref: "#/components/schemas/QueryDto" + text/csv: {} + "404": + description: Failed to find database in metadata database or query in query + store of the data database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Malformed select query + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - basicAuth: [] + - bearerAuth: [] +components: + schemas: + ApiErrorDto: + required: + - code + - message + - status + type: object + properties: + status: + type: string + example: NOT_FOUND + enum: + - 100 CONTINUE + - 101 SWITCHING_PROTOCOLS + - 102 PROCESSING + - 103 EARLY_HINTS + - 103 CHECKPOINT + - 200 OK + - 201 CREATED + - 202 ACCEPTED + - 203 NON_AUTHORITATIVE_INFORMATION + - 204 NO_CONTENT + - 205 RESET_CONTENT + - 206 PARTIAL_CONTENT + - 207 MULTI_STATUS + - 208 ALREADY_REPORTED + - 226 IM_USED + - 300 MULTIPLE_CHOICES + - 301 MOVED_PERMANENTLY + - 302 FOUND + - 302 MOVED_TEMPORARILY + - 303 SEE_OTHER + - 304 NOT_MODIFIED + - 305 USE_PROXY + - 307 TEMPORARY_REDIRECT + - 308 PERMANENT_REDIRECT + - 400 BAD_REQUEST + - 401 UNAUTHORIZED + - 402 PAYMENT_REQUIRED + - 403 FORBIDDEN + - 404 NOT_FOUND + - 405 METHOD_NOT_ALLOWED + - 406 NOT_ACCEPTABLE + - 407 PROXY_AUTHENTICATION_REQUIRED + - 408 REQUEST_TIMEOUT + - 409 CONFLICT + - 410 GONE + - 411 LENGTH_REQUIRED + - 412 PRECONDITION_FAILED + - 413 PAYLOAD_TOO_LARGE + - 413 REQUEST_ENTITY_TOO_LARGE + - 414 URI_TOO_LONG + - 414 REQUEST_URI_TOO_LONG + - 415 UNSUPPORTED_MEDIA_TYPE + - 416 REQUESTED_RANGE_NOT_SATISFIABLE + - 417 EXPECTATION_FAILED + - 418 I_AM_A_TEAPOT + - 419 INSUFFICIENT_SPACE_ON_RESOURCE + - 420 METHOD_FAILURE + - 421 DESTINATION_LOCKED + - 422 UNPROCESSABLE_ENTITY + - 423 LOCKED + - 424 FAILED_DEPENDENCY + - 425 TOO_EARLY + - 426 UPGRADE_REQUIRED + - 428 PRECONDITION_REQUIRED + - 429 TOO_MANY_REQUESTS + - 431 REQUEST_HEADER_FIELDS_TOO_LARGE + - 451 UNAVAILABLE_FOR_LEGAL_REASONS + - 500 INTERNAL_SERVER_ERROR + - 501 NOT_IMPLEMENTED + - 502 BAD_GATEWAY + - 503 SERVICE_UNAVAILABLE + - 504 GATEWAY_TIMEOUT + - 505 HTTP_VERSION_NOT_SUPPORTED + - 506 VARIANT_ALSO_NEGOTIATES + - 507 INSUFFICIENT_STORAGE + - 508 LOOP_DETECTED + - 509 BANDWIDTH_LIMIT_EXCEEDED + - 510 NOT_EXTENDED + - 511 NETWORK_AUTHENTICATION_REQUIRED + message: + type: string + example: Error message + code: + type: string + example: error.service.code + TupleUpdateDto: + required: + - data + - keys + type: object + properties: + data: + type: object + additionalProperties: + type: object + example: + key: value + example: + key: value + keys: + type: object + additionalProperties: + type: object + example: + id: 1 + example: + id: 1 + QueryPersistDto: + required: + - persist + type: object + properties: + persist: + type: boolean + example: true + CreatorBriefDto: + required: + - creator_name + - id + type: object + properties: + id: + type: integer + format: int64 + example: 11 + affiliation: + type: string + example: Brown University + creator_name: + type: string + example: "Carberry, Josiah" + name_type: + type: string + example: Personal + enum: + - Personal + - Organizational + name_identifier: + type: string + example: 0000-0002-1825-0097 + name_identifier_scheme: + type: string + example: ORCID + enum: + - ORCID + - ROR + - ISNI + - GRID + affiliation_identifier: + type: string + example: https://ror.org/05gq02987 + affiliation_identifier_scheme: + type: string + example: ROR + enum: + - ROR + - GRID + - ISNI + IdentifierBriefDto: + required: + - creators + - database_id + - id + - owned_by + - publication_year + - publisher + - status + - titles + - type + type: object + properties: + id: + type: integer + format: int64 + example: 2 + type: + type: string + example: database + enum: + - database + - subset + - table + - view + creators: + type: array + items: + $ref: "#/components/schemas/CreatorBriefDto" + titles: + type: array + items: + $ref: "#/components/schemas/IdentifierTitleDto" + doi: + type: string + example: 10.1038/nphys1170 + publisher: + type: string + example: TU Wien + status: + type: string + example: draft + enum: + - draft + - published + database_id: + type: integer + format: int64 + example: 1 + query_id: + type: integer + format: int64 + example: 1 + table_id: + type: integer + format: int64 + example: 1 + view_id: + type: integer + format: int64 + example: 1 + publication_year: + type: integer + format: int32 + example: 2022 + owned_by: + type: string + format: uuid + example: 2f45ef7a-7f9b-4667-9156-152c87fe1ca5 + IdentifierTitleDto: + required: + - id + type: object + properties: + id: + type: integer + format: int64 + example: 4 + title: + type: string + example: Airquality Demonstrator + language: + type: string + example: en + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - "no" + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + type: + type: string + enum: + - AlternativeTitle + - Subtitle + - TranslatedTitle + - Other + QueryDto: + required: + - database_id + - execution + - id + - identifiers + - is_persisted + - owner + - query + - query_hash + - query_normalized + type: object + properties: + id: + type: integer + format: int64 + example: 4 + owner: + $ref: "#/components/schemas/UserBriefDto" + execution: + type: string + format: date-time + example: 2021-03-12T15:26:21Z + query: + type: string + example: SELECT `id` FROM `air_quality` + type: + type: string + example: query + enum: + - query + - view + identifiers: + type: array + items: + $ref: "#/components/schemas/IdentifierBriefDto" + database_id: + type: integer + format: int64 + example: 1 + query_normalized: + type: string + example: SELECT `id` FROM `air_quality` + query_hash: + type: string + example: 17e682f060b5f8e47ea04c5c4855908b0a5ad612022260fe50e11ecb0cc0ab76 + is_persisted: + type: boolean + example: true + result_hash: + type: string + example: 17e682f060b5f8e47ea04c5c4855908b0a5ad612022260fe50e11ecb0cc0ab76 + result_number: + type: integer + format: int64 + example: 1 + UserBriefDto: + required: + - id + - username + type: object + properties: + id: + type: string + format: uuid + example: 1ffc7b0e-9aeb-4e8b-b8f1-68f3936155b4 + username: + type: string + description: Only contains lowercase characters + example: jcarberry + name: + type: string + example: Josiah Carberry + orcid: + type: string + example: 0000-0002-1825-0097 + qualified_name: + type: string + example: Josiah Carberry — @jcarberry + given_name: + type: string + example: Josiah + family_name: + type: string + example: Carberry + TupleDto: + required: + - data + type: object + properties: + data: + type: object + additionalProperties: + type: object + example: + key: value + example: + key: value + ImportDto: + required: + - header + - location + - separator + type: object + properties: + location: + type: string + example: file.csv + header: + type: boolean + description: "If true, the first line contains the column names, otherwise\ + \ it contains only data" + example: true + separator: + type: string + example: "," + quote: + type: string + example: '"' + line_termination: + type: string + example: \r\n + ExecuteStatementDto: + required: + - statement + type: object + properties: + statement: + type: string + example: SELECT `id` FROM `air_quality` + TableHistoryDto: + required: + - event + - timestamp + - total + type: object + properties: + timestamp: + type: string + format: date-time + example: 2021-03-12T15:26:21Z + event: + type: string + total: + type: integer + format: int64 + example: 1 + TupleDeleteDto: + required: + - keys + type: object + properties: + keys: + type: object + additionalProperties: + type: object + example: + id: 1 + example: + id: 1 + securitySchemes: + basicAuth: + type: http + scheme: basic + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT diff --git a/.docs/.openapi/api-metadata.yaml b/.docs/.openapi/api-metadata.yaml new file mode 100644 index 0000000000000000000000000000000000000000..18fb71db29de89369c93de29296e1d85abc58b37 --- /dev/null +++ b/.docs/.openapi/api-metadata.yaml @@ -0,0 +1,7243 @@ +openapi: 3.0.1 +info: + title: Database Repository Metadata Service API + description: Service that manages the metadata + contact: + name: Prof. Andreas Rauber + email: andreas.rauber@tuwien.ac.at + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0 + version: 1.6.2 +externalDocs: + description: Sourcecode Documentation + url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6.2/system-services-metadata/ +servers: +- url: http://localhost + description: Development instance +- url: https://test.dbrepo.tuwien.ac.at + description: Staging instance +paths: + /api/database: + get: + tags: + - database-endpoint + summary: List databases + description: "Lists all databases in the metadata database. Requests with HTTP\ + \ method **GET** return the list of databases, requests with HTTP method **HEAD**\ + \ only the number in the `X-Count` header." + operationId: list + parameters: + - name: internal_name + in: query + required: false + schema: + type: string + responses: + "200": + description: List of databases + headers: + Access-Control-Expose-Headers: + description: Expose `X-Count` custom header + required: true + style: simple + X-Count: + description: Number of databases + required: true + style: simple + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/DatabaseBriefDto" + post: + tags: + - database-endpoint + summary: Create database + description: Creates a database in the container with id. Requires roles `create-database`. + operationId: create_5 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/CreateDatabaseDto" + required: true + responses: + "403": + description: Database create permission is missing or grant permissions + at broker service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "423": + description: Database quota exceeded + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Database create query is malformed or image is not supported + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to fin container/user/database in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "201": + description: Created a new database + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseBriefDto" + "409": + description: Query store could not be created + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + head: + tags: + - database-endpoint + summary: List databases + description: "Lists all databases in the metadata database. Requests with HTTP\ + \ method **GET** return the list of databases, requests with HTTP method **HEAD**\ + \ only the number in the `X-Count` header." + operationId: list_1 + parameters: + - name: internal_name + in: query + required: false + schema: + type: string + responses: + "200": + description: List of databases + headers: + Access-Control-Expose-Headers: + description: Expose `X-Count` custom header + required: true + style: simple + X-Count: + description: Number of databases + required: true + style: simple + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/DatabaseBriefDto" + /api/database/{databaseId}/access/{userId}: + get: + tags: + - access-endpoint + summary: Find/Check access + description: "Finds or checks access of a user with given id to a database with\ + \ given id. Requests with HTTP method **GET** return the access object, requests\ + \ with HTTP method **HEAD** only the status. When the user has at least *READ*\ + \ access, the status 200 is returned, 403 otherwise. Requires role `check-database-access`\ + \ or `check-foreign-database-access`." + operationId: find + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: userId + in: path + required: true + schema: + type: string + format: uuid + responses: + "200": + description: Found database access + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseAccessDto" + "403": + description: No access to this database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Database not found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + put: + tags: + - access-endpoint + summary: Modify access + description: Modifies access of a user with given id to database with given + id. Requires role `update-database-access`. + operationId: update_5 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: userId + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/CreateAccessDto" + required: true + responses: + "403": + description: Modify access not permitted when no access is granted in the + first place + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Access could not be updated due to connection error in the + data service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Access could not be updated in the data service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Modified access + "404": + description: Database or user not found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Modify access query or database connection is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + post: + tags: + - access-endpoint + summary: Give access + description: Give a user with given id access to some database with given id. + Requires role `create-database-access`. + operationId: create_8 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: userId + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/CreateAccessDto" + required: true + responses: + "502": + description: Access could not be created due to connection error + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Access could not be created in the data service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Granting access query or database connection is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Failed giving access + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Database or user not found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Granting access succeeded + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseAccessDto" + security: + - bearerAuth: [] + - basicAuth: [] + delete: + tags: + - access-endpoint + summary: Delete access + description: Delete access of a user with id to a database with id. Requires + role `delete-database-access`. + operationId: revoke + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: userId + in: path + required: true + schema: + type: string + format: uuid + responses: + "502": + description: Access could not be created due to connection error + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Revoke of access not permitted as no access was found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Deleted access + "400": + description: Modify access query or database connection is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: "User, database with access was not found" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Access could not be revoked in the data service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + head: + tags: + - access-endpoint + summary: Find/Check access + description: "Finds or checks access of a user with given id to a database with\ + \ given id. Requests with HTTP method **GET** return the access object, requests\ + \ with HTTP method **HEAD** only the status. When the user has at least *READ*\ + \ access, the status 200 is returned, 403 otherwise. Requires role `check-database-access`\ + \ or `check-foreign-database-access`." + operationId: find_1 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: userId + in: path + required: true + schema: + type: string + format: uuid + responses: + "200": + description: Found database access + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseAccessDto" + "403": + description: No access to this database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Database not found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/user/{userId}: + get: + tags: + - user-endpoint + summary: Get user + description: Gets own user information from the metadata database. Requires + authentication. Foreign user information can only be obtained if additional + role `find-foreign-user` is present. Finding information about internal users + results in a 404 error. + operationId: find_2 + parameters: + - name: userId + in: path + required: true + schema: + type: string + format: uuid + responses: + "404": + description: User was not found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Found user + content: + application/json: + schema: + $ref: "#/components/schemas/UserDto" + "403": + description: Find user is not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + put: + tags: + - user-endpoint + summary: Update user + description: Updates user with id. Requires role `modify-user-information`. + operationId: modify + parameters: + - name: userId + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UserUpdateDto" + required: true + responses: + "202": + description: Modified user information + content: + application/json: + schema: + $ref: "#/components/schemas/UserDto" + "403": + description: Not allowed to modify user metadata + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Modify user query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database/user in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/user/{userId}/password: + put: + tags: + - user-endpoint + summary: Update user password + description: Updates password of user with id. Requires authentication. + operationId: password + parameters: + - name: userId + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UserPasswordDto" + required: true + responses: + "400": + description: Invalid password payload + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Modified user password + "403": + description: Not allowed to change foreign user password + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database/user in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to get user in auth service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to auth service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/user/token: + put: + tags: + - user-endpoint + summary: Refresh token + description: Refreshes user token by refresh token. + operationId: refreshToken + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/RefreshTokenRequestDto" + required: true + responses: + "403": + description: Not allowed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Invalid refresh token + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Refreshed user token + content: + application/json: + schema: + $ref: "#/components/schemas/TokenDto" + "502": + description: Connection to auth service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + post: + tags: + - user-endpoint + summary: Create token + description: Creates a user token via the Auth Service. + operationId: getToken + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/LoginRequestDto" + required: true + responses: + "404": + description: Failed to find user in auth database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "428": + description: Account is not fully setup in auth service (requires password + change?) + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Invalid login request + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Obtained user token + content: + application/json: + schema: + $ref: "#/components/schemas/TokenDto" + "403": + description: Not allowed to get token + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to get user in auth service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to auth service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + /api/ontology/{ontologyId}: + get: + tags: + - ontology-endpoint + summary: Find ontology + description: Finds an ontology with id in the metadata database. + operationId: find_3 + parameters: + - name: ontologyId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: Find one ontology + content: + application/json: + schema: + $ref: "#/components/schemas/OntologyDto" + "404": + description: Could not find ontology + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + put: + tags: + - ontology-endpoint + summary: Update ontology + description: Updates an ontology with id. Requires role `update-ontology`. + operationId: update + parameters: + - name: ontologyId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/OntologyModifyDto" + required: true + responses: + "202": + description: Updated ontology successfully + content: + application/json: + schema: + $ref: "#/components/schemas/OntologyDto" + "404": + description: Could not find ontology + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + delete: + tags: + - ontology-endpoint + summary: Delete ontology + description: Deletes an ontology with given id. Requires role `delete-ontology`. + operationId: delete + parameters: + - name: ontologyId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "404": + description: Could not find ontology + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Deleted ontology successfully + content: + application/json: {} + security: + - bearerAuth: [] + - basicAuth: [] + /api/message/{messageId}: + put: + tags: + - message-endpoint + summary: Update message + description: Updates a message with id. Requires role `update-maintenance-message`. + operationId: update_1 + parameters: + - name: messageId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/BannerMessageUpdateDto" + required: true + responses: + "202": + description: Updated message + content: + application/json: + schema: + $ref: "#/components/schemas/BannerMessageBriefDto" + "404": + description: Could not find message + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + delete: + tags: + - message-endpoint + summary: Delete message + description: Deletes a message with id. Requires role `delete-maintenance-message`. + operationId: delete_1 + parameters: + - name: messageId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "404": + description: Could not find message + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Deleted message + content: + application/json: {} + security: + - bearerAuth: [] + - basicAuth: [] + /api/image/{imageId}: + get: + tags: + - image-endpoint + summary: Find image + description: Finds a container image in the metadata database. + operationId: findById + parameters: + - name: imageId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: Found image + content: + application/json: + schema: + $ref: "#/components/schemas/ImageDto" + "404": + description: Image could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + put: + tags: + - image-endpoint + summary: Update image + description: Updates container image in the metadata database. Requires role + `modify-image`. + operationId: update_2 + parameters: + - name: imageId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ImageChangeDto" + required: true + responses: + "404": + description: Image could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Updated image successfully + content: + application/json: + schema: + $ref: "#/components/schemas/ImageDto" + security: + - bearerAuth: [] + - basicAuth: [] + delete: + tags: + - image-endpoint + summary: Delete image + description: Deletes a container image in the metadata database. Requires role + `delete-image`. + operationId: delete_2 + parameters: + - name: imageId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "404": + description: Image could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Deleted image successfully + security: + - bearerAuth: [] + - basicAuth: [] + /api/identifier/{identifierId}: + get: + tags: + - identifier-endpoint + summary: Find identifier + description: Finds an identifier with id. The response format depends on the + HTTP `Accept` header set on the request. + operationId: find_6 + parameters: + - name: identifierId + in: path + required: true + schema: + type: integer + format: int64 + - name: Accept + in: header + required: true + schema: + type: string + responses: + "410": + description: Failed to retrieve from S3 endpoint + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to data service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to find in data service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Found identifier successfully + content: + application/json: + schema: + $ref: "#/components/schemas/IdentifierDto" + application/ld+json: + schema: + $ref: "#/components/schemas/LdDatasetDto" + text/csv: {} + text/xml: {} + text/bibliography: {} + text/bibliography; style=apa: {} + text/bibliography; style=ieee: {} + text/bibliography; style=bibtex: {} + "400": + description: "Identifier could not be exported, the requested style is not\ + \ known" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "409": + description: Exported resource was not found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Identifier could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "406": + description: Failed to find acceptable representation + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + put: + tags: + - identifier-endpoint + summary: Save identifier + description: Saves an identifier with id as a draft identifier. Identifiers + can only be created for objects the user has at least *READ* access in the + associated database (requires role `create-identifier`) or for any object + in any database (requires role `create-foreign-identifier`). + operationId: save + parameters: + - name: identifierId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/IdentifierSaveDto" + required: true + responses: + "400": + description: Identifier form contains invalid request data + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: "Failed to find database, table or view" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Insufficient access rights or authorities + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Saved identifier + content: + application/json: + schema: + $ref: "#/components/schemas/IdentifierDto" + security: + - bearerAuth: [] + - basicAuth: [] + delete: + tags: + - identifier-endpoint + summary: Delete identifier + description: Deletes an identifier with id. Requires role `delete-identifier`. + operationId: delete_3 + parameters: + - name: identifierId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "403": + description: Deleting identifier not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Identifier or database could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to delete in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Deleted identifier + security: + - bearerAuth: [] + - basicAuth: [] + /api/identifier/{identifierId}/publish: + put: + tags: + - identifier-endpoint + summary: Publish identifier + description: Publishes an identifier with id. A published identifier cannot + be changed anymore. Requires role `publish-identifier`. + operationId: publish + parameters: + - name: identifierId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "400": + description: Identifier form contains invalid request data + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: "Failed to find database, table or view" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Insufficient access rights or authorities + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Published identifier + content: + application/json: + schema: + $ref: "#/components/schemas/IdentifierDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/visibility: + put: + tags: + - database-endpoint + summary: Update database visibility + description: Updates the database with id on the visibility. Only the database + owner can perform this operation. Requires role `modify-database-visibility`. + operationId: visibility + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseModifyVisibilityDto" + required: true + responses: + "400": + description: The visibility payload is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Visibility modified successfully + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseBriefDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Visibility modification is not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/view/{viewId}: + get: + tags: + - view-endpoint + summary: Get view + description: Gets a view with id in the metadata database. + operationId: find_7 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: viewId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "403": + description: Find view is not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: "Database, view or user could not be found" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Find view successfully + headers: + X-Username: + description: The authentication username + style: simple + Access-Control-Expose-Headers: + description: Expose custom headers + style: simple + X-Type: + description: The JDBC connection type + style: simple + X-View: + description: The view internal name + style: simple + X-Database: + description: The database internal name + style: simple + X-Password: + description: The authentication password + style: simple + X-Host: + description: The database hostname + style: simple + X-Port: + description: The database port number + style: simple + content: + application/json: + schema: + $ref: "#/components/schemas/ViewDto" + security: + - bearerAuth: [] + - basicAuth: [] + put: + tags: + - view-endpoint + summary: Update view + description: Updates a view with id. This can only be performed by the view + owner or database owner. Requires role `create-database-view`. + operationId: update_3 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: viewId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ViewUpdateDto" + required: true + responses: + "403": + description: Update not allowed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Database or View could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Update view successfully + content: + '*/*': + schema: + $ref: "#/components/schemas/ViewBriefDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Update view query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + delete: + tags: + - view-endpoint + summary: Delete view + description: Deletes a view with id. Requires role `delete-database-view`. + operationId: delete_4 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: viewId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "202": + description: Delete view successfully + "423": + description: Delete view resulted in an invalid query statement + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: "Database, view or user could not be found" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Delete view query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Deletion not allowed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/table/{tableId}: + get: + tags: + - table-endpoint + summary: Find table + description: "Finds a table with id. When a table is hidden (i.e. when `is_public`\ + \ is `false`), then the user needs to have at least read access and the role\ + \ `find-table`. When the `system` role is present, the endpoint responds with\ + \ additional connection metadata in the header." + operationId: findById_2 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "502": + description: Failed to establish connection with broker service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: "Table, database or container could not be found" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to obtain queue information from broker service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Find table successfully + headers: + X-Username: + description: The authentication username + style: simple + Access-Control-Expose-Headers: + description: Expose custom headers + style: simple + X-Password: + description: The authentication password + style: simple + content: + application/json: + schema: + $ref: "#/components/schemas/TableDto" + "403": + description: Access to the database is forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + put: + tags: + - table-endpoint + summary: Update table + description: Updates a table in the database with id. Requires role `update-table`. + operationId: update_4 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/TableUpdateDto" + required: true + responses: + "400": + description: Update table visibility payload is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Updated the table + content: + application/json: + schema: + $ref: "#/components/schemas/TableBriefDto" + "403": + description: Update table visibility not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Table could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + delete: + tags: + - table-endpoint + summary: Delete table + description: Deletes a table with id. Only the owner of a table can perform + this action (requires role `delete-table`) or anyone can delete a table (requires + role `delete-foreign-table`). + operationId: delete_5 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "400": + description: Delete table query resulted in an invalid query statement + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Delete table successfully + "404": + description: "Table, database or container could not be found" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Access to the database is forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/table/{tableId}/statistic: + put: + tags: + - table-endpoint + summary: Update statistics + description: "Updates basic statistical properties (min, max, mean, median,\ + \ std.dev) for numerical columns in a table with id. This action can only\ + \ be performed by the table owner. Requires role `update-table-statistic`." + operationId: updateStatistic + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "400": + description: Failed to map column statistic to known columns + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Not the owner + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database/table in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Updated table statistics successfully + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/table/{tableId}/column/{columnId}: + put: + tags: + - table-endpoint + summary: Update semantics + description: Updates column semantics of a table column with id. Only the table + owner with at least *READ* access to the associated database can update the + column semantics (requires role `modify-table-column-semantics`) or foreign + table columns if role `modify-foreign-table-column-semantics`. + operationId: updateColumn + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + - name: columnId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ColumnSemanticsUpdateDto" + required: true + responses: + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Updated column semantics successfully + content: + application/json: + schema: + $ref: "#/components/schemas/ColumnDto" + "404": + description: Failed to find user/table/database/ontology in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Update semantic concept query is malformed or update unit of + measurement query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Access to the database is forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/owner: + put: + tags: + - database-endpoint + summary: Update database owner + description: Updates the database with id on the owner. Only the database owner + can perform this operation. Requires role `modify-database-owner`. + operationId: transfer + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseTransferDto" + required: true + responses: + "400": + description: Owner payload is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Transfer of ownership was successful + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseBriefDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Transfer of ownership is not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Database or user could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/metadata/view: + put: + tags: + - database-endpoint + summary: Update database view schemas + description: Updates the database with id with generated metadata from view + that are not yet known to the database. Only the database owner can perform + this operation. Requires role `find-database`. + operationId: refreshViewMetadata + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: Refreshed database views metadata + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseBriefDto" + "403": + description: Refresh view metadata is not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/metadata/table: + put: + tags: + - database-endpoint + summary: Update database table schemas + description: Updates the database with id with generated metadata from tables + that are not yet known to the database. Only the database owner can perform + this operation. Requires role `find-database`. + operationId: refreshTableMetadata + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "400": + description: Failed to parse payload at search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Refreshed database tables metadata + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseBriefDto" + "403": + description: Not allowed to refresh table metadata + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to fin user/database in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/image: + get: + tags: + - database-endpoint + summary: Get database preview image + description: Gets the database with id on the preview image. + operationId: findPreviewImage + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: View of image was successful + content: + '*/*': + schema: + type: array + items: + type: string + format: byte + "404": + description: Database or user could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + put: + tags: + - database-endpoint + summary: Update database preview image + description: Updates the database with id on the preview image. Only the database + owner can perform this operation. Requires role `modify-database-image`. + operationId: modifyImage + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseModifyImageDto" + required: true + responses: + "403": + description: Modify of image is not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Database could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Modify of image was successful + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseBriefDto" + "410": + description: File was not found in the Storage Service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/user: + get: + tags: + - user-endpoint + summary: List users + description: "Lists users known to the metadata database. Internal users are\ + \ omitted from the result list. If the optional query parameter `username`\ + \ is present, the result list can be filtered by matching this exact username." + operationId: findAll + parameters: + - name: username + in: query + required: false + schema: + type: string + responses: + "200": + description: List users + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/UserBriefDto" + post: + tags: + - user-endpoint + summary: Create user + description: Creates a user in the auth service and metadata database. Requires + that no credentials are sent in the request. + operationId: create + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/CreateUserDto" + required: true + responses: + "201": + description: Created user + content: + application/json: + schema: + $ref: "#/components/schemas/UserDto" + "404": + description: Default role not found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Failed to create in auth service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Internal authentication to the auth service is invalid + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "409": + description: User with username already exists + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Parameters are not well-formed (likely email) + content: + application/json: {} + "417": + description: User with e-mail already exists + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to create in auth service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + /api/ontology: + get: + tags: + - ontology-endpoint + summary: List ontologies + description: Lists all ontologies known to the metadata database. + operationId: findAll_2 + responses: + "200": + description: List ontologies + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/OntologyBriefDto" + post: + tags: + - ontology-endpoint + summary: Create ontology + description: Creates an ontology in the metadata database. Requires role `create-ontology`. + operationId: create_1 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/OntologyCreateDto" + required: true + responses: + "201": + description: Registered ontology successfully + content: + application/json: + schema: + $ref: "#/components/schemas/OntologyDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/message: + get: + tags: + - message-endpoint + summary: List messages + description: "Lists messages known to the metadata database. Messages can be\ + \ filtered be filtered with the optional `active` parameter. If set to *true*,\ + \ only active messages (that is, messages whose end time has not been reached)\ + \ will be returned. Otherwise only inactive messages are returned. If not\ + \ set, active and inactive messages are returned." + operationId: list_2 + parameters: + - name: active + in: query + required: false + schema: + type: boolean + responses: + "200": + description: List messages + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/BannerMessageDto" + post: + tags: + - message-endpoint + summary: Create message + description: Creates a message in the metadata database. Requires role `create-maintenance-message`. + operationId: create_2 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/BannerMessageCreateDto" + required: true + responses: + "201": + description: Created message + content: + application/json: + schema: + $ref: "#/components/schemas/BannerMessageBriefDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/image: + get: + tags: + - image-endpoint + summary: List images + description: Lists all container images known to the metadata database. + operationId: findAll_3 + responses: + "200": + description: List images + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/ImageBriefDto" + post: + tags: + - image-endpoint + summary: Create image + description: Creates a container image in the metadata database. Requires role + `create-image`. + operationId: create_3 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ImageCreateDto" + required: true + responses: + "201": + description: Created image + content: + application/json: + schema: + $ref: "#/components/schemas/ImageDto" + "409": + description: Image already exists + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Image specification is invalid + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/identifier: + get: + tags: + - identifier-endpoint + summary: List identifiers + description: Lists all identifiers known to the metadata database + operationId: findAll_4 + parameters: + - name: dbid + in: query + required: false + schema: + type: integer + format: int64 + - name: qid + in: query + required: false + schema: + type: integer + format: int64 + - name: vid + in: query + required: false + schema: + type: integer + format: int64 + - name: tid + in: query + required: false + schema: + type: integer + format: int64 + - name: Accept + in: header + required: true + schema: + type: string + responses: + "200": + description: Found identifiers successfully + content: + application/json: + schema: + type: array + items: + type: string + application/ld+json: + schema: + type: array + items: + $ref: "#/components/schemas/LdDatasetDto" + "406": + description: "Identifier could not be exported, the requested style is not\ + \ known" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + post: + tags: + - identifier-endpoint + summary: Create identifier + description: Create an identifier with id to create a draft identifier. Identifiers + can only be created for objects the user has at least *READ* access in the + associated database (requires role `create-identifier`) or for any object + in any database (requires role `create-foreign-identifier`). + operationId: create_4 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/CreateIdentifierDto" + required: true + responses: + "201": + description: Drafted identifier + content: + application/json: + schema: + $ref: "#/components/schemas/IdentifierDto" + "400": + description: Identifier form contains invalid request data + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: "Failed to find database, table or view" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Insufficient access rights or authorities + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/view: + get: + tags: + - view-endpoint + summary: List views + description: Lists views known to the metadata database. + operationId: findAll_5 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: Find views successfully + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/ViewBriefDto" + "404": + description: Database or user could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + post: + tags: + - view-endpoint + summary: Create view + description: Creates a view. This can only be performed by the database owner. + Requires role `create-database-view`. + operationId: create_6 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/CreateViewDto" + required: true + responses: + "201": + description: Create view successfully + content: + application/json: + schema: + $ref: "#/components/schemas/ViewBriefDto" + "423": + description: Create view resulted in an invalid query statement + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Create view query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Credentials missing + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database/user in metadata database. + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/table: + get: + tags: + - table-endpoint + summary: List tables + description: "Lists all tables known to the metadata database. When a database\ + \ has a hidden schema (i.e. when `is_schema_public` is `false`), then the\ + \ user needs to have at least read access and the role `list-tables`." + operationId: list_4 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "403": + description: List tables not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Database could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: List tables + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/TableBriefDto" + security: + - bearerAuth: [] + - basicAuth: [] + post: + tags: + - table-endpoint + summary: Create table + description: Creates a table in the database with id. Requires role `create-table`. + operationId: create_7 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/CreateTableDto" + required: true + responses: + "409": + description: Create table conflicts with existing table name + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Create table query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: "Database, container or user could not be found" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Create table not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "201": + description: Created a new table + content: + application/json: + schema: + $ref: "#/components/schemas/TableBriefDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/container: + get: + tags: + - container-endpoint + summary: List containers + description: List all containers in the metadata database. + operationId: findAll_6 + parameters: + - name: limit + in: query + required: false + schema: + type: integer + format: int32 + responses: + "200": + description: List containers + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/ContainerBriefDto" + post: + tags: + - container-endpoint + summary: Create container + description: Creates a container in the metadata database. Requires role `create-container`. + operationId: create_9 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/CreateContainerDto" + required: true + responses: + "409": + description: Container name already exists + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: "Create container not permitted, need authority `create-container`" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "201": + description: Created a new container + content: + application/json: + schema: + $ref: "#/components/schemas/ContainerDto" + "400": + description: Container payload malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Container image or user could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/unit: + get: + tags: + - unit-endpoint + summary: List units + description: Lists units known to the metadata database. + operationId: findAll_1 + responses: + "200": + description: Find all semantic units + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/UnitDto" + /api/ontology/{ontologyId}/entity: + get: + tags: + - ontology-endpoint + summary: Find entities + description: Finds semantic entities by label or uri in an ontology with id. + Requires role `execute-semantic-query`. + operationId: find_4 + parameters: + - name: ontologyId + in: path + required: true + schema: + type: integer + format: int64 + - name: label + in: query + required: false + schema: + type: string + - name: uri + in: query + required: false + schema: + type: string + responses: + "422": + description: Ontology does not have rdf or sparql endpoint + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Filter params are invalid + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Could not find ontology + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "417": + description: Generated query or uri is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Found entities + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/EntityDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/oai: + get: + tags: + - metadata-endpoint + summary: Get record + operationId: identify_1_1_1_1 + parameters: + - name: verb + in: query + - name: parameters + in: query + required: true + schema: + $ref: "#/components/schemas/OaiListIdentifiersParameters" + responses: + "200": + description: List containers + content: + text/xml: {} + /api/message/message/{messageId}: + get: + tags: + - message-endpoint + summary: Find message + description: Finds a message with id in the metadata database. + operationId: find_5 + parameters: + - name: messageId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: Get messages + content: + application/json: + schema: + $ref: "#/components/schemas/BannerMessageDto" + "404": + description: Could not find message + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + /api/license: + get: + tags: + - license-endpoint + summary: List licenses + description: Lists licenses known to the metadata database. + operationId: list_3 + responses: + "200": + description: List of licenses + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/LicenseDto" + /api/identifier/retrieve: + get: + tags: + - identifier-endpoint + summary: Retrieve PID metadata + description: "Retrieves Persistent Identifier (PID) metadata from external endpoints.\ + \ Supported PIDs are: ORCID, ROR, DOI." + operationId: retrieve + parameters: + - name: url + in: query + required: true + schema: + type: string + responses: + "404": + description: Failed to find metadata for identifier + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Retrieved metadata from identifier + content: + application/json: + schema: + $ref: "#/components/schemas/IdentifierDto" + /api/database/{databaseId}: + get: + tags: + - database-endpoint + summary: Find database + description: Finds a database with id. + operationId: findById_1 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "404": + description: "Database, user or exchange could not be found" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Not allowed to view database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Database found successfully + headers: + X-Username: + description: The authentication username + style: simple + Access-Control-Expose-Headers: + description: Expose custom headers + style: simple + X-Password: + description: The authentication password + style: simple + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseBriefDto" + "503": + description: Failed to find queue information in broker service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to the broker service could not be established + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/table/{tableId}/suggest: + get: + tags: + - table-endpoint + summary: Suggest semantics + description: Suggests semantic concepts for a table. This action can only be + performed by the table owner. Requires role `table-semantic-analyse`. + operationId: analyseTable + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "403": + description: Not the table owner. + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "422": + description: Ontology does not have rdf or sparql endpoint + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Suggested table semantics successfully + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/EntityDto" + "417": + description: Generated query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database/table in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Failed to parse statistic in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/table/{tableId}/column/{columnId}/suggest: + get: + tags: + - table-endpoint + summary: Suggest semantics + description: Suggests column semantics. Requires role `table-semantic-analyse`. + operationId: analyseTableColumn + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + - name: columnId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "422": + description: Ontology does not have rdf or sparql endpoint + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Suggested table column semantics successfully + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/TableColumnEntityDto" + "400": + description: Generated query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database/table in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/container/{containerId}: + get: + tags: + - container-endpoint + summary: Find container + description: Finds a container in the metadata database. + operationId: findById_3 + parameters: + - name: containerId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "404": + description: Container image could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Found container + content: + application/json: + schema: + $ref: "#/components/schemas/ContainerDto" + delete: + tags: + - container-endpoint + summary: Delete container + description: Deletes a container in the metadata database. Requires role `delete-container`. + operationId: delete_6 + parameters: + - name: containerId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "403": + description: "Create container not permitted, need authority `delete-container`" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Container not found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Deleted container + security: + - bearerAuth: [] + - basicAuth: [] + /api/concept: + get: + tags: + - concept-endpoint + summary: List concepts + description: List all semantic concepts known to the metadata database + operationId: findAll_7 + responses: + "200": + description: List concepts + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/ConceptDto" +components: + schemas: + CreatorBriefDto: + required: + - creator_name + - id + type: object + properties: + id: + type: integer + format: int64 + example: 11 + affiliation: + type: string + example: Brown University + creator_name: + type: string + example: "Carberry, Josiah" + name_type: + type: string + example: Personal + enum: + - Personal + - Organizational + name_identifier: + type: string + example: 0000-0002-1825-0097 + name_identifier_scheme: + type: string + example: ORCID + enum: + - ORCID + - ROR + - ISNI + - GRID + affiliation_identifier: + type: string + example: https://ror.org/05gq02987 + affiliation_identifier_scheme: + type: string + example: ROR + enum: + - ROR + - GRID + - ISNI + DatabaseBriefDto: + required: + - contact + - id + - identifiers + - internal_name + - is_public + - is_schema_public + - name + - owner_id + type: object + properties: + id: + type: integer + format: int64 + example: 3 + name: + type: string + example: Air Quality + description: + type: string + example: Air Quality + identifiers: + type: array + items: + $ref: "#/components/schemas/IdentifierBriefDto" + contact: + $ref: "#/components/schemas/UserBriefDto" + internal_name: + type: string + example: air_quality + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + owner_id: + type: string + format: uuid + example: 2f45ef7a-7f9b-4667-9156-152c87fe1ca5 + preview_image: + type: string + IdentifierBriefDto: + required: + - creators + - database_id + - id + - owned_by + - publication_year + - publisher + - status + - titles + - type + type: object + properties: + id: + type: integer + format: int64 + example: 2 + type: + type: string + example: database + enum: + - database + - subset + - table + - view + creators: + type: array + items: + $ref: "#/components/schemas/CreatorBriefDto" + titles: + type: array + items: + $ref: "#/components/schemas/IdentifierTitleDto" + doi: + type: string + example: 10.1038/nphys1170 + publisher: + type: string + example: TU Wien + status: + type: string + example: draft + enum: + - draft + - published + database_id: + type: integer + format: int64 + example: 1 + query_id: + type: integer + format: int64 + example: 1 + table_id: + type: integer + format: int64 + example: 1 + view_id: + type: integer + format: int64 + example: 1 + publication_year: + type: integer + format: int32 + example: 2022 + owned_by: + type: string + format: uuid + example: 2f45ef7a-7f9b-4667-9156-152c87fe1ca5 + IdentifierTitleDto: + required: + - id + type: object + properties: + id: + type: integer + format: int64 + example: 4 + title: + type: string + example: Airquality Demonstrator + language: + type: string + example: en + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - "no" + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + type: + type: string + enum: + - AlternativeTitle + - Subtitle + - TranslatedTitle + - Other + UserBriefDto: + required: + - id + - username + type: object + properties: + id: + type: string + format: uuid + example: 1ffc7b0e-9aeb-4e8b-b8f1-68f3936155b4 + username: + type: string + description: Only contains lowercase characters + example: jcarberry + name: + type: string + example: Josiah Carberry + orcid: + type: string + example: 0000-0002-1825-0097 + qualified_name: + type: string + example: Josiah Carberry — @jcarberry + given_name: + type: string + example: Josiah + family_name: + type: string + example: Carberry + DatabaseAccessDto: + required: + - type + - user + type: object + properties: + user: + $ref: "#/components/schemas/UserBriefDto" + type: + type: string + example: read + enum: + - read + - write_own + - write_all + ApiErrorDto: + required: + - code + - message + - status + type: object + properties: + status: + type: string + example: NOT_FOUND + enum: + - 100 CONTINUE + - 101 SWITCHING_PROTOCOLS + - 102 PROCESSING + - 103 EARLY_HINTS + - 103 CHECKPOINT + - 200 OK + - 201 CREATED + - 202 ACCEPTED + - 203 NON_AUTHORITATIVE_INFORMATION + - 204 NO_CONTENT + - 205 RESET_CONTENT + - 206 PARTIAL_CONTENT + - 207 MULTI_STATUS + - 208 ALREADY_REPORTED + - 226 IM_USED + - 300 MULTIPLE_CHOICES + - 301 MOVED_PERMANENTLY + - 302 FOUND + - 302 MOVED_TEMPORARILY + - 303 SEE_OTHER + - 304 NOT_MODIFIED + - 305 USE_PROXY + - 307 TEMPORARY_REDIRECT + - 308 PERMANENT_REDIRECT + - 400 BAD_REQUEST + - 401 UNAUTHORIZED + - 402 PAYMENT_REQUIRED + - 403 FORBIDDEN + - 404 NOT_FOUND + - 405 METHOD_NOT_ALLOWED + - 406 NOT_ACCEPTABLE + - 407 PROXY_AUTHENTICATION_REQUIRED + - 408 REQUEST_TIMEOUT + - 409 CONFLICT + - 410 GONE + - 411 LENGTH_REQUIRED + - 412 PRECONDITION_FAILED + - 413 PAYLOAD_TOO_LARGE + - 413 REQUEST_ENTITY_TOO_LARGE + - 414 URI_TOO_LONG + - 414 REQUEST_URI_TOO_LONG + - 415 UNSUPPORTED_MEDIA_TYPE + - 416 REQUESTED_RANGE_NOT_SATISFIABLE + - 417 EXPECTATION_FAILED + - 418 I_AM_A_TEAPOT + - 419 INSUFFICIENT_SPACE_ON_RESOURCE + - 420 METHOD_FAILURE + - 421 DESTINATION_LOCKED + - 422 UNPROCESSABLE_ENTITY + - 423 LOCKED + - 424 FAILED_DEPENDENCY + - 425 TOO_EARLY + - 426 UPGRADE_REQUIRED + - 428 PRECONDITION_REQUIRED + - 429 TOO_MANY_REQUESTS + - 431 REQUEST_HEADER_FIELDS_TOO_LARGE + - 451 UNAVAILABLE_FOR_LEGAL_REASONS + - 500 INTERNAL_SERVER_ERROR + - 501 NOT_IMPLEMENTED + - 502 BAD_GATEWAY + - 503 SERVICE_UNAVAILABLE + - 504 GATEWAY_TIMEOUT + - 505 HTTP_VERSION_NOT_SUPPORTED + - 506 VARIANT_ALSO_NEGOTIATES + - 507 INSUFFICIENT_STORAGE + - 508 LOOP_DETECTED + - 509 BANDWIDTH_LIMIT_EXCEEDED + - 510 NOT_EXTENDED + - 511 NETWORK_AUTHENTICATION_REQUIRED + message: + type: string + example: Error message + code: + type: string + example: error.service.code + UserUpdateDto: + required: + - language + - theme + type: object + properties: + firstname: + type: string + example: Josiah + lastname: + type: string + example: Carberry + affiliation: + type: string + example: Brown University + orcid: + type: string + example: 0000-0002-1825-0097 + theme: + type: string + example: dark + language: + type: string + example: en + UserAttributesDto: + required: + - language + - theme + type: object + properties: + theme: + type: string + example: light + orcid: + type: string + example: https://orcid.org/0000-0002-1825-0097 + affiliation: + type: string + example: Brown University + language: + type: string + example: en + UserDto: + required: + - attributes + - id + - password + - username + type: object + properties: + id: + type: string + format: uuid + example: 1ffc7b0e-9aeb-4e8b-b8f1-68f3936155b4 + name: + type: string + example: Josiah Carberry + username: + type: string + example: username + password: + type: string + example: p4ssw0rd + attributes: + $ref: "#/components/schemas/UserAttributesDto" + last_retrieved: + type: string + format: date-time + qualified_name: + type: string + example: Josiah Carberry — @jcarberry + given_name: + type: string + example: Josiah + family_name: + type: string + example: Carberry + UserPasswordDto: + required: + - password + type: object + properties: + password: + type: string + RefreshTokenRequestDto: + required: + - refresh_token + type: object + properties: + refresh_token: + type: string + example: refresh_token + TokenDto: + required: + - access_token + - expires_in + - id_token + - not-before-policy + - refresh_expires_in + - refresh_token + - scope + - session_state + - token_type + type: object + properties: + scope: + type: string + access_token: + type: string + expires_in: + type: integer + format: int64 + refresh_token: + type: string + refresh_expires_in: + type: integer + format: int64 + id_token: + type: string + session_state: + type: string + token_type: + type: string + not-before-policy: + type: integer + format: int64 + OntologyModifyDto: + required: + - prefix + - uri + type: object + properties: + uri: + type: string + example: Ontology URI + prefix: + type: string + example: Ontology prefix + sparql_endpoint: + type: string + example: Ontology SPARQL endpoint + rdf_path: + type: string + example: rdf/om-2.0.rdf + OntologyDto: + required: + - id + - prefix + - rdf + - sparql + - uri + type: object + properties: + id: + type: integer + format: int64 + uri: + type: string + example: http://www.wikidata.org/ + prefix: + type: string + example: wd + sparql: + type: boolean + example: true + rdf: + type: boolean + example: false + uri_pattern: + type: string + example: http://www.wikidata.org/entity/.* + sparql_endpoint: + type: string + example: https://query.wikidata.org/sparql + rdf_path: + type: string + example: rdf/om-2.0.rdf + BannerMessageUpdateDto: + required: + - message + - type + type: object + properties: + type: + type: string + enum: + - error + - warning + - info + message: + type: string + example: Maintenance starts on 8am on Monday + link: + type: string + example: https://example.com + link_text: + type: string + example: More + display_start: + type: string + format: date-time + example: 2021-03-12T15:26:21Z + display_end: + type: string + format: date-time + example: 2021-03-12T15:26:21Z + BannerMessageBriefDto: + required: + - message + - type + type: object + properties: + type: + type: string + enum: + - error + - warning + - info + message: + type: string + example: Maintenance starts on 8am on Monday + link: + type: string + example: https://example.com + link_text: + type: string + example: More + ImageChangeDto: + required: + - dialect + - driver_class + - jdbc_method + - registry + type: object + properties: + registry: + type: string + example: docker.io/library + defaultPort: + maximum: 65535 + minimum: 1024 + type: integer + format: int32 + example: 5432 + dialect: + type: string + example: Postgres + driver_class: + type: string + example: org.postgresql.Driver + jdbc_method: + type: string + example: postgresql + DataTypeDto: + required: + - display_name + - documentation + - is_buildable + - is_quoted + - value + type: object + properties: + value: + type: string + example: time + documentation: + type: string + example: https://mariadb.com/kb/en/time/ + display_name: + type: string + example: TIME(fsp) + size_min: + type: integer + format: int32 + example: 0 + size_max: + type: integer + format: int32 + example: 6 + size_default: + type: integer + format: int32 + example: 0 + size_required: + type: boolean + example: false + d_min: + type: integer + format: int32 + d_max: + type: integer + format: int32 + d_default: + type: integer + format: int32 + d_required: + type: boolean + data_hint: + type: string + example: "e.g. HH:MM:SS, HH:MM, HHMMSS, H:M:S" + type_hint: + type: string + example: "fsp=microsecond precision, min. 0, max. 6" + is_quoted: + type: boolean + description: frontend needs to quote this data type + example: false + is_buildable: + type: boolean + description: frontend can build this data type + example: true + ImageDto: + required: + - data_types + - default + - default_port + - dialect + - driver_class + - id + - jdbc_method + - name + - operators + - registry + - version + type: object + properties: + id: + type: integer + format: int64 + example: 1 + registry: + type: string + example: docker.io/library + name: + type: string + example: mariadb + version: + type: string + example: "10.5" + dialect: + type: string + example: org.hibernate.dialect.MariaDBDialect + operators: + type: array + items: + $ref: "#/components/schemas/OperatorDto" + driver_class: + type: string + example: org.mariadb.jdbc.Driver + jdbc_method: + type: string + example: mariadb + default: + type: boolean + example: false + default_port: + type: integer + format: int32 + example: 3306 + data_types: + type: array + items: + $ref: "#/components/schemas/DataTypeDto" + OperatorDto: + required: + - display_name + - documentation + - value + type: object + properties: + id: + type: integer + format: int64 + value: + type: string + example: XOR + documentation: + type: string + example: https://mariadb.com/kb/en/xor/ + display_name: + type: string + example: XOR + IdentifierSaveDto: + required: + - creators + - database_id + - id + - publication_year + - publisher + - titles + - type + type: object + properties: + id: + type: integer + format: int64 + example: 1 + type: + type: string + example: database + enum: + - database + - subset + - table + - view + doi: + type: string + example: 10.1111/11111111 + titles: + type: array + items: + $ref: "#/components/schemas/SaveIdentifierTitleDto" + descriptions: + type: array + items: + $ref: "#/components/schemas/SaveIdentifierDescriptionDto" + funders: + type: array + items: + $ref: "#/components/schemas/SaveIdentifierFunderDto" + licenses: + type: array + items: + $ref: "#/components/schemas/LicenseDto" + publisher: + type: string + example: TU Wien + language: + type: string + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - "no" + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + creators: + type: array + items: + $ref: "#/components/schemas/SaveIdentifierCreatorDto" + database_id: + type: integer + format: int64 + example: 1 + query_id: + type: integer + format: int64 + view_id: + type: integer + format: int64 + table_id: + type: integer + format: int64 + publication_day: + type: integer + format: int32 + example: 15 + publication_month: + type: integer + format: int32 + example: 12 + publication_year: + type: integer + format: int32 + example: 2022 + related_identifiers: + type: array + items: + $ref: "#/components/schemas/SaveRelatedIdentifierDto" + LicenseDto: + required: + - identifier + - uri + type: object + properties: + identifier: + type: string + example: MIT + uri: + type: string + example: https://opensource.org/licenses/MIT + description: + type: string + example: "A short and simple permissive license with conditions only requiring\ + \ preservation of copyright and license notices. Licensed works, modifications,\ + \ and larger works may be distributed under different terms and without\ + \ source code." + SaveIdentifierCreatorDto: + required: + - creator_name + - id + type: object + properties: + id: + type: integer + format: int64 + example: 1 + firstname: + type: string + example: Josiah + lastname: + type: string + example: Carberry + affiliation: + type: string + example: Wesleyan University + creator_name: + type: string + example: "Carberry, Josiah" + name_type: + type: string + example: Personal + enum: + - Personal + - Organizational + name_identifier: + type: string + example: 0000-0002-1825-0097 + name_identifier_scheme: + type: string + example: ORCID + enum: + - ORCID + - ROR + - ISNI + - GRID + affiliation_identifier: + type: string + example: https://ror.org/04d836q62 + affiliation_identifier_scheme: + type: string + example: ROR + enum: + - ROR + - GRID + - ISNI + SaveIdentifierDescriptionDto: + required: + - description + - id + type: object + properties: + id: + type: integer + format: int64 + example: 1 + description: + type: string + example: "Air quality reports at Stephansplatz, Vienna" + language: + type: string + example: en + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - "no" + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + type: + type: string + example: Abstract + enum: + - Abstract + - Methods + - SeriesInformation + - TableOfContents + - TechnicalInfo + - Other + SaveIdentifierFunderDto: + required: + - funder_name + - id + type: object + properties: + id: + type: integer + format: int64 + example: 1 + funder_name: + type: string + example: European Commission + funder_identifier: + type: string + example: http://doi.org/10.13039/501100000780 + funder_identifier_type: + type: string + example: Crossref Funder ID + enum: + - Crossref Funder ID + - ROR + - GND + - ISNI + - Other + scheme_uri: + type: string + example: http://doi.org/ + award_number: + type: string + example: "824087" + award_title: + type: string + example: EOSC-Life + SaveIdentifierTitleDto: + required: + - id + - title + type: object + properties: + id: + type: integer + format: int64 + example: 1 + title: + type: string + example: Airquality Demonstrator + language: + type: string + example: en + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - "no" + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + type: + type: string + example: Subtitle + enum: + - AlternativeTitle + - Subtitle + - TranslatedTitle + - Other + SaveRelatedIdentifierDto: + required: + - id + - relation + - type + - value + type: object + properties: + id: + type: integer + format: int64 + example: 1 + value: + type: string + example: 10.70124/dc4zh-9ce78 + type: + type: string + example: DOI + enum: + - DOI + - URL + - URN + - ARK + - arXiv + - bibcode + - EAN13 + - EISSN + - Handle + - IGSN + - ISBN + - ISTC + - LISSN + - LSID + - PMID + - PURL + - UPC + - w3id + relation: + type: string + example: Cites + enum: + - IsCitedBy + - Cites + - IsSupplementTo + - IsSupplementedBy + - IsContinuedBy + - Continues + - IsDescribedBy + - Describes + - HasMetadata + - IsMetadataFor + - HasVersion + - IsVersionOf + - IsNewVersionOf + - IsPreviousVersionOf + - IsPartOf + - HasPart + - IsPublishedIn + - IsReferencedBy + - References + - IsDocumentedBy + - Documents + - IsCompiledBy + - Compiles + - IsVariantFormOf + - IsOriginalFormOf + - IsIdenticalTo + - IsReviewedBy + - Reviews + - IsDerivedFrom + - IsSourceOf + - IsRequiredBy + - Requires + - IsObsoletedBy + - Obsoletes + CreatorDto: + required: + - creator_name + - id + type: object + properties: + id: + type: integer + format: int64 + example: 11 + firstname: + type: string + example: Josiah + lastname: + type: string + example: Carberry + affiliation: + type: string + example: Brown University + creator_name: + type: string + example: "Carberry, Josiah" + name_type: + type: string + example: Personal + enum: + - Personal + - Organizational + name_identifier: + type: string + example: 0000-0002-1825-0097 + name_identifier_scheme: + type: string + example: ORCID + enum: + - ORCID + - ROR + - ISNI + - GRID + name_identifier_scheme_uri: + type: string + example: https://orcid.org/ + affiliation_identifier: + type: string + example: https://ror.org/05gq02987 + affiliation_identifier_scheme: + type: string + example: ROR + enum: + - ROR + - GRID + - ISNI + affiliation_identifier_scheme_uri: + type: string + example: https://ror.org/ + IdentifierDescriptionDto: + required: + - id + type: object + properties: + id: + type: integer + format: int64 + example: 3 + description: + type: string + example: "Air quality reports at Stephansplatz, Vienna" + language: + type: string + example: en + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - "no" + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + type: + type: string + example: Abstract + enum: + - Abstract + - Methods + - SeriesInformation + - TableOfContents + - TechnicalInfo + - Other + IdentifierDto: + required: + - creators + - database_id + - descriptions + - funders + - id + - language + - licenses + - owner + - publication_year + - publisher + - query + - query_hash + - query_normalized + - status + - titles + - type + type: object + properties: + id: + type: integer + format: int64 + example: 2 + type: + type: string + example: database + enum: + - database + - subset + - table + - view + titles: + type: array + items: + $ref: "#/components/schemas/IdentifierTitleDto" + descriptions: + type: array + items: + $ref: "#/components/schemas/IdentifierDescriptionDto" + funders: + type: array + items: + $ref: "#/components/schemas/IdentifierFunderDto" + query: + type: string + example: "SELECT `id`, `value`, `location` FROM `air_quality` WHERE `location`\ + \ = \"09:STEF\"" + execution: + type: string + format: date-time + example: 2021-03-12T15:26:21Z + doi: + type: string + example: 10.1038/nphys1170 + publisher: + type: string + example: TU Wien + owner: + $ref: "#/components/schemas/UserBriefDto" + language: + type: string + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - "no" + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + licenses: + type: array + items: + $ref: "#/components/schemas/LicenseDto" + creators: + type: array + items: + $ref: "#/components/schemas/CreatorDto" + status: + type: string + example: draft + enum: + - draft + - published + database_id: + type: integer + format: int64 + example: 1 + query_id: + type: integer + format: int64 + example: 1 + table_id: + type: integer + format: int64 + example: 1 + view_id: + type: integer + format: int64 + example: 1 + query_normalized: + type: string + example: "SELECT `id`, `value`, `location` FROM `air_quality` WHERE `location`\ + \ = \"09:STEF\"" + related_identifiers: + type: array + items: + $ref: "#/components/schemas/RelatedIdentifierDto" + query_hash: + type: string + description: query hash in sha512 + result_hash: + type: string + example: 34fe82cda2c53f13f8d90cfd7a3469e3a939ff311add50dce30d9136397bf8e5 + result_number: + type: integer + format: int64 + example: 1 + publication_day: + type: integer + format: int32 + example: 15 + publication_month: + type: integer + format: int32 + example: 12 + publication_year: + type: integer + format: int32 + example: 2022 + IdentifierFunderDto: + required: + - funder_name + - id + type: object + properties: + id: + type: integer + format: int64 + example: 2 + funder_name: + type: string + example: European Commission + funder_identifier: + type: string + example: http://doi.org/10.13039/501100000780 + funder_identifier_type: + type: string + example: Crossref Funder ID + enum: + - Crossref Funder ID + - ROR + - GND + - ISNI + - Other + scheme_uri: + type: string + example: http://doi.org/ + award_number: + type: string + example: "824087" + award_title: + type: string + example: EOSC-Life + RelatedIdentifierDto: + required: + - id + - relation + - type + - value + type: object + properties: + id: + type: integer + format: int64 + example: 8 + value: + type: string + example: 10.70124/dc4zh-9ce78 + type: + type: string + example: DOI + enum: + - DOI + - URL + - URN + - ARK + - arXiv + - bibcode + - EAN13 + - EISSN + - Handle + - IGSN + - ISBN + - ISTC + - LISSN + - LSID + - PMID + - PURL + - UPC + - w3id + relation: + type: string + example: Cites + enum: + - IsCitedBy + - Cites + - IsSupplementTo + - IsSupplementedBy + - IsContinuedBy + - Continues + - IsDescribedBy + - Describes + - HasMetadata + - IsMetadataFor + - HasVersion + - IsVersionOf + - IsNewVersionOf + - IsPreviousVersionOf + - IsPartOf + - HasPart + - IsPublishedIn + - IsReferencedBy + - References + - IsDocumentedBy + - Documents + - IsCompiledBy + - Compiles + - IsVariantFormOf + - IsOriginalFormOf + - IsIdenticalTo + - IsReviewedBy + - Reviews + - IsDerivedFrom + - IsSourceOf + - IsRequiredBy + - Requires + - IsObsoletedBy + - Obsoletes + DatabaseModifyVisibilityDto: + required: + - is_public + - is_schema_public + type: object + properties: + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + ViewUpdateDto: + required: + - is_public + - is_schema_public + type: object + properties: + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + ViewBriefDto: + required: + - database_id + - id + - internal_name + - name + - query + - query_hash + type: object + properties: + id: + type: integer + format: int64 + example: 4 + name: + type: string + example: Air Quality + query: + type: string + example: SELECT `id` FROM `air_quality` ORDER BY `value` DESC + database_id: + type: integer + format: int64 + example: 1 + internal_name: + type: string + example: air_quality + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + initial_view: + type: boolean + description: True if it is the default view for the database + example: true + query_hash: + type: string + example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916 + owned_by: + type: string + format: uuid + example: ac750fcf-ea02-4fce-85ac-d73857e18b35 + TableUpdateDto: + required: + - is_public + - is_schema_public + type: object + properties: + description: + maxLength: 180 + minLength: 0 + type: string + example: Air Quality in Austria + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + TableBriefDto: + required: + - database_id + - id + - internal_name + - is_public + - is_schema_public + - is_versioned + - name + - owned_by + type: object + properties: + id: + type: integer + format: int64 + example: 3 + name: + type: string + example: Air Quality + description: + type: string + example: Air Quality in Austria + database_id: + type: integer + format: int64 + example: 2 + internal_name: + type: string + example: air_quality + is_versioned: + type: boolean + example: true + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + owned_by: + type: string + format: uuid + example: 78337b80-5699-45db-8111-cec86439ab6b + ColumnSemanticsUpdateDto: + type: object + properties: + concept_uri: + type: string + unit_uri: + type: string + ColumnDto: + required: + - database_id + - id + - internal_name + - is_null_allowed + - name + - ord + - table_id + - type + type: object + properties: + id: + type: integer + format: int64 + example: 1 + name: + maxLength: 64 + minLength: 0 + type: string + example: Given Name + alias: + type: string + example: firstname + size: + type: integer + format: int64 + example: 255 + d: + type: integer + format: int64 + example: 0 + mean: + type: number + example: 45.4 + median: + type: number + example: 51 + concept: + $ref: "#/components/schemas/ConceptBriefDto" + unit: + $ref: "#/components/schemas/UnitBriefDto" + description: + maxLength: 2048 + minLength: 0 + type: string + example: Column comment + enums: + type: array + example: + - val1 + items: + type: string + example: "[\"val1\"]" + sets: + type: array + example: + - val1 + items: + type: string + example: "[\"val1\"]" + database_id: + type: integer + format: int64 + example: 2 + table_id: + type: integer + format: int64 + example: 3 + ord: + type: integer + format: int32 + example: 0 + internal_name: + maxLength: 64 + minLength: 0 + type: string + example: given_name + index_length: + type: integer + format: int64 + example: 255 + length: + type: integer + format: int64 + example: 255 + type: + type: string + example: varchar + enum: + - char + - varchar + - binary + - varbinary + - tinyblob + - tinytext + - text + - blob + - mediumtext + - mediumblob + - longtext + - longblob + - enum + - set + - serial + - bit + - tinyint + - bool + - smallint + - mediumint + - int + - bigint + - float + - double + - decimal + - date + - datetime + - timestamp + - time + - year + data_length: + type: integer + format: int64 + example: 34300 + max_data_length: + type: integer + format: int64 + example: 34300 + num_rows: + type: integer + format: int64 + example: 32 + val_min: + type: number + example: 0 + val_max: + type: number + example: 100 + std_dev: + type: number + example: 5.32 + is_null_allowed: + type: boolean + example: false + ConceptBriefDto: + required: + - id + - uri + type: object + properties: + id: + type: integer + format: int64 + example: 23 + uri: + type: string + example: http://www.wikidata.org/entity/Q202444 + name: + type: string + example: given name + description: + type: string + example: "name typically used to differentiate people from the same family,\ + \ clan, or other social group who have a common last name" + UnitBriefDto: + required: + - id + - uri + type: object + properties: + id: + type: integer + format: int64 + example: 34 + uri: + type: string + example: http://www.wikidata.org/entity/Q1422583 + name: + type: string + example: importance + description: + type: string + example: "subjective magnitude of value, meaning, or purpose" + DatabaseTransferDto: + required: + - id + type: object + properties: + id: + type: string + format: uuid + DatabaseModifyImageDto: + type: object + properties: + key: + type: string + CreateAccessDto: + required: + - type + type: object + properties: + type: + type: string + example: read + enum: + - read + - write_own + - write_all + CreateUserDto: + required: + - email + - password + - username + type: object + properties: + username: + pattern: "^[a-z0-9]{3,}$" + type: string + example: user + email: + type: string + example: user@example.com + password: + type: string + LoginRequestDto: + required: + - password + - username + type: object + properties: + username: + type: string + example: user + password: + type: string + OntologyCreateDto: + required: + - prefix + - uri + type: object + properties: + uri: + type: string + example: Ontology URI + prefix: + type: string + example: Ontology prefix + sparql_endpoint: + type: string + example: Ontology SPARQL endpoint + BannerMessageCreateDto: + required: + - message + - type + type: object + properties: + type: + type: string + enum: + - error + - warning + - info + message: + type: string + example: Maintenance starts on 8am on Monday + link: + type: string + example: https://example.com + link_text: + type: string + example: More + display_start: + type: string + format: date-time + example: 2021-03-12T15:26:21Z + display_end: + type: string + format: date-time + example: 2021-03-12T15:26:21Z + ImageCreateDto: + required: + - default_port + - dialect + - driver_class + - is_default + - jdbc_method + - name + - registry + - version + type: object + properties: + registry: + type: string + example: docker.io/library + name: + type: string + example: mariadb + version: + type: string + dialect: + type: string + is_default: + type: boolean + example: false + driver_class: + type: string + jdbc_method: + type: string + default_port: + maximum: 65535 + minimum: 1024 + type: integer + format: int32 + CreateIdentifierDto: + required: + - creators + - database_id + - publication_year + - publisher + - titles + - type + type: object + properties: + type: + type: string + example: database + enum: + - database + - subset + - table + - view + doi: + type: string + example: 10.1111/11111111 + titles: + type: array + items: + $ref: "#/components/schemas/SaveIdentifierTitleDto" + descriptions: + type: array + items: + $ref: "#/components/schemas/SaveIdentifierDescriptionDto" + funders: + type: array + items: + $ref: "#/components/schemas/SaveIdentifierFunderDto" + licenses: + type: array + items: + $ref: "#/components/schemas/LicenseDto" + publisher: + type: string + example: TU Wien + language: + type: string + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - "no" + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + creators: + type: array + items: + $ref: "#/components/schemas/SaveIdentifierCreatorDto" + database_id: + type: integer + format: int64 + example: 1 + query_id: + type: integer + format: int64 + view_id: + type: integer + format: int64 + table_id: + type: integer + format: int64 + publication_day: + type: integer + format: int32 + example: 15 + publication_month: + type: integer + format: int32 + example: 12 + publication_year: + type: integer + format: int32 + example: 2022 + related_identifiers: + type: array + items: + $ref: "#/components/schemas/SaveRelatedIdentifierDto" + CreateDatabaseDto: + required: + - container_id + - is_public + - is_schema_public + - name + type: object + properties: + name: + type: string + example: Air Quality + container_id: + type: integer + format: int64 + example: 1 + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + CreateViewDto: + required: + - is_public + - is_schema_public + - name + - query + type: object + properties: + name: + maxLength: 63 + minLength: 1 + type: string + example: Air Quality + query: + type: string + example: SELECT `id` FROM `air_quality` + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + CreateForeignKeyDto: + required: + - columns + - referenced_columns + - referenced_table + type: object + properties: + columns: + type: array + items: + type: string + referenced_table: + type: string + referenced_columns: + type: array + items: + type: string + on_update: + type: string + enum: + - restrict + - cascade + - set_null + - no_action + - set_default + on_delete: + type: string + enum: + - restrict + - cascade + - set_null + - no_action + - set_default + CreateTableColumnDto: + required: + - name + - null_allowed + - type + type: object + properties: + name: + type: string + example: Date + type: + type: string + example: string + enum: + - char + - varchar + - binary + - varbinary + - tinyblob + - tinytext + - text + - blob + - mediumtext + - mediumblob + - longtext + - longblob + - enum + - set + - serial + - bit + - tinyint + - bool + - smallint + - mediumint + - int + - bigint + - float + - double + - decimal + - date + - datetime + - timestamp + - time + - year + size: + type: integer + format: int64 + example: 255 + d: + type: integer + format: int64 + example: 0 + description: + maxLength: 2048 + minLength: 0 + type: string + example: Formatted as YYYY-MM-dd + enums: + type: array + description: "enum values, only considered when type = ENUM" + items: + type: string + description: "enum values, only considered when type = ENUM" + sets: + type: array + description: "set values, only considered when type = SET" + items: + type: string + description: "set values, only considered when type = SET" + index_length: + type: integer + format: int64 + null_allowed: + type: boolean + example: true + concept_uri: + type: string + unit_uri: + type: string + CreateTableConstraintsDto: + required: + - checks + - foreign_keys + - primary_key + - uniques + type: object + properties: + uniques: + type: array + items: + type: array + items: + type: string + checks: + uniqueItems: true + type: array + items: + type: string + foreign_keys: + type: array + items: + $ref: "#/components/schemas/CreateForeignKeyDto" + primary_key: + uniqueItems: true + type: array + items: + type: string + CreateTableDto: + required: + - columns + - constraints + - is_public + - is_schema_public + - name + type: object + properties: + name: + maxLength: 64 + minLength: 1 + type: string + example: Air Quality + description: + maxLength: 180 + minLength: 0 + type: string + example: Air Quality in Austria + columns: + type: array + items: + $ref: "#/components/schemas/CreateTableColumnDto" + constraints: + $ref: "#/components/schemas/CreateTableConstraintsDto" + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + CreateContainerDto: + required: + - host + - image_id + - name + - privileged_password + - privileged_username + - quota + type: object + properties: + name: + type: string + example: Air Quality + host: + type: string + description: Hostname of container + example: data-db2 + port: + type: integer + description: Port of container + format: int32 + example: 3306 + quota: + type: integer + format: int64 + example: 50 + image_id: + type: integer + description: Image ID + format: int64 + example: 1 + ui_host: + type: string + example: example.com + ui_port: + type: integer + format: int32 + example: 3306 + privileged_username: + type: string + description: Username of privileged user + example: root + privileged_password: + type: string + description: Password of privileged user + example: dbrepo + ContainerDto: + required: + - count + - id + - image + - internal_name + - name + - quota + type: object + properties: + id: + type: integer + format: int64 + example: 4 + name: + type: string + example: Air Quality + host: + type: string + example: data-db + port: + type: integer + format: int32 + example: 3306 + image: + $ref: "#/components/schemas/ImageDto" + quota: + type: integer + format: int64 + example: 50 + count: + type: integer + format: int64 + example: 10 + username: + type: string + example: username + password: + type: string + example: p4ssw0rd + last_retrieved: + type: string + format: date-time + internal_name: + type: string + example: air_quality + ui_host: + type: string + example: example.com + ui_port: + type: integer + format: int32 + example: 3306 + ColumnBriefDto: + required: + - database_id + - id + - internal_name + - name + - table_id + - type + type: object + properties: + id: + type: integer + format: int64 + example: 1 + name: + maxLength: 64 + minLength: 0 + type: string + example: Given Name + alias: + type: string + example: firstname + database_id: + type: integer + format: int64 + example: 2 + table_id: + type: integer + format: int64 + example: 3 + internal_name: + maxLength: 64 + minLength: 0 + type: string + example: given_name + type: + type: string + example: varchar + enum: + - char + - varchar + - binary + - varbinary + - tinyblob + - tinytext + - text + - blob + - mediumtext + - mediumblob + - longtext + - longblob + - enum + - set + - serial + - bit + - tinyint + - bool + - smallint + - mediumint + - int + - bigint + - float + - double + - decimal + - date + - datetime + - timestamp + - time + - year + UnitDto: + required: + - columns + - id + - uri + type: object + properties: + id: + type: integer + format: int64 + uri: + type: string + name: + type: string + description: + type: string + columns: + type: array + items: + $ref: "#/components/schemas/ColumnBriefDto" + OntologyBriefDto: + required: + - id + - prefix + - rdf + - sparql + - uri + type: object + properties: + id: + type: integer + format: int64 + uri: + type: string + example: http://www.wikidata.org/ + prefix: + type: string + example: wd + sparql: + type: boolean + example: true + rdf: + type: boolean + example: false + uri_pattern: + type: string + example: http://www.wikidata.org/entity/.* + EntityDto: + required: + - label + - uri + type: object + properties: + uri: + type: string + example: https://www.wikidata.org/entity/Q1686799 + label: + type: string + example: Apache Jena + description: + type: string + example: open source semantic web framework for Java + OaiListIdentifiersParameters: + type: object + properties: + metadataPrefix: + type: string + from: + type: string + until: + type: string + set: + type: string + resumptionToken: + type: string + fromDate: + type: string + format: date-time + untilDate: + type: string + format: date-time + parametersString: + type: string + BannerMessageDto: + required: + - id + - message + - type + type: object + properties: + id: + type: integer + format: int64 + type: + type: string + enum: + - error + - warning + - info + message: + type: string + example: Maintenance starts on 8am on Monday + link: + type: string + example: https://example.com + link_text: + type: string + example: More + display_start: + type: string + format: date-time + example: 2021-03-12T15:26:21Z + display_end: + type: string + format: date-time + example: 2021-03-12T15:26:21Z + ImageBriefDto: + required: + - default + - id + - jdbc_method + - name + - version + type: object + properties: + id: + type: integer + format: int64 + example: 5 + name: + type: string + example: mariadb + version: + type: string + example: "10.5" + jdbc_method: + type: string + example: mariadb + default: + type: boolean + example: false + LdCreatorDto: + required: + - '@type' + - name + type: object + properties: + name: + type: string + sameAs: + type: string + givenName: + type: string + familyName: + type: string + '@type': + type: string + LdDatasetDto: + required: + - '@context' + - '@type' + - citation + - creator + - description + - hasPart + - identifier + - name + - temporalCoverage + - url + - version + type: object + properties: + name: + type: string + description: + type: string + url: + type: string + identifier: + type: array + items: + type: string + license: + type: string + creator: + type: array + items: + $ref: "#/components/schemas/LdCreatorDto" + citation: + type: string + hasPart: + type: array + items: + $ref: "#/components/schemas/LdDatasetDto" + temporalCoverage: + type: string + version: + type: string + format: date-time + '@context': + type: string + '@type': + type: string + ConstraintsDto: + type: object + properties: + uniques: + type: array + items: + $ref: "#/components/schemas/UniqueDto" + checks: + uniqueItems: true + type: array + example: + - value > 1 + items: + type: string + example: "[\"value > 1\"]" + foreign_keys: + type: array + items: + $ref: "#/components/schemas/ForeignKeyDto" + primary_key: + uniqueItems: true + type: array + items: + $ref: "#/components/schemas/PrimaryKeyDto" + DatabaseDto: + required: + - accesses + - contact + - exchange_name + - id + - identifiers + - internal_name + - is_public + - is_schema_public + - name + - owner + - subsets + - tables + - views + type: object + properties: + id: + type: integer + format: int64 + example: 3 + name: + type: string + example: Air Quality + description: + type: string + example: Air Quality + tables: + type: array + items: + $ref: "#/components/schemas/TableDto" + views: + type: array + items: + $ref: "#/components/schemas/ViewDto" + container: + $ref: "#/components/schemas/ContainerDto" + accesses: + type: array + items: + $ref: "#/components/schemas/DatabaseAccessDto" + identifiers: + type: array + items: + $ref: "#/components/schemas/IdentifierDto" + subsets: + type: array + items: + $ref: "#/components/schemas/IdentifierDto" + contact: + $ref: "#/components/schemas/UserBriefDto" + owner: + $ref: "#/components/schemas/UserBriefDto" + last_retrieved: + type: string + format: date-time + exchange_name: + type: string + example: dbrepo + exchange_type: + type: string + example: topic + internal_name: + type: string + example: air_quality + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + preview_image: + type: string + ForeignKeyBriefDto: + type: object + properties: + id: + type: integer + format: int64 + example: 8 + ForeignKeyDto: + required: + - name + - referenced_table + - references + - table + type: object + properties: + id: + type: integer + format: int64 + example: 4 + name: + type: string + example: fk_name + references: + type: array + items: + $ref: "#/components/schemas/ForeignKeyReferenceDto" + table: + $ref: "#/components/schemas/TableBriefDto" + referenced_table: + $ref: "#/components/schemas/TableBriefDto" + on_update: + type: string + example: restrict + enum: + - restrict + - cascade + - set_null + - no_action + - set_default + on_delete: + type: string + example: restrict + enum: + - restrict + - cascade + - set_null + - no_action + - set_default + ForeignKeyReferenceDto: + required: + - column + - foreign_key + - referenced_column + type: object + properties: + id: + type: integer + format: int64 + example: 8 + column: + $ref: "#/components/schemas/ColumnBriefDto" + foreign_key: + $ref: "#/components/schemas/ForeignKeyBriefDto" + referenced_column: + $ref: "#/components/schemas/ColumnBriefDto" + PrimaryKeyDto: + required: + - column + - table + type: object + properties: + id: + type: integer + format: int64 + example: 8 + table: + $ref: "#/components/schemas/TableBriefDto" + column: + $ref: "#/components/schemas/ColumnBriefDto" + TableDto: + required: + - columns + - constraints + - database_id + - id + - internal_name + - is_public + - is_schema_public + - is_versioned + - name + - owner + - queue_name + - routing_key + type: object + properties: + id: + type: integer + format: int64 + example: 3 + name: + type: string + example: Air Quality + alias: + type: string + example: a + identifiers: + type: array + items: + $ref: "#/components/schemas/IdentifierDto" + owner: + $ref: "#/components/schemas/UserBriefDto" + description: + maxLength: 2048 + minLength: 0 + type: string + example: Air Quality in Austria + columns: + type: array + items: + $ref: "#/components/schemas/ColumnDto" + database: + $ref: "#/components/schemas/DatabaseDto" + constraints: + $ref: "#/components/schemas/ConstraintsDto" + last_retrieved: + type: string + format: date-time + database_id: + type: integer + format: int64 + example: 2 + internal_name: + type: string + example: air_quality + is_versioned: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + queue_name: + type: string + example: air_quality + queue_type: + type: string + example: quorum + routing_key: + type: string + example: dbrepo.1.2 + is_public: + type: boolean + example: true + num_rows: + type: integer + format: int64 + example: 5 + data_length: + type: integer + description: in bytes + format: int64 + example: 16384 + max_data_length: + type: integer + description: in bytes + format: int64 + example: 0 + avg_row_length: + type: integer + description: in bytes + format: int64 + example: 3276 + UniqueDto: + required: + - columns + - id + - name + - table + type: object + properties: + id: + type: integer + format: int64 + example: 5 + name: + type: string + example: uk_name + table: + $ref: "#/components/schemas/TableBriefDto" + columns: + type: array + items: + $ref: "#/components/schemas/ColumnBriefDto" + ViewColumnDto: + required: + - database_id + - id + - internal_name + - is_null_allowed + - name + - ord + - type + type: object + properties: + id: + type: integer + format: int64 + example: 12 + name: + maxLength: 64 + minLength: 0 + type: string + example: Given Name + size: + type: integer + format: int64 + example: 255 + d: + type: integer + format: int64 + example: 0 + description: + maxLength: 2048 + minLength: 0 + type: string + example: Column comment + database_id: + type: integer + format: int64 + example: 1 + ord: + type: integer + format: int32 + example: 0 + internal_name: + maxLength: 64 + minLength: 0 + type: string + example: given_name + index_length: + type: integer + format: int64 + example: 255 + length: + type: integer + format: int64 + example: 255 + type: + type: string + example: varchar + enum: + - char + - varchar + - binary + - varbinary + - tinyblob + - tinytext + - text + - blob + - mediumtext + - mediumblob + - longtext + - longblob + - enum + - set + - serial + - bit + - tinyint + - bool + - smallint + - mediumint + - int + - bigint + - float + - double + - decimal + - date + - datetime + - timestamp + - time + - year + is_null_allowed: + type: boolean + example: false + ViewDto: + required: + - columns + - database_id + - id + - identifiers + - internal_name + - name + - owner + - query + - query_hash + type: object + properties: + id: + type: integer + format: int64 + example: 4 + name: + type: string + example: Air Quality + identifiers: + type: array + items: + $ref: "#/components/schemas/IdentifierDto" + query: + type: string + example: SELECT `id` FROM `air_quality` ORDER BY `value` DESC + database: + $ref: "#/components/schemas/DatabaseDto" + owner: + $ref: "#/components/schemas/UserBriefDto" + columns: + type: array + items: + $ref: "#/components/schemas/ViewColumnDto" + last_retrieved: + type: string + format: date-time + database_id: + type: integer + format: int64 + example: 1 + internal_name: + type: string + example: air_quality + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + initial_view: + type: boolean + description: True if it is the default view for the database + example: true + query_hash: + type: string + example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916 + TableColumnEntityDto: + required: + - column_id + - database_id + - table_id + - uri + type: object + properties: + uri: + type: string + example: https://www.wikidata.org/entity/Q1686799 + label: + type: string + example: Apache Jena + description: + type: string + example: open source semantic web framework for Java + database_id: + type: integer + format: int64 + example: 1 + table_id: + type: integer + format: int64 + example: 1 + column_id: + type: integer + format: int64 + example: 1 + ContainerBriefDto: + required: + - count + - hash + - id + - image + - internal_name + - name + - quota + type: object + properties: + id: + type: integer + format: int64 + example: 4 + hash: + type: string + example: f829dd8a884182d0da846f365dee1221fd16610a14c81b8f9f295ff162749e50 + name: + type: string + example: Air Quality + image: + $ref: "#/components/schemas/ImageBriefDto" + quota: + type: integer + format: int32 + example: 50 + count: + type: integer + format: int32 + example: 10 + internal_name: + type: string + example: air-quality + ConceptDto: + required: + - columns + - id + - uri + type: object + properties: + id: + type: integer + format: int64 + uri: + type: string + name: + type: string + description: + type: string + columns: + type: array + items: + $ref: "#/components/schemas/ColumnBriefDto" + securitySchemes: + basicAuth: + type: http + scheme: basic + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT diff --git a/.docs/.openapi/api-search.yaml b/.docs/.openapi/api-search.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c47cbfb649c8e832ccbd8238ea5e574ac522900b --- /dev/null +++ b/.docs/.openapi/api-search.yaml @@ -0,0 +1,387 @@ +{ + "components": { + "schemas": { + "IndexDto": { + "properties": { + "results": { + "items": { + "type": "object" + }, + "type": "array" + }, + "type": { + "description": "Same as the requested type", + "enum": [ + "database", + "table", + "view", + "column", + "user", + "identifier", + "concept", + "unit" + ], + "type": "string" + } + }, + "required": [ + "results", + "type" + ] + }, + "IndexFieldDto": { + "properties": { + "attr_friendly_name": { + "example": "Name", + "type": "string" + }, + "attr_name": { + "example": "name", + "type": "string" + }, + "type": { + "description": "OpenSearch data types.", + "example": "string", + "type": "string" + } + }, + "required": [ + "attr_name", + "attr_friendly_name", + "type" + ], + "type": "object" + }, + "IndexFieldsDto": { + "properties": { + "results": { + "items": { + "$ref": "#/components/schemas/IndexFieldDto" + }, + "type": "array" + } + }, + "required": [ + "results" + ], + "type": "object" + }, + "SearchRequestDto": { + "properties": { + "field_value_pairs": { + "type": "object" + }, + "search_term": { + "type": "string" + } + }, + "required": [ + "search_term", + "field_value_pairs" + ], + "type": "object" + } + }, + "securitySchemes": { + "basicAuth": { + "in": "header", + "scheme": "basic", + "type": "http" + }, + "bearerAuth": { + "bearerFormat": "JWT", + "in": "header", + "scheme": "bearer", + "type": "http" + } + } + }, + "externalDocs": { + "description": "Sourcecode Documentation", + "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.5/" + }, + "info": { + "contact": { + "email": "andreas.rauber@tuwien.ac.at", + "name": "Prof. Andreas Rauber" + }, + "description": "Service that searches the search database", + "license": { + "name": "Apache 2.0", + "url": "https://www.apache.org/licenses/LICENSE-2.0" + }, + "title": "Database Repository Search Service API", + "version": "1.5" + }, + "openapi": "3.0.0", + "paths": { + "/api/search": { + "get": { + "consumes": [ + "application/json" + ], + "description": "Performs a fuzzy search", + "operationId": "post_fuzzy_search", + "parameters": [ + { + "in": "query", + "name": "q", + "required": true, + "schema": { + "type": "string" + } + } + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "id": { + "type": "string" + } + }, + "type": "array" + } + } + }, + "description": "OK, contains the elements formatted as an array of JSON arrays" + }, + "415": { + "description": "Wrong accept type" + } + }, + "summary": "Performs a fuzzy search", + "tags": [ + "search-endpoint" + ] + } + }, + "/api/search/{field_type}": { + "post": { + "consumes": [ + "application/json" + ], + "description": "Performs a general search", + "operationId": "post_general_search", + "parameters": [ + { + "description": "The search type.", + "in": "path", + "name": "type", + "required": true, + "schema": { + "enum": [ + "database", + "table", + "view", + "column", + "user", + "identifier", + "concept", + "unit" + ], + "type": "string" + } + }, + { + "in": "query", + "name": "t1", + "schema": { + "type": "integer" + } + }, + { + "in": "query", + "name": "t2", + "schema": { + "type": "integer" + } + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "$ref": "#/components/schemas/SearchRequestDto" + } + } + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "properties": { + "results": { + "items": { + "type": "object" + }, + "type": "array" + }, + "type": { + "description": "Same as the requested type", + "enum": [ + "database", + "table", + "view", + "column", + "user", + "identifier", + "concept", + "unit" + ], + "type": "string" + } + }, + "type": "object" + } + } + }, + "description": "OK, contains the elements formatted as an array of JSON arrays" + } + }, + "summary": "Performs a general search", + "tags": [ + "search-endpoint" + ] + } + }, + "/api/search/{field_type}/fields": { + "get": { + "operationId": "get_fields", + "parameters": [ + { + "description": "The search type.", + "in": "path", + "name": "type", + "required": true, + "schema": { + "enum": [ + "database", + "table", + "view", + "column", + "user", + "identifier", + "concept", + "unit" + ], + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexFieldsDto" + } + } + }, + "description": "List of fields" + }, + "404": { + "description": "Invalid type." + } + }, + "summary": "Get searchable fields", + "tags": [ + "search-endpoint" + ] + } + }, + "/api/search/{index}": { + "get": { + "consumes": [ + "application/json" + ], + "description": "Gets the index", + "operationId": "get_index", + "parameters": [ + { + "description": "The search type.", + "in": "path", + "name": "type", + "required": true, + "schema": { + "enum": [ + "database", + "table", + "view", + "column", + "user", + "identifier", + "concept", + "unit" + ], + "type": "string" + } + }, + { + "in": "body", + "name": "body", + "required": true, + "schema": { + "properties": { + "field_value_pairs": { + "type": "object" + }, + "search_term": { + "example": "air quality", + "type": "string" + }, + "t1": { + "example": 0, + "type": "integer" + }, + "t2": { + "example": 100, + "type": "integer" + } + }, + "type": "object" + } + } + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexDto" + } + } + }, + "description": "OK, contains the elements formatted as an array of JSON arrays" + } + }, + "summary": "Gets the index", + "tags": [ + "search-endpoint" + ] + } + } + }, + "servers": [ + { + "description": "Generated server url", + "url": "http://localhost:4000" + }, + { + "description": "Sandbox", + "url": "https://test.dbrepo.tuwien.ac.at" + } + ] +} diff --git a/.docs/.swagger/api.base.yaml b/.docs/.openapi/api.base.yaml similarity index 98% rename from .docs/.swagger/api.base.yaml rename to .docs/.openapi/api.base.yaml index fc0a733ccc7e1c4134f8a444c9b6fe08acb7aabb..ee32aad2ff6d82927876773fb76d26b79c7b846c 100644 --- a/.docs/.swagger/api.base.yaml +++ b/.docs/.openapi/api.base.yaml @@ -24,7 +24,7 @@ info: name: Apache 2.0 url: https://www.apache.org/licenses/LICENSE-2.0 title: DBRepo REST API - version: 1.6.1 + version: 1.6.2 openapi: 3.1.0 servers: - description: Test Instance diff --git a/.docs/.swagger/api.yaml b/.docs/.openapi/api.yaml similarity index 94% rename from .docs/.swagger/api.yaml rename to .docs/.openapi/api.yaml index dc7a627e743279d6eddf788cc9b1c18411912e50..c5d75bca5ae848f542e636fe91d656195e2dc6b2 100644 --- a/.docs/.swagger/api.yaml +++ b/.docs/.openapi/api.yaml @@ -16,7 +16,7 @@ info: name: Apache 2.0 url: 'https://www.apache.org/licenses/LICENSE-2.0' title: DBRepo REST API - version: 1.6.1 + version: 1.6.2 servers: - description: Test Instance url: 'https://test.dbrepo.tuwien.ac.at' @@ -432,6 +432,11 @@ paths: schema: type: integer format: int64 + - name: Authorization + in: header + required: true + schema: + type: string requestBody: content: application/json: @@ -490,6 +495,11 @@ paths: schema: type: integer format: int64 + - name: Authorization + in: header + required: true + schema: + type: string requestBody: content: application/json: @@ -550,6 +560,11 @@ paths: schema: type: integer format: int64 + - name: Authorization + in: header + required: true + schema: + type: string requestBody: content: application/json: @@ -695,6 +710,12 @@ paths: schema: type: integer format: int64 + - name: timestamp + in: query + required: false + schema: + type: string + format: date-time - name: page in: query required: false @@ -782,6 +803,12 @@ paths: schema: type: integer format: int64 + - name: timestamp + in: query + required: false + schema: + type: string + format: date-time - name: page in: query required: false @@ -937,6 +964,11 @@ paths: schema: type: integer format: int64 + - name: Authorization + in: header + required: true + schema: + type: string requestBody: content: application/json: @@ -979,9 +1011,11 @@ paths: - subset-endpoint summary: Find subsets description: >- - Finds subsets in the query store. The result can be optionally filtered - by setting `persisted`. When set to *true*, only persisted queries are - returned, otherwise only non-persisted queries are returned. + Finds subsets in the query store. When the database schema is marked as + hidden, the user needs to be authorized, have at least read-access to + the database. The result can be optionally filtered by setting + `persisted`. When set to *true*, only persisted queries are returned, + otherwise only non-persisted queries are returned. operationId: list parameters: - name: databaseId @@ -1032,8 +1066,10 @@ paths: - subset-endpoint summary: Create subset description: >- - Creates a subset in the query store of the data database. Requires role - `execute-query` for private databases. + Creates a subset in the query store of the data database. Can also be + used without authentication if (and only if) the database is marked as + public (i.e. when `is_public` = `is_schema_public` is set to `true`). + Otherwise at least read access is required. operationId: create parameters: - name: databaseId @@ -1313,9 +1349,11 @@ paths: - subset-endpoint summary: Find subset description: >- - Finds a subset in the data database. Requests with HTTP header - `Accept=application/json` return the metadata, requests with HTTP header - `Accept=text/csv` return the data as downloadable file. + Finds a subset in the data database. When the database schema is marked + as hidden, the user needs to be authorized, have at least read-access to + the database. Requests with HTTP header `Accept=application/json` + return the metadata, requests with HTTP header `Accept=text/csv` return + the data as downloadable file. operationId: findById parameters: - name: databaseId @@ -1330,6 +1368,11 @@ paths: schema: type: integer format: int64 + - name: Accept + in: header + required: true + schema: + type: string - name: timestamp in: query required: false @@ -1412,7 +1455,7 @@ paths: schema: type: array items: - $ref: '#/components/schemas/DatabaseDto' + $ref: '#/components/schemas/DatabaseBriefDto' post: tags: - database-endpoint @@ -1425,7 +1468,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/DatabaseCreateDto' + $ref: '#/components/schemas/CreateDatabaseDto' required: true responses: '201': @@ -1433,7 +1476,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/DatabaseDto' + $ref: '#/components/schemas/DatabaseBriefDto' '400': description: Database create query is malformed or image is not supported content: @@ -1513,7 +1556,7 @@ paths: schema: type: array items: - $ref: '#/components/schemas/DatabaseDto' + $ref: '#/components/schemas/DatabaseBriefDto' '/api/database/{databaseId}/access/{userId}': get: tags: @@ -1568,7 +1611,7 @@ paths: description: >- Modifies access of a user with given id to database with given id. Requires role `update-database-access`. - operationId: update_6 + operationId: update_5 parameters: - name: databaseId in: path @@ -1586,7 +1629,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/UpdateDatabaseAccessDto' + $ref: '#/components/schemas/CreateAccessDto' required: true responses: '202': @@ -1653,7 +1696,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/UpdateDatabaseAccessDto' + $ref: '#/components/schemas/CreateAccessDto' required: true responses: '202': @@ -1803,7 +1846,11 @@ paths: tags: - user-endpoint summary: Get user - description: Gets user with id from the metadata database. Requires authentication. + description: >- + Gets own user information from the metadata database. Requires + authentication. Foreign user information can only be obtained if + additional role `find-foreign-user` is present. Finding information + about internal users results in a 404 error. operationId: find_2 parameters: - name: userId @@ -1979,7 +2026,7 @@ paths: tags: - user-endpoint summary: Create token - description: Creates a user token via the auth service. + description: Creates a user token via the Auth Service. operationId: getToken requestBody: content: @@ -2544,7 +2591,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/DatabaseDto' + $ref: '#/components/schemas/DatabaseBriefDto' '400': description: The visibility payload is malformed content: @@ -2678,7 +2725,7 @@ paths: content: '*/*': schema: - $ref: '#/components/schemas/ViewDto' + $ref: '#/components/schemas/ViewBriefDto' '400': description: Update view query is malformed content: @@ -2734,10 +2781,6 @@ paths: responses: '202': description: Delete view successfully - content: - '*/*': - schema: - type: object '400': description: Delete view query is malformed content: @@ -2783,8 +2826,10 @@ paths: - table-endpoint summary: Find table description: >- - Finds a table with id. When the `system` role is present, the endpoint - responds with additional connection metadata in the header. + Finds a table with id. When a table is hidden (i.e. when `is_public` is + `false`), then the user needs to have at least read access and the role + `find-table`. When the `system` role is present, the endpoint responds + with additional connection metadata in the header. operationId: findById_2 parameters: - name: databaseId @@ -2806,27 +2851,12 @@ paths: X-Username: description: The authentication username style: simple - X-Table: - description: The table internal name - style: simple Access-Control-Expose-Headers: description: Expose custom headers style: simple - X-Type: - description: The JDBC connection type - style: simple - X-Database: - description: The database internal name - style: simple X-Password: description: The authentication password style: simple - X-Host: - description: The database hostname - style: simple - X-Port: - description: The database port number - style: simple content: application/json: schema: @@ -2988,8 +3018,8 @@ paths: summary: Update statistics description: >- Updates basic statistical properties (min, max, mean, median, std.dev) - for numerical columns in a table with id. Requires role - `update-table-statistic`. + for numerical columns in a table with id. This action can only be + performed by the table owner. Requires role `update-table-statistic`. operationId: updateStatistic parameters: - name: databaseId @@ -3013,6 +3043,12 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + '403': + description: Not the owner + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' '404': description: Failed to find database/table in metadata database content: @@ -3044,7 +3080,7 @@ paths: with at least *READ* access to the associated database can update the column semantics (requires role `modify-table-column-semantics`) or foreign table columns if role `modify-foreign-table-column-semantics`. - operationId: update_5 + operationId: updateColumn parameters: - name: databaseId in: path @@ -3140,7 +3176,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/DatabaseDto' + $ref: '#/components/schemas/DatabaseBriefDto' '400': description: Owner payload is malformed content: @@ -3197,7 +3233,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/DatabaseDto' + $ref: '#/components/schemas/DatabaseBriefDto' '403': description: Refresh view metadata is not permitted content: @@ -3248,7 +3284,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/DatabaseDto' + $ref: '#/components/schemas/DatabaseBriefDto' '400': description: Failed to parse payload at search service content: @@ -3342,7 +3378,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/DatabaseDto' + $ref: '#/components/schemas/DatabaseBriefDto' '403': description: Modify of image is not permitted content: @@ -3350,7 +3386,7 @@ paths: schema: $ref: '#/components/schemas/ApiErrorDto' '404': - description: Database or user could not be found + description: Database could not be found content: application/json: schema: @@ -3381,7 +3417,11 @@ paths: tags: - user-endpoint summary: List users - description: Lists users known to the metadata database. + description: >- + Lists users known to the metadata database. Internal users are omitted + from the result list. If the optional query parameter `username` is + present, the result list can be filtered by matching this exact + username. operationId: findAll parameters: - name: username @@ -3410,7 +3450,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/SignupRequestDto' + $ref: '#/components/schemas/CreateUserDto' required: true responses: '201': @@ -3673,7 +3713,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/IdentifierCreateDto' + $ref: '#/components/schemas/CreateIdentifierDto' required: true responses: '201': @@ -3766,7 +3806,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ViewCreateDto' + $ref: '#/components/schemas/CreateViewDto' required: true responses: '201': @@ -3819,7 +3859,10 @@ paths: tags: - table-endpoint summary: List tables - description: Lists all tables known to the metadata database. + description: >- + Lists all tables known to the metadata database. When a database has a + hidden schema (i.e. when `is_schema_public` is `false`), then the user + needs to have at least read access and the role `list-tables`. operationId: list_4 parameters: - name: databaseId @@ -3869,7 +3912,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/TableCreateDto' + $ref: '#/components/schemas/CreateTableDto' required: true responses: '201': @@ -3952,7 +3995,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ContainerCreateDto' + $ref: '#/components/schemas/CreateContainerDto' required: true responses: '201': @@ -4186,7 +4229,13 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/DatabaseDto' + $ref: '#/components/schemas/DatabaseBriefDto' + '403': + description: Not allowed to view database + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' '404': description: 'Database, user or exchange could not be found' content: @@ -4214,8 +4263,8 @@ paths: - table-endpoint summary: Suggest semantics description: >- - Suggests semantic concepts for a table. Requires role - `table-semantic-analyse`. + Suggests semantic concepts for a table. This action can only be + performed by the table owner. Requires role `table-semantic-analyse`. operationId: analyseTable parameters: - name: databaseId @@ -4245,6 +4294,12 @@ paths: application/json: schema: $ref: '#/components/schemas/ApiErrorDto' + '403': + description: Not the table owner. + content: + application/json: + schema: + $ref: '#/components/schemas/ApiErrorDto' '404': description: Failed to find database/table in metadata database content: @@ -4417,7 +4472,10 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/SearchResultDto' + properties: + id: + type: string + type: array description: 'OK, contains the elements formatted as an array of JSON arrays' '415': description: Wrong accept type @@ -4741,10 +4799,18 @@ components: type: object additionalProperties: type: object + example: + key: value + example: + key: value keys: type: object additionalProperties: type: object + example: + id: 1 + example: + id: 1 QueryPersistDto: required: - persist @@ -4753,13 +4819,58 @@ components: persist: type: boolean example: true + CreatorBriefDto: + required: + - creator_name + - id + type: object + properties: + id: + type: integer + format: int64 + example: 11 + affiliation: + type: string + example: Brown University + creator_name: + type: string + example: 'Carberry, Josiah' + name_type: + type: string + example: Personal + enum: + - Personal + - Organizational + name_identifier: + type: string + example: 0000-0002-1825-0097 + name_identifier_scheme: + type: string + example: ORCID + enum: + - ORCID + - ROR + - ISNI + - GRID + affiliation_identifier: + type: string + example: 'https://ror.org/05gq02987' + affiliation_identifier_scheme: + type: string + example: ROR + enum: + - ROR + - GRID + - ISNI IdentifierBriefDto: required: - - created_by + - creators - database_id - id + - owned_by - publication_year - publisher + - status - titles - type type: object @@ -4767,13 +4878,19 @@ components: id: type: integer format: int64 + example: 2 type: type: string + example: database enum: - database - subset - table - view + creators: + type: array + items: + $ref: '#/components/schemas/CreatorBriefDto' titles: type: array items: @@ -4786,6 +4903,7 @@ components: example: TU Wien status: type: string + example: draft enum: - draft - published @@ -4809,9 +4927,10 @@ components: type: integer format: int32 example: 2022 - created_by: + owned_by: type: string format: uuid + example: 2f45ef7a-7f9b-4667-9156-152c87fe1ca5 IdentifierTitleDto: required: - id @@ -4820,6 +4939,7 @@ components: id: type: integer format: int64 + example: 4 title: type: string example: Airquality Demonstrator @@ -5034,6 +5154,7 @@ components: id: type: integer format: int64 + example: 4 owner: $ref: '#/components/schemas/UserBriefDto' execution: @@ -5056,6 +5177,7 @@ components: database_id: type: integer format: int64 + example: 1 query_normalized: type: string example: SELECT `id` FROM `air_quality` @@ -5110,6 +5232,10 @@ components: type: object additionalProperties: type: object + example: + key: value + example: + key: value ImportDto: required: - header @@ -5125,6 +5251,7 @@ components: description: >- If true, the first line contains the column names, otherwise it contains only data + example: true separator: type: string example: ',' @@ -5168,107 +5295,38 @@ components: type: object additionalProperties: type: object - ContainerBriefDto: - required: - - count - - hash - - id - - image - - internal_name - - name - - quota - type: object - properties: - id: - type: integer - format: int64 - hash: - type: string - example: f829dd8a884182d0da846f365dee1221fd16610a14c81b8f9f295ff162749e50 - name: - type: string - example: Air Quality - image: - $ref: '#/components/schemas/ImageBriefDto' - quota: - type: integer - format: int32 - example: 50 - count: - type: integer - format: int32 - example: 10 - internal_name: - type: string - example: air-quality - DatabaseAccessDto: - required: - - type - - user - type: object - properties: - user: - $ref: '#/components/schemas/UserBriefDto' - type: - type: string - enum: - - read - - write_own - - write_all - DatabaseDto: + example: + id: 1 + example: + id: 1 + DatabaseBriefDto: required: - contact - - container - - exchange_name - id + - identifiers - internal_name - is_public - is_schema_public - name - - owner + - owner_id type: object properties: id: type: integer format: int64 + example: 3 name: type: string example: Air Quality description: type: string example: Air Quality - tables: - type: array - items: - $ref: '#/components/schemas/TableBriefDto' - views: - type: array - items: - $ref: '#/components/schemas/ViewBriefDto' - container: - $ref: '#/components/schemas/ContainerBriefDto' - accesses: - type: array - items: - $ref: '#/components/schemas/DatabaseAccessDto' identifiers: type: array items: $ref: '#/components/schemas/IdentifierBriefDto' - subsets: - type: array - items: - $ref: '#/components/schemas/IdentifierBriefDto' contact: $ref: '#/components/schemas/UserBriefDto' - owner: - $ref: '#/components/schemas/UserBriefDto' - exchange_name: - type: string - example: dbrepo - exchange_type: - type: string - example: topic internal_name: type: string example: air_quality @@ -5278,119 +5336,34 @@ components: is_schema_public: type: boolean example: true + owner_id: + type: string + format: uuid + example: 2f45ef7a-7f9b-4667-9156-152c87fe1ca5 preview_image: type: string - ImageBriefDto: + DatabaseAccessDto: required: - - default - - id - - jdbc_method - - name - - version + - type + - user type: object properties: - id: - type: integer - format: int64 - name: - type: string - example: mariadb - version: - type: string - example: '10.5' - jdbc_method: + user: + $ref: '#/components/schemas/UserBriefDto' + type: type: string - example: mariadb - default: - type: boolean - example: false - TableBriefDto: + example: read + enum: + - read + - write_own + - write_all + UserUpdateDto: required: - - database_id - - id - - internal_name - - is_public - - is_schema_public - - is_versioned - - name - - owned_by + - language + - theme type: object properties: - id: - type: integer - format: int64 - name: - type: string - example: Air Quality - description: - type: string - example: Air Quality in Austria - database_id: - type: integer - format: int64 - internal_name: - type: string - example: air_quality - is_versioned: - type: boolean - example: true - is_public: - type: boolean - example: true - is_schema_public: - type: boolean - example: true - owned_by: - type: string - format: uuid - ViewBriefDto: - required: - - database_id - - id - - internal_name - - name - - query - - query_hash - type: object - properties: - id: - type: integer - format: int64 - name: - type: string - example: Air Quality - query: - type: string - example: SELECT `id` FROM `air_quality` ORDER BY `value` DESC - database_id: - type: integer - format: int64 - internal_name: - type: string - example: air_quality - is_public: - type: boolean - example: true - is_schema_public: - type: boolean - example: true - initial_view: - type: boolean - description: True if it is the default view for the database - example: true - query_hash: - type: string - example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916 - owned_by: - type: string - format: uuid - UserUpdateDto: - required: - - language - - theme - type: object - properties: - firstname: + firstname: type: string example: Josiah lastname: @@ -5430,6 +5403,7 @@ components: required: - attributes - id + - password - username type: object properties: @@ -5437,15 +5411,20 @@ components: type: string format: uuid example: 1ffc7b0e-9aeb-4e8b-b8f1-68f3936155b4 - username: - type: string - description: Only contains lowercase characters - example: jcarberry name: type: string example: Josiah Carberry + username: + type: string + example: username + password: + type: string + example: p4ssw0rd attributes: $ref: '#/components/schemas/UserAttributesDto' + last_retrieved: + type: string + format: date-time qualified_name: type: string example: Josiah Carberry — @jcarberry @@ -5707,6 +5686,7 @@ components: id: type: integer format: int64 + example: 1 registry: type: string example: docker.io/library @@ -5747,6 +5727,9 @@ components: - value type: object properties: + id: + type: integer + format: int64 value: type: string example: XOR @@ -5756,105 +5739,53 @@ components: display_name: type: string example: XOR - CreatorSaveDto: - required: - - creator_name - - id - type: object - properties: - id: - type: integer - format: int64 - example: 1 - firstname: - type: string - example: Josiah - lastname: - type: string - example: Carberry - affiliation: - type: string - example: Wesleyan University - creator_name: - type: string - example: 'Carberry, Josiah' - name_type: - type: string - example: Personal - enum: - - Personal - - Organizational - name_identifier: - type: string - example: 0000-0002-1825-0097 - name_identifier_scheme: - type: string - example: ORCID - enum: - - ORCID - - ROR - - ISNI - - GRID - affiliation_identifier: - type: string - example: 'https://ror.org/04d836q62' - affiliation_identifier_scheme: - type: string - example: ROR - enum: - - ROR - - GRID - - ISNI - IdentifierFunderSaveDto: + IdentifierSaveDto: required: - - funder_name + - creators + - database_id - id + - publication_year + - publisher + - titles + - type type: object properties: id: type: integer format: int64 example: 1 - funder_name: - type: string - example: European Commission - funder_identifier: - type: string - example: 'http://doi.org/10.13039/501100000780' - funder_identifier_type: + type: type: string - example: Crossref Funder ID + example: database enum: - - Crossref Funder ID - - ROR - - GND - - ISNI - - Other - scheme_uri: - type: string - example: 'http://doi.org/' - award_number: - type: string - example: '824087' - award_title: + - database + - subset + - table + - view + doi: type: string - example: EOSC-Life - IdentifierSaveDescriptionDto: - required: - - description - - id - type: object - properties: - id: - type: integer - format: int64 - example: 1 - description: + example: 10.1111/11111111 + titles: + type: array + items: + $ref: '#/components/schemas/SaveIdentifierTitleDto' + descriptions: + type: array + items: + $ref: '#/components/schemas/SaveIdentifierDescriptionDto' + funders: + type: array + items: + $ref: '#/components/schemas/SaveIdentifierFunderDto' + licenses: + type: array + items: + $ref: '#/components/schemas/LicenseDto' + publisher: type: string - example: 'Air quality reports at Stephansplatz, Vienna' + example: TU Wien language: type: string - example: en enum: - ab - aa @@ -6040,63 +5971,123 @@ components: - yo - za - zu - type: - type: string - example: Abstract - enum: - - Abstract - - Methods - - SeriesInformation - - TableOfContents - - TechnicalInfo - - Other - IdentifierSaveDto: - required: - - creators - - database_id - - id - - publication_year - - publisher - - titles - - type - type: object - properties: - id: + creators: + type: array + items: + $ref: '#/components/schemas/SaveIdentifierCreatorDto' + database_id: type: integer format: int64 example: 1 - type: - type: string - example: database - enum: - - database - - subset - - table - - view - doi: - type: string - example: 10.1111/11111111 - titles: + query_id: + type: integer + format: int64 + view_id: + type: integer + format: int64 + table_id: + type: integer + format: int64 + publication_day: + type: integer + format: int32 + example: 15 + publication_month: + type: integer + format: int32 + example: 12 + publication_year: + type: integer + format: int32 + example: 2022 + related_identifiers: type: array items: - $ref: '#/components/schemas/IdentifierSaveTitleDto' - descriptions: - type: array - items: - $ref: '#/components/schemas/IdentifierSaveDescriptionDto' - funders: - type: array - items: - $ref: '#/components/schemas/IdentifierFunderSaveDto' - licenses: - type: array - items: - $ref: '#/components/schemas/LicenseDto' - publisher: + $ref: '#/components/schemas/SaveRelatedIdentifierDto' + LicenseDto: + required: + - identifier + - uri + type: object + properties: + identifier: type: string - example: TU Wien + example: MIT + uri: + type: string + example: 'https://opensource.org/licenses/MIT' + description: + type: string + example: >- + A short and simple permissive license with conditions only requiring + preservation of copyright and license notices. Licensed works, + modifications, and larger works may be distributed under different + terms and without source code. + SaveIdentifierCreatorDto: + required: + - creator_name + - id + type: object + properties: + id: + type: integer + format: int64 + example: 1 + firstname: + type: string + example: Josiah + lastname: + type: string + example: Carberry + affiliation: + type: string + example: Wesleyan University + creator_name: + type: string + example: 'Carberry, Josiah' + name_type: + type: string + example: Personal + enum: + - Personal + - Organizational + name_identifier: + type: string + example: 0000-0002-1825-0097 + name_identifier_scheme: + type: string + example: ORCID + enum: + - ORCID + - ROR + - ISNI + - GRID + affiliation_identifier: + type: string + example: 'https://ror.org/04d836q62' + affiliation_identifier_scheme: + type: string + example: ROR + enum: + - ROR + - GRID + - ISNI + SaveIdentifierDescriptionDto: + required: + - description + - id + type: object + properties: + id: + type: integer + format: int64 + example: 1 + description: + type: string + example: 'Air quality reports at Stephansplatz, Vienna' language: type: string + example: en enum: - ab - aa @@ -6282,40 +6273,51 @@ components: - yo - za - zu - creators: - type: array - items: - $ref: '#/components/schemas/CreatorSaveDto' - database_id: + type: + type: string + example: Abstract + enum: + - Abstract + - Methods + - SeriesInformation + - TableOfContents + - TechnicalInfo + - Other + SaveIdentifierFunderDto: + required: + - funder_name + - id + type: object + properties: + id: type: integer format: int64 example: 1 - query_id: - type: integer - format: int64 - view_id: - type: integer - format: int64 - table_id: - type: integer - format: int64 - publication_day: - type: integer - format: int32 - example: 15 - publication_month: - type: integer - format: int32 - example: 12 - publication_year: - type: integer - format: int32 - example: 2022 - related_identifiers: - type: array - items: - $ref: '#/components/schemas/RelatedIdentifierSaveDto' - IdentifierSaveTitleDto: + funder_name: + type: string + example: European Commission + funder_identifier: + type: string + example: 'http://doi.org/10.13039/501100000780' + funder_identifier_type: + type: string + example: Crossref Funder ID + enum: + - Crossref Funder ID + - ROR + - GND + - ISNI + - Other + scheme_uri: + type: string + example: 'http://doi.org/' + award_number: + type: string + example: '824087' + award_title: + type: string + example: EOSC-Life + SaveIdentifierTitleDto: required: - id - title @@ -6524,26 +6526,7 @@ components: - Subtitle - TranslatedTitle - Other - LicenseDto: - required: - - identifier - - uri - type: object - properties: - identifier: - type: string - example: MIT - uri: - type: string - example: 'https://opensource.org/licenses/MIT' - description: - type: string - example: >- - A short and simple permissive license with conditions only requiring - preservation of copyright and license notices. Licensed works, - modifications, and larger works may be distributed under different - terms and without source code. - RelatedIdentifierSaveDto: + SaveRelatedIdentifierDto: required: - id - relation @@ -6627,6 +6610,7 @@ components: id: type: integer format: int64 + example: 11 firstname: type: string example: Josiah @@ -6680,6 +6664,7 @@ components: id: type: integer format: int64 + example: 3 description: type: string example: 'Air quality reports at Stephansplatz, Vienna' @@ -6883,17 +6868,20 @@ components: - Other IdentifierDto: required: - - created_by - creators - database_id - - execution + - descriptions + - funders - id + - language + - licenses - owner - publication_year - publisher - query - query_hash - query_normalized + - status - titles - type type: object @@ -6901,8 +6889,10 @@ components: id: type: integer format: int64 + example: 2 type: type: string + example: database enum: - database - subset @@ -6936,7 +6926,7 @@ components: type: string example: TU Wien owner: - $ref: '#/components/schemas/UserDto' + $ref: '#/components/schemas/UserBriefDto' language: type: string enum: @@ -7134,6 +7124,7 @@ components: $ref: '#/components/schemas/CreatorDto' status: type: string + example: draft enum: - draft - published @@ -7184,9 +7175,6 @@ components: type: integer format: int32 example: 2022 - created_by: - type: string - format: uuid IdentifierFunderDto: required: - funder_name @@ -7196,6 +7184,7 @@ components: id: type: integer format: int64 + example: 2 funder_name: type: string example: European Commission @@ -7231,6 +7220,7 @@ components: id: type: integer format: int64 + example: 8 value: type: string example: 10.70124/dc4zh-9ce78 @@ -7318,276 +7308,109 @@ components: is_schema_public: type: boolean example: true - ColumnBriefDto: + ViewBriefDto: required: - - column_type - database_id - id - internal_name - name - - table_id + - query + - query_hash type: object properties: id: type: integer format: int64 + example: 4 name: type: string - example: date - alias: + example: Air Quality + query: type: string + example: SELECT `id` FROM `air_quality` ORDER BY `value` DESC database_id: type: integer format: int64 - table_id: - type: integer - format: int64 + example: 1 internal_name: type: string - example: mdb_date - column_type: + example: air_quality + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + initial_view: + type: boolean + description: True if it is the default view for the database + example: true + query_hash: type: string - example: date - enum: - - char - - varchar - - binary - - varbinary - - tinyblob - - tinytext - - text - - blob - - mediumtext - - mediumblob - - longtext - - longblob - - enum - - set - - serial - - bit - - tinyint - - bool - - smallint - - mediumint - - int - - bigint - - float - - double - - decimal - - date - - datetime - - timestamp - - time - - year - ConceptDto: + example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916 + owned_by: + type: string + format: uuid + example: ac750fcf-ea02-4fce-85ac-d73857e18b35 + TableUpdateDto: required: - - columns - - id - - uri + - is_public + - is_schema_public type: object properties: - id: - type: integer - format: int64 - uri: - type: string - name: - type: string - description: - type: string - columns: - type: array - items: - $ref: '#/components/schemas/ColumnBriefDto' - UnitDto: - required: - - columns - - id - - uri - type: object - properties: - id: - type: integer - format: int64 - uri: - type: string - name: - type: string - description: - type: string - columns: - type: array - items: - $ref: '#/components/schemas/ColumnBriefDto' - ViewColumnDto: - required: - - auto_generated - - column_type - - database_id - - id - - internal_name - - is_null_allowed - - is_public - - name - - ordinal_position - type: object - properties: - id: - type: integer - format: int64 - name: - maxLength: 64 - minLength: 0 - type: string - example: Date - size: - type: integer - format: int64 - example: 255 - d: - type: integer - format: int64 - example: 0 - concept: - $ref: '#/components/schemas/ConceptDto' - unit: - $ref: '#/components/schemas/UnitDto' description: - maxLength: 2048 - minLength: 0 - type: string - example: Column comment - database_id: - type: integer - format: int64 - ordinal_position: - type: integer - format: int32 - example: 0 - internal_name: - maxLength: 64 + maxLength: 180 minLength: 0 type: string - example: mdb_date - auto_generated: - type: boolean - example: false - index_length: - type: integer - format: int64 - length: - type: integer - format: int64 - column_type: - type: string - example: string - enum: - - char - - varchar - - binary - - varbinary - - tinyblob - - tinytext - - text - - blob - - mediumtext - - mediumblob - - longtext - - longblob - - enum - - set - - serial - - bit - - tinyint - - bool - - smallint - - mediumint - - int - - bigint - - float - - double - - decimal - - date - - datetime - - timestamp - - time - - year + example: Air Quality in Austria is_public: type: boolean example: true - is_null_allowed: + is_schema_public: type: boolean - example: false - ViewDto: + example: true + TableBriefDto: required: - - columns - - database - database_id - id - internal_name + - is_public + - is_schema_public + - is_versioned - name - - owner - - query - - query_hash + - owned_by type: object properties: id: type: integer format: int64 - database: - $ref: '#/components/schemas/DatabaseDto' + example: 3 name: type: string example: Air Quality - identifiers: - type: array - items: - $ref: '#/components/schemas/IdentifierDto' - query: + description: type: string - example: SELECT `id` FROM `air_quality` ORDER BY `value` DESC - owner: - $ref: '#/components/schemas/UserBriefDto' - columns: - type: array - items: - $ref: '#/components/schemas/ViewColumnDto' + example: Air Quality in Austria database_id: type: integer format: int64 + example: 2 internal_name: type: string example: air_quality - is_public: - type: boolean - example: true - is_schema_public: - type: boolean - example: true - initial_view: + is_versioned: type: boolean - description: True if it is the default view for the database example: true - query_hash: - type: string - example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916 - TableUpdateDto: - required: - - is_public - - is_schema_public - type: object - properties: - description: - maxLength: 180 - minLength: 0 - type: string - example: Air Quality in Austria is_public: type: boolean example: true is_schema_public: type: boolean example: true + owned_by: + type: string + format: uuid + example: 78337b80-5699-45db-8111-cec86439ab6b ColumnSemanticsUpdateDto: type: object properties: @@ -7597,27 +7420,28 @@ components: type: string ColumnDto: required: - - column_type - database_id - id - internal_name - is_null_allowed - - is_public - name - - ordinal_position + - ord - table_id + - type type: object properties: id: type: integer format: int64 + example: 1 name: maxLength: 64 minLength: 0 type: string - example: Date + example: Given Name alias: type: string + example: firstname size: type: integer format: int64 @@ -7633,9 +7457,9 @@ components: type: number example: 51 concept: - $ref: '#/components/schemas/ConceptDto' + $ref: '#/components/schemas/ConceptBriefDto' unit: - $ref: '#/components/schemas/UnitDto' + $ref: '#/components/schemas/UnitBriefDto' description: maxLength: 2048 minLength: 0 @@ -7643,19 +7467,27 @@ components: example: Column comment enums: type: array + example: + - val1 items: type: string + example: '["val1"]' sets: type: array + example: + - val1 items: type: string + example: '["val1"]' database_id: type: integer format: int64 + example: 2 table_id: type: integer format: int64 - ordinal_position: + example: 3 + ord: type: integer format: int32 example: 0 @@ -7663,16 +7495,18 @@ components: maxLength: 64 minLength: 0 type: string - example: mdb_date + example: given_name index_length: type: integer format: int64 + example: 255 length: type: integer format: int64 - column_type: + example: 255 + type: type: string - example: string + example: varchar enum: - char - varchar @@ -7725,12 +7559,49 @@ components: std_dev: type: number example: 5.32 - is_public: - type: boolean - example: true is_null_allowed: type: boolean example: false + ConceptBriefDto: + required: + - id + - uri + type: object + properties: + id: + type: integer + format: int64 + example: 23 + uri: + type: string + example: 'http://www.wikidata.org/entity/Q202444' + name: + type: string + example: given name + description: + type: string + example: >- + name typically used to differentiate people from the same family, + clan, or other social group who have a common last name + UnitBriefDto: + required: + - id + - uri + type: object + properties: + id: + type: integer + format: int64 + example: 34 + uri: + type: string + example: 'http://www.wikidata.org/entity/Q1422583' + name: + type: string + example: importance + description: + type: string + example: 'subjective magnitude of value, meaning, or purpose' DatabaseTransferDto: required: - id @@ -7744,18 +7615,19 @@ components: properties: key: type: string - UpdateDatabaseAccessDto: + CreateAccessDto: required: - type type: object properties: type: type: string + example: read enum: - read - write_own - write_all - SignupRequestDto: + CreateUserDto: required: - email - password @@ -7860,7 +7732,7 @@ components: minimum: 1024 type: integer format: int32 - IdentifierCreateDto: + CreateIdentifierDto: required: - creators - database_id @@ -7884,15 +7756,15 @@ components: titles: type: array items: - $ref: '#/components/schemas/IdentifierSaveTitleDto' + $ref: '#/components/schemas/SaveIdentifierTitleDto' descriptions: type: array items: - $ref: '#/components/schemas/IdentifierSaveDescriptionDto' + $ref: '#/components/schemas/SaveIdentifierDescriptionDto' funders: type: array items: - $ref: '#/components/schemas/IdentifierFunderSaveDto' + $ref: '#/components/schemas/SaveIdentifierFunderDto' licenses: type: array items: @@ -8090,7 +7962,7 @@ components: creators: type: array items: - $ref: '#/components/schemas/CreatorSaveDto' + $ref: '#/components/schemas/SaveIdentifierCreatorDto' database_id: type: integer format: int64 @@ -8119,8 +7991,8 @@ components: related_identifiers: type: array items: - $ref: '#/components/schemas/RelatedIdentifierSaveDto' - DatabaseCreateDto: + $ref: '#/components/schemas/SaveRelatedIdentifierDto' + CreateDatabaseDto: required: - container_id - is_public @@ -8141,7 +8013,7 @@ components: is_schema_public: type: boolean example: true - ViewCreateDto: + CreateViewDto: required: - is_public - is_schema_public @@ -8163,7 +8035,40 @@ components: is_schema_public: type: boolean example: true - ColumnCreateDto: + CreateForeignKeyDto: + required: + - columns + - referenced_columns + - referenced_table + type: object + properties: + columns: + type: array + items: + type: string + referenced_table: + type: string + referenced_columns: + type: array + items: + type: string + on_update: + type: string + enum: + - restrict + - cascade + - set_null + - no_action + - set_default + on_delete: + type: string + enum: + - restrict + - cascade + - set_null + - no_action + - set_default + CreateTableColumnDto: required: - name - null_allowed @@ -8242,7 +8147,7 @@ components: type: string unit_uri: type: string - ConstraintsCreateDto: + CreateTableConstraintsDto: required: - checks - foreign_keys @@ -8264,57 +8169,24 @@ components: foreign_keys: type: array items: - $ref: '#/components/schemas/ForeignKeyCreateDto' + $ref: '#/components/schemas/CreateForeignKeyDto' primary_key: uniqueItems: true type: array items: type: string - ForeignKeyCreateDto: + CreateTableDto: required: - columns - - referenced_columns - - referenced_table + - constraints + - is_public + - is_schema_public + - name type: object properties: - columns: - type: array - items: - type: string - referenced_table: - type: string - referenced_columns: - type: array - items: - type: string - on_update: - type: string - enum: - - restrict - - cascade - - set_null - - no_action - - set_default - on_delete: - type: string - enum: - - restrict - - cascade - - set_null - - no_action - - set_default - TableCreateDto: - required: - - columns - - constraints - - is_public - - is_schema_public - - name - type: object - properties: - name: - maxLength: 64 - minLength: 1 + name: + maxLength: 64 + minLength: 1 type: string example: Air Quality description: @@ -8325,16 +8197,16 @@ components: columns: type: array items: - $ref: '#/components/schemas/ColumnCreateDto' + $ref: '#/components/schemas/CreateTableColumnDto' constraints: - $ref: '#/components/schemas/ConstraintsCreateDto' + $ref: '#/components/schemas/CreateTableConstraintsDto' is_public: type: boolean example: true is_schema_public: type: boolean example: true - ContainerCreateDto: + CreateContainerDto: required: - host - image_id @@ -8350,10 +8222,12 @@ components: host: type: string description: Hostname of container + example: data-db2 port: type: integer description: Port of container format: int32 + example: 3306 quota: type: integer format: int64 @@ -8362,11 +8236,14 @@ components: type: integer description: Image ID format: int64 + example: 1 ui_host: type: string + example: example.com ui_port: type: integer format: int32 + example: 3306 privileged_username: type: string description: Username of privileged user @@ -8374,29 +8251,31 @@ components: privileged_password: type: string description: Password of privileged user + example: dbrepo ContainerDto: required: - count - - host - id - image - internal_name - name - - port - quota type: object properties: id: type: integer format: int64 + example: 4 name: type: string example: Air Quality host: type: string + example: data-db port: type: integer format: int32 + example: 3306 image: $ref: '#/components/schemas/ImageDto' quota: @@ -8407,14 +8286,114 @@ components: type: integer format: int64 example: 10 + username: + type: string + example: username + password: + type: string + example: p4ssw0rd + last_retrieved: + type: string + format: date-time internal_name: type: string - example: data-db + example: air_quality ui_host: type: string + example: example.com ui_port: type: integer format: int32 + example: 3306 + ColumnBriefDto: + required: + - database_id + - id + - internal_name + - name + - table_id + - type + type: object + properties: + id: + type: integer + format: int64 + example: 1 + name: + maxLength: 64 + minLength: 0 + type: string + example: Given Name + alias: + type: string + example: firstname + database_id: + type: integer + format: int64 + example: 2 + table_id: + type: integer + format: int64 + example: 3 + internal_name: + maxLength: 64 + minLength: 0 + type: string + example: given_name + type: + type: string + example: varchar + enum: + - char + - varchar + - binary + - varbinary + - tinyblob + - tinytext + - text + - blob + - mediumtext + - mediumblob + - longtext + - longblob + - enum + - set + - serial + - bit + - tinyint + - bool + - smallint + - mediumint + - int + - bigint + - float + - double + - decimal + - date + - datetime + - timestamp + - time + - year + UnitDto: + required: + - columns + - id + - uri + type: object + properties: + id: + type: integer + format: int64 + uri: + type: string + name: + type: string + description: + type: string + columns: + type: array + items: + $ref: '#/components/schemas/ColumnBriefDto' OntologyBriefDto: required: - id @@ -8470,14 +8449,14 @@ components: type: string resumptionToken: type: string - parametersString: - type: string fromDate: type: string format: date-time untilDate: type: string format: date-time + parametersString: + type: string BannerMessageDto: required: - id @@ -8511,6 +8490,31 @@ components: type: string format: date-time example: '2021-03-12T15:26:21.000Z' + ImageBriefDto: + required: + - default + - id + - jdbc_method + - name + - version + type: object + properties: + id: + type: integer + format: int64 + example: 5 + name: + type: string + example: mariadb + version: + type: string + example: '10.5' + jdbc_method: + type: string + example: mariadb + default: + type: boolean + example: false LdCreatorDto: required: - '@type' @@ -8583,8 +8587,11 @@ components: checks: uniqueItems: true type: array + example: + - value > 1 items: type: string + example: '["value > 1"]' foreign_keys: type: array items: @@ -8594,12 +8601,86 @@ components: type: array items: $ref: '#/components/schemas/PrimaryKeyDto' + DatabaseDto: + required: + - accesses + - contact + - exchange_name + - id + - identifiers + - internal_name + - is_public + - is_schema_public + - name + - owner + - subsets + - tables + - views + type: object + properties: + id: + type: integer + format: int64 + example: 3 + name: + type: string + example: Air Quality + description: + type: string + example: Air Quality + tables: + type: array + items: + $ref: '#/components/schemas/TableDto' + views: + type: array + items: + $ref: '#/components/schemas/ViewDto' + container: + $ref: '#/components/schemas/ContainerDto' + accesses: + type: array + items: + $ref: '#/components/schemas/DatabaseAccessDto' + identifiers: + type: array + items: + $ref: '#/components/schemas/IdentifierDto' + subsets: + type: array + items: + $ref: '#/components/schemas/IdentifierDto' + contact: + $ref: '#/components/schemas/UserBriefDto' + owner: + $ref: '#/components/schemas/UserBriefDto' + last_retrieved: + type: string + format: date-time + exchange_name: + type: string + example: dbrepo + exchange_type: + type: string + example: topic + internal_name: + type: string + example: air_quality + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + preview_image: + type: string ForeignKeyBriefDto: type: object properties: id: type: integer format: int64 + example: 8 ForeignKeyDto: required: - name @@ -8611,8 +8692,10 @@ components: id: type: integer format: int64 + example: 4 name: type: string + example: fk_name references: type: array items: @@ -8623,6 +8706,7 @@ components: $ref: '#/components/schemas/TableBriefDto' on_update: type: string + example: restrict enum: - restrict - cascade @@ -8631,6 +8715,7 @@ components: - set_default on_delete: type: string + example: restrict enum: - restrict - cascade @@ -8647,6 +8732,7 @@ components: id: type: integer format: int64 + example: 8 column: $ref: '#/components/schemas/ColumnBriefDto' foreign_key: @@ -8662,6 +8748,7 @@ components: id: type: integer format: int64 + example: 8 table: $ref: '#/components/schemas/TableBriefDto' column: @@ -8685,11 +8772,13 @@ components: id: type: integer format: int64 + example: 3 name: type: string example: Air Quality alias: type: string + example: a identifiers: type: array items: @@ -8705,11 +8794,17 @@ components: type: array items: $ref: '#/components/schemas/ColumnDto' + database: + $ref: '#/components/schemas/DatabaseDto' constraints: $ref: '#/components/schemas/ConstraintsDto' + last_retrieved: + type: string + format: date-time database_id: type: integer format: int64 + example: 2 internal_name: type: string example: air_quality @@ -8761,14 +8856,165 @@ components: id: type: integer format: int64 + example: 5 name: type: string + example: uk_name table: $ref: '#/components/schemas/TableBriefDto' columns: type: array items: - $ref: '#/components/schemas/ColumnDto' + $ref: '#/components/schemas/ColumnBriefDto' + ViewColumnDto: + required: + - database_id + - id + - internal_name + - is_null_allowed + - name + - ord + - type + type: object + properties: + id: + type: integer + format: int64 + example: 12 + name: + maxLength: 64 + minLength: 0 + type: string + example: Given Name + size: + type: integer + format: int64 + example: 255 + d: + type: integer + format: int64 + example: 0 + description: + maxLength: 2048 + minLength: 0 + type: string + example: Column comment + database_id: + type: integer + format: int64 + example: 1 + ord: + type: integer + format: int32 + example: 0 + internal_name: + maxLength: 64 + minLength: 0 + type: string + example: given_name + index_length: + type: integer + format: int64 + example: 255 + length: + type: integer + format: int64 + example: 255 + type: + type: string + example: varchar + enum: + - char + - varchar + - binary + - varbinary + - tinyblob + - tinytext + - text + - blob + - mediumtext + - mediumblob + - longtext + - longblob + - enum + - set + - serial + - bit + - tinyint + - bool + - smallint + - mediumint + - int + - bigint + - float + - double + - decimal + - date + - datetime + - timestamp + - time + - year + is_null_allowed: + type: boolean + example: false + ViewDto: + required: + - columns + - database_id + - id + - identifiers + - internal_name + - name + - owner + - query + - query_hash + type: object + properties: + id: + type: integer + format: int64 + example: 4 + name: + type: string + example: Air Quality + identifiers: + type: array + items: + $ref: '#/components/schemas/IdentifierDto' + query: + type: string + example: SELECT `id` FROM `air_quality` ORDER BY `value` DESC + database: + $ref: '#/components/schemas/DatabaseDto' + owner: + $ref: '#/components/schemas/UserBriefDto' + columns: + type: array + items: + $ref: '#/components/schemas/ViewColumnDto' + last_retrieved: + type: string + format: date-time + database_id: + type: integer + format: int64 + example: 1 + internal_name: + type: string + example: air_quality + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + initial_view: + type: boolean + description: True if it is the default view for the database + example: true + query_hash: + type: string + example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916 TableColumnEntityDto: required: - column_id @@ -8798,6 +9044,60 @@ components: type: integer format: int64 example: 1 + ContainerBriefDto: + required: + - count + - hash + - id + - image + - internal_name + - name + - quota + type: object + properties: + id: + type: integer + format: int64 + example: 4 + hash: + type: string + example: f829dd8a884182d0da846f365dee1221fd16610a14c81b8f9f295ff162749e50 + name: + type: string + example: Air Quality + image: + $ref: '#/components/schemas/ImageBriefDto' + quota: + type: integer + format: int32 + example: 50 + count: + type: integer + format: int32 + example: 10 + internal_name: + type: string + example: air-quality + ConceptDto: + required: + - columns + - id + - uri + type: object + properties: + id: + type: integer + format: int64 + uri: + type: string + name: + type: string + description: + type: string + columns: + type: array + items: + $ref: '#/components/schemas/ColumnBriefDto' IndexDto: properties: results: @@ -8855,12 +9155,3 @@ components: - search_term - field_value_pairs type: object - SearchResultDto: - properties: - results: - items: - type: object - type: array - required: - - results - type: object diff --git a/.docs/.swagger/custom.css b/.docs/.openapi/custom.css similarity index 100% rename from .docs/.swagger/custom.css rename to .docs/.openapi/custom.css diff --git a/.docs/.swagger/swagger-generate.sh b/.docs/.openapi/openapi-generate.sh similarity index 82% rename from .docs/.swagger/swagger-generate.sh rename to .docs/.openapi/openapi-generate.sh index 884c2adface7aa773fe83e429ecea7f3b5ab4eef..edd927d202b42256f1da21a4415410ccee50466d 100644 --- a/.docs/.swagger/swagger-generate.sh +++ b/.docs/.openapi/openapi-generate.sh @@ -10,10 +10,10 @@ services[9099]=metadata function retrieve () { if [[ "$2" == analyse ]] || [[ "$2" == search ]]; then echo "... retrieve json api from localhost:$1" - curl -sSL "http://localhost:$1/api-$2.json" | yq -p=json > "./.docs/.swagger/api-$2.yaml" + curl -sSL "http://localhost:$1/api-$2.json" | yq -o=json - > "./.docs/.openapi/api-$2.yaml" else echo "... retrieve yaml api from localhost:$1" - curl -sSL "http://localhost:$1/v3/api-docs.yaml" > "./.docs/.swagger/api-$2.yaml" + curl -sSL "http://localhost:$1/v3/api-docs.yaml" > "./.docs/.openapi/api-$2.yaml" fi } diff --git a/.docs/.swagger/openapi-merge.json b/.docs/.openapi/openapi-merge.json similarity index 100% rename from .docs/.swagger/openapi-merge.json rename to .docs/.openapi/openapi-merge.json diff --git a/.docs/.swagger/swagger-ui.html b/.docs/.openapi/swagger-ui.html similarity index 80% rename from .docs/.swagger/swagger-ui.html rename to .docs/.openapi/swagger-ui.html index 0bb08a1c07c1bfca6cc820474190dada3580df48..e84dd2ca47861ad5cdc87f51d9671a9d28e2c97b 100644 --- a/.docs/.swagger/swagger-ui.html +++ b/.docs/.openapi/swagger-ui.html @@ -5,7 +5,7 @@ <meta name="viewport" content="width=device-width, initial-scale=1"/> <meta name="description" content="DBRepo REST API description in OpenAPI 3.0"/> <title>DBRepo REST API</title> - <link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5.17.12/swagger-ui.css"/> + <link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5.18.2/swagger-ui.css"/> <link rel="stylesheet" href="./custom.css"/> <link rel="icon" href="https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/master/.docs/images/logos/favicon.png" /> </head> @@ -17,8 +17,8 @@ </div> </div> <div id="swagger-ui"></div> -<script src="https://unpkg.com/swagger-ui-dist@5.17.12/swagger-ui-bundle.js" crossorigin></script> -<script src="https://unpkg.com/swagger-ui-dist@5.17.12/swagger-ui-standalone-preset.js" crossorigin></script> +<script src="https://unpkg.com/swagger-ui-dist@5.18.2/swagger-ui-bundle.js" crossorigin></script> +<script src="https://unpkg.com/swagger-ui-dist@5.18.2/swagger-ui-standalone-preset.js" crossorigin></script> <script> window.onload = () => { window.ui = SwaggerUIBundle({ diff --git a/.docs/api/auth-service.md b/.docs/api/auth-service.md index 93e87beaf280b5ed9b96a2aca508308098676173..7b28901a9b9d49a01d48a313187f86832509a03b 100644 --- a/.docs/api/auth-service.md +++ b/.docs/api/auth-service.md @@ -88,10 +88,6 @@ which is imported into Keycloak on startup. ## Limitations -* No support for sending e-mails through Keycloak by default. -* No support for temporary passwords. -* No support for multi-factor authentication. - !!! question "Do you miss functionality? Do these limitations affect you?" We strongly encourage you to help us implement it as we are welcoming contributors to open-source software and get diff --git a/.docs/api/ui.md b/.docs/api/ui.md index 30b32c0a0ccde771c8bde22f21ca630d6354a9b3..b82058c19bae4c4e629e0f1e06eca29985c94f67 100644 --- a/.docs/api/ui.md +++ b/.docs/api/ui.md @@ -101,6 +101,7 @@ See the [API Overview](..) page for detailed examples. ## Limitations +* Changing the OIDC provider URL requires to build the UI from scratch. * When developing locally, the `axios` module does not parse custom headers (such as `X-Count`, `X-Headers`) and/or blocks CORS requests wrongfully. diff --git a/.docs/changelog.md b/.docs/changelog.md index f2bb1ab0571500d7cb4a80d955381d3ef03a2b52..efdb4dd291dbbc3194ffc3ec3168ed71befffee3 100644 --- a/.docs/changelog.md +++ b/.docs/changelog.md @@ -2,6 +2,33 @@ author: Martin Weise --- +## v1.6.3 (2025-02-05) + +[:simple-gitlab: GitLab Release](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/tags/v1.6.3) + +### What's Changed + +#### Changes + +* Refactored the UI to support OIDC and added an event listener to the Auth Service that syncs users on creation to the + Metadata DB in [#488](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/488). + +## v1.6.2 (2025-01-24) + +[:simple-gitlab: GitLab Release](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/tags/v1.6.2) + +### What's Changed + +#### Changes + +* Added interface tests for the Python library in Gitlab CI/CD pipeline + in [#486](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/486). + +#### Fixes + +* Fixed a bug where no pagination was possible + in [#487](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/487). + ## v1.6.1 (2025-01-21) [:simple-gitlab: GitLab Release](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/tags/v1.6.1) @@ -15,7 +42,7 @@ author: Martin Weise #### Fixes -* Added init container that adds the admin user to the Metadata Database +* Added init container that adds the admin user to the Metadata Database in [#480](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/480). ## v1.6.0 (2025-01-07) diff --git a/.docs/concepts/data-visibility.md b/.docs/concepts/data-visibility.md index 04f37c6979bd9019d954859535a757c72da4b63e..31c6ca3682780c4353c6aa5baaae666047893635 100644 --- a/.docs/concepts/data-visibility.md +++ b/.docs/concepts/data-visibility.md @@ -8,28 +8,40 @@ subset of a database. ## Visibility -In total there are three possible scenarios: +In total there are four possible visibility settings that can be applied on database level and then at the subsequent +levels (table, view, subset). We give two examples for better understanding: -#### Public +!!! example "Example: Database that is hidden but certain views are visible" + + Database *Airquality* has the settings to hide all data and schema by default. + + * Table `sensor` inherits the settings from the database by default and therefore is also **hidden**. Nobody can + read/write to this database by default. Only designated users that the database owner allows to read/write can do + so. + * View `v_sensor` inherits the settings from the database by default and therefore is also **hidden**. The database + owner wants the data to be visible to the public (anonymously), so he changes the settings to data=visible, + schema=hidden. Now everybody can see the data but not the table(s) that contain the data. + +#### Visible !!! info "Possible use-case: data publication supplement to an open-access publication" -Where the database's data and metadata is set to be *visible*. This means everything in the database (tables, views, -subsets) are visible by anyone from the public. +Where the resource's data and schema is set to be visible. -#### Private +#### Data-only !!! info "Possible use-case: private sensor measurements with timed embargo" -Where the database's data set to be *hidden* but the schema to be *visible*. This means everything in the database -(tables, views, subsets) are by default not visible by anyone from the public. You can however make specific views that -join tables and/or filter certain columns and apply a 14-day delay-embargo. +Where the resource's schema visibility is hidden but the data is visible. -<figure markdown> - -<figcaption>Figure 1: Public view that joins two private tables and applies a time-embargo</figcaption> -</figure> +#### Schema-only + +!!! info "Possible use-case: publish data for reviewers before the final publication" + +Where the resource's data visibility is hidden but the schema is visible. #### Draft -!!! info "Possible use-case: project data storage before publication" \ No newline at end of file +!!! info "Possible use-case: project data storage before publication" + +Where the resource's data and schema visibility is hidden. It will not be findable even in the search. \ No newline at end of file diff --git a/.docs/images/architecture.drawio b/.docs/images/architecture.drawio index 71536a321290f6c8cb39d147529a8b00fb458eed..b1aed4cb4035dfa1cbc08818c44ca5d7fac5a803 100644 --- a/.docs/images/architecture.drawio +++ b/.docs/images/architecture.drawio @@ -1,4 +1,4 @@ -<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/25.0.2 Chrome/128.0.6613.186 Electron/32.2.5 Safari/537.36" version="25.0.2" pages="9"> +<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/26.0.9 Chrome/128.0.6613.186 Electron/32.2.5 Safari/537.36" version="26.0.9" pages="9"> <diagram id="mvBsv1rP8O80Qe3yGnn_" name="docker-compose"> <mxGraphModel dx="683" dy="391" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0"> <root> @@ -1109,47 +1109,10 @@ </mxGraphModel> </diagram> <diagram id="7HywRA3nQAgvNxZjCRq2" name="private-embargo"> - <mxGraphModel dx="985" dy="394" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0"> + <mxGraphModel dx="1434" dy="822" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0"> <root> <mxCell id="0" /> <mxCell id="1" parent="0" /> - <mxCell id="n6nk3BLY6128t3IB6Ma7-8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.25;entryY=0;entryDx=0;entryDy=0;curved=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="n6nk3BLY6128t3IB6Ma7-1" target="n6nk3BLY6128t3IB6Ma7-5"> - <mxGeometry relative="1" as="geometry" /> - </mxCell> - <mxCell id="n6nk3BLY6128t3IB6Ma7-11" value="<span style="text-wrap: wrap; background-color: rgb(251, 251, 251);">value,loc_id</span>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=8;" vertex="1" connectable="0" parent="n6nk3BLY6128t3IB6Ma7-8"> - <mxGeometry x="0.0303" relative="1" as="geometry"> - <mxPoint as="offset" /> - </mxGeometry> - </mxCell> - <mxCell id="n6nk3BLY6128t3IB6Ma7-1" value="" style="shape=internalStorage;whiteSpace=wrap;html=1;backgroundOutline=1;" vertex="1" parent="1"> - <mxGeometry x="250" y="170" width="80" height="80" as="geometry" /> - </mxCell> - <mxCell id="n6nk3BLY6128t3IB6Ma7-2" value="<b>table</b>: sensor (private)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> - <mxGeometry x="227.5" y="150" width="125" height="20" as="geometry" /> - </mxCell> - <mxCell id="n6nk3BLY6128t3IB6Ma7-9" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.75;entryY=0;entryDx=0;entryDy=0;curved=1;" edge="1" parent="1" source="n6nk3BLY6128t3IB6Ma7-3" target="n6nk3BLY6128t3IB6Ma7-5"> - <mxGeometry relative="1" as="geometry" /> - </mxCell> - <mxCell id="n6nk3BLY6128t3IB6Ma7-12" value="id,name,lat,lng" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=8;" vertex="1" connectable="0" parent="n6nk3BLY6128t3IB6Ma7-9"> - <mxGeometry x="0.1455" relative="1" as="geometry"> - <mxPoint as="offset" /> - </mxGeometry> - </mxCell> - <mxCell id="n6nk3BLY6128t3IB6Ma7-3" value="" style="shape=internalStorage;whiteSpace=wrap;html=1;backgroundOutline=1;" vertex="1" parent="1"> - <mxGeometry x="430" y="170" width="80" height="80" as="geometry" /> - </mxCell> - <mxCell id="n6nk3BLY6128t3IB6Ma7-4" value="<b>table</b>: location (private)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> - <mxGeometry x="405" y="150" width="130" height="20" as="geometry" /> - </mxCell> - <mxCell id="n6nk3BLY6128t3IB6Ma7-5" value="" style="shape=internalStorage;whiteSpace=wrap;html=1;backgroundOutline=1;fontSize=8;" vertex="1" parent="1"> - <mxGeometry x="340" y="290" width="80" height="80" as="geometry" /> - </mxCell> - <mxCell id="n6nk3BLY6128t3IB6Ma7-6" value="<b>view</b>: validated_sensor (public)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> - <mxGeometry x="290" y="370" width="180" height="20" as="geometry" /> - </mxCell> - <mxCell id="n6nk3BLY6128t3IB6Ma7-7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="n6nk3BLY6128t3IB6Ma7-4" target="n6nk3BLY6128t3IB6Ma7-4"> - <mxGeometry relative="1" as="geometry" /> - </mxCell> </root> </mxGraphModel> </diagram> diff --git a/.docs/index.md b/.docs/index.md index e16f9f5da6ccc94637fc0c1b56868e4fda84b023..d86224726f28fb78b3022601e02b00859a5ecc7d 100644 --- a/.docs/index.md +++ b/.docs/index.md @@ -14,7 +14,7 @@ author: Martin Weise   -Documentation for version: [v1.6.1](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/releases). +Documentation for version: [v1.6.3](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/releases). DBRepo is a repository for data in databases that are used from the beginning until the end of a research project supporting data evolution, -citation and -versioning. It implements the query store of the diff --git a/.docs/installation.md b/.docs/installation.md index ee0d9b88faa47ca33f74c12c5cf63200e7ff7ffc..1c6db304ccf3d760c44e56b7d49aef49d76330ff 100644 --- a/.docs/installation.md +++ b/.docs/installation.md @@ -31,11 +31,11 @@ settings. - min. 200GB free SSD storage Since DBRepo is intended to be a publicly available repository, an optional fixed/static IP-address with optional -SSL/TLS certificate is recommended. Follow the [secure install](#secure-install) guide. +SSL/TLS certificate is recommended. Follow the [secure installation](#secure-installation) guide. ## Secure Installation -Execute the install script to download only the environment and save it to `dist`. +Execute the installation script to download only the environment and save it to `dist`. ```shell curl -sSL https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/raw/release-1.6/install.sh | DOWNLOAD_ONLY=1 bash @@ -50,6 +50,8 @@ Update the rest of the default secrets in the `.env` file to secure passwords. Y `openssl rand -hex 16`. Set `auth_ldap.dn_lookup_bind.password` in `dist/rabbitmq.conf` to the value of `SYSTEM_PASSWORD`. +Only set the `BASE_URL` environment variable in `.env` when your hostname is **not** `localhost`. + ### Runtime Configuration The [Auth Service](../api/auth-service) can be configured easily when DBRepo is running. Start DBRepo temporarily: diff --git a/.docs/kubernetes.md b/.docs/kubernetes.md index cc16bbe210d1b4ea98cd27ad8c47248bc551bafb..170bc863f58206778bf4488c48f322e6ad801996 100644 --- a/.docs/kubernetes.md +++ b/.docs/kubernetes.md @@ -14,7 +14,7 @@ helm upgrade --install dbrepo \ -n dbrepo \ "oci://registry.datalab.tuwien.ac.at/dbrepo/helm/dbrepo" \ --values ./values.yaml \ - --version "1.6.1" \ + --version "1.6.3" \ --create-namespace \ --cleanup-on-fail ``` diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 122597e69534f19b49a1361c7db99f398bf0f811..85e5d640bbce875195f6c560d3e60e0d210f650e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -10,8 +10,8 @@ variables: SONARQUBE_VERSION: "10.0" BUN_VERSION: "1.1.40" DOC_VERSION: "1.6" - APP_VERSION: "1.6.1" - CHART_VERSION: "1.6.1" + APP_VERSION: "1.6.3" + CHART_VERSION: "1.6.3" CACHE_FALLBACK_KEY: "${CI_DEFAULT_BRANCH}" # This will supress any download for dependencies and plugins or upload messages which would clutter the console log. # `showDateTime` will show the passed time in milliseconds. You need to specify `--batch-mode` to make this work. @@ -44,34 +44,34 @@ lint-docker-compose: image: docker.io/alpine:${ALPINE_VERSION} stage: lint variables: - VERSION: 3.3.0 + VERSION: 4.45.1 BINARY: yq_linux_amd64 before_script: - 'apk --no-cache add bash wget' - - 'wget https://github.com/mikefarah/yq/releases/download/${VERSION}/${BINARY} -O /usr/bin/yq && chmod +x /usr/bin/yq' - - 'ls -la .scripts' + - 'wget https://github.com/mikefarah/yq/releases/download/v${VERSION}/${BINARY} -O /usr/bin/yq && chmod +x /usr/bin/yq' script: - "bash .scripts/check-compose.sh" - - "yq compare -P docker-compose.yml .docker/docker-compose.yml 'volumes.*'" + - "diff <(yq '.volumes' docker-compose.yml) <(yq '.volumes' .docker/docker-compose.yml)" - "IGNORE_IMAGE=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-analyse-service'" - - "bash .scripts/check-service.sh 'dbrepo-auth-db'" + - "IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-auth-db'" - "IGNORE_IMAGE=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-auth-service'" + - "IGNORE_VOLUMES=1 IGNORE_IMAGE=1 bash .scripts/check-service.sh 'dbrepo-auth-service-init'" - "IGNORE_IMAGE=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-broker-service'" - "IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-dashboard-service'" - "bash .scripts/check-service.sh 'dbrepo-data-db'" - "IGNORE_IMAGE=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-data-service'" - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-gateway-service'" - - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-identity-service'" + - "IGNORE_VOLUMES=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-identity-service'" - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-metadata-db'" - "IGNORE_IMAGE=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-metadata-service'" - - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-metric-db'" + - "IGNORE_VOLUMES=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-metric-db'" - "IGNORE_IMAGE=1 bash .scripts/check-service.sh 'dbrepo-search-db'" - "IGNORE_IMAGE=1 IGNORE_PORTS=1 bash .scripts/check-service.sh 'dbrepo-search-service'" - "IGNORE_IMAGE=1 bash .scripts/check-service.sh 'dbrepo-search-service-init'" - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-storage-service'" - - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-storage-service-init'" + - "IGNORE_VOLUMES=1 IGNORE_IMAGE=1 bash .scripts/check-service.sh 'dbrepo-storage-service-init'" - "IGNORE_IMAGE=1 bash .scripts/check-service.sh 'dbrepo-ui'" - - "bash .scripts/check-service.sh 'dbrepo-upload-service'" + - "IGNORE_VOLUMES=1 bash .scripts/check-service.sh 'dbrepo-upload-service'" lint-helm-chart: image: docker.io/alpine:${ALPINE_VERSION} @@ -117,6 +117,19 @@ lint-metadata-schema: script: - diff dbrepo-metadata-db/1_setup-schema.sql helm/dbrepo/files/01-setup-schema.sql +lint-open-api-version: + image: docker.io/alpine:${ALPINE_VERSION} + stage: lint + variables: + VERSION: 4.45.1 + BINARY: yq_linux_amd64 + before_script: + - 'apk --no-cache add bash wget' + - 'wget https://github.com/mikefarah/yq/releases/download/v${VERSION}/${BINARY} -O /usr/bin/yq && chmod +x /usr/bin/yq' + script: + - yq '.externalDocs.url' ./.docs/.openapi/api.base.yaml | grep "${DOC_VERSION}" + - yq '.info.version' ./.docs/.openapi/api.base.yaml | grep "${DOC_VERSION}" + build-metadata-service: image: maven:3-openjdk-${JAVA_VERSION} stage: build @@ -253,7 +266,7 @@ test-data-service: dependencies: - build-data-service script: - - "mvn -f ./dbrepo-metadata-service/pom.xml clean install $MAVEN_OPTS" + - "mvn -f ./dbrepo-metadata-service/pom.xml clean install -DskipTests $MAVEN_OPTS" - "mvn -f ./dbrepo-data-service/pom.xml clean test verify $MAVEN_OPTS" - "cat ./dbrepo-data-service/report/target/site/jacoco-aggregate/index.html | grep -o 'Total[^%]*%' | sed 's/<.*>/ /; s/Total/Jacoco Coverage Total:/'" artifacts: @@ -471,9 +484,9 @@ release-docs: script: - "make gen-lib-doc gen-docs-doc package-config" - "cp -r ./lib/python/docs/build/html ./final/${DOC_VERSION}/python" # sphinx - - "cp .docs/.swagger/api.yaml ./final/${DOC_VERSION}/rest/api.yaml" # swagger - - "cp .docs/.swagger/swagger-ui.html ./final/${DOC_VERSION}/rest/index.html" # swagger - - "cp .docs/.swagger/custom.css ./final/${DOC_VERSION}/rest/custom.css" # swagger + - "cp .docs/.openapi/api.yaml ./final/${DOC_VERSION}/rest/api.yaml" # openapi + - "cp .docs/.openapi/swagger-ui.html ./final/${DOC_VERSION}/rest/index.html" # openapi + - "cp .docs/.openapi/custom.css ./final/${DOC_VERSION}/rest/custom.css" # openapi - "cp -r ./site/* ./final/${DOC_VERSION}" # mkdocs - "cp .docker/dist.tar.gz ./final/${APP_VERSION}/dist.tar.gz" # dist - "cp .docs/index.html.tpl ./final/index.html" # redirect patch docs diff --git a/.gitlab/agents/dev/values.yaml b/.gitlab/agents/dev/values.yaml index aa241d7f0eef507e104fb2ea49c9c01e37390ed5..5841a5e97bd5d9f9ddde4d13a2b74623a91cf4fb 100644 --- a/.gitlab/agents/dev/values.yaml +++ b/.gitlab/agents/dev/values.yaml @@ -26,6 +26,9 @@ authservice: client: id: dbrepo-client secret: MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG + setupJob: + image: + name: registry.datalab.tuwien.ac.at/dbrepo/auth-service-init:1.6.3 persistence: enabled: true @@ -33,6 +36,7 @@ brokerservice: enabled: true ldap: bindpw: b8534187c9adf9618e7bd1c79c7f4639 + identityservice: enabled: true global: @@ -66,9 +70,13 @@ searchdb: analyseservice: enabled: true + image: + name: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.6.3 metadataservice: enabled: true + image: + name: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.3 admin: email: noreply@example.com deletedRecord: permanent @@ -83,6 +91,8 @@ metadataservice: dataservice: enabled: true + image: + name: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.6.3 rabbitmq: consumer: username: admin @@ -95,9 +105,17 @@ dataservice: searchservice: enabled: true + image: + name: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.6.3 + init: + image: + name: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.6.3 storageservice: enabled: true + init: + image: + name: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.6.3 uploadservice: enabled: true @@ -113,13 +131,15 @@ metricdb: ui: enabled: true + image: + name: registry.datalab.tuwien.ac.at/dbrepo/ui:1.6.3 public: api: client: https://s155.datalab.tuwien.ac.at server: https://s155.datalab.tuwien.ac.at title: "Database Repository" logo: "https://ec.tuwien.ac.at/~weise/images/DS_white_hiRes.png" - icon: "https://ec.tuwien.ac.at/~weise/images/DS-icon_white_hiRes.png" + icon: "https://ec.tuwien.ac.at/~weise/images/favicon.ico" touch: "https://ec.tuwien.ac.at/~weise/images/DS-icon_white_hiRes.png" broker: host: s155.datalab.tuwien.ac.at diff --git a/.scripts/check-service.sh b/.scripts/check-service.sh index decc22312b8a44049d4675cc36a5be3e6aafe072..1af6d7eea1556ca90f30b0abbe10abe2b623d140 100755 --- a/.scripts/check-service.sh +++ b/.scripts/check-service.sh @@ -1,16 +1,21 @@ #!/bin/bash -yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.restart" -yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.container_name" -yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.hostname" +function compare () { + diff <(yq ".$1" docker-compose.yml) <(yq ".$1" .docker/docker-compose.yml) +} + +compare "services.$1.restart" +compare "services.$1.container_name" +compare "services.$1.hostname" +compare "services.$1.environment" +compare "services.$1.healthcheck" +compare "services.$1.logging" + if [ -z "$IGNORE_IMAGE" ]; then - yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.image" + compare "services.$1.image" fi if [ -z "$IGNORE_VOLUMES" ]; then - yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.volumes" + compare "services.$1.volumes" fi if [ -z "$IGNORE_PORTS" ]; then - yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.ports" + compare "services.$1.ports" fi -yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.environment" -yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.healthcheck" -yq compare -P docker-compose.yml .docker/docker-compose.yml "services.$1.logging" \ No newline at end of file diff --git a/Makefile b/Makefile index 2479e382e55e3c20f1dd7f9c998fa5807a3f0e05..0dd2ae5e0a756aa713a101ddfff2ff8513222fa4 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ .PHONY: all -APP_VERSION ?= 1.6.1 -CHART_VERSION ?= 1.6.1 +APP_VERSION ?= 1.6.3 +CHART_VERSION ?= 1.6.3 REPOSITORY_URL ?= registry.datalab.tuwien.ac.at/dbrepo .PHONY: all diff --git a/dbrepo-analyse-service/.gitignore b/dbrepo-analyse-service/.gitignore index d339f8575ccfbafdb8eef6431cce6c1add7aa92e..4ae9f6930d70a7da1f7b06d28fc7dcecf7ce24c4 100644 --- a/dbrepo-analyse-service/.gitignore +++ b/dbrepo-analyse-service/.gitignore @@ -17,12 +17,6 @@ venv/ .venv/ env* -# Libraries -./lib/dbrepo-1.4.4* -./lib/dbrepo-1.4.5* -./lib/dbrepo-1.4.6* -./lib/dbrepo-1.4.7rc* - # LLM *.bin diff --git a/dbrepo-analyse-service/Pipfile b/dbrepo-analyse-service/Pipfile index 831f8e532dd5f5796ca93cc6ca52fa7cecebb608..22a8e79b3a232b73784971df01dc283b8171388d 100644 --- a/dbrepo-analyse-service/Pipfile +++ b/dbrepo-analyse-service/Pipfile @@ -21,7 +21,7 @@ numpy = "*" pandas = "*" minio = "*" pydantic = "*" -dbrepo = {path = "./lib/dbrepo-1.6.1.tar.gz"} +dbrepo = {path = "./lib/dbrepo-1.6.3.tar.gz"} opensearch-py = "*" [dev-packages] diff --git a/dbrepo-analyse-service/Pipfile.lock b/dbrepo-analyse-service/Pipfile.lock index 99d70b613229b3fcc81638d99d038034b58ef9d6..5d2ace3655c32086fe018e0267ab207a9f1703b6 100644 --- a/dbrepo-analyse-service/Pipfile.lock +++ b/dbrepo-analyse-service/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "683cc19a3205b9b5f9b99db8b71c0abadadfd652a94dcf710a73aeca92b97227" + "sha256": "9cc4c161729b642069bbf4ab379c0f4a9122035afcb3ac7b5b1bfc13281f76aa" }, "pipfile-spec": 6, "requires": { @@ -159,11 +159,11 @@ }, "attrs": { "hashes": [ - "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", - "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308" + "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e", + "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a" ], "markers": "python_version >= '3.8'", - "version": "==24.3.0" + "version": "==25.1.0" }, "blinker": { "hashes": [ @@ -175,20 +175,20 @@ }, "boto3": { "hashes": [ - "sha256:7d398f66a11e67777c189d1f58c0a75d9d60f98d0ee51b8817e828930bf19e4e", - "sha256:8e49416216a6e3a62c2a0c44fba4dd2852c85472e7b702516605b1363867d220" + "sha256:7f61c9d0ea64f484a17c1e3115fdf90fd7b17ab6771e07cb4549f42b9fd28fb9", + "sha256:ac47215d320b0c2534340db58d6d5284cb1860b7bff172b4dd6eee2dee1d5779" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.35.97" + "version": "==1.36.8" }, "botocore": { "hashes": [ - "sha256:88f2fab29192ffe2f2115d5bafbbd823ff4b6eb2774296e03ec8b5b0fe074f61", - "sha256:fed4f156b1a9b8ece53738f702ba5851b8c6216b4952de326547f349cc494f14" + "sha256:59d3fdfbae6d916b046e973bebcbeb70a102f9e570ca86d5ba512f1854b78fc2", + "sha256:81c88e5566cf018e1411a68304dc1fb9e4156ca2b50a3a0f0befc274299e67fa" ], "markers": "python_version >= '3.8'", - "version": "==1.35.97" + "version": "==1.36.8" }, "certifi": { "hashes": [ @@ -412,9 +412,9 @@ }, "dbrepo": { "hashes": [ - "sha256:7cddcbdcb3eade84f67db01fa32e0649ecc01d4c3cc5e7542d3c402ad52efc19" + "sha256:ac99f4bd19961f08665abd513e4d9452fcea5554f122457840e95f90698bab4d" ], - "path": "./lib/dbrepo-1.6.1.tar.gz" + "path": "./lib/dbrepo-1.6.3.tar.gz" }, "events": { "hashes": [ @@ -829,20 +829,20 @@ }, "minio": { "hashes": [ - "sha256:868dfe907e1702ce4bec86df1f3ced577a73ca85f344ef898d94fe2b5237f8c1", - "sha256:f5c24bf236fefd2edc567cd4455dc49a11ad8ff7ac984bb031b849d82f01222a" + "sha256:5247df5d4dca7bfa4c9b20093acd5ad43e82d8710ceb059d79c6eea970f49f79", + "sha256:c06ef7a43e5d67107067f77b6c07ebdd68733e5aa7eed03076472410ca19d876" ], "index": "pypi", "markers": "python_version >= '3.9'", - "version": "==7.2.14" + "version": "==7.2.15" }, "mistune": { "hashes": [ - "sha256:b05198cf6d671b3deba6c87ec6cf0d4eb7b72c524636eddb6dbf13823b52cee1", - "sha256:dbcac2f78292b9dc066cd03b7a3a26b62d85f8159f2ea5fd28e55df79908d667" + "sha256:02106ac2aa4f66e769debbfa028509a275069dcffce0dfa578edd7b991ee700a", + "sha256:e0740d635f515119f7d1feb6f9b192ee60f0cc649f80a8f944f905706a21654c" ], "markers": "python_version >= '3.8'", - "version": "==3.1.0" + "version": "==3.1.1" }, "multidict": { "hashes": [ @@ -944,65 +944,65 @@ }, "numpy": { "hashes": [ - "sha256:059e6a747ae84fce488c3ee397cee7e5f905fd1bda5fb18c66bc41807ff119b2", - "sha256:08ef779aed40dbc52729d6ffe7dd51df85796a702afbf68a4f4e41fafdc8bda5", - "sha256:164a829b6aacf79ca47ba4814b130c4020b202522a93d7bff2202bfb33b61c60", - "sha256:26c9c4382b19fcfbbed3238a14abf7ff223890ea1936b8890f058e7ba35e8d71", - "sha256:27f5cdf9f493b35f7e41e8368e7d7b4bbafaf9660cba53fb21d2cd174ec09631", - "sha256:31b89fa67a8042e96715c68e071a1200c4e172f93b0fbe01a14c0ff3ff820fc8", - "sha256:32cb94448be47c500d2c7a95f93e2f21a01f1fd05dd2beea1ccd049bb6001cd2", - "sha256:360137f8fb1b753c5cde3ac388597ad680eccbbbb3865ab65efea062c4a1fd16", - "sha256:3683a8d166f2692664262fd4900f207791d005fb088d7fdb973cc8d663626faa", - "sha256:38efc1e56b73cc9b182fe55e56e63b044dd26a72128fd2fbd502f75555d92591", - "sha256:3d03883435a19794e41f147612a77a8f56d4e52822337844fff3d4040a142964", - "sha256:3ecc47cd7f6ea0336042be87d9e7da378e5c7e9b3c8ad0f7c966f714fc10d821", - "sha256:40f9e544c1c56ba8f1cf7686a8c9b5bb249e665d40d626a23899ba6d5d9e1484", - "sha256:4250888bcb96617e00bfa28ac24850a83c9f3a16db471eca2ee1f1714df0f957", - "sha256:4511d9e6071452b944207c8ce46ad2f897307910b402ea5fa975da32e0102800", - "sha256:45681fd7128c8ad1c379f0ca0776a8b0c6583d2f69889ddac01559dfe4390918", - "sha256:48fd472630715e1c1c89bf1feab55c29098cb403cc184b4859f9c86d4fcb6a95", - "sha256:4c86e2a209199ead7ee0af65e1d9992d1dce7e1f63c4b9a616500f93820658d0", - "sha256:4dfda918a13cc4f81e9118dea249e192ab167a0bb1966272d5503e39234d694e", - "sha256:5062dc1a4e32a10dc2b8b13cedd58988261416e811c1dc4dbdea4f57eea61b0d", - "sha256:51faf345324db860b515d3f364eaa93d0e0551a88d6218a7d61286554d190d73", - "sha256:526fc406ab991a340744aad7e25251dd47a6720a685fa3331e5c59fef5282a59", - "sha256:53c09385ff0b72ba79d8715683c1168c12e0b6e84fb0372e97553d1ea91efe51", - "sha256:55ba24ebe208344aa7a00e4482f65742969a039c2acfcb910bc6fcd776eb4355", - "sha256:5b6c390bfaef8c45a260554888966618328d30e72173697e5cabe6b285fb2348", - "sha256:5c5cc0cbabe9452038ed984d05ac87910f89370b9242371bd9079cb4af61811e", - "sha256:5edb4e4caf751c1518e6a26a83501fda79bff41cc59dac48d70e6d65d4ec4440", - "sha256:61048b4a49b1c93fe13426e04e04fdf5a03f456616f6e98c7576144677598675", - "sha256:676f4eebf6b2d430300f1f4f4c2461685f8269f94c89698d832cdf9277f30b84", - "sha256:67d4cda6fa6ffa073b08c8372aa5fa767ceb10c9a0587c707505a6d426f4e046", - "sha256:694f9e921a0c8f252980e85bce61ebbd07ed2b7d4fa72d0e4246f2f8aa6642ab", - "sha256:733585f9f4b62e9b3528dd1070ec4f52b8acf64215b60a845fa13ebd73cd0712", - "sha256:7671dc19c7019103ca44e8d94917eba8534c76133523ca8406822efdd19c9308", - "sha256:780077d95eafc2ccc3ced969db22377b3864e5b9a0ea5eb347cc93b3ea900315", - "sha256:7ba9cc93a91d86365a5d270dee221fdc04fb68d7478e6bf6af650de78a8339e3", - "sha256:89b16a18e7bba224ce5114db863e7029803c179979e1af6ad6a6b11f70545008", - "sha256:9036d6365d13b6cbe8f27a0eaf73ddcc070cae584e5ff94bb45e3e9d729feab5", - "sha256:93cf4e045bae74c90ca833cba583c14b62cb4ba2cba0abd2b141ab52548247e2", - "sha256:9ad014faa93dbb52c80d8f4d3dcf855865c876c9660cb9bd7553843dd03a4b1e", - "sha256:9b1d07b53b78bf84a96898c1bc139ad7f10fda7423f5fd158fd0f47ec5e01ac7", - "sha256:a7746f235c47abc72b102d3bce9977714c2444bdfaea7888d241b4c4bb6a78bf", - "sha256:aa3017c40d513ccac9621a2364f939d39e550c542eb2a894b4c8da92b38896ab", - "sha256:b34d87e8a3090ea626003f87f9392b3929a7bbf4104a05b6667348b6bd4bf1cd", - "sha256:b541032178a718c165a49638d28272b771053f628382d5e9d1c93df23ff58dbf", - "sha256:ba5511d8f31c033a5fcbda22dd5c813630af98c70b2661f2d2c654ae3cdfcfc8", - "sha256:bc8a37ad5b22c08e2dbd27df2b3ef7e5c0864235805b1e718a235bcb200cf1cb", - "sha256:bff7d8ec20f5f42607599f9994770fa65d76edca264a87b5e4ea5629bce12268", - "sha256:c1ad395cf254c4fbb5b2132fee391f361a6e8c1adbd28f2cd8e79308a615fe9d", - "sha256:f1d09e520217618e76396377c81fba6f290d5f926f50c35f3a5f72b01a0da780", - "sha256:f3eac17d9ec51be534685ba877b6ab5edc3ab7ec95c8f163e5d7b39859524716", - "sha256:f419290bc8968a46c4933158c91a0012b7a99bb2e465d5ef5293879742f8797e", - "sha256:f62aa6ee4eb43b024b0e5a01cf65a0bb078ef8c395e8713c6e8a12a697144528", - "sha256:f74e6fdeb9a265624ec3a3918430205dff1df7e95a230779746a6af78bc615af", - "sha256:f9b57eaa3b0cd8db52049ed0330747b0364e899e8a606a624813452b8203d5f7", - "sha256:fce4f615f8ca31b2e61aa0eb5865a21e14f5629515c9151850aa936c02a1ee51" + "sha256:02935e2c3c0c6cbe9c7955a8efa8908dd4221d7755644c59d1bba28b94fd334f", + "sha256:0349b025e15ea9d05c3d63f9657707a4e1d471128a3b1d876c095f328f8ff7f0", + "sha256:09d6a2032faf25e8d0cadde7fd6145118ac55d2740132c1d845f98721b5ebcfd", + "sha256:0bc61b307655d1a7f9f4b043628b9f2b721e80839914ede634e3d485913e1fb2", + "sha256:0eec19f8af947a61e968d5429f0bd92fec46d92b0008d0a6685b40d6adf8a4f4", + "sha256:106397dbbb1896f99e044efc90360d098b3335060375c26aa89c0d8a97c5f648", + "sha256:128c41c085cab8a85dc29e66ed88c05613dccf6bc28b3866cd16050a2f5448be", + "sha256:149d1113ac15005652e8d0d3f6fd599360e1a708a4f98e43c9c77834a28238cb", + "sha256:159ff6ee4c4a36a23fe01b7c3d07bd8c14cc433d9720f977fcd52c13c0098160", + "sha256:22ea3bb552ade325530e72a0c557cdf2dea8914d3a5e1fecf58fa5dbcc6f43cd", + "sha256:23ae9f0c2d889b7b2d88a3791f6c09e2ef827c2446f1c4a3e3e76328ee4afd9a", + "sha256:250c16b277e3b809ac20d1f590716597481061b514223c7badb7a0f9993c7f84", + "sha256:2ec6c689c61df613b783aeb21f945c4cbe6c51c28cb70aae8430577ab39f163e", + "sha256:2ffbb1acd69fdf8e89dd60ef6182ca90a743620957afb7066385a7bbe88dc748", + "sha256:3074634ea4d6df66be04f6728ee1d173cfded75d002c75fac79503a880bf3825", + "sha256:356ca982c188acbfa6af0d694284d8cf20e95b1c3d0aefa8929376fea9146f60", + "sha256:3fbe72d347fbc59f94124125e73fc4976a06927ebc503ec5afbfb35f193cd957", + "sha256:40c7ff5da22cd391944a28c6a9c638a5eef77fcf71d6e3a79e1d9d9e82752715", + "sha256:41184c416143defa34cc8eb9d070b0a5ba4f13a0fa96a709e20584638254b317", + "sha256:451e854cfae0febe723077bd0cf0a4302a5d84ff25f0bfece8f29206c7bed02e", + "sha256:4525b88c11906d5ab1b0ec1f290996c0020dd318af8b49acaa46f198b1ffc283", + "sha256:463247edcee4a5537841d5350bc87fe8e92d7dd0e8c71c995d2c6eecb8208278", + "sha256:4dbd80e453bd34bd003b16bd802fac70ad76bd463f81f0c518d1245b1c55e3d9", + "sha256:57b4012e04cc12b78590a334907e01b3a85efb2107df2b8733ff1ed05fce71de", + "sha256:5a8c863ceacae696aff37d1fd636121f1a512117652e5dfb86031c8d84836369", + "sha256:5acea83b801e98541619af398cc0109ff48016955cc0818f478ee9ef1c5c3dcb", + "sha256:642199e98af1bd2b6aeb8ecf726972d238c9877b0f6e8221ee5ab945ec8a2189", + "sha256:64bd6e1762cd7f0986a740fee4dff927b9ec2c5e4d9a28d056eb17d332158014", + "sha256:6d9fc9d812c81e6168b6d405bf00b8d6739a7f72ef22a9214c4241e0dc70b323", + "sha256:7079129b64cb78bdc8d611d1fd7e8002c0a2565da6a47c4df8062349fee90e3e", + "sha256:7dca87ca328f5ea7dafc907c5ec100d187911f94825f8700caac0b3f4c384b49", + "sha256:860fd59990c37c3ef913c3ae390b3929d005243acca1a86facb0773e2d8d9e50", + "sha256:8e6da5cffbbe571f93588f562ed130ea63ee206d12851b60819512dd3e1ba50d", + "sha256:8ec0636d3f7d68520afc6ac2dc4b8341ddb725039de042faf0e311599f54eb37", + "sha256:9491100aba630910489c1d0158034e1c9a6546f0b1340f716d522dc103788e39", + "sha256:97b974d3ba0fb4612b77ed35d7627490e8e3dff56ab41454d9e8b23448940576", + "sha256:995f9e8181723852ca458e22de5d9b7d3ba4da3f11cc1cb113f093b271d7965a", + "sha256:9dd47ff0cb2a656ad69c38da850df3454da88ee9a6fde0ba79acceee0e79daba", + "sha256:9fad446ad0bc886855ddf5909cbf8cb5d0faa637aaa6277fb4b19ade134ab3c7", + "sha256:a972cec723e0563aa0823ee2ab1df0cb196ed0778f173b381c871a03719d4826", + "sha256:ac9bea18d6d58a995fac1b2cb4488e17eceeac413af014b1dd26170b766d8467", + "sha256:b0531f0b0e07643eb089df4c509d30d72c9ef40defa53e41363eca8a8cc61495", + "sha256:b208cfd4f5fe34e1535c08983a1a6803fdbc7a1e86cf13dd0c61de0b51a0aadc", + "sha256:b3482cb7b3325faa5f6bc179649406058253d91ceda359c104dac0ad320e1391", + "sha256:b6fb9c32a91ec32a689ec6410def76443e3c750e7cfc3fb2206b985ffb2b85f0", + "sha256:b78ea78450fd96a498f50ee096f69c75379af5138f7881a51355ab0e11286c97", + "sha256:bd249bc894af67cbd8bad2c22e7cbcd46cf87ddfca1f1289d1e7e54868cc785c", + "sha256:c7d1fd447e33ee20c1f33f2c8e6634211124a9aabde3c617687d8b739aa69eac", + "sha256:d0bbe7dd86dca64854f4b6ce2ea5c60b51e36dfd597300057cf473d3615f2369", + "sha256:d6d6a0910c3b4368d89dde073e630882cdb266755565155bc33520283b2d9df8", + "sha256:da1eeb460ecce8d5b8608826595c777728cdf28ce7b5a5a8c8ac8d949beadcf2", + "sha256:e0c8854b09bc4de7b041148d8550d3bd712b5c21ff6a8ed308085f190235d7ff", + "sha256:e0d4142eb40ca6f94539e4db929410f2a46052a0fe7a2c1c59f6179c39938d2a", + "sha256:e9e82dcb3f2ebbc8cb5ce1102d5f1c5ed236bf8a11730fb45ba82e2841ec21df", + "sha256:ed6906f61834d687738d25988ae117683705636936cc605be0bb208b23df4d8f" ], "index": "pypi", "markers": "python_version >= '3.10'", - "version": "==2.2.1" + "version": "==2.2.2" }, "opensearch-py": { "hashes": [ @@ -1230,12 +1230,12 @@ }, "pydantic": { "hashes": [ - "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff", - "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53" + "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584", + "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==2.10.5" + "version": "==2.10.6" }, "pydantic-core": { "hashes": [ @@ -1427,11 +1427,11 @@ }, "referencing": { "hashes": [ - "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c", - "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de" + "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", + "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0" ], - "markers": "python_version >= '3.8'", - "version": "==0.35.1" + "markers": "python_version >= '3.9'", + "version": "==0.36.2" }, "requests": { "hashes": [ @@ -1553,11 +1553,11 @@ }, "s3transfer": { "hashes": [ - "sha256:244a76a24355363a68164241438de1b72f8781664920260c48465896b712a41e", - "sha256:29edc09801743c21eb5ecbc617a152df41d3c287f67b615f73e5f750583666a7" + "sha256:3b39185cb72f5acc77db1a58b6e25b977f28d20496b6e58d6813d75f464d632f", + "sha256:be6ecb39fadd986ef1701097771f87e4d2f821f27f6071c872143884d2950fbc" ], "markers": "python_version >= '3.8'", - "version": "==0.10.4" + "version": "==0.11.2" }, "setuptools": { "hashes": [ @@ -1601,11 +1601,11 @@ }, "tzdata": { "hashes": [ - "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc", - "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd" + "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694", + "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639" ], "markers": "python_version >= '2'", - "version": "==2024.2" + "version": "==2025.1" }, "urllib3": { "hashes": [ @@ -2079,12 +2079,12 @@ }, "minio": { "hashes": [ - "sha256:868dfe907e1702ce4bec86df1f3ced577a73ca85f344ef898d94fe2b5237f8c1", - "sha256:f5c24bf236fefd2edc567cd4455dc49a11ad8ff7ac984bb031b849d82f01222a" + "sha256:5247df5d4dca7bfa4c9b20093acd5ad43e82d8710ceb059d79c6eea970f49f79", + "sha256:c06ef7a43e5d67107067f77b6c07ebdd68733e5aa7eed03076472410ca19d876" ], "index": "pypi", "markers": "python_version >= '3.9'", - "version": "==7.2.14" + "version": "==7.2.15" }, "opensearch-py": { "hashes": [ @@ -2241,81 +2241,88 @@ }, "wrapt": { "hashes": [ - "sha256:09f5141599eaf36d6cc0b760ad87c2ab6b8618d009b2922639266676775a73a6", - "sha256:0aad4f54b3155d673a5c4706a71a0a84f3d415b2fc8a2a399a964d70f18846a2", - "sha256:0eb33799b7582bb73787b9903b70595f8eff67eecc9455f668ed01adf53f9eea", - "sha256:0ee037e4cc9d039efe712b13c483f4efa2c3499642369e01570b3bb1842eea3f", - "sha256:0fdc4e73a3fa0c25eed4d836d9732226f0326957cb075044a7f252b465299433", - "sha256:13887d1415dc0e213a9adeb9026ae1f427023f77110d988fbd478643490aa40c", - "sha256:144ed42a4ec3aca5d6f1524f99ee49493bbd0d9c66c24da7ec44b4661dca4dcc", - "sha256:14f78f8c313884f889c6696af62aa881af302a989a7c0df398d2b541fa53e8a9", - "sha256:15f96fe5e2efdc613983327240ae89cf6368c07eeb0f194d240e9549aa1ea739", - "sha256:162d5f15bdd3b8037e06540902227ef9e0f298496c0afaadd9e2875851446693", - "sha256:169033329022739c6f0d8cd3031a113953b0ba500f3d5978904bdd40baec4568", - "sha256:16b2fdfa09a74a3930175b6d9d7d008022aa72a4f02de2b3eecafcc1adfd3cfe", - "sha256:181a844005c9818792212a32e004cb4c6bd8e35cae8e97b1a39a1918d95cef58", - "sha256:18fb16fb6bb75f4ec6272829007f3129a9a5264d0230372f9651e5f75cfec552", - "sha256:1c119802ae432b8c5d55dd5253825d09c1dca1c97ffc7b32c53ecdb348712f64", - "sha256:20888d886186d19eab53816db2e615950b1ce7dbd5c239107daf2c8a6a4a03c6", - "sha256:21ffcf16f5c243a626b0f8da637948e3d5984e3bc0c1bc500ad990e88e974e3b", - "sha256:27a49f217839bf559d436308bae8fc4a9dd0ac98ffdb9d6aeb3f00385b0fb72c", - "sha256:2b20fcef5a3ee410671a5a59472e1ff9dda21cfbe5dfd15e23ee4b99ac455c8e", - "sha256:2c160bb8815787646b27a0c8575a26a4d6bf6abd7c5eb250ad3f2d38b29cb2cb", - "sha256:2f1bc359f6c52e53565e7af24b423e7a1eea97d155f38ac9e90e95303514710b", - "sha256:30c0c08434fe2af6e40c5c75c036d7e3c7e7f499079fc479e740d9586b09fb0d", - "sha256:3260178f3bc006acae93378bfd6dbf33c9249de93cc1b78d8cc7b7416f4ea99a", - "sha256:3dfd4738a630eddfcb7ff6c8e9fe863df3821f9c991dec73821e05450074ae09", - "sha256:50a4e3b45e62b1ccb96b3fc0e427f1b458ff2e0def34ae084de88418157a09d1", - "sha256:50bbfa7a92da7540426c774e09d6901e44d8f9b513b276ebae03ae244f0c6dbf", - "sha256:52f0907287d9104112dbebda46af4db0793fcc4c64c8a867099212d116b6db64", - "sha256:53e2986a65eba7c399d7ad1ccd204562d4ffe6e937344fe5a49eb5a83858f797", - "sha256:5660e470edfa15ae7ef407272c642d29e9962777a6b30bfa8fc0da2173dc9afd", - "sha256:57e932ad1908b53e9ad67a746432f02bc8473a9ee16e26a47645a2b224fba5fd", - "sha256:589f24449fd58508533c4a69b2a0f45e9e3419b86b43a0607e2fdb989c6f2552", - "sha256:5c2e24ba455af4b0a237a890ea6ed9bafd01fac2c47095f87c53ea3344215d43", - "sha256:5ebea3ebb6a394f50f150a52e279508e91c8770625ac8fcb5d8cf35995a320f2", - "sha256:67c30d3fe245adb0eb1061a0e526905970a0dabe7c5fba5078e0ee9d19f28167", - "sha256:6bb82447ddae4e3d9b51f40c494f66e6cbd8fb0e8e8b993678416535c67f9a0d", - "sha256:6ce4cff3922707048d754e365c4ebf41a3bcbf29b329349bf85d51873c7c7e9e", - "sha256:6d44b14f3a2f6343a07c90344850b7af5515538ce3a5d01f9c87d8bae9bd8724", - "sha256:6fd88935b12b59a933ef45facb57575095f205d30d0ae8dd1a3b485bc4fa2fbd", - "sha256:78da796b74f2c8e0af021ee99feb3bff7cb46f8e658fe25c20e66be1080db4a2", - "sha256:7966f98fa36933333d8a1c3d8552aa3d0735001901a4aabcfbd5a502b4ef14fe", - "sha256:7eca3a1afa9820785b79cb137c68ca38c2f77cfedc3120115da42e1d5800907e", - "sha256:823a262d967cbdf835787039b873ff551e36c14658bdc2e43267968b67f61f88", - "sha256:88623fd957ba500d8bb0f7427a76496d99313ca2f9e932481c0882e034cf1add", - "sha256:889587664d245dae75c752b643061f922e8a590d43a4cd088eca415ca83f2d13", - "sha256:9176057c60438c2ce2284cdefc2b3ee5eddc8c87cd6e24c558d9f5c64298fa4a", - "sha256:93018dbb956e0ad99ea2fa2c3c22f033549dcb1f56ad9f4555dfe25e49688c5d", - "sha256:97eaff096fcb467e0f486f3bf354c1072245c2045859d71ba71158717ec97dcc", - "sha256:997e8f9b984e4263993d3baf3329367e7c7673b63789bc761718a6f9ed68653d", - "sha256:99e544e6ce26f89ad5acc6f407bc4daf7c1d42321e836f5c768f834100bdf35c", - "sha256:9e04f3bd30e0b23c0ca7e1d4084e7d28b6d7d2feb8b7bc69b496fe881280579b", - "sha256:a7aa07603d67007c15b33d20095cc9276f3e127bfb1b8106b3e84ec6907d137e", - "sha256:a992f9e019145e84616048556546edeaba68e05e1c1ffbe8391067a63cdadb0c", - "sha256:b1a4c8edd038fee0ce67bf119b16eaa45d22a52bbaf7d0a17d2312eb0003b1bb", - "sha256:b8bd35c15bc82c5cbe397e8196fa57a17ce5d3f30e925a6fd39e4c5bb02fdcff", - "sha256:b9a58a1cbdc0588ed4c8ab0c191002d5d831a58c3bad88523fe471ea97eaf57d", - "sha256:bac64f57a5a7926ebc9ab519fb9eba1fc6dcd1f65d7f45937b2ce38da65c2270", - "sha256:bca1c0824f824bcd97b4b179dd55dcad1dab419252be2b2faebbcacefa3b27b2", - "sha256:bdf7b0e3d3713331c0bb9daac47cd10e5aa60d060e53696f50de4e560bd5617f", - "sha256:c53ef8936c4d587cb96bb1cf0d076e822fa38266c2b646837ef60465da8db22e", - "sha256:cbead724daa13cae46e8ab3bb24938d8514d123f34345535b184f3eb1b7ad717", - "sha256:cd7649f0c493d35f9aad9790bbecd7b6fd2e2f7141f6cb1e1e9bb7a681d6d0a4", - "sha256:d609f0ab0603bbcbf2de906b366b9f9bec75c32b4493550a940de658cc2ce512", - "sha256:d792631942a102d6d4f71e4948aceb307310ac0a0af054be6d28b4f79583e0f1", - "sha256:d87334b521ab0e2564902c0b10039dee8670485e9d397fe97c34b88801f474f7", - "sha256:da0d0c1c4bd55f9ace919454776dbf0821f537b9a77f739f0c3e34b14728b3b3", - "sha256:e0f0e731e0ca1583befd3af71b9f90d64ded1535da7b80181cb9e907cc10bbae", - "sha256:e5bd9186d52cf3d36bf1823be0e85297e4dbad909bc6dd495ce0d272806d84a7", - "sha256:e72053cc4706dac537d5a772135dc3e1de5aff52883f49994c1757c1b2dc9db2", - "sha256:e8a7b0699a381226d81d75b48ea58414beb5891ba8982bdc8e42912f766de074", - "sha256:ec3e763e7ca8dcba0792fc3e8ff7061186f59e9aafe4438e6bb1f635a6ab0901", - "sha256:f17e8d926f63aed65ff949682c922f96d00f65c2e852c24272232313fa7823d5", - "sha256:f3117feb1fc479eaf84b549d3f229d5d2abdb823f003bc2a1c6dd70072912fa0" + "sha256:08e7ce672e35efa54c5024936e559469436f8b8096253404faeb54d2a878416f", + "sha256:0a6e821770cf99cc586d33833b2ff32faebdbe886bd6322395606cf55153246c", + "sha256:0b929ac182f5ace000d459c59c2c9c33047e20e935f8e39371fa6e3b85d56f4a", + "sha256:129a150f5c445165ff941fc02ee27df65940fcb8a22a61828b1853c98763a64b", + "sha256:13e6afb7fe71fe7485a4550a8844cc9ffbe263c0f1a1eea569bc7091d4898555", + "sha256:1473400e5b2733e58b396a04eb7f35f541e1fb976d0c0724d0223dd607e0f74c", + "sha256:18983c537e04d11cf027fbb60a1e8dfd5190e2b60cc27bc0808e653e7b218d1b", + "sha256:1a7ed2d9d039bd41e889f6fb9364554052ca21ce823580f6a07c4ec245c1f5d6", + "sha256:1e1fe0e6ab7775fd842bc39e86f6dcfc4507ab0ffe206093e76d61cde37225c8", + "sha256:1fb5699e4464afe5c7e65fa51d4f99e0b2eadcc176e4aa33600a3df7801d6662", + "sha256:2696993ee1eebd20b8e4ee4356483c4cb696066ddc24bd70bcbb80fa56ff9061", + "sha256:35621ae4c00e056adb0009f8e86e28eb4a41a4bfa8f9bfa9fca7d343fe94f998", + "sha256:36ccae62f64235cf8ddb682073a60519426fdd4725524ae38874adf72b5f2aeb", + "sha256:3cedbfa9c940fdad3e6e941db7138e26ce8aad38ab5fe9dcfadfed9db7a54e62", + "sha256:3d57c572081fed831ad2d26fd430d565b76aa277ed1d30ff4d40670b1c0dd984", + "sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392", + "sha256:4011d137b9955791f9084749cba9a367c68d50ab8d11d64c50ba1688c9b457f2", + "sha256:40d615e4fe22f4ad3528448c193b218e077656ca9ccb22ce2cb20db730f8d306", + "sha256:410a92fefd2e0e10d26210e1dfb4a876ddaf8439ef60d6434f21ef8d87efc5b7", + "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3", + "sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9", + "sha256:49703ce2ddc220df165bd2962f8e03b84c89fee2d65e1c24a7defff6f988f4d6", + "sha256:4a721d3c943dae44f8e243b380cb645a709ba5bd35d3ad27bc2ed947e9c68192", + "sha256:4afd5814270fdf6380616b321fd31435a462019d834f83c8611a0ce7484c7317", + "sha256:4c82b8785d98cdd9fed4cac84d765d234ed3251bd6afe34cb7ac523cb93e8b4f", + "sha256:4db983e7bca53819efdbd64590ee96c9213894272c776966ca6306b73e4affda", + "sha256:582530701bff1dec6779efa00c516496968edd851fba224fbd86e46cc6b73563", + "sha256:58455b79ec2661c3600e65c0a716955adc2410f7383755d537584b0de41b1d8a", + "sha256:58705da316756681ad3c9c73fd15499aa4d8c69f9fd38dc8a35e06c12468582f", + "sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d", + "sha256:5c803c401ea1c1c18de70a06a6f79fcc9c5acfc79133e9869e730ad7f8ad8ef9", + "sha256:5cbabee4f083b6b4cd282f5b817a867cf0b1028c54d445b7ec7cfe6505057cf8", + "sha256:612dff5db80beef9e649c6d803a8d50c409082f1fedc9dbcdfde2983b2025b82", + "sha256:62c2caa1585c82b3f7a7ab56afef7b3602021d6da34fbc1cf234ff139fed3cd9", + "sha256:69606d7bb691b50a4240ce6b22ebb319c1cfb164e5f6569835058196e0f3a845", + "sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82", + "sha256:6ed6ffac43aecfe6d86ec5b74b06a5be33d5bb9243d055141e8cabb12aa08125", + "sha256:703919b1633412ab54bcf920ab388735832fdcb9f9a00ae49387f0fe67dad504", + "sha256:766d8bbefcb9e00c3ac3b000d9acc51f1b399513f44d77dfe0eb026ad7c9a19b", + "sha256:80dd7db6a7cb57ffbc279c4394246414ec99537ae81ffd702443335a61dbf3a7", + "sha256:8112e52c5822fc4253f3901b676c55ddf288614dc7011634e2719718eaa187dc", + "sha256:8c8b293cd65ad716d13d8dd3624e42e5a19cc2a2f1acc74b30c2c13f15cb61a6", + "sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40", + "sha256:91bd7d1773e64019f9288b7a5101f3ae50d3d8e6b1de7edee9c2ccc1d32f0c0a", + "sha256:95c658736ec15602da0ed73f312d410117723914a5c91a14ee4cdd72f1d790b3", + "sha256:99039fa9e6306880572915728d7f6c24a86ec57b0a83f6b2491e1d8ab0235b9a", + "sha256:9a2bce789a5ea90e51a02dfcc39e31b7f1e662bc3317979aa7e5538e3a034f72", + "sha256:9a7d15bbd2bc99e92e39f49a04653062ee6085c0e18b3b7512a4f2fe91f2d681", + "sha256:9abc77a4ce4c6f2a3168ff34b1da9b0f311a8f1cfd694ec96b0603dff1c79438", + "sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae", + "sha256:9fee687dce376205d9a494e9c121e27183b2a3df18037f89d69bd7b35bcf59e2", + "sha256:a5aaeff38654462bc4b09023918b7f21790efb807f54c000a39d41d69cf552cb", + "sha256:a604bf7a053f8362d27eb9fefd2097f82600b856d5abe996d623babd067b1ab5", + "sha256:abbb9e76177c35d4e8568e58650aa6926040d6a9f6f03435b7a522bf1c487f9a", + "sha256:acc130bc0375999da18e3d19e5a86403667ac0c4042a094fefb7eec8ebac7cf3", + "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8", + "sha256:b4e42a40a5e164cbfdb7b386c966a588b1047558a990981ace551ed7e12ca9c2", + "sha256:b5e251054542ae57ac7f3fba5d10bfff615b6c2fb09abeb37d2f1463f841ae22", + "sha256:b60fb58b90c6d63779cb0c0c54eeb38941bae3ecf7a73c764c52c88c2dcb9d72", + "sha256:b870b5df5b71d8c3359d21be8f0d6c485fa0ebdb6477dda51a1ea54a9b558061", + "sha256:ba0f0eb61ef00ea10e00eb53a9129501f52385c44853dbd6c4ad3f403603083f", + "sha256:bb87745b2e6dc56361bfde481d5a378dc314b252a98d7dd19a651a3fa58f24a9", + "sha256:bb90fb8bda722a1b9d48ac1e6c38f923ea757b3baf8ebd0c82e09c5c1a0e7a04", + "sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98", + "sha256:c86563182421896d73858e08e1db93afdd2b947a70064b813d515d66549e15f9", + "sha256:c958bcfd59bacc2d0249dcfe575e71da54f9dcf4a8bdf89c4cb9a68a1170d73f", + "sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b", + "sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925", + "sha256:e3890b508a23299083e065f435a492b5435eba6e304a7114d2f919d400888cc6", + "sha256:e496a8ce2c256da1eb98bd15803a79bee00fc351f5dfb9ea82594a3f058309e0", + "sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9", + "sha256:eaf675418ed6b3b31c7a989fd007fa7c3be66ce14e5c3b27336383604c9da85c", + "sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991", + "sha256:ecc840861360ba9d176d413a5489b9a0aff6d6303d7e733e2c4623cfa26904a6", + "sha256:f09b286faeff3c750a879d336fb6d8713206fc97af3adc14def0cdd349df6000", + "sha256:f393cda562f79828f38a819f4788641ac7c4085f30f1ce1a68672baa686482bb", + "sha256:f917c1180fdb8623c2b75a99192f4025e412597c50b2ac870f156de8fb101119", + "sha256:fc78a84e2dfbc27afe4b2bd7c80c8db9bca75cc5b85df52bfe634596a1da846b", + "sha256:ff04ef6eec3eee8a5efef2401495967a916feaa353643defcc03fc74fe213b58" ], "markers": "python_version >= '3.8'", - "version": "==1.17.1" + "version": "==1.17.2" } } } diff --git a/dbrepo-analyse-service/lib/dbrepo-1.6.0.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.6.0.tar.gz deleted file mode 100644 index 80c2ba74f662e7b02895122a37e301fde2157b82..0000000000000000000000000000000000000000 Binary files a/dbrepo-analyse-service/lib/dbrepo-1.6.0.tar.gz and /dev/null differ diff --git a/dbrepo-analyse-service/lib/dbrepo-1.6.1.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.6.1.tar.gz deleted file mode 100644 index 7914db1bb84dddf85611cda3b766c0c0cdc094c7..0000000000000000000000000000000000000000 Binary files a/dbrepo-analyse-service/lib/dbrepo-1.6.1.tar.gz and /dev/null differ diff --git a/dbrepo-analyse-service/lib/dbrepo-1.6.2-py3-none-any.whl b/dbrepo-analyse-service/lib/dbrepo-1.6.2-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..256d325e8bdbdacd8c967d852c98e39d8d3b9eb9 Binary files /dev/null and b/dbrepo-analyse-service/lib/dbrepo-1.6.2-py3-none-any.whl differ diff --git a/dbrepo-analyse-service/lib/dbrepo-1.6.2.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.6.2.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..ad4d6f9c5590836360d1a919f4be84b5cc5f9ade Binary files /dev/null and b/dbrepo-analyse-service/lib/dbrepo-1.6.2.tar.gz differ diff --git a/dbrepo-analyse-service/lib/dbrepo-1.6.3-py3-none-any.whl b/dbrepo-analyse-service/lib/dbrepo-1.6.3-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..b7f45eecc067d496a9d39d189e619ac7524c66b1 Binary files /dev/null and b/dbrepo-analyse-service/lib/dbrepo-1.6.3-py3-none-any.whl differ diff --git a/dbrepo-analyse-service/lib/dbrepo-1.6.3.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.6.3.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..2aa4f75ed8dd08245bd29d34c151dbe9b7eb2253 Binary files /dev/null and b/dbrepo-analyse-service/lib/dbrepo-1.6.3.tar.gz differ diff --git a/dbrepo-auth-service/dbrepo-realm.json b/dbrepo-auth-service/dbrepo-realm.json index b48be9a6bdc607bbfe2f7190b3733238f31f29b8..1c703b83750c5aa21d4da06c7895d74211122ae9 100644 --- a/dbrepo-auth-service/dbrepo-realm.json +++ b/dbrepo-auth-service/dbrepo-realm.json @@ -27,7 +27,7 @@ "oauth2DevicePollingInterval" : 5, "enabled" : true, "sslRequired" : "none", - "registrationAllowed" : false, + "registrationAllowed" : true, "registrationEmailAsUsername" : false, "rememberMe" : false, "verifyEmail" : true, @@ -38,6 +38,7 @@ "bruteForceProtected" : false, "permanentLockout" : false, "maxTemporaryLockouts" : 0, + "bruteForceStrategy" : "MULTIPLE", "maxFailureWaitSeconds" : 900, "minimumQuickLoginWaitSeconds" : 60, "waitIncrementSeconds" : 60, @@ -1308,8 +1309,8 @@ "protocol" : "openid-connect", "attributes" : { "realm_client" : "false", - "post.logout.redirect.uris" : "+", - "client.use.lightweight.access.token.enabled" : "true" + "client.use.lightweight.access.token.enabled" : "true", + "post.logout.redirect.uris" : "+" }, "authenticationFlowBindingOverrides" : { }, "fullScopeAllowed" : true, @@ -1383,6 +1384,38 @@ "fullScopeAllowed" : true, "nodeReRegistrationTimeout" : -1, "protocolMappers" : [ { + "id" : "266edf62-a19a-483b-b594-81428e4af792", + "name" : "orcid", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "ORCID", + "id.token.claim" : "true", + "lightweight.claim" : "false", + "access.token.claim" : "true", + "claim.name" : "orcid", + "jsonType.label" : "String" + } + }, { + "id" : "1a21798a-38b6-4df5-89f0-86942415246f", + "name" : "theme", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "THEME", + "id.token.claim" : "true", + "lightweight.claim" : "false", + "access.token.claim" : "true", + "claim.name" : "theme", + "jsonType.label" : "String" + } + }, { "id" : "da0b27c1-ae2e-4baa-bf78-db233e15c78d", "name" : "preferred_username", "protocol" : "openid-connect", @@ -1396,18 +1429,66 @@ "userinfo.token.claim" : "true" } }, { - "id" : "7c94de93-f60f-487b-b4b7-1891c67f74cc", - "name" : "aud", + "id" : "1bc6a1f4-4be2-439c-8c7f-b3fb0bb9956a", + "name" : "affiliation", "protocol" : "openid-connect", - "protocolMapper" : "oidc-hardcoded-claim-mapper", + "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "claim.value" : "dbrepo", + "introspection.token.claim" : "true", "userinfo.token.claim" : "true", + "user.attribute" : "AFFILIATION", "id.token.claim" : "true", + "lightweight.claim" : "false", "access.token.claim" : "true", - "claim.name" : "aud", - "access.tokenResponse.claim" : "false" + "claim.name" : "affiliation", + "jsonType.label" : "String" + } + }, { + "id" : "7cbf6dc6-653e-40a9-9974-0e5bf7a363c3", + "name" : "given name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "firstName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "given_name", + "jsonType.label" : "String" + } + }, { + "id" : "70bbd779-d085-4204-ac4b-3a40abab9d88", + "name" : "language", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "LANGUAGE", + "id.token.claim" : "true", + "lightweight.claim" : "false", + "access.token.claim" : "true", + "claim.name" : "language", + "jsonType.label" : "String" + } + }, { + "id" : "b817424d-7f91-43d8-b7d0-6a32582377fb", + "name" : "family name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "lastName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "family_name", + "jsonType.label" : "String" } }, { "id" : "030a1cd9-53d1-4a62-a375-94d50a2dc6fc", @@ -1424,9 +1505,26 @@ "access.token.claim" : "true", "claim.name" : "uid" } + }, { + "id" : "c304ed2f-5952-4772-838d-91998a45f154", + "name" : "aud", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-hardcoded-claim-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "claim.value" : "account", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "lightweight.claim" : "false", + "access.token.claim" : "true", + "claim.name" : "aud", + "jsonType.label" : "String", + "access.tokenResponse.claim" : "false" + } } ], - "defaultClientScopes" : [ "roles", "attributes", "basic" ], - "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ] + "defaultClientScopes" : [ "roles", "basic" ], + "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "attributes", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ] }, { "id" : "25741f6b-4867-4138-8238-6345c6ba8702", "clientId" : "rabbitmq-client", @@ -1471,12 +1569,12 @@ "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "false", "user.attribute" : "username", "id.token.claim" : "false", "access.token.claim" : "true", "claim.name" : "client_id", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "false" } }, { "id" : "f1afc22d-f595-403b-ba2e-6ab19d98205e", @@ -1485,11 +1583,11 @@ "protocolMapper" : "oidc-hardcoded-claim-mapper", "consentRequired" : false, "config" : { - "claim.value" : "rabbitmq", - "userinfo.token.claim" : "false", "id.token.claim" : "false", "access.token.claim" : "true", "claim.name" : "aud", + "claim.value" : "rabbitmq", + "userinfo.token.claim" : "false", "access.tokenResponse.claim" : "false" } } ], @@ -1548,8 +1646,8 @@ "protocol" : "openid-connect", "attributes" : { "realm_client" : "false", - "post.logout.redirect.uris" : "+", "client.use.lightweight.access.token.enabled" : "true", + "post.logout.redirect.uris" : "+", "pkce.code.challenge.method" : "S256" }, "authenticationFlowBindingOverrides" : { }, @@ -1562,12 +1660,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "locale", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "locale", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } } ], "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], @@ -1591,8 +1689,8 @@ "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${emailScopeConsentText}" + "consent.screen.text" : "${emailScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "782819fe-ba5d-4ddb-9f95-cabb69d79c8d", @@ -1601,12 +1699,12 @@ "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "emailVerified", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "email_verified", - "jsonType.label" : "boolean" + "jsonType.label" : "boolean", + "userinfo.token.claim" : "true" } }, { "id" : "ca613fc8-bbf2-4240-8b33-a1874f1559f3", @@ -1615,12 +1713,12 @@ "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "email", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "email", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } } ] }, { @@ -1630,8 +1728,8 @@ "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${profileScopeConsentText}" + "consent.screen.text" : "${profileScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "84f0487a-1d7d-470c-9b8e-5835294ae235", @@ -1640,12 +1738,12 @@ "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "username", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "preferred_username", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "bbdcdb36-3ec0-443d-b1af-9993d40f0567", @@ -1654,12 +1752,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "gender", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "gender", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "9faa870b-5491-4ce9-b27d-c9ce07d6a95e", @@ -1668,12 +1766,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "birthdate", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "birthdate", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "f0e3c012-9523-4076-83ae-e466e2d08220", @@ -1693,12 +1791,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "profile", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "profile", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "18cfbf4b-0a8e-45c7-a832-c0f72c92f3f3", @@ -1707,12 +1805,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "updatedAt", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "updated_at", - "jsonType.label" : "long" + "jsonType.label" : "long", + "userinfo.token.claim" : "true" } }, { "id" : "841ea785-26ab-429a-a420-09ce3948924d", @@ -1721,12 +1819,12 @@ "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "lastName", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "family_name", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "bfba13ff-f952-4e89-bbb1-a693fdebfae8", @@ -1735,12 +1833,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "website", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "website", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "475f071d-5149-4379-b928-76482f5f519c", @@ -1749,12 +1847,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "zoneinfo", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "zoneinfo", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "b8bebfed-b5e9-4604-a0ee-9817f7d439ac", @@ -1763,12 +1861,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "middleName", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "middle_name", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "445232c8-6830-476c-a6f1-8bbef167595a", @@ -1777,12 +1875,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "picture", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "picture", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "65f2e474-6ede-4872-86e4-e49504dd0f2a", @@ -1791,12 +1889,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "locale", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "locale", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "16cd5a27-ccf3-453c-ae1e-8621813ab73c", @@ -1805,12 +1903,12 @@ "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "firstName", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "given_name", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "f9efedfc-3388-457c-b10a-1dff4525ff9b", @@ -1819,12 +1917,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "nickname", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "nickname", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } } ] }, { @@ -1858,12 +1956,12 @@ "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "username", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "upn", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } } ] }, { @@ -1905,8 +2003,8 @@ "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${phoneScopeConsentText}" + "consent.screen.text" : "${phoneScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "dae802fb-9138-408a-b80e-a40eb0f56814", @@ -1915,12 +2013,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "phoneNumber", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "phone_number", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "feb06a8d-b0eb-4911-8464-368d93f566fa", @@ -1929,12 +2027,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "phoneNumberVerified", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "phone_number_verified", - "jsonType.label" : "boolean" + "jsonType.label" : "boolean", + "userinfo.token.claim" : "true" } } ] }, { @@ -1944,8 +2042,8 @@ "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "false", - "display.on.consent.screen" : "false", - "consent.screen.text" : "" + "consent.screen.text" : "", + "display.on.consent.screen" : "false" }, "protocolMappers" : [ { "id" : "c6411e3b-6478-453d-b530-5fe175a4d786", @@ -2025,6 +2123,61 @@ "gui.order" : "", "consent.screen.text" : "" } + }, { + "id" : "aa5c6ca7-812d-4fff-80b9-f5095ca82ce6", + "name" : "service_account", + "description" : "Specific scope for a client enabled for service accounts", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "bb359b0f-97dc-4d6a-9a2f-89458b53c512", + "name" : "Client IP Address", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "clientAddress", + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "clientAddress", + "jsonType.label" : "String" + } + }, { + "id" : "7aa3a4d2-3dd1-48dd-8886-562906eadb2a", + "name" : "Client Host", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "clientHost", + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "clientHost", + "jsonType.label" : "String" + } + }, { + "id" : "c4882d39-e815-49f5-8a73-eb8b83572eae", + "name" : "Client ID", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "client_id", + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "client_id", + "jsonType.label" : "String" + } + } ] }, { "id" : "210cc792-6c07-45a6-a77e-827cdf3b41ba", "name" : "offline_access", @@ -2041,8 +2194,8 @@ "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${addressScopeConsentText}" + "consent.screen.text" : "${addressScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "8d4ffe4d-1d01-4ca1-8ff4-44eacca61b30", @@ -2115,8 +2268,8 @@ "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "false", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${rolesScopeConsentText}" + "consent.screen.text" : "${rolesScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "3b6b6914-8ad1-4a71-88ec-444f754aaacb", @@ -2132,11 +2285,15 @@ "protocolMapper" : "oidc-usermodel-realm-role-mapper", "consentRequired" : false, "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "false", + "multivalued" : "true", "user.attribute" : "foo", + "id.token.claim" : "true", + "lightweight.claim" : "false", "access.token.claim" : "true", "claim.name" : "realm_access.roles", - "jsonType.label" : "String", - "multivalued" : "true" + "jsonType.label" : "String" } }, { "id" : "a7bd6723-e58e-47f7-95c0-2925ce99283d", @@ -2166,8 +2323,12 @@ "strictTransportSecurity" : "max-age=31536000; includeSubDomains" }, "smtpServer" : { }, + "loginTheme" : "keycloak.v2", + "accountTheme" : "", + "adminTheme" : "", + "emailTheme" : "", "eventsEnabled" : false, - "eventsListeners" : [ "jboss-logging" ], + "eventsListeners" : [ "create-event-listener", "jboss-logging" ], "enabledEventTypes" : [ "SEND_RESET_PASSWORD", "UPDATE_CONSENT_ERROR", "GRANT_CONSENT", "VERIFY_PROFILE_ERROR", "REMOVE_TOTP", "REVOKE_GRANT", "UPDATE_TOTP", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "IMPERSONATE_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "OAUTH2_DEVICE_CODE_TO_TOKEN_ERROR", "RESTART_AUTHENTICATION", "IMPERSONATE", "UPDATE_PROFILE_ERROR", "LOGIN", "OAUTH2_DEVICE_VERIFY_USER_CODE", "UPDATE_PASSWORD_ERROR", "CLIENT_INITIATED_ACCOUNT_LINKING", "TOKEN_EXCHANGE", "AUTHREQID_TO_TOKEN", "LOGOUT", "REGISTER", "DELETE_ACCOUNT_ERROR", "CLIENT_REGISTER", "IDENTITY_PROVIDER_LINK_ACCOUNT", "DELETE_ACCOUNT", "UPDATE_PASSWORD", "CLIENT_DELETE", "FEDERATED_IDENTITY_LINK_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN", "CLIENT_DELETE_ERROR", "VERIFY_EMAIL", "CLIENT_LOGIN_ERROR", "RESTART_AUTHENTICATION_ERROR", "EXECUTE_ACTIONS", "REMOVE_FEDERATED_IDENTITY_ERROR", "TOKEN_EXCHANGE_ERROR", "PERMISSION_TOKEN", "SEND_IDENTITY_PROVIDER_LINK_ERROR", "EXECUTE_ACTION_TOKEN_ERROR", "SEND_VERIFY_EMAIL", "OAUTH2_DEVICE_AUTH", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "OAUTH2_DEVICE_CODE_TO_TOKEN", "IDENTITY_PROVIDER_POST_LOGIN", "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR", "OAUTH2_DEVICE_VERIFY_USER_CODE_ERROR", "UPDATE_EMAIL", "REGISTER_ERROR", "REVOKE_GRANT_ERROR", "EXECUTE_ACTION_TOKEN", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "CLIENT_UPDATE_ERROR", "AUTHREQID_TO_TOKEN_ERROR", "UPDATE_PROFILE", "CLIENT_REGISTER_ERROR", "FEDERATED_IDENTITY_LINK", "SEND_IDENTITY_PROVIDER_LINK", "SEND_VERIFY_EMAIL_ERROR", "RESET_PASSWORD", "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR", "OAUTH2_DEVICE_AUTH_ERROR", "UPDATE_CONSENT", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "SEND_RESET_PASSWORD_ERROR", "CLIENT_UPDATE", "CUSTOM_REQUIRED_ACTION_ERROR", "IDENTITY_PROVIDER_POST_LOGIN_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN", "VERIFY_PROFILE", "GRANT_CONSENT_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR" ], "adminEventsEnabled" : false, "adminEventsDetailsEnabled" : false, @@ -2215,7 +2376,7 @@ "subType" : "anonymous", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", "saml-role-list-mapper" ] + "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper", "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper" ] } }, { "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1", @@ -2241,7 +2402,15 @@ "subType" : "authenticated", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "oidc-address-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper" ] + "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-address-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "oidc-sha256-pairwise-sub-mapper" ] + } + } ], + "org.keycloak.userprofile.UserProfileProvider" : [ { + "id" : "a407a1d6-a7f6-4a72-ba3a-149de03d5a43", + "providerId" : "declarative-user-profile", + "subComponents" : { }, + "config" : { + "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}],\"unmanagedAttributePolicy\":\"ENABLED\"}" ] } } ], "org.keycloak.storage.UserStorageProvider" : [ { @@ -2257,8 +2426,8 @@ "config" : { "ldap.attribute" : [ "createTimestamp" ], "is.mandatory.in.ldap" : [ "false" ], - "read.only" : [ "true" ], "always.read.value.from.ldap" : [ "true" ], + "read.only" : [ "true" ], "user.model.attribute" : [ "createTimestamp" ] } }, { @@ -2269,8 +2438,8 @@ "config" : { "ldap.attribute" : [ "sn" ], "is.mandatory.in.ldap" : [ "true" ], - "always.read.value.from.ldap" : [ "true" ], "read.only" : [ "false" ], + "always.read.value.from.ldap" : [ "true" ], "user.model.attribute" : [ "lastName" ] } }, { @@ -2293,8 +2462,8 @@ "config" : { "ldap.attribute" : [ "mail" ], "is.mandatory.in.ldap" : [ "false" ], - "read.only" : [ "false" ], "always.read.value.from.ldap" : [ "false" ], + "read.only" : [ "false" ], "user.model.attribute" : [ "email" ] } }, { @@ -2303,19 +2472,19 @@ "providerId" : "group-ldap-mapper", "subComponents" : { }, "config" : { + "mode" : [ "LDAP_ONLY" ], "membership.attribute.type" : [ "DN" ], + "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ], "group.name.ldap.attribute" : [ "cn" ], - "preserve.group.inheritance" : [ "false" ], "membership.user.ldap.attribute" : [ "uid" ], - "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ], - "mode" : [ "LDAP_ONLY" ], - "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ], - "membership.ldap.attribute" : [ "member" ], "ignore.missing.groups" : [ "false" ], + "preserve.group.inheritance" : [ "false" ], + "membership.ldap.attribute" : [ "member" ], "memberof.ldap.attribute" : [ "memberOf" ], "group.object.classes" : [ "groupOfNames" ], - "drop.non.existing.groups.during.sync" : [ "false" ], - "groups.path" : [ "/" ] + "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ], + "groups.path" : [ "/" ], + "drop.non.existing.groups.during.sync" : [ "false" ] } }, { "id" : "b6ff3285-35af-4e86-8bb4-d94b8e0d70bb", @@ -2339,15 +2508,15 @@ "is.mandatory.in.ldap" : [ "true" ], "attribute.force.default" : [ "false" ], "is.binary.attribute" : [ "false" ], - "read.only" : [ "false" ], "always.read.value.from.ldap" : [ "false" ], + "read.only" : [ "false" ], "user.model.attribute" : [ "username" ] } } ] }, "config" : { - "pagination" : [ "false" ], "fullSyncPeriod" : [ "-1" ], + "pagination" : [ "false" ], "startTls" : [ "false" ], "connectionPooling" : [ "true" ], "usersDn" : [ "ou=users,dc=dbrepo,dc=at" ], @@ -2355,15 +2524,15 @@ "useKerberosForPasswordAuthentication" : [ "false" ], "importEnabled" : [ "true" ], "enabled" : [ "true" ], + "bindCredential" : [ "admin" ], "changedSyncPeriod" : [ "-1" ], - "bindDn" : [ "cn=admin,dc=dbrepo,dc=at" ], "usernameLDAPAttribute" : [ "uid" ], - "bindCredential" : [ "admin" ], + "bindDn" : [ "cn=admin,dc=dbrepo,dc=at" ], "lastSync" : [ "1719252666" ], "vendor" : [ "other" ], "uuidLDAPAttribute" : [ "entryUUID" ], - "connectionUrl" : [ "ldap://identity-service:1389" ], "allowKerberosAuthentication" : [ "false" ], + "connectionUrl" : [ "ldap://identity-service:1389" ], "syncRegistrations" : [ "true" ], "authType" : [ "simple" ], "useTruststoreSpi" : [ "always" ], @@ -2375,14 +2544,6 @@ "validatePasswordPolicy" : [ "false" ] } } ], - "org.keycloak.userprofile.UserProfileProvider" : [ { - "id" : "a407a1d6-a7f6-4a72-ba3a-149de03d5a43", - "providerId" : "declarative-user-profile", - "subComponents" : { }, - "config" : { - "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}],\"unmanagedAttributePolicy\":\"ENABLED\"}" ] - } - } ], "org.keycloak.keys.KeyProvider" : [ { "id" : "2f53ccf3-37b0-4d34-83e7-ed497499ee51", "name" : "rsa-enc-generated", @@ -2995,10 +3156,12 @@ "actionTokenGeneratedByUserLifespan-idp-verify-account-via-email" : "", "parRequestUriLifespan" : "60", "clientSessionMaxLifespan" : "0", + "organizationsEnabled" : "false", "shortVerificationUri" : "" }, - "keycloakVersion" : "24.0.5", + "keycloakVersion" : "26.0.4", "userManagedAccessAllowed" : false, + "organizationsEnabled" : false, "clientProfiles" : { "profiles" : [ ] }, diff --git a/dbrepo-auth-service/init/Pipfile.lock b/dbrepo-auth-service/init/Pipfile.lock index c8224a7844942ed36a6fef30185dc094f516378d..57631a05559948613a5c9a63b37463c95a48da9a 100644 --- a/dbrepo-auth-service/init/Pipfile.lock +++ b/dbrepo-auth-service/init/Pipfile.lock @@ -18,11 +18,11 @@ "default": { "certifi": { "hashes": [ - "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", - "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db" + "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", + "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe" ], "markers": "python_version >= '3.6'", - "version": "==2024.12.14" + "version": "==2025.1.31" }, "charset-normalizer": { "hashes": [ @@ -175,11 +175,11 @@ "develop": { "certifi": { "hashes": [ - "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", - "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db" + "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", + "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe" ], "markers": "python_version >= '3.6'", - "version": "==2024.12.14" + "version": "==2025.1.31" }, "charset-normalizer": { "hashes": [ diff --git a/dbrepo-auth-service/init/app.py b/dbrepo-auth-service/init/app.py index 270e959fecb30c9f200ba96c8186357cb94599b9..5e42003a192d4b6536ccd8f6c6ccc1be9dcedd6d 100644 --- a/dbrepo-auth-service/init/app.py +++ b/dbrepo-auth-service/init/app.py @@ -7,7 +7,7 @@ endpoint = os.getenv('AUTH_SERVICE_ENDPOINT', 'http://localhost:8080') system_username = os.getenv('SYSTEM_USERNAME', 'admin') -def fetch() -> str: +def fetch() -> (str, str): print(f'Fetching user id of internal user with username: {system_username}') response = post(url=f'{endpoint}/realms/master/protocol/openid-connect/token', data=dict({ 'username': os.getenv('AUTH_SERVICE_ADMIN', 'admin'), @@ -25,7 +25,8 @@ def fetch() -> str: if response.status_code != 200 or len(response.json()) != 1: raise FileNotFoundError(f'Failed to obtain user') ldap_user = response.json()[0] - print(f'Successfully fetched user id: {ldap_user["id"]}') + user_id = ldap_user["id"] + print(f'Successfully fetched user id: {user_id}') if 'attributes' not in ldap_user or ldap_user['attributes'] is None: raise ModuleNotFoundError(f'Failed to obtain user attributes: {ldap_user}') ldap_user_attrs = ldap_user['attributes'] @@ -35,10 +36,10 @@ def fetch() -> str: raise EnvironmentError(f'Failed to obtain ldap id: wrong length {len(ldap_user_attrs["LDAP_ID"])} != 1') ldap_user_id = ldap_user_attrs['LDAP_ID'][0] print(f'Successfully fetched ldap user id: {ldap_user_id}') - return ldap_user_id + return (ldap_user_id, user_id) -def save(user_id: str) -> None: +def save(user_id: str, keycloak_id: str) -> None: conn = mariadb.connect(user=os.getenv('METADATA_USERNAME', 'root'), password=os.getenv('METADATA_DB_PASSWORD', 'dbrepo'), host="metadata-db", @@ -46,12 +47,13 @@ def save(user_id: str) -> None: database=os.getenv('METADATA_DB', 'dbrepo')) cursor = conn.cursor() cursor.execute( - "INSERT IGNORE INTO `mdb_users` (`id`, `username`, `email`, `mariadb_password`, `is_internal`) VALUES (?, ?, LEFT(UUID(), 20), PASSWORD(LEFT(UUID(), 20)), true)", - (user_id, system_username)) + "INSERT IGNORE INTO `mdb_users` (`id`, `keycloak_id`, `username`, `mariadb_password`, `is_internal`) VALUES (?, ?, ?, PASSWORD(LEFT(UUID(), 20)), true)", + (user_id, keycloak_id, system_username)) conn.commit() conn.close() if __name__ == '__main__': - save(fetch()) + user_id, keycloak_id = fetch() + save(user_id, keycloak_id) print(f'Successfully inserted user') diff --git a/dbrepo-auth-service/init/test/test_unit_app.py b/dbrepo-auth-service/init/test/test_unit_app.py index 624b7d8d53e7393d2077c214278bdb98f32297ba..af6aed379a3780157718d760bdabd79475e8d249 100644 --- a/dbrepo-auth-service/init/test/test_unit_app.py +++ b/dbrepo-auth-service/init/test/test_unit_app.py @@ -16,38 +16,6 @@ class AppUnitTest(unittest.TestCase): "session_state": "ae64d2bd-3225-4e05-9943-2bb91fb8fe52", "scope": "profile email" } - user_res = [ - {"id": "5b516520-67cb-4aa0-86a6-d12f8b8f1a20", - "username": "admin", - "firstName": "User1", - "lastName": "Bar1", - "emailVerified": False, - "attributes": {"LDAP_ENTRY_DN": ["cn=admin,ou=users,dc=dbrepo,dc=at"], - "createTimestamp": ["20250120141013Z"], - "modifyTimestamp": ["20250120141013Z"], - "LDAP_ID": ["02b6e096-6b84-103f-81f6-1f6da137f2bb"]}, - "createdTimestamp": 1737382606939, - "enabled": True, - "totp": False, - "federationLink": "c109d473-5ce1-4032-af7b-02e5442f5c07", - "disableableCredentialTypes": [], - "requiredActions": [], - "notBefore": 0, - "access": {"manageGroupMembership": True, - "view": True, - "mapRoles": True, - "impersonate": True, - "manage": True}}] - - def test_fetch_succeeds(self): - with requests_mock.Mocker() as mock: - # mock - mock.post(f'{endpoint}/realms/master/protocol/openid-connect/token', json=self.token_res, status_code=200) - mock.get(f'{endpoint}/admin/realms/dbrepo/users/?username=admin', json=self.user_res, status_code=200) - - # test - user_id = fetch() - self.assertEqual("02b6e096-6b84-103f-81f6-1f6da137f2bb", user_id) def test_fetch_token_bad_request_fails(self): with requests_mock.Mocker() as mock: diff --git a/dbrepo-auth-service/listeners/.gitignore b/dbrepo-auth-service/listeners/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..5d6e1ae3b181727bbd28cdb0107283899c3a0fd2 --- /dev/null +++ b/dbrepo-auth-service/listeners/.gitignore @@ -0,0 +1,30 @@ +### IntelliJ IDEA ### +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ +target/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/dbrepo-auth-service/listeners/pom.xml b/dbrepo-auth-service/listeners/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..e70201b96ac3d853a0274c7f06499d336f1c27cf --- /dev/null +++ b/dbrepo-auth-service/listeners/pom.xml @@ -0,0 +1,111 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-parent</artifactId> + <version>24.0.5</version> + </parent> + + <groupId>at.tuwien</groupId> + <artifactId>create-event-listener</artifactId> + <name>dbrepo-auth-service</name> + <version>24.0.5</version> + + <description>Create event listener</description> + + <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6/</url> + <developers> + <developer> + <name>Martin Weise</name> + <email>martin.weise@tuwien.ac.at</email> + <organization>TU Wien</organization> + </developer> + </developers> + + <properties> + <java.version>17</java.version> + <maven.version>3.9.8</maven.version> + <maven.compiler.source>${java.version}</maven.compiler.source> + <maven.compiler.target>${java.version}</maven.compiler.target> + <maven.compiler.release>${java.version}</maven.compiler.release> + <maven-compiler-plugin.version>3.13.0</maven-compiler-plugin.version> + <testcontainers.version>1.19.1</testcontainers.version> + <keycloak-testcontainer.version>3.2.0</keycloak-testcontainer.version> + </properties> + + <dependencies> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-core</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-server-spi</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-server-spi-private</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-services</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-saml-core-public</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.jboss.logging</groupId> + <artifactId>jboss-logging</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.jboss.spec.javax.ws.rs</groupId> + <artifactId>jboss-jaxrs-api_2.1_spec</artifactId> + </dependency> + <!-- Tests --> + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>junit-jupiter</artifactId> + <version>${testcontainers.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.github.dasniko</groupId> + <artifactId>testcontainers-keycloak</artifactId> + <version>${keycloak-testcontainer.version}</version> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <finalName>create-event-listener</finalName> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>${maven-compiler-plugin.version}</version> + <configuration> + <source>${java.version}</source> + <target>${java.version}</target> + </configuration> + </plugin> + <plugin> + <groupId>org.wildfly.plugins</groupId> + <artifactId>wildfly-maven-plugin</artifactId> + <configuration> + <skip>false</skip> + </configuration> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/dbrepo-auth-service/listeners/src/main/java/at/tuwien/Client.java b/dbrepo-auth-service/listeners/src/main/java/at/tuwien/Client.java new file mode 100644 index 0000000000000000000000000000000000000000..769ec49097223e5fd49f76d855d9acef1cfbe35c --- /dev/null +++ b/dbrepo-auth-service/listeners/src/main/java/at/tuwien/Client.java @@ -0,0 +1,65 @@ +package at.tuwien; + +import org.jboss.logging.Logger; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.Base64; + +public class Client { + private static final Logger log = Logger.getLogger(Client.class); + + public static void postService(String data) throws IOException { + try { + final String urlString = System.getenv("METADATA_SERVICE_ENDPOINT"); + log.debugf("METADATA_SERVICE_ENDPOINT: %s", urlString); + if (urlString == null || urlString.isEmpty()) { + throw new IllegalArgumentException("Environment variable METADATA_SERVICE_ENDPOINT is not set or is empty."); + } + final String systemUsername = System.getenv("SYSTEM_USERNAME"); + if (systemUsername == null || systemUsername.isEmpty()) { + throw new IllegalArgumentException("Environment variable SYSTEM_USERNAME is not set or is empty."); + } + log.debugf("SYSTEM_USERNAME: %s", systemUsername); + final String systemPassword = System.getenv("SYSTEM_PASSWORD"); + if (systemPassword == null || systemPassword.isEmpty()) { + throw new IllegalArgumentException("Environment variable SYSTEM_PASSWORD is not set or is empty."); + } + + URL url = URI.create(urlString).toURL(); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setDoOutput(true); + conn.setRequestMethod("POST"); + final String token = systemUsername + ":" + systemPassword; + conn.setRequestProperty("Authorization", "Basic " + Base64.getEncoder().encodeToString(token.getBytes( + Charset.defaultCharset()))); + conn.setRequestProperty("Content-Type", "application/json; utf-8"); + + OutputStream os = conn.getOutputStream(); + os.write(data.getBytes()); + os.flush(); + + final int responseCode = conn.getResponseCode(); + if (responseCode != HttpURLConnection.HTTP_CREATED && responseCode != HttpURLConnection.HTTP_OK) { + throw new RuntimeException("Failed : HTTP error code : " + responseCode); + } + + final BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); + String output; + log.debugf("Output from Server .... \n"); + while ((output = br.readLine()) != null) { + System.out.println(output); + log.debugf("Input from Server: %s", output); + } + conn.disconnect(); + } catch (IOException e) { + throw new IOException("Failed to post service: " + e.getMessage(), e); + } + } +} diff --git a/dbrepo-auth-service/listeners/src/main/java/at/tuwien/CreateEventListenerProvider.java b/dbrepo-auth-service/listeners/src/main/java/at/tuwien/CreateEventListenerProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..2b5d9221a7beb49385e129f6ccb3fff0aed73002 --- /dev/null +++ b/dbrepo-auth-service/listeners/src/main/java/at/tuwien/CreateEventListenerProvider.java @@ -0,0 +1,139 @@ +package at.tuwien; + +import org.jboss.logging.Logger; +import org.keycloak.events.Event; +import org.keycloak.events.EventListenerProvider; +import org.keycloak.events.EventType; +import org.keycloak.events.admin.AdminEvent; +import org.keycloak.events.admin.OperationType; +import org.keycloak.events.admin.ResourceType; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; +import org.keycloak.models.RealmProvider; +import org.keycloak.models.UserModel; + +import java.util.StringJoiner; + +public class CreateEventListenerProvider implements EventListenerProvider { + + private static final Logger log = Logger.getLogger(CreateEventListenerProvider.class); + + private final KeycloakSession session; + private final RealmProvider model; + + public CreateEventListenerProvider(KeycloakSession session) { + this.session = session; + this.model = session.realms(); + } + + @Override + public void onEvent(Event event) { + + log.debugf("New %s Event", event.getType()); + log.debugf("onEvent-> %s", toString(event)); + + if (EventType.REGISTER.equals(event.getType())) { + + event.getDetails().forEach((key, value) -> log.debugf("%s : %s", key, value)); + + RealmModel realm = this.model.getRealm(event.getRealmId()); + UserModel user = this.session.users().getUserById(realm, event.getUserId()); + sendUserData(user); + } + + } + + @Override + public void onEvent(AdminEvent adminEvent, boolean b) { + log.debug("onEvent(AdminEvent)"); + log.debugf("Resource path: %s", adminEvent.getResourcePath()); + log.debugf("Resource type: %s", adminEvent.getResourceType()); + log.debugf("Operation type: %s", adminEvent.getOperationType()); + log.debugf("AdminEvent.toString(): %s", toString(adminEvent)); + if (ResourceType.USER.equals(adminEvent.getResourceType()) + && OperationType.CREATE.equals(adminEvent.getOperationType())) { + RealmModel realm = this.model.getRealm(adminEvent.getRealmId()); + UserModel user = this.session.users().getUserById(realm, adminEvent.getResourcePath().substring(6)); + + sendUserData(user); + } + } + + private void sendUserData(UserModel user) { + final String userData = "{" + + quoteAttr("id", user.getId()) + ", " + + quoteAttr("username", user.getUsername()) + ", " + + quoteAttr("email", user.getEmail()) + ", " + + quoteAttr("ldap_id", user.getFirstAttribute("LDAP_ID")) + ", " + + quoteAttr("given_name", user.getFirstName()) + ", " + + quoteAttr("family_name", user.getLastName()) + + "}"; + try { + log.debugf("create new user in API: %s", userData); + Client.postService(userData); + } catch (Exception e) { + log.errorf("Failed to call API: %s", e); + } + } + + private static String quoteAttr(String key, String value) { + if (value == null || value.isBlank() || value.isEmpty() || value.contentEquals(" ")) { + return "\"" + key + "\": null"; + } + return "\"" + key + "\": \"" + value + "\""; + } + + @Override + public void close() { + } + + private String toString(Event event) { + final StringJoiner joiner = new StringJoiner(", "); + joiner.add("type=" + event.getType()) + .add("realmId=" + event.getRealmId()) + .add("clientId=" + event.getClientId()) + .add("userId=" + event.getUserId()) + .add("ipAddress=" + event.getIpAddress()); + if (event.getError() != null) { + joiner.add("error=" + event.getError()); + } + if (event.getDetails() != null) { + event.getDetails().forEach((key, value) -> { + if (value == null || !value.contains(" ")) { + joiner.add(key + "=" + value); + } else { + joiner.add(key + "='" + value + "'"); + } + }); + } + return joiner.toString(); + } + + private String toString(AdminEvent event) { + RealmModel realm = this.model.getRealm(event.getRealmId()); + UserModel newRegisteredUser = this.session.users().getUserById(realm, event.getAuthDetails().getUserId()); + + StringJoiner joiner = new StringJoiner(", "); + + joiner.add("operationType=" + event.getOperationType()) + .add("realmId=" + event.getAuthDetails().getRealmId()) + .add("clientId=" + event.getAuthDetails().getClientId()) + .add("userId=" + event.getAuthDetails().getUserId()); + + if (newRegisteredUser != null) { + joiner.add("email=" + newRegisteredUser.getEmail()) + .add("username=" + newRegisteredUser.getUsername()) + .add("firstName=" + newRegisteredUser.getFirstName()) + .add("lastName=" + newRegisteredUser.getLastName()); + } + + joiner.add("ipAddress=" + event.getAuthDetails().getIpAddress()) + .add("resourcePath=" + event.getResourcePath()); + + if (event.getError() != null) { + joiner.add("error=" + event.getError()); + } + + return joiner.toString(); + } +} diff --git a/dbrepo-auth-service/listeners/src/main/java/at/tuwien/CreateEventListenerProviderFactory.java b/dbrepo-auth-service/listeners/src/main/java/at/tuwien/CreateEventListenerProviderFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..61477ffa33169504a3368d11d0750c9c1404e160 --- /dev/null +++ b/dbrepo-auth-service/listeners/src/main/java/at/tuwien/CreateEventListenerProviderFactory.java @@ -0,0 +1,36 @@ +package at.tuwien; + +import org.keycloak.Config; +import org.keycloak.events.EventListenerProvider; +import org.keycloak.events.EventListenerProviderFactory; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakSessionFactory; + +public class CreateEventListenerProviderFactory implements EventListenerProviderFactory { + + @Override + public EventListenerProvider create(KeycloakSession keycloakSession) { + return new CreateEventListenerProvider(keycloakSession); + } + + @Override + public void init(Config.Scope scope) { + + } + + @Override + public void postInit(KeycloakSessionFactory keycloakSessionFactory) { + + } + + @Override + public void close() { + + } + + @Override + public String getId() { + return "create-event-listener"; + } + +} diff --git a/dbrepo-auth-service/listeners/src/main/resources/META-INF/jboss-deployment-structure.xml b/dbrepo-auth-service/listeners/src/main/resources/META-INF/jboss-deployment-structure.xml new file mode 100644 index 0000000000000000000000000000000000000000..c0330ba082479a3bd9d0caf86508b5067251ed84 --- /dev/null +++ b/dbrepo-auth-service/listeners/src/main/resources/META-INF/jboss-deployment-structure.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<jboss-deployment-structure> + <deployment> + <dependencies> + <module name="org.keycloak.keycloak-services" /> + </dependencies> + </deployment> +</jboss-deployment-structure> \ No newline at end of file diff --git a/dbrepo-auth-service/listeners/src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory b/dbrepo-auth-service/listeners/src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory new file mode 100644 index 0000000000000000000000000000000000000000..df3c5521f0958fed5fadb4f006d8ee6eb50f97c2 --- /dev/null +++ b/dbrepo-auth-service/listeners/src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory @@ -0,0 +1 @@ +at.tuwien.CreateEventListenerProviderFactory \ No newline at end of file diff --git a/dbrepo-auth-service/listeners/src/test/java/at/tuwien/EventListenerIntegrationTest.java b/dbrepo-auth-service/listeners/src/test/java/at/tuwien/EventListenerIntegrationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c3d6ee94ccd764d16d589b33b51d501e2a2a3d82 --- /dev/null +++ b/dbrepo-auth-service/listeners/src/test/java/at/tuwien/EventListenerIntegrationTest.java @@ -0,0 +1,18 @@ +package at.tuwien; + +import dasniko.testcontainers.keycloak.KeycloakContainer; +import org.testcontainers.images.PullPolicy; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +@Testcontainers +public class EventListenerIntegrationTest { + + @Container + private static KeycloakContainer keycloakContainer = new KeycloakContainer("quay.io/keycloak/keycloak:24.0") + .withImagePullPolicy(PullPolicy.alwaysPull()) + .withAdminUsername("admin") + .withAdminPassword("admin") + .withRealmImportFile("dbrepo-realm.json") + .withEnv("KC_HOSTNAME_STRICT_HTTPS", "false"); +} diff --git a/dbrepo-auth-service/listeners/src/test/resources/dbrepo-realm.json b/dbrepo-auth-service/listeners/src/test/resources/dbrepo-realm.json new file mode 100644 index 0000000000000000000000000000000000000000..56f2003e961a14d09bcd56832437f915cae04dea --- /dev/null +++ b/dbrepo-auth-service/listeners/src/test/resources/dbrepo-realm.json @@ -0,0 +1,2798 @@ +{ + "id" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "realm" : "dbrepo", + "notBefore" : 0, + "defaultSignatureAlgorithm" : "RS256", + "revokeRefreshToken" : false, + "refreshTokenMaxReuse" : 1, + "accessTokenLifespan" : 900, + "accessTokenLifespanForImplicitFlow" : 900, + "ssoSessionIdleTimeout" : 864000, + "ssoSessionMaxLifespan" : 2592000, + "ssoSessionIdleTimeoutRememberMe" : 0, + "ssoSessionMaxLifespanRememberMe" : 0, + "offlineSessionIdleTimeout" : 2592000, + "offlineSessionMaxLifespanEnabled" : false, + "offlineSessionMaxLifespan" : 5184000, + "clientSessionIdleTimeout" : 0, + "clientSessionMaxLifespan" : 0, + "clientOfflineSessionIdleTimeout" : 0, + "clientOfflineSessionMaxLifespan" : 0, + "accessCodeLifespan" : 60, + "accessCodeLifespanUserAction" : 300, + "accessCodeLifespanLogin" : 1800, + "actionTokenGeneratedByAdminLifespan" : 43200, + "actionTokenGeneratedByUserLifespan" : 1800, + "oauth2DeviceCodeLifespan" : 600, + "oauth2DevicePollingInterval" : 5, + "enabled" : true, + "sslRequired" : "none", + "registrationAllowed" : false, + "registrationEmailAsUsername" : false, + "rememberMe" : false, + "verifyEmail" : true, + "loginWithEmailAllowed" : false, + "duplicateEmailsAllowed" : false, + "resetPasswordAllowed" : false, + "editUsernameAllowed" : false, + "bruteForceProtected" : false, + "permanentLockout" : false, + "maxTemporaryLockouts" : 0, + "maxFailureWaitSeconds" : 900, + "minimumQuickLoginWaitSeconds" : 60, + "waitIncrementSeconds" : 60, + "quickLoginCheckMilliSeconds" : 1000, + "maxDeltaTimeSeconds" : 43200, + "failureFactor" : 30, + "roles" : { + "realm" : [ { + "id" : "48f38342-1e3f-427a-995d-c436eaee65cb", + "name" : "default-user-handling", + "description" : "${default-user-handling}", + "composite" : true, + "composites" : { + "realm" : [ "modify-user-theme", "modify-user-information" ] + }, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "9bb4a8dc-28e0-4645-b62f-cc94425f0cb0", + "name" : "default-maintenance-handling", + "description" : "${default-maintenance-handling}", + "composite" : true, + "composites" : { + "realm" : [ "create-maintenance-message", "find-maintenance-message", "update-maintenance-message", "delete-maintenance-message", "list-maintenance-messages" ] + }, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "7ee1c424-11b0-46a9-b0ed-725e9b7fc40c", + "name" : "default-system-roles", + "description" : "${default-system-roles}", + "composite" : true, + "composites" : { + "realm" : [ "delete-database-view", "update-semantic-unit", "export-query-data", "default-data-steward-roles", "execute-query", "default-user-handling", "delete-table-data", "find-query", "list-database-views", "persist-query", "update-search-index", "delete-database-access", "view-table-history", "create-ontology", "update-ontology", "modify-user-theme", "default-system-roles", "create-semantic-concept", "default-container-handling", "create-container", "create-table", "default-broker-handling", "default-maintenance-handling", "execute-semantic-query", "uma_authorization", "table-semantic-analyse", "list-containers", "check-database-access", "escalated-query-handling", "delete-identifier", "modify-database-owner", "list-tables", "export-table-data", "create-database-access", "delete-container", "re-execute-query", "create-semantic-unit", "escalated-identifier-handling", "system", "update-table-statistic", "escalated-semantics-handling", "default-database-handling", "delete-ontology", "find-database", "find-database-view", "update-semantic-concept", "find-user", "import-database-data", "publish-identifier", "default-roles-dbrepo", "find-foreign-user", "create-database", "create-maintenance-message", "find-maintenance-message", "escalated-container-handling", "default-researcher-roles", "default-identifier-handling", "escalated-user-handling", "modify-user-information", "create-database-view", "update-maintenance-message", "delete-foreign-table", "offline_access", "modify-foreign-table-column-semantics", "delete-maintenance-message", "find-container", "insert-table-data", "modify-identifier-metadata", "modify-database-image", "escalated-broker-handling", "modify-table-column-semantics", "escalated-database-handling", "default-semantics-handling", "update-database-access", "default-query-handling", "find-table", "list-queries", "default-developer-roles", "create-identifier", "escalated-table-handling", "find-identifier", "view-table-data", "list-licenses", "default-table-handling", "list-identifiers", "create-foreign-identifier", "list-databases", "list-ontologies", "modify-database-visibility", "list-maintenance-messages", "delete-table" ] + }, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "143ba359-5fa2-451e-8296-43ecf20bb251", + "name" : "update-semantic-concept", + "description" : "${update-semantic-concept}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "5136d7a3-e3f0-4585-bacd-15cb8a56095c", + "name" : "escalated-container-handling", + "description" : "${escalated-container-handling}", + "composite" : true, + "composites" : { + "realm" : [ "create-container", "delete-container" ] + }, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "b0bc8649-7d84-4dd3-84f0-7f174425babe", + "name" : "list-tables", + "description" : "${list-tables}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "bfd85d9c-2772-4660-a8f0-cdc0cd8252b3", + "name" : "default-database-handling", + "description" : "${default-database-handling}", + "composite" : true, + "composites" : { + "realm" : [ "modify-database-image", "modify-database-owner", "update-database-access", "create-database", "list-databases", "create-database-access", "find-database", "modify-database-visibility", "import-database-data", "delete-database-access", "check-database-access" ] + }, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "74648f9a-777e-4ef9-b97b-4c5d749d862f", + "name" : "update-search-index", + "description" : "${update-search-index}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "22492b64-c633-48a0-9678-b28669f2885b", + "name" : "execute-semantic-query", + "description" : "${execute-semantic-query}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "4ed919fa-edc5-44e5-9411-607786e4a86d", + "name" : "view-table-history", + "description" : "${view-table-history}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "d89a2881-b642-4abb-b990-196e71372f6b", + "name" : "default-table-handling", + "description" : "${default-table-handling}", + "composite" : true, + "composites" : { + "realm" : [ "modify-table-column-semantics", "list-tables", "update-table-statistic", "find-table", "create-table", "delete-table" ] + }, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "b0d66d3d-59b4-4aae-aa66-e3d5a49f28e3", + "name" : "view-database-view-data", + "description" : "${view-database-view-data}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "f5ea431a-9b2c-4195-bcb4-9511f38e4b44", + "name" : "create-database-view", + "description" : "${create-database-view}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "a5ffc20e-8b11-498c-9f3b-b5740aec24c7", + "name" : "default-semantics-handling", + "description" : "${default-semantics-handling}", + "composite" : true, + "composites" : { + "realm" : [ "create-semantic-unit", "create-semantic-concept", "execute-semantic-query", "table-semantic-analyse" ] + }, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "fe4a01f3-6590-4df6-9ade-5a9c1fae4736", + "name" : "create-semantic-unit", + "description" : "${create-semantic-unit}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "0e12eedf-545d-4d32-ac4d-2821dcb118b8", + "name" : "update-table-statistic", + "description" : "${update-table-statistic}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "e63e61a2-d852-4ad3-bfb5-92d9ceafef6a", + "name" : "escalated-user-handling", + "description" : "${escalated-user-handling}", + "composite" : true, + "composites" : { + "realm" : [ "find-user" ] + }, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "be4e1aba-e276-4241-b6ea-01dce6c52f8b", + "name" : "find-container", + "description" : "${find-container}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "3a801b48-f3c2-4bc6-aa25-c7a91d5b32a7", + "name" : "default-researcher-roles", + "description" : "${default-researcher-roles}", + "composite" : true, + "composites" : { + "realm" : [ "default-table-handling", "default-semantics-handling", "default-container-handling", "default-query-handling", "default-user-handling", "default-database-handling", "default-broker-handling", "default-identifier-handling" ] + }, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "3d8104fb-8307-40f0-b4b2-c3e518957110", + "name" : "view-table-data", + "description" : "${view-table-data}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "fe71b907-7020-44ab-9964-da2b87264582", + "name" : "create-database", + "description" : "${create-database}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "e51b63c2-48dd-4bd6-95fb-d257d21b26ba", + "name" : "import-database-data", + "description" : "${import-database-data}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "1f0a9b13-c2b8-474c-bc08-59dbd71835a6", + "name" : "modify-database-image", + "description" : "${modify-database-image}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "a7ad038c-5c06-42fc-951c-15ac09d4df66", + "name" : "modify-database-owner", + "description" : "${modify-database-owner}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "c12c1f4e-186f-4153-a795-26e79fb623d6", + "name" : "create-ontology", + "description" : "${create-ontology}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "b60a5694-4099-4f7d-a7e9-4c433e0eb9c9", + "name" : "update-semantic-unit", + "description" : "${update-semantic-unit}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "e9854bbb-4580-4757-b1ae-305934173249", + "name" : "create-database-access", + "description" : "${create-database-access}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "50c604c1-7c6e-43f3-9c43-2398f5eff66e", + "name" : "list-databases", + "description" : "${list-databases}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "535f1484-4514-4d24-8d97-e3f6c11a426b", + "name" : "create-container", + "description" : "${create-container}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "f4116230-8642-4bb7-bbc8-db9c5c07b558", + "name" : "create-maintenance-message", + "description" : "${create-maintenance-message}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "973f0999-cc70-4b28-9f43-979c470bea8e", + "name" : "default-data-steward-roles", + "description" : "${default-data-steward-roles}", + "composite" : true, + "composites" : { + "realm" : [ "escalated-identifier-handling", "default-semantics-handling", "escalated-semantics-handling", "default-user-handling" ] + }, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "e1383fb7-d54c-4732-9146-93030eb2ca50", + "name" : "escalated-query-handling", + "description" : "${escalated-query-handling}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "993b5c69-9eb2-42af-ac28-b4a46c6b61f2", + "name" : "find-user", + "description" : "${find-user}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "e4cfdc4d-2373-477b-a8df-161db99aba00", + "name" : "create-foreign-identifier", + "description" : "${create-foreign-identifier}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "6a5872a5-2b51-415d-ae2d-25a6db4a35df", + "name" : "escalated-semantics-handling", + "description" : "${escalated-semantics-handling}", + "composite" : true, + "composites" : { + "realm" : [ "update-semantic-unit", "create-ontology", "update-ontology", "list-ontologies", "delete-ontology", "modify-foreign-table-column-semantics", "update-semantic-concept" ] + }, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "09147c48-273b-450b-8b11-7ef9b9245244", + "name" : "export-table-data", + "description" : "${export-table-data}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "d14af590-60a8-4d75-b864-40ee0165bd7f", + "name" : "delete-database-access", + "description" : "${delete-database-access}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "be051d45-cd74-4b13-8a45-f2d3351bd995", + "name" : "table-semantic-analyse", + "description" : "${table-semantic-analyse}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "272a79a7-e282-4261-8f7d-5d5d1364243a", + "name" : "update-maintenance-message", + "description" : "${update-maintenance-message}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "64c16bfb-2015-48ad-a23f-637ff24419cb", + "name" : "default-query-handling", + "description" : "${default-query-handling}", + "composite" : true, + "composites" : { + "realm" : [ "delete-database-view", "export-query-data", "execute-query", "delete-table-data", "export-table-data", "list-queries", "find-query", "list-database-views", "persist-query", "view-table-data", "re-execute-query", "view-table-history", "create-database-view", "find-database-view", "insert-table-data" ] + }, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "c047d521-cec3-4444-86c4-aef098489b7b", + "name" : "delete-maintenance-message", + "description" : "${delete-maintenance-message}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "88f82262-be80-4d18-9fb4-5529da031f33", + "name" : "system", + "description" : "${system}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "e14ab76b-1c24-484d-ae2d-478b8457edea", + "name" : "list-licenses", + "description" : "${list-licenses}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "d4f29937-3ca0-41e9-9786-2b7b921b6cdd", + "name" : "modify-foreign-table-column-semantics", + "description" : "${modify-foreign-table-column-semantics}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "8eda9f5c-938c-4915-bed5-6a81a1de15a8", + "name" : "list-database-views", + "description" : "${list-database-views}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "b372f8f7-d203-4293-b991-ad93fb505917", + "name" : "escalated-database-handling", + "description" : "${escalated-database-handling}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "abd2d9ee-ebc4-4d0a-839e-6b588a6d442a", + "name" : "default-roles-dbrepo", + "description" : "${role_default-roles}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "3293799a-82b9-4f47-8f25-1aad2e0222fd", + "name" : "find-identifier", + "description" : "${find-identifier}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "aaa3f804-38a0-4474-b8e9-f1020c4b3f62", + "name" : "list-queries", + "description" : "${list-queries}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "76e38f7b-99bf-4d12-8d74-1c7d8812f443", + "name" : "update-ontology", + "description" : "${update-ontology}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "11f7973e-d1eb-42cb-a35d-c59dfc122775", + "name" : "modify-user-theme", + "description" : "${modify-user-theme}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "f392bfcb-0be5-4fad-9ce4-8ac6396f176d", + "name" : "export-query-data", + "description" : "${export-query-data}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "da493b7e-fb9b-43ca-82a5-e274ad2e6b39", + "name" : "find-query", + "description" : "${find-query}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "a4d4a788-ebcf-4d32-baed-4a85616ca037", + "name" : "escalated-identifier-handling", + "description" : "${escalated-identifier-handling}", + "composite" : true, + "composites" : { + "realm" : [ "create-foreign-identifier", "modify-identifier-metadata" ] + }, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "ea38d69d-17b8-4c65-95e8-1c3501b83618", + "name" : "default-container-handling", + "description" : "${default-container-handling}", + "composite" : true, + "composites" : { + "realm" : [ "find-container", "list-containers" ] + }, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "8b8813e0-af07-4d04-a8c1-e3f37192bace", + "name" : "publish-identifier", + "description" : "${publish-identifier}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "47f5eee7-9821-4bf8-b434-0da1f81c3e5a", + "name" : "default-broker-handling", + "description" : "${default-broker-handling}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "71874bde-64a5-4a69-8685-d8998303a80c", + "name" : "delete-table-data", + "description" : "${delete-table-data}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "7c0306fc-3b03-4c64-87d1-9a34f2073977", + "name" : "modify-table-column-semantics", + "description" : "${modify-table-column-semantics}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "cd0ee04c-4a5e-4035-a11b-f6a1165f7829", + "name" : "delete-container", + "description" : "${delete-container}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "67ee39c0-d601-4a67-a0fe-c4f0021d557e", + "name" : "list-containers", + "description" : "${list-containers}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "795c7bb8-3502-414a-a97b-2ba1cfd6a79c", + "name" : "persist-query", + "description" : "${persist-query}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "d05e7698-ddf5-4f20-9027-771afb2cc3c7", + "name" : "list-identifiers", + "description" : "${list-identifiers}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "e4bfaf36-9a5d-43e0-9fa3-0f4ea7bad8d0", + "name" : "default-developer-roles", + "description" : "${default-developer-roles}", + "composite" : true, + "composites" : { + "realm" : [ "escalated-query-handling", "escalated-broker-handling", "default-table-handling", "escalated-database-handling", "default-container-handling", "default-query-handling", "default-user-handling", "default-database-handling", "default-maintenance-handling", "escalated-container-handling", "escalated-table-handling", "default-identifier-handling" ] + }, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "e2cb054e-ea41-4ab0-881b-e6f576f7424e", + "name" : "create-semantic-concept", + "description" : "${create-semantic-concept}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "feb612cc-96a6-4ed2-aaa5-01f39b25beb5", + "name" : "insert-table-data", + "description" : "${insert-table-data}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "a0942e33-441b-4343-9f02-4353d03f7bbb", + "name" : "find-database", + "description" : "${find-database}", + "composite" : false, + "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", + "description" : "${modify-database-visibility}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "4a5df51d-f14d-41a2-ad70-6521df5a5b4f", + "name" : "offline_access", + "description" : "${role_offline-access}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "fd41c4c3-d2f8-4f49-84c7-dba84e9a5575", + "name" : "execute-query", + "description" : "${execute-query}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "2963c2bb-b129-4224-b98f-c8eeab8e72d1", + "name" : "create-table", + "description" : "${create-table}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "0c487c93-448f-4a82-8b9f-ebd8a0904bf8", + "name" : "find-foreign-user", + "description" : "${find-foreign-user}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "cf9735a9-fb70-4cc5-b5f4-75afc4e5654b", + "name" : "modify-identifier-metadata", + "description" : "${modify-identifier-metadata}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "64c2b8f2-1527-4928-81ea-b2651512d028", + "name" : "delete-ontology", + "description" : "${delete-ontology}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "d6e38368-b40f-423b-82e4-e8aa595237c9", + "name" : "find-maintenance-message", + "description" : "${find-maintenance-message}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "fd1cc463-3e67-49d9-81b8-2cd90c1daa9c", + "name" : "check-database-access", + "description" : "${check-database-access}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "74013867-e426-46cc-ab98-2f4a9225ad1e", + "name" : "find-table", + "description" : "${find-table}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "a2cc60df-d280-46c5-a539-92e2aa249b4a", + "name" : "modify-user-information", + "description" : "${modify-user-information}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "c367241f-b5b5-491f-84d5-07fe1bef3877", + "name" : "default-identifier-handling", + "description" : "${default-identifier-handling}", + "composite" : true, + "composites" : { + "realm" : [ "delete-identifier", "list-identifiers", "create-identifier", "find-identifier", "publish-identifier" ] + }, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "ba1ad8f2-39aa-487d-987f-645e8a459559", + "name" : "delete-table", + "description" : "${delete-table}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "09f7bdb0-296f-46c8-a3a3-8f9254fb17e4", + "name" : "list-maintenance-messages", + "description" : "${list-maintenance-messages}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "fe3bc45c-61c2-4ece-bcaf-d410dc7de501", + "name" : "update-database-access", + "description" : "${update-database-access}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "f43e86ed-76de-4ca8-9b5e-c292c9359bfe", + "name" : "escalated-broker-handling", + "description" : "${escalated-broker-handling}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "916b1e65-f60c-42cd-96e4-5c98ffc1ba3c", + "name" : "uma_authorization", + "description" : "${role_uma_authorization}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "d1afa3ed-bf4f-469a-a061-ad7325fb8d9e", + "name" : "delete-database-view", + "description" : "${delete-database-view}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "6f044bad-6651-4408-bffa-20c2d8f92eee", + "name" : "create-identifier", + "description" : "${create-identifier}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "be91195a-e30a-4d15-a8da-0aca0a68782f", + "name" : "escalated-table-handling", + "description" : "${escalated-table-handling}", + "composite" : true, + "composites" : { + "realm" : [ "delete-foreign-table" ] + }, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "98bee7d6-d78c-4e7f-b6a3-3705968b248c", + "name" : "list-ontologies", + "description" : "${list-ontologies}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "15720c6b-027d-4d53-a0ff-0124bfab7c4c", + "name" : "re-execute-query", + "description" : "${re-execute-query}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "a9b5181a-8135-41d3-9862-ef80af42211d", + "name" : "delete-identifier", + "description" : "${delete-identifier}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + }, { + "id" : "469c2e63-cda6-48d4-ab8f-eb59a2c69798", + "name" : "find-database-view", + "description" : "${find-database-view}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } + } ], + "client" : { + "realm-management" : [ { + "id" : "4628f654-f8f3-483b-8f92-2a7fc5930b14", + "name" : "query-realms", + "description" : "${role_query-realms}", + "composite" : false, + "clientRole" : true, + "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", + "attributes" : { } + }, { + "id" : "95c2cc47-12f5-4d73-8b74-67e270c45ade", + "name" : "manage-authorization", + "description" : "${role_manage-authorization}", + "composite" : false, + "clientRole" : true, + "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", + "attributes" : { } + }, { + "id" : "824791f3-c345-42f8-b103-b7e6d7e40114", + "name" : "manage-identity-providers", + "description" : "${role_manage-identity-providers}", + "composite" : false, + "clientRole" : true, + "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", + "attributes" : { } + }, { + "id" : "1f840202-b7e2-4195-bac9-64e64dad2037", + "name" : "view-identity-providers", + "description" : "${role_view-identity-providers}", + "composite" : false, + "clientRole" : true, + "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", + "attributes" : { } + }, { + "id" : "3c32c096-bb13-44c9-a080-d756a48a9ea3", + "name" : "query-clients", + "description" : "${role_query-clients}", + "composite" : false, + "clientRole" : true, + "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", + "attributes" : { } + }, { + "id" : "e4b85a68-7f31-4fcf-89a2-f10d7df358e9", + "name" : "view-authorization", + "description" : "${role_view-authorization}", + "composite" : false, + "clientRole" : true, + "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", + "attributes" : { } + }, { + "id" : "7d317752-ae56-46f2-a2ce-67c64d1b35f6", + "name" : "view-users", + "description" : "${role_view-users}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-users", "query-groups" ] + } + }, + "clientRole" : true, + "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", + "attributes" : { } + }, { + "id" : "28824208-976e-4622-b4d7-3d18efbb46fa", + "name" : "realm-admin", + "description" : "${role_realm-admin}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-realms", "view-identity-providers", "manage-identity-providers", "manage-authorization", "query-clients", "view-authorization", "view-users", "manage-users", "view-realm", "query-users", "view-clients", "query-groups", "create-client", "manage-clients", "manage-events", "impersonation", "view-events", "manage-realm" ] + } + }, + "clientRole" : true, + "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", + "attributes" : { } + }, { + "id" : "57e846a2-930d-4621-819d-c35086507146", + "name" : "manage-users", + "description" : "${role_manage-users}", + "composite" : false, + "clientRole" : true, + "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", + "attributes" : { } + }, { + "id" : "7fad9cde-bf96-475a-9174-14a87da51f95", + "name" : "view-realm", + "description" : "${role_view-realm}", + "composite" : false, + "clientRole" : true, + "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", + "attributes" : { } + }, { + "id" : "bbcac294-d78a-4ea1-a4bf-0384266d2fe1", + "name" : "query-users", + "description" : "${role_query-users}", + "composite" : false, + "clientRole" : true, + "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", + "attributes" : { } + }, { + "id" : "480e1437-ab9e-47de-b47a-edc6b6e285de", + "name" : "view-clients", + "description" : "${role_view-clients}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-clients" ] + } + }, + "clientRole" : true, + "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", + "attributes" : { } + }, { + "id" : "b9a9a8f5-f91e-4e73-9e88-1cdf42bd49f9", + "name" : "create-client", + "description" : "${role_create-client}", + "composite" : false, + "clientRole" : true, + "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", + "attributes" : { } + }, { + "id" : "4d1397fb-247c-436f-b26f-124cd89afb08", + "name" : "query-groups", + "description" : "${role_query-groups}", + "composite" : false, + "clientRole" : true, + "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", + "attributes" : { } + }, { + "id" : "e31f522b-b283-4ae1-b875-52afcd98b1d2", + "name" : "impersonation", + "description" : "${role_impersonation}", + "composite" : false, + "clientRole" : true, + "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", + "attributes" : { } + }, { + "id" : "51822d02-fa28-4a49-89da-bc534719d8a8", + "name" : "manage-clients", + "description" : "${role_manage-clients}", + "composite" : false, + "clientRole" : true, + "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", + "attributes" : { } + }, { + "id" : "b2743ce5-0ce8-4157-ae00-f693560f0b39", + "name" : "manage-events", + "description" : "${role_manage-events}", + "composite" : false, + "clientRole" : true, + "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", + "attributes" : { } + }, { + "id" : "7ea3d7e0-9bf4-438a-b773-243daf622aaa", + "name" : "view-events", + "description" : "${role_view-events}", + "composite" : false, + "clientRole" : true, + "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", + "attributes" : { } + }, { + "id" : "fb73f6f5-0ed5-41d0-852c-0eb3b195b15a", + "name" : "manage-realm", + "description" : "${role_manage-realm}", + "composite" : false, + "clientRole" : true, + "containerId" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", + "attributes" : { } + } ], + "security-admin-console" : [ ], + "dbrepo-client" : [ ], + "admin-cli" : [ ], + "rabbitmq-client" : [ ], + "account-console" : [ ], + "broker" : [ { + "id" : "de0cfd5e-c2fe-4082-ac39-e3b092139a0f", + "name" : "read-token", + "description" : "${role_read-token}", + "composite" : false, + "clientRole" : true, + "containerId" : "88694c91-753d-4c44-9740-ec9ac06bba45", + "attributes" : { } + } ], + "account" : [ { + "id" : "acd78c04-eefc-4344-a5b4-3fc83d848936", + "name" : "delete-account", + "description" : "${role_delete-account}", + "composite" : false, + "clientRole" : true, + "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142", + "attributes" : { } + }, { + "id" : "939be844-8c49-45b3-9ca1-4b10a454b346", + "name" : "view-profile", + "description" : "${role_view-profile}", + "composite" : false, + "clientRole" : true, + "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142", + "attributes" : { } + }, { + "id" : "e52fdf00-3e73-4c17-bc1c-643493710a6b", + "name" : "view-applications", + "description" : "${role_view-applications}", + "composite" : false, + "clientRole" : true, + "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142", + "attributes" : { } + }, { + "id" : "b02a822e-a708-420a-bddc-1a315033fd7c", + "name" : "view-consent", + "description" : "${role_view-consent}", + "composite" : false, + "clientRole" : true, + "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142", + "attributes" : { } + }, { + "id" : "c590e5f5-2cbf-4151-b1dc-96c454f1f654", + "name" : "view-groups", + "description" : "${role_view-groups}", + "composite" : false, + "clientRole" : true, + "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142", + "attributes" : { } + }, { + "id" : "15974151-6c13-426b-8cc3-7683dd1311e1", + "name" : "manage-account-links", + "description" : "${role_manage-account-links}", + "composite" : false, + "clientRole" : true, + "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142", + "attributes" : { } + }, { + "id" : "c12d8d94-c2df-498e-bbe4-2f934a83ae92", + "name" : "manage-consent", + "description" : "${role_manage-consent}", + "composite" : true, + "composites" : { + "client" : { + "account" : [ "view-consent" ] + } + }, + "clientRole" : true, + "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142", + "attributes" : { } + }, { + "id" : "55f85811-bded-4d6b-8f7b-45844b963875", + "name" : "manage-account", + "description" : "${role_manage-account}", + "composite" : true, + "composites" : { + "client" : { + "account" : [ "manage-account-links" ] + } + }, + "clientRole" : true, + "containerId" : "e767a4a6-79e9-4e08-82b7-1076e1a09142", + "attributes" : { } + } ] + } + }, + "groups" : [ { + "id" : "f2ce17fe-7b15-47a4-bbf8-86f415298fa9", + "name" : "data-stewards", + "path" : "/data-stewards", + "subGroups" : [ ], + "attributes" : { }, + "realmRoles" : [ "default-data-steward-roles" ], + "clientRoles" : { } + }, { + "id" : "124d9888-0b6e-46aa-8225-077dcedaf16e", + "name" : "developers", + "path" : "/developers", + "subGroups" : [ ], + "attributes" : { }, + "realmRoles" : [ "default-developer-roles" ], + "clientRoles" : { } + }, { + "id" : "f467c38e-9041-4faa-ae0b-39cec65ff4db", + "name" : "researchers", + "path" : "/researchers", + "subGroups" : [ ], + "attributes" : { }, + "realmRoles" : [ "default-researcher-roles" ], + "clientRoles" : { } + }, { + "id" : "2b9f94b4-d434-4a98-8eab-25678cfee983", + "name" : "system", + "path" : "/system", + "subGroups" : [ ], + "attributes" : { }, + "realmRoles" : [ "default-system-roles" ], + "clientRoles" : { } + } ], + "defaultRole" : { + "id" : "abd2d9ee-ebc4-4d0a-839e-6b588a6d442a", + "name" : "default-roles-dbrepo", + "description" : "${role_default-roles}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0" + }, + "defaultGroups" : [ "/researchers" ], + "requiredCredentials" : [ "password" ], + "otpPolicyType" : "totp", + "otpPolicyAlgorithm" : "HmacSHA1", + "otpPolicyInitialCounter" : 0, + "otpPolicyDigits" : 6, + "otpPolicyLookAheadWindow" : 1, + "otpPolicyPeriod" : 30, + "otpPolicyCodeReusable" : false, + "otpSupportedApplications" : [ "totpAppFreeOTPName", "totpAppGoogleName", "totpAppMicrosoftAuthenticatorName" ], + "localizationTexts" : { }, + "webAuthnPolicyRpEntityName" : "keycloak", + "webAuthnPolicySignatureAlgorithms" : [ "ES256" ], + "webAuthnPolicyRpId" : "", + "webAuthnPolicyAttestationConveyancePreference" : "not specified", + "webAuthnPolicyAuthenticatorAttachment" : "not specified", + "webAuthnPolicyRequireResidentKey" : "not specified", + "webAuthnPolicyUserVerificationRequirement" : "not specified", + "webAuthnPolicyCreateTimeout" : 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister" : false, + "webAuthnPolicyAcceptableAaguids" : [ ], + "webAuthnPolicyExtraOrigins" : [ ], + "webAuthnPolicyPasswordlessRpEntityName" : "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms" : [ "ES256" ], + "webAuthnPolicyPasswordlessRpId" : "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference" : "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment" : "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey" : "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement" : "not specified", + "webAuthnPolicyPasswordlessCreateTimeout" : 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false, + "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ], + "webAuthnPolicyPasswordlessExtraOrigins" : [ ], + "scopeMappings" : [ { + "clientScope" : "rabbitmq.tag:administrator", + "roles" : [ "escalated-broker-handling" ] + }, { + "clientScope" : "rabbitmq.tag:management", + "roles" : [ "default-broker-handling" ] + } ], + "clientScopeMappings" : { + "account" : [ { + "client" : "account-console", + "roles" : [ "manage-account", "view-groups" ] + } ] + }, + "clients" : [ { + "id" : "e767a4a6-79e9-4e08-82b7-1076e1a09142", + "clientId" : "account", + "name" : "${client_account}", + "rootUrl" : "${authBaseUrl}", + "baseUrl" : "/realms/dbrepo/account/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/realms/dbrepo/account/*" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "post.logout.redirect.uris" : "+" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "d3c4a04e-39ce-4549-a34a-11e25774cd96", + "clientId" : "account-console", + "name" : "${client_account-console}", + "rootUrl" : "${authBaseUrl}", + "baseUrl" : "/realms/dbrepo/account/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/realms/dbrepo/account/*" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "post.logout.redirect.uris" : "+", + "pkce.code.challenge.method" : "S256" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "protocolMappers" : [ { + "id" : "22d90d9c-9881-474c-8dfd-a62c808a9f1c", + "name" : "audience resolve", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-audience-resolve-mapper", + "consentRequired" : false, + "config" : { } + } ], + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "81ef0f59-a5ca-4be4-a1d1-0c32edf1cfd6", + "clientId" : "admin-cli", + "name" : "${client_admin-cli}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : false, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "post.logout.redirect.uris" : "+" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "88694c91-753d-4c44-9740-ec9ac06bba45", + "clientId" : "broker", + "name" : "${client_broker}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : true, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "post.logout.redirect.uris" : "+" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "6b7ef364-4132-4831-b4e2-b6e9e9dc63ee", + "clientId" : "dbrepo-client", + "name" : "${dbrepo-client}", + "description" : "", + "rootUrl" : "", + "adminUrl" : "", + "baseUrl" : "", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : true, + "clientAuthenticatorType" : "client-secret", + "secret" : "MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG", + "redirectUris" : [ "*" ], + "webOrigins" : [ "*" ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : true, + "protocol" : "openid-connect", + "attributes" : { + "oidc.ciba.grant.enabled" : "false", + "client.secret.creation.time" : "1680085365", + "backchannel.logout.session.required" : "true", + "post.logout.redirect.uris" : "*", + "oauth2.device.authorization.grant.enabled" : "false", + "backchannel.logout.revoke.offline.tokens" : "false" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : true, + "nodeReRegistrationTimeout" : -1, + "protocolMappers" : [ { + "id" : "da0b27c1-ae2e-4baa-bf78-db233e15c78d", + "name" : "preferred_username", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "user.attribute" : "username", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "preferred_username", + "userinfo.token.claim" : "true" + } + }, { + "id" : "7c94de93-f60f-487b-b4b7-1891c67f74cc", + "name" : "aud", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-hardcoded-claim-mapper", + "consentRequired" : false, + "config" : { + "claim.value" : "dbrepo", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "aud", + "access.tokenResponse.claim" : "false" + } + }, { + "id" : "0b4c644f-0cf0-4794-8395-d5d83009dabe", + "name" : "uid", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "CUSTOM_ID", + "id.token.claim" : "true", + "lightweight.claim" : "false", + "access.token.claim" : "true", + "claim.name" : "uid", + "jsonType.label" : "String" + } + } ], + "defaultClientScopes" : [ "roles", "attributes" ], + "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ] + }, { + "id" : "25741f6b-4867-4138-8238-6345c6ba8702", + "clientId" : "rabbitmq-client", + "name" : "${rabbitmq-client}", + "description" : "", + "rootUrl" : "", + "adminUrl" : "", + "baseUrl" : "", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "secret" : "JEC2FexxrX4N65fLeDGukAl6R3Lc9y0u", + "redirectUris" : [ "*" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : true, + "protocol" : "openid-connect", + "attributes" : { + "oidc.ciba.grant.enabled" : "false", + "client.secret.creation.time" : "1680000860", + "backchannel.logout.session.required" : "true", + "post.logout.redirect.uris" : "*", + "oauth2.device.authorization.grant.enabled" : "false", + "backchannel.logout.revoke.offline.tokens" : "false" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : -1, + "protocolMappers" : [ { + "id" : "01a937ed-f0e8-4137-80f3-3be3c447f7fb", + "name" : "username", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "false", + "user.attribute" : "username", + "id.token.claim" : "false", + "access.token.claim" : "true", + "claim.name" : "client_id", + "jsonType.label" : "String" + } + }, { + "id" : "f1afc22d-f595-403b-ba2e-6ab19d98205e", + "name" : "Audience", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-hardcoded-claim-mapper", + "consentRequired" : false, + "config" : { + "claim.value" : "rabbitmq", + "userinfo.token.claim" : "false", + "id.token.claim" : "false", + "access.token.claim" : "true", + "claim.name" : "aud", + "access.tokenResponse.claim" : "false" + } + } ], + "defaultClientScopes" : [ "web-origins", "acr", "rabbitmq.tag:management" ], + "optionalClientScopes" : [ "rabbitmq.read:*/*", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "roles", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ] + }, { + "id" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", + "clientId" : "realm-management", + "name" : "${client_realm-management}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : true, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "post.logout.redirect.uris" : "+" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "f205c451-9524-4380-acc3-947f7ecb6b7c", + "clientId" : "security-admin-console", + "name" : "${client_security-admin-console}", + "rootUrl" : "${authAdminUrl}", + "baseUrl" : "/admin/dbrepo/console/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/admin/dbrepo/console/*" ], + "webOrigins" : [ "+" ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "post.logout.redirect.uris" : "+", + "pkce.code.challenge.method" : "S256" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "protocolMappers" : [ { + "id" : "c4d54410-3f22-4259-9571-94da2c43b752", + "name" : "locale", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "locale", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "locale", + "jsonType.label" : "String" + } + } ], + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + } ], + "clientScopes" : [ { + "id" : "69f4ecf0-4165-49ab-bf0d-38409b15b706", + "name" : "rabbitmq.tag:administrator", + "description" : "administrator", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "gui.order" : "", + "consent.screen.text" : "" + } + }, { + "id" : "7f6e9b44-e2eb-417d-b0fe-db820c9a6564", + "name" : "email", + "description" : "OpenID Connect built-in scope: email", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${emailScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "782819fe-ba5d-4ddb-9f95-cabb69d79c8d", + "name" : "email verified", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "emailVerified", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "email_verified", + "jsonType.label" : "boolean" + } + }, { + "id" : "ca613fc8-bbf2-4240-8b33-a1874f1559f3", + "name" : "email", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "email", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "email", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "b9da268f-6745-49dc-a764-3c54e385accc", + "name" : "profile", + "description" : "OpenID Connect built-in scope: profile", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${profileScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "84f0487a-1d7d-470c-9b8e-5835294ae235", + "name" : "username", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "username", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "preferred_username", + "jsonType.label" : "String" + } + }, { + "id" : "bbdcdb36-3ec0-443d-b1af-9993d40f0567", + "name" : "gender", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "gender", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "gender", + "jsonType.label" : "String" + } + }, { + "id" : "9faa870b-5491-4ce9-b27d-c9ce07d6a95e", + "name" : "birthdate", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "birthdate", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "birthdate", + "jsonType.label" : "String" + } + }, { + "id" : "f0e3c012-9523-4076-83ae-e466e2d08220", + "name" : "full name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-full-name-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "access.token.claim" : "true", + "userinfo.token.claim" : "true" + } + }, { + "id" : "f757d8ec-e181-429c-9287-9ad0600b061f", + "name" : "profile", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "profile", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "profile", + "jsonType.label" : "String" + } + }, { + "id" : "18cfbf4b-0a8e-45c7-a832-c0f72c92f3f3", + "name" : "updated at", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "updatedAt", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "updated_at", + "jsonType.label" : "long" + } + }, { + "id" : "841ea785-26ab-429a-a420-09ce3948924d", + "name" : "family name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "lastName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "family_name", + "jsonType.label" : "String" + } + }, { + "id" : "bfba13ff-f952-4e89-bbb1-a693fdebfae8", + "name" : "website", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "website", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "website", + "jsonType.label" : "String" + } + }, { + "id" : "475f071d-5149-4379-b928-76482f5f519c", + "name" : "zoneinfo", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "zoneinfo", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "zoneinfo", + "jsonType.label" : "String" + } + }, { + "id" : "b8bebfed-b5e9-4604-a0ee-9817f7d439ac", + "name" : "middle name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "middleName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "middle_name", + "jsonType.label" : "String" + } + }, { + "id" : "445232c8-6830-476c-a6f1-8bbef167595a", + "name" : "picture", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "picture", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "picture", + "jsonType.label" : "String" + } + }, { + "id" : "65f2e474-6ede-4872-86e4-e49504dd0f2a", + "name" : "locale", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "locale", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "locale", + "jsonType.label" : "String" + } + }, { + "id" : "16cd5a27-ccf3-453c-ae1e-8621813ab73c", + "name" : "given name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "firstName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "given_name", + "jsonType.label" : "String" + } + }, { + "id" : "f9efedfc-3388-457c-b10a-1dff4525ff9b", + "name" : "nickname", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "nickname", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "nickname", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "627fa054-08eb-4206-af71-9e838e984b8b", + "name" : "microprofile-jwt", + "description" : "Microprofile - JWT built-in scope", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "e6cc53e5-5d7e-468e-88c8-0737dd3dc759", + "name" : "groups", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-realm-role-mapper", + "consentRequired" : false, + "config" : { + "multivalued" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "foo", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "groups", + "jsonType.label" : "String" + } + }, { + "id" : "83b4444c-10fc-44e8-a0c0-0c1da1f9bba3", + "name" : "upn", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "username", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "upn", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "4122ff9e-ad3c-4142-afc6-9aefdecfc86d", + "name" : "role_list", + "description" : "SAML role list", + "protocol" : "saml", + "attributes" : { + "consent.screen.text" : "${samlRoleListScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "bb0747fa-c008-4af3-93be-e7739650ebd5", + "name" : "role list", + "protocol" : "saml", + "protocolMapper" : "saml-role-list-mapper", + "consentRequired" : false, + "config" : { + "single" : "false", + "attribute.nameformat" : "Basic", + "attribute.name" : "Role" + } + } ] + }, { + "id" : "2e76447d-fbe7-4fa7-a16c-54a381b960ae", + "name" : "rabbitmq.configure:*/*", + "description" : "", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "false", + "gui.order" : "", + "consent.screen.text" : "" + } + }, { + "id" : "52aad832-c6c4-49df-8a04-6ad4a406fdfa", + "name" : "phone", + "description" : "OpenID Connect built-in scope: phone", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${phoneScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "dae802fb-9138-408a-b80e-a40eb0f56814", + "name" : "phone number", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "phoneNumber", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "phone_number", + "jsonType.label" : "String" + } + }, { + "id" : "feb06a8d-b0eb-4911-8464-368d93f566fa", + "name" : "phone number verified", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "phoneNumberVerified", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "phone_number_verified", + "jsonType.label" : "boolean" + } + } ] + }, { + "id" : "f64d64e8-57ce-4eb2-b99e-9f02fdbd99f9", + "name" : "web-origins", + "description" : "OpenID Connect scope for add allowed web origins to the access token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false", + "consent.screen.text" : "" + }, + "protocolMappers" : [ { + "id" : "c6411e3b-6478-453d-b530-5fe175a4d786", + "name" : "allowed web origins", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-allowed-origins-mapper", + "consentRequired" : false, + "config" : { } + } ] + }, { + "id" : "55341d34-0086-4173-ae61-d9b175b179d8", + "name" : "acr", + "description" : "OpenID Connect scope for add acr (authentication context class reference) to the token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "58ea3217-0fff-4207-9d08-919f5493b629", + "name" : "acr loa level", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-acr-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "access.token.claim" : "true", + "userinfo.token.claim" : "true" + } + } ] + }, { + "id" : "a02c2c38-923c-46ec-9899-321412b388e5", + "name" : "attributes", + "description" : "User Attributes", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false", + "gui.order" : "", + "consent.screen.text" : "" + }, + "protocolMappers" : [ { + "id" : "78c461c1-f3f9-4d10-8835-097f13bdcd60", + "name" : "Theme", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "aggregate.attrs" : "false", + "multivalued" : "false", + "userinfo.token.claim" : "true", + "user.attribute" : "theme_dark", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "attributes.theme_dark" + } + } ] + }, { + "id" : "06062e22-89c0-4e1d-a25b-2483903b02d5", + "name" : "rabbitmq.write:*/*", + "description" : "", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "false", + "gui.order" : "", + "consent.screen.text" : "" + } + }, { + "id" : "db63e03b-7918-492f-997b-f2dda98f3b39", + "name" : "rabbitmq.tag:management", + "description" : "management", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "gui.order" : "", + "consent.screen.text" : "" + } + }, { + "id" : "210cc792-6c07-45a6-a77e-827cdf3b41ba", + "name" : "offline_access", + "description" : "OpenID Connect built-in scope: offline_access", + "protocol" : "openid-connect", + "attributes" : { + "consent.screen.text" : "${offlineAccessScopeConsentText}", + "display.on.consent.screen" : "true" + } + }, { + "id" : "425abf4a-2ee2-431d-aa92-e373a36fe556", + "name" : "address", + "description" : "OpenID Connect built-in scope: address", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${addressScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "8d4ffe4d-1d01-4ca1-8ff4-44eacca61b30", + "name" : "address", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-address-mapper", + "consentRequired" : false, + "config" : { + "user.attribute.formatted" : "formatted", + "user.attribute.country" : "country", + "user.attribute.postal_code" : "postal_code", + "userinfo.token.claim" : "true", + "user.attribute.street" : "street", + "id.token.claim" : "true", + "user.attribute.region" : "region", + "access.token.claim" : "true", + "user.attribute.locality" : "locality" + } + } ] + }, { + "id" : "c96f0b73-ea79-4b46-93ef-d1092297f855", + "name" : "rabbitmq.read:*/*", + "description" : "", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "false", + "gui.order" : "", + "consent.screen.text" : "" + } + }, { + "id" : "37f61543-dad7-4a82-8e10-77acdd1eefdc", + "name" : "roles", + "description" : "OpenID Connect scope for add user roles to the access token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${rolesScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "3b6b6914-8ad1-4a71-88ec-444f754aaacb", + "name" : "audience resolve", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-audience-resolve-mapper", + "consentRequired" : false, + "config" : { } + }, { + "id" : "2defedf5-9af3-4531-822c-a879dedcd29d", + "name" : "realm roles", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-realm-role-mapper", + "consentRequired" : false, + "config" : { + "user.attribute" : "foo", + "access.token.claim" : "true", + "claim.name" : "realm_access.roles", + "jsonType.label" : "String", + "multivalued" : "true" + } + }, { + "id" : "a7bd6723-e58e-47f7-95c0-2925ce99283d", + "name" : "client roles", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-client-role-mapper", + "consentRequired" : false, + "config" : { + "user.attribute" : "foo", + "access.token.claim" : "true", + "claim.name" : "resource_access.${client_id}.roles", + "jsonType.label" : "String", + "multivalued" : "true" + } + } ] + } ], + "defaultDefaultClientScopes" : [ "rabbitmq.tag:administrator", "rabbitmq.tag:management" ], + "defaultOptionalClientScopes" : [ "rabbitmq.write:*/*", "offline_access", "rabbitmq.configure:*/*", "roles", "role_list", "address", "phone", "acr", "microprofile-jwt", "email", "attributes", "profile", "rabbitmq.read:*/*", "web-origins" ], + "browserSecurityHeaders" : { + "contentSecurityPolicyReportOnly" : "", + "xContentTypeOptions" : "nosniff", + "referrerPolicy" : "no-referrer", + "xRobotsTag" : "none", + "xFrameOptions" : "SAMEORIGIN", + "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection" : "1; mode=block", + "strictTransportSecurity" : "max-age=31536000; includeSubDomains" + }, + "smtpServer" : { }, + "eventsEnabled" : false, + "eventsListeners" : [ "jboss-logging" ], + "enabledEventTypes" : [ "SEND_RESET_PASSWORD", "UPDATE_CONSENT_ERROR", "GRANT_CONSENT", "VERIFY_PROFILE_ERROR", "REMOVE_TOTP", "REVOKE_GRANT", "UPDATE_TOTP", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "IMPERSONATE_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "OAUTH2_DEVICE_CODE_TO_TOKEN_ERROR", "RESTART_AUTHENTICATION", "IMPERSONATE", "UPDATE_PROFILE_ERROR", "LOGIN", "OAUTH2_DEVICE_VERIFY_USER_CODE", "UPDATE_PASSWORD_ERROR", "CLIENT_INITIATED_ACCOUNT_LINKING", "TOKEN_EXCHANGE", "AUTHREQID_TO_TOKEN", "LOGOUT", "REGISTER", "DELETE_ACCOUNT_ERROR", "CLIENT_REGISTER", "IDENTITY_PROVIDER_LINK_ACCOUNT", "DELETE_ACCOUNT", "UPDATE_PASSWORD", "CLIENT_DELETE", "FEDERATED_IDENTITY_LINK_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN", "CLIENT_DELETE_ERROR", "VERIFY_EMAIL", "CLIENT_LOGIN_ERROR", "RESTART_AUTHENTICATION_ERROR", "EXECUTE_ACTIONS", "REMOVE_FEDERATED_IDENTITY_ERROR", "TOKEN_EXCHANGE_ERROR", "PERMISSION_TOKEN", "SEND_IDENTITY_PROVIDER_LINK_ERROR", "EXECUTE_ACTION_TOKEN_ERROR", "SEND_VERIFY_EMAIL", "OAUTH2_DEVICE_AUTH", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "OAUTH2_DEVICE_CODE_TO_TOKEN", "IDENTITY_PROVIDER_POST_LOGIN", "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR", "OAUTH2_DEVICE_VERIFY_USER_CODE_ERROR", "UPDATE_EMAIL", "REGISTER_ERROR", "REVOKE_GRANT_ERROR", "EXECUTE_ACTION_TOKEN", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "CLIENT_UPDATE_ERROR", "AUTHREQID_TO_TOKEN_ERROR", "UPDATE_PROFILE", "CLIENT_REGISTER_ERROR", "FEDERATED_IDENTITY_LINK", "SEND_IDENTITY_PROVIDER_LINK", "SEND_VERIFY_EMAIL_ERROR", "RESET_PASSWORD", "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR", "OAUTH2_DEVICE_AUTH_ERROR", "UPDATE_CONSENT", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "SEND_RESET_PASSWORD_ERROR", "CLIENT_UPDATE", "CUSTOM_REQUIRED_ACTION_ERROR", "IDENTITY_PROVIDER_POST_LOGIN_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN", "VERIFY_PROFILE", "GRANT_CONSENT_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR" ], + "adminEventsEnabled" : false, + "adminEventsDetailsEnabled" : false, + "identityProviders" : [ ], + "identityProviderMappers" : [ ], + "components" : { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ { + "id" : "4d3f9f14-f5d2-4b0c-8ea7-e6d078aa2191", + "name" : "Max Clients Limit", + "providerId" : "max-clients", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "max-clients" : [ "200" ] + } + }, { + "id" : "f35bce67-1e75-408b-b065-52183368d4fd", + "name" : "Allowed Client Scopes", + "providerId" : "allowed-client-templates", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "allow-default-scopes" : [ "true" ] + } + }, { + "id" : "0efa669d-1017-4b4a-82e1-c2eaf72de2c9", + "name" : "Allowed Client Scopes", + "providerId" : "allowed-client-templates", + "subType" : "authenticated", + "subComponents" : { }, + "config" : { + "allow-default-scopes" : [ "true" ] + } + }, { + "id" : "528fb423-d66e-472e-9120-1f03ba9e0f18", + "name" : "Consent Required", + "providerId" : "consent-required", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { } + }, { + "id" : "3ab11d74-5e76-408a-b85a-26bf8950f979", + "name" : "Allowed Protocol Mapper Types", + "providerId" : "allowed-protocol-mappers", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper", "saml-role-list-mapper" ] + } + }, { + "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1", + "name" : "Trusted Hosts", + "providerId" : "trusted-hosts", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "host-sending-registration-request-must-match" : [ "true" ], + "client-uris-must-match" : [ "true" ] + } + }, { + "id" : "f565cb47-3bcf-4078-8f94-eb4179c375b8", + "name" : "Full Scope Disabled", + "providerId" : "scope", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { } + }, { + "id" : "104ec5a9-025b-4c44-8ac0-82d22887ca3e", + "name" : "Allowed Protocol Mapper Types", + "providerId" : "allowed-protocol-mappers", + "subType" : "authenticated", + "subComponents" : { }, + "config" : { + "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-full-name-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper" ] + } + } ], + "org.keycloak.userprofile.UserProfileProvider" : [ { + "id" : "fb763636-e1ea-49c7-adca-ea105cdec4ad", + "providerId" : "declarative-user-profile", + "subComponents" : { }, + "config" : { + "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}],\"unmanagedAttributePolicy\":\"ENABLED\"}" ] + } + } ], + "org.keycloak.keys.KeyProvider" : [ { + "id" : "2f53ccf3-37b0-4d34-83e7-ed497499ee51", + "name" : "rsa-enc-generated", + "providerId" : "rsa-enc-generated", + "subComponents" : { }, + "config" : { + "privateKey" : [ "MIIEowIBAAKCAQEA3b1tNLfcjFLUw9UShVDNf+ZD8sQqb4YBaIXcSJTX/zDQUPiCp176BBGI3s4VplDArnOW+LumozmKogeoHEnGEIDW8ovgK5uMU9tSA2p0qqGBUMOdR8YATTIfCJe7qGiiuGa3WZy3sQLM70SuRzx02YU8gvUcvl2Js4KyqAziOUX/w3Wa59H9jjGNUXYyqaPWJp73eHzbVYWySzyLG22mVlcUtBx5siL5T2/Xu0p9z4l7/bapwwmOVi1ZrcHjbEAwdGEiSMGI/uWqAF+r1BRpmJLR7HNXcL3eK4/56VYLaiwSejfyYeRFMITEn/UxGYhcXZ5xMUUCG0TxjBhLYpTBuwIDAQABAoIBAA4dwebcxkrH99Poa8+WkiE7JgaS9sahx9OBI2xwJANoIU2TpzGuNLQZ76uLgB+rPWZTD9Xm5a1iJjwOyQ9/937TzPCk91D0tpgcusRikb8jx/6TGB9acL4kBjYUVCCHr3BA2G75MKKGtJ2OMvAbCQSosZj+r2VDwYFEPUkV2jheE5JHSBkwyIRrus3JCwu8gu5fyCg9z8ljcxJxI5HIsi4v8Z21aCw/cLj7h5cMt44wCjQz4rOfYNBEFeHDtlfR1QtWKgjm4ZHHJbKrzf9b2kQXclziceEbSM0tYbROEXKi+s0Zc+z3HEG89vv0vfN400clmzzIAijKY6gg3pPRWdECgYEA+lnWYbSlXDMNYx6RBXm1RnlMUYIm4oy4/9ljgnoGJ6WCn3SjFkgaDtiKfGIG1BSB85r04pAPANgcWHf5tWDnq0ARvBVG0BX2bKd++7B3D4d3CRYKCwm88SslJXv9dfHVhq4+zViFPiUWwT20A72jCuUCvL88y5fh/YBecfdh+jECgYEA4r5RD0NB9dMaeg5/jk/GEHIo4Z9KLc6FrSoOFo2xFkPOy1sgDpDOiNtypuWvniO7k7Ose3DS3hlfTMsKzIW/CgQJ20+Y4cvBWDaOsRxfjj7w3d+jH5OSJdKKSzTrgLKc9ZhlRzVXy0J0hipIA6HG5kdVdLXmh85ITmf1CbJhE6sCgYBjPVeBNbXTHZ2x6/z62aslO5IoQVqetb/kE82hfDOSZcao5Ph9Lam+ttH2ynkAevykj4mBgi+gWwqpey2uW7KaLPSaxShj9kDQA3mP1fzsV/u0y1rB02Nlin/YIxVvOqU1FT9p8SwoXVVu1sHUNck62VtDbN9xqUx5S/ikXrclEQKBgQCoTssOwEcK+Vty9KYcdfy4onTUHZBLdjxl8Iyqkxy7QTQUYRznkvesQPDXEDGO+kk3dyx2KKZt9Hl4IFNww2quPZcvcuMx4DQxjbXXpA8OIIxcta95NepLJwA+mRai3nKCH1A2TlNP7pFeMa5o+8IPly3Ix2lKr4Wepa4PN5i1pwKBgCZ1QP6XAOERl9NznNmU0rXVcvYNP4PIIfQWfvGsldZ4QKkmjjAGiS0/oYqdWs+UDRZyCRChaVjDXO9fk0PEG5OGKAj9nyiYCT/M8xtJ3UeP5ffZZvJ/vnye3QdDIo1e38ZzsWwJHmLYw7fRqY9W5Vxo0Vsy22U3CJY70KTxVdTy" ], + "keyUse" : [ "ENC" ], + "certificate" : [ "MIICmzCCAYMCBgGG3GWycDANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZkYnJlcG8wHhcNMjMwMzEzMTkxMzE3WhcNMzMwMzEzMTkxNDU3WjARMQ8wDQYDVQQDDAZkYnJlcG8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDdvW00t9yMUtTD1RKFUM1/5kPyxCpvhgFohdxIlNf/MNBQ+IKnXvoEEYjezhWmUMCuc5b4u6ajOYqiB6gcScYQgNbyi+Arm4xT21IDanSqoYFQw51HxgBNMh8Il7uoaKK4ZrdZnLexAszvRK5HPHTZhTyC9Ry+XYmzgrKoDOI5Rf/DdZrn0f2OMY1RdjKpo9Ymnvd4fNtVhbJLPIsbbaZWVxS0HHmyIvlPb9e7Sn3PiXv9tqnDCY5WLVmtweNsQDB0YSJIwYj+5aoAX6vUFGmYktHsc1dwvd4rj/npVgtqLBJ6N/Jh5EUwhMSf9TEZiFxdnnExRQIbRPGMGEtilMG7AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAK3kQ1VkQrzvSWvmXmazmNoA1ZiPzRDs1XhGUWxgsxzgPylr3dGBuqQbKvgnLUBQLSqlJHpI4fZflHswu1qrvVZYtekPcGef4WhcKAu2i1RwxrKa6RJQ1tRbrLuVYCzPv5p/DWgltWVn88aoLnqQn0SK/0PB/o4a4Cm7Kq2ZzCr1dACBr06LvOHsc7249OySmbG4HH+pLK6jVURhZ9VaObqAHe2FJBVVoIzURbdiRRURqumrIvbnpeaU1aFyg6ED5wTnXvmMPmVPt9F79mcB33bASO5wyu00X8t1hyN2Show2l2vxLACGUzVkTQt15s7uDLKE7qLmKSR3EuSGXWv3wA=" ], + "priority" : [ "100" ], + "algorithm" : [ "RSA-OAEP" ] + } + }, { + "id" : "230cb681-9ceb-4b1b-8a4c-929a11b08de0", + "name" : "hmac-generated-hs512", + "providerId" : "hmac-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "8a489935-9a95-459b-9059-59b438ef0fa8" ], + "secret" : [ "xSCVgBlrLPWoF54gKQdR7BqXlfNaCD43xtS_ZgQRC0tGNAbqhy2Q9y8LdD2IR7K__8VGaDGYtyZayopgTebhDBb4gHDjDOBX7flhFYRrm0G3aTIuCIyFG-bPULwmyP_oHeC6tjwdQhqx5G0tE2mQQqPC9dDZuUA5I7QREIGK8cI" ], + "priority" : [ "100" ], + "algorithm" : [ "HS512" ] + } + }, { + "id" : "28ca0b6d-b2e2-4785-b04b-2391e6344e30", + "name" : "aes-generated", + "providerId" : "aes-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "6dc4834f-a1de-4cfe-a29d-e84ac8e9b1a8" ], + "secret" : [ "HpuzG_jWYKwypLeoPEMC4A" ], + "priority" : [ "100" ] + } + }, { + "id" : "bd7945cf-6d35-4e03-9c3a-197f2dc76973", + "name" : "hmac-generated", + "providerId" : "hmac-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "5034d264-cb50-4006-a59e-2ce636eb5f38" ], + "secret" : [ "ToVIw-a4IE-Yp9JpP8ztb8NAICYO8CT3tUiDPT6DdiBcgzKJ9Ym9vspxGVdmPceX3mAgbnGLAcTx1PkInSVrbZs-tX9QXFwdlyGbewhKiNpH8wEg32Wk4GuUDpTv8JCsymgWyQBY681jvIMv05eCoK2QWpqCzcgP828KM5peCzo" ], + "priority" : [ "100" ], + "algorithm" : [ "HS256" ] + } + }, { + "id" : "2293ff99-3c6d-46d1-8635-5e679d5b134a", + "name" : "rsa-generated", + "providerId" : "rsa-generated", + "subComponents" : { }, + "config" : { + "privateKey" : [ "MIIEpAIBAAKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQABAoIBADNcMt6hAHub4JTAYS6Mra0EPRBO2XhWmACBrv3+8ETClXd5475KPLDewgRVtlmtbwU8G8awUXESQgPS9lfiqvQhPreA3cHlm6oP2WMKOEtakr2s8I+frsTBLCo0Ini9RaSzjoVVgS0zofyhASKi+T970MafSj5P3XNb8YBFdXgoYDiA7FXLH6a/+m7LScL+wGcFMAAeYESxZbMQLfH3v8L+4EcTraiwjLG17ZdlF3dpybMyUSse6ZQ/PdlyvBuzzLXhN6Ce2gd9ATfS+YWTzo7Yf+GU+ex5bIpVOfHqtuM/hyq7YGKENClsXwNZIAoFnvGCbvECAfgyapVrD30IfykCgYEA0rgsSZ82pxT40NxwgBD1g9lbNVBKXphRB/3S078qusUzJjT7AldEj4imGPhAbI7bI8gAeWJsp1XJWkjM8ktaVrh+NQl7p8e9OPh0pQF/5Bdg8ajbjXESpjnaU66pVYRQy/d+jNli/YRAHX5RUfsBl+6W4+WSVMGmKBiqJsur+ecCgYEAz1YVXClcmUnyZem5B+2E9noIzjF6ROE+jIb6rawM85P3Xd0lXtECQavtxw+Qk7I32qOwrxl1UpK2foVel3pazi+4OpMfmqtYGenRP1Zk1cZwrDo0cIemTDGjj3kJ8tYn12CGolFQpJZgK6OHzvG0tOxI5VZgjIViWNPe1PGWXtUCgYEAxXGNDe8BZs1f11S2lUlOw5yGug3hoYFXbAWJ5p7Ziuf8ZXB/QlJDC7se54a11wKEk6Jzz0lKRgE8CjzszJuOqnN0zn10QGIIC7nCklo1W6QMUmPGVWH994N976tZP6gbjQL6sT+AYcvpx7j0ubxYYeRNvnz+ACzzY964kGGHY0ECgYEAumlwPPNnMN7+VEjGNm2D7UMdJZ3wi3tkjF5ThdA5uMohTsAk+FG80KSu3RmOaGyEsUwY7+VYyYvlDm4E9PZqLBVVczyR3rMNPAcwPd0EPfvzk7WlLkOX7ct3fehaXH3VRlyfz9KCSeh1wOZ/lT1VtpD2nVOC7PSDzs92+kfXZZ0CgYAnrD1y4skgXkdwolZ3unn3EFyGm2d+X5aMTHwQPdWxqoNIAl/9wdghlzihwnPhhsxq1WzlxuC3V2IMrNPtRx70Mi+FbSmR5m4Xx5RptgMtMlwno+L40PzNJgMjHGjt0wcx3Vel8wuohDtnqMyS7P5nG1/TQx0Cyzwn7QOXlNpgbQ==" ], + "keyUse" : [ "SIG" ], + "certificate" : [ "MIICmzCCAYMCBgGG3GWyBTANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZkYnJlcG8wHhcNMjMwMzEzMTkxMzE3WhcNMzMwMzEzMTkxNDU3WjARMQ8wDQYDVQQDDAZkYnJlcG8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqqcdDYFZZb28M0tEJzEP77FmD/Xqioyj9zWX6VwUSOMAgmMmn8eqs9hT9T0a+q4YTo9tUW1PNbUpwprA5b4Uk04DcIajxDVMUR/PjcHytmkqwVskq9AZW/Vngdoo+8tSbuIybwe/3Vwt266hbHpDcM97a+DXcYooRl7tQWCEX7RP27wQrMD9epDQ6IgKayZg9vC9/03dsIqwH9jXQRiZlFvwiEKhX2aY7lPGBaCK414JO00K/Z49iov9TRa/IYVbSt5qwgrx6DcqsBSPwOnI6A85UGfeUEZ/7coVJiL7RvBlsllapsL9eWTbQajVh94k9Ei3sibEPbtH+U2OAM78zAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAASnN1Cuif1sdfEK2kWAURSXGJCohCROLWdKFjaeHPRaEfpbFJsgxW0Yj3nwX5O3bUlOWoTyENwnXSsXMQsqnNi+At32CKaKO8+AkhAbgQL9F0B+KeJwmYv3cUj5N/LYkJjBvZBzUZ4Ugu5dcxH0k7AktLAIwimkyEnxTNolOA3UyrGGpREr8MCKWVr10RFuOpF/0CsJNNwbHXzalO9D756EUcRWZ9VSg6QVNso0YYRKTnILWDn9hcTRnqGy3SHo3anFTqQZ+BB57YbgFWy6udC0LYRB3zdp6zNti87eu/VEymiDY/mmo1AB8Tm0b6vxFz4AKcL3ax5qS6YnZ9efSzk=" ], + "priority" : [ "100" ] + } + } ] + }, + "internationalizationEnabled" : false, + "supportedLocales" : [ ], + "authenticationFlows" : [ { + "id" : "88e5d526-2298-413c-a904-133ad839d47f", + "alias" : "Account verification options", + "description" : "Method with which to verity the existing account", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-email-verification", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "ALTERNATIVE", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Verify Existing Account by Re-authentication", + "userSetupAllowed" : false + } ] + }, { + "id" : "a690c715-fbae-4c20-b680-bd4010718761", + "alias" : "Browser - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "auth-otp-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "ad6d407e-c73e-4439-baf3-d7c99c6cb6ad", + "alias" : "Direct Grant - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "direct-grant-validate-otp", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "e5d03405-e10a-408a-adb2-41dbb4f24515", + "alias" : "First broker login - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "auth-otp-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "96b93843-62d0-44f1-84dd-21cc5f95f523", + "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", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-confirm-link", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Account verification options", + "userSetupAllowed" : false + } ] + }, { + "id" : "088f4051-36ab-4952-a4f2-4ba53c408083", + "alias" : "Reset - Conditional OTP", + "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "reset-otp", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "05f37bb2-779d-4e3f-ad1b-f6eb33bb3de4", + "alias" : "User creation or linking", + "description" : "Flow for the existing/non-existing user alternatives", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticatorConfig" : "create unique user config", + "authenticator" : "idp-create-user-if-unique", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "ALTERNATIVE", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Handle Existing Account", + "userSetupAllowed" : false + } ] + }, { + "id" : "300a5647-7d2c-4348-9f1f-51504bfda1c4", + "alias" : "Verify Existing Account by Re-authentication", + "description" : "Reauthentication of existing account", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-username-password-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "First broker login - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "26afc672-314b-4ad9-9711-7aaeafd7c00c", + "alias" : "browser", + "description" : "browser based authentication", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "auth-cookie", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "auth-spnego", + "authenticatorFlow" : false, + "requirement" : "DISABLED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "identity-provider-redirector", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 25, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "ALTERNATIVE", + "priority" : 30, + "autheticatorFlow" : true, + "flowAlias" : "forms", + "userSetupAllowed" : false + } ] + }, { + "id" : "9b301f6c-eda7-4da0-ba09-1a6454ff910d", + "alias" : "clients", + "description" : "Base authentication for clients", + "providerId" : "client-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "client-secret", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "client-jwt", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "client-secret-jwt", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 30, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "client-x509", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 40, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "6e54f1be-dbad-4b6d-8eee-8e048d413c63", + "alias" : "direct grant", + "description" : "OpenID Connect Resource Owner Grant", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "direct-grant-validate-username", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "direct-grant-validate-password", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 30, + "autheticatorFlow" : true, + "flowAlias" : "Direct Grant - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "31da4b94-03c4-4d79-9ac3-5df1445c0781", + "alias" : "docker auth", + "description" : "Used by Docker clients to authenticate against the IDP", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "docker-http-basic-authenticator", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "2e16651d-681f-4d9b-9dd4-9acdb465cd43", + "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", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticatorConfig" : "review profile config", + "authenticator" : "idp-review-profile", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "User creation or linking", + "userSetupAllowed" : false + } ] + }, { + "id" : "da109a26-fefa-48a4-ae8e-1d49627c2db8", + "alias" : "forms", + "description" : "Username, password, otp and other auth forms.", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "auth-username-password-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Browser - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "4c983c77-241f-41c5-8b8a-e2cd6fc08914", + "alias" : "registration", + "description" : "registration flow", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "registration-page-form", + "authenticatorFlow" : true, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : true, + "flowAlias" : "registration form", + "userSetupAllowed" : false + } ] + }, { + "id" : "d62c8dd6-633c-408a-aa99-43071510efb4", + "alias" : "registration form", + "description" : "registration form", + "providerId" : "form-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "registration-user-creation", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "registration-password-action", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 50, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "registration-recaptcha-action", + "authenticatorFlow" : false, + "requirement" : "DISABLED", + "priority" : 60, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "c8ca5be7-e76d-4e16-b5ca-3ced99d92dbb", + "alias" : "reset credentials", + "description" : "Reset credentials for a user if they forgot their password or something", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "reset-credentials-choose-user", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "reset-credential-email", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "reset-password", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 30, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 40, + "autheticatorFlow" : true, + "flowAlias" : "Reset - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "389c1c37-e8af-4610-a507-e1257f55b954", + "alias" : "saml ecp", + "description" : "SAML ECP Profile Authentication Flow", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "http-basic-authenticator", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + } ], + "authenticatorConfig" : [ { + "id" : "d66ca9d0-1645-4c84-abfe-c0a696f17de4", + "alias" : "create unique user config", + "config" : { + "require.password.update.after.registration" : "false" + } + }, { + "id" : "061cc6b8-90be-4423-9bf9-974ead709b5d", + "alias" : "review profile config", + "config" : { + "update.profile.on.first.login" : "missing" + } + } ], + "requiredActions" : [ { + "alias" : "CONFIGURE_TOTP", + "name" : "Configure OTP", + "providerId" : "CONFIGURE_TOTP", + "enabled" : true, + "defaultAction" : false, + "priority" : 10, + "config" : { } + }, { + "alias" : "TERMS_AND_CONDITIONS", + "name" : "Terms and Conditions", + "providerId" : "TERMS_AND_CONDITIONS", + "enabled" : false, + "defaultAction" : false, + "priority" : 20, + "config" : { } + }, { + "alias" : "UPDATE_PASSWORD", + "name" : "Update Password", + "providerId" : "UPDATE_PASSWORD", + "enabled" : false, + "defaultAction" : false, + "priority" : 30, + "config" : { } + }, { + "alias" : "UPDATE_PROFILE", + "name" : "Update Profile", + "providerId" : "UPDATE_PROFILE", + "enabled" : true, + "defaultAction" : false, + "priority" : 40, + "config" : { } + }, { + "alias" : "VERIFY_EMAIL", + "name" : "Verify Email", + "providerId" : "VERIFY_EMAIL", + "enabled" : false, + "defaultAction" : false, + "priority" : 50, + "config" : { } + }, { + "alias" : "delete_account", + "name" : "Delete Account", + "providerId" : "delete_account", + "enabled" : false, + "defaultAction" : false, + "priority" : 60, + "config" : { } + }, { + "alias" : "webauthn-register", + "name" : "Webauthn Register", + "providerId" : "webauthn-register", + "enabled" : true, + "defaultAction" : false, + "priority" : 70, + "config" : { } + }, { + "alias" : "webauthn-register-passwordless", + "name" : "Webauthn Register Passwordless", + "providerId" : "webauthn-register-passwordless", + "enabled" : true, + "defaultAction" : false, + "priority" : 80, + "config" : { } + }, { + "alias" : "delete_credential", + "name" : "Delete Credential", + "providerId" : "delete_credential", + "enabled" : true, + "defaultAction" : false, + "priority" : 100, + "config" : { } + }, { + "alias" : "update_user_locale", + "name" : "Update User Locale", + "providerId" : "update_user_locale", + "enabled" : true, + "defaultAction" : false, + "priority" : 1000, + "config" : { } + } ], + "browserFlow" : "browser", + "registrationFlow" : "registration", + "directGrantFlow" : "direct grant", + "resetCredentialsFlow" : "reset credentials", + "clientAuthenticationFlow" : "clients", + "dockerAuthenticationFlow" : "docker auth", + "firstBrokerLoginFlow" : "first broker login", + "attributes" : { + "cibaBackchannelTokenDeliveryMode" : "poll", + "cibaAuthRequestedUserHint" : "login_hint", + "clientOfflineSessionMaxLifespan" : "0", + "oauth2DevicePollingInterval" : "5", + "clientSessionIdleTimeout" : "0", + "actionTokenGeneratedByUserLifespan-execute-actions" : "", + "actionTokenGeneratedByUserLifespan-verify-email" : "", + "clientOfflineSessionIdleTimeout" : "0", + "actionTokenGeneratedByUserLifespan-reset-credentials" : "", + "cibaInterval" : "5", + "realmReusableOtpCode" : "false", + "cibaExpiresIn" : "120", + "oauth2DeviceCodeLifespan" : "600", + "actionTokenGeneratedByUserLifespan-idp-verify-account-via-email" : "", + "parRequestUriLifespan" : "60", + "clientSessionMaxLifespan" : "0", + "shortVerificationUri" : "" + }, + "keycloakVersion" : "24.0.5", + "userManagedAccessAllowed" : false, + "clientProfiles" : { + "profiles" : [ ] + }, + "clientPolicies" : { + "policies" : [ ] + } +} \ No newline at end of file diff --git a/dbrepo-auth-service/listeners/target/create-event-listener.jar b/dbrepo-auth-service/listeners/target/create-event-listener.jar new file mode 100644 index 0000000000000000000000000000000000000000..26cb91c37666c966f6382d35feaaf9f5da5c7f8c Binary files /dev/null and b/dbrepo-auth-service/listeners/target/create-event-listener.jar differ diff --git a/dbrepo-auth-service/master-realm.json b/dbrepo-auth-service/master-realm.json index ef06561e687af0d808781b6c71a1a2b2ea664275..1cf53fe49cffabe7e5833675db95ebff6eec7034 100644 --- a/dbrepo-auth-service/master-realm.json +++ b/dbrepo-auth-service/master-realm.json @@ -40,6 +40,7 @@ "bruteForceProtected" : false, "permanentLockout" : false, "maxTemporaryLockouts" : 0, + "bruteForceStrategy" : "MULTIPLE", "maxFailureWaitSeconds" : 900, "minimumQuickLoginWaitSeconds" : 60, "waitIncrementSeconds" : 60, @@ -664,8 +665,8 @@ "protocol" : "openid-connect", "attributes" : { "realm_client" : "false", - "post.logout.redirect.uris" : "+", - "client.use.lightweight.access.token.enabled" : "true" + "client.use.lightweight.access.token.enabled" : "true", + "post.logout.redirect.uris" : "+" }, "authenticationFlowBindingOverrides" : { }, "fullScopeAllowed" : true, @@ -783,8 +784,8 @@ "protocol" : "openid-connect", "attributes" : { "realm_client" : "false", - "post.logout.redirect.uris" : "+", "client.use.lightweight.access.token.enabled" : "true", + "post.logout.redirect.uris" : "+", "pkce.code.challenge.method" : "S256" }, "authenticationFlowBindingOverrides" : { }, @@ -816,8 +817,8 @@ "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${addressScopeConsentText}" + "consent.screen.text" : "${addressScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "4aed5e41-0d8d-4c24-80a0-cd9822072756", @@ -845,8 +846,8 @@ "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${organizationScopeConsentText}" + "consent.screen.text" : "${organizationScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "5e80a7d2-c9d0-48e1-aadc-d8848ff90f92", @@ -864,6 +865,61 @@ "jsonType.label" : "String" } } ] + }, { + "id" : "1be1e284-2749-4bbb-890a-2d519cc1531c", + "name" : "service_account", + "description" : "Specific scope for a client enabled for service accounts", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "c913a673-cf66-4493-a2ed-14556c07617c", + "name" : "Client ID", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "client_id", + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "client_id", + "jsonType.label" : "String" + } + }, { + "id" : "5c244d68-5c63-4356-ac71-5a586f40c77e", + "name" : "Client IP Address", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "clientAddress", + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "clientAddress", + "jsonType.label" : "String" + } + }, { + "id" : "600285d4-ae51-4b39-a7be-bb83cf5870db", + "name" : "Client Host", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "clientHost", + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "clientHost", + "jsonType.label" : "String" + } + } ] }, { "id" : "0411ea86-a074-4781-850d-ea3ca94590a2", "name" : "offline_access", @@ -915,8 +971,8 @@ "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${profileScopeConsentText}" + "consent.screen.text" : "${profileScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "2d1400be-4053-4393-ba87-91b64f699054", @@ -1217,8 +1273,8 @@ "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "false", - "display.on.consent.screen" : "false", - "consent.screen.text" : "" + "consent.screen.text" : "", + "display.on.consent.screen" : "false" }, "protocolMappers" : [ { "id" : "635cbac1-7cab-43bd-99fc-f7084aca2fa2", @@ -1254,8 +1310,8 @@ "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "false", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${rolesScopeConsentText}" + "consent.screen.text" : "${rolesScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "2b5a3df4-1adb-402d-bc28-2bd43224e682", @@ -1264,12 +1320,12 @@ "protocolMapper" : "oidc-usermodel-realm-role-mapper", "consentRequired" : false, "config" : { - "introspection.token.claim" : "true", - "multivalued" : "true", "user.attribute" : "foo", + "introspection.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "realm_access.roles", - "jsonType.label" : "String" + "jsonType.label" : "String", + "multivalued" : "true" } }, { "id" : "f3b60071-ef26-48a7-9554-67f62f84d543", @@ -1278,12 +1334,12 @@ "protocolMapper" : "oidc-usermodel-client-role-mapper", "consentRequired" : false, "config" : { - "introspection.token.claim" : "true", - "multivalued" : "true", "user.attribute" : "foo", + "introspection.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "resource_access.${client_id}.roles", - "jsonType.label" : "String" + "jsonType.label" : "String", + "multivalued" : "true" } }, { "id" : "b757200e-494a-4585-857e-e4c18aef7a0c", @@ -1303,8 +1359,8 @@ "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${emailScopeConsentText}" + "consent.screen.text" : "${emailScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "e18769b3-778b-47d8-be52-dd2769deebd1", @@ -1344,8 +1400,8 @@ "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${phoneScopeConsentText}" + "consent.screen.text" : "${phoneScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "98cc724c-3f53-47f7-bf9f-baf2f7e08026", @@ -1431,7 +1487,7 @@ "subType" : "anonymous", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-usermodel-property-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-sha256-pairwise-sub-mapper" ] + "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "saml-user-property-mapper" ] } }, { "id" : "4b976576-c880-48a0-9b4d-2956cfd19b4a", @@ -1440,7 +1496,7 @@ "subType" : "authenticated", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper" ] + "allowed-protocol-mapper-types" : [ "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "saml-user-attribute-mapper" ] } }, { "id" : "e1861ec9-2761-46fb-8048-149492269ff0", @@ -1470,6 +1526,14 @@ "allow-default-scopes" : [ "true" ] } } ], + "org.keycloak.userprofile.UserProfileProvider" : [ { + "id" : "34049725-5a66-456c-b895-87ca7c11bb6b", + "providerId" : "declarative-user-profile", + "subComponents" : { }, + "config" : { + "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}]}" ] + } + } ], "org.keycloak.storage.UserStorageProvider" : [ { "id" : "3a6f24e8-128b-4ac1-b3ab-694836db82fd", "name" : "Identity Service", @@ -1483,8 +1547,8 @@ "config" : { "ldap.attribute" : [ "mail" ], "is.mandatory.in.ldap" : [ "false" ], - "read.only" : [ "false" ], "always.read.value.from.ldap" : [ "false" ], + "read.only" : [ "false" ], "user.model.attribute" : [ "email" ] } }, { @@ -1495,8 +1559,8 @@ "config" : { "ldap.attribute" : [ "sn" ], "is.mandatory.in.ldap" : [ "true" ], - "read.only" : [ "false" ], "always.read.value.from.ldap" : [ "true" ], + "read.only" : [ "false" ], "user.model.attribute" : [ "lastName" ] } }, { @@ -1507,8 +1571,8 @@ "config" : { "ldap.attribute" : [ "modifyTimestamp" ], "is.mandatory.in.ldap" : [ "false" ], - "always.read.value.from.ldap" : [ "true" ], "read.only" : [ "true" ], + "always.read.value.from.ldap" : [ "true" ], "user.model.attribute" : [ "modifyTimestamp" ] } }, { @@ -1541,17 +1605,17 @@ "providerId" : "group-ldap-mapper", "subComponents" : { }, "config" : { + "mode" : [ "LDAP_ONLY" ], "membership.attribute.type" : [ "DN" ], + "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ], "group.name.ldap.attribute" : [ "cn" ], + "ignore.missing.groups" : [ "false" ], "membership.user.ldap.attribute" : [ "uid" ], "preserve.group.inheritance" : [ "false" ], - "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ], - "mode" : [ "LDAP_ONLY" ], - "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ], "membership.ldap.attribute" : [ "member" ], - "ignore.missing.groups" : [ "false" ], - "group.object.classes" : [ "groupOfNames" ], + "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ], "memberof.ldap.attribute" : [ "memberOf" ], + "group.object.classes" : [ "groupOfNames" ], "drop.non.existing.groups.during.sync" : [ "false" ], "groups.path" : [ "/" ] } @@ -1563,8 +1627,8 @@ "config" : { "ldap.attribute" : [ "createTimestamp" ], "is.mandatory.in.ldap" : [ "false" ], - "always.read.value.from.ldap" : [ "true" ], "read.only" : [ "true" ], + "always.read.value.from.ldap" : [ "true" ], "user.model.attribute" : [ "createTimestamp" ] } } ] @@ -1580,9 +1644,9 @@ "importEnabled" : [ "true" ], "enabled" : [ "true" ], "changedSyncPeriod" : [ "-1" ], + "usernameLDAPAttribute" : [ "uid" ], "bindCredential" : [ "admin" ], "bindDn" : [ "cn=admin,dc=dbrepo,dc=at" ], - "usernameLDAPAttribute" : [ "uid" ], "vendor" : [ "other" ], "uuidLDAPAttribute" : [ "entryUUID" ], "allowKerberosAuthentication" : [ "false" ], @@ -1600,14 +1664,6 @@ "validatePasswordPolicy" : [ "false" ] } } ], - "org.keycloak.userprofile.UserProfileProvider" : [ { - "id" : "34049725-5a66-456c-b895-87ca7c11bb6b", - "providerId" : "declarative-user-profile", - "subComponents" : { }, - "config" : { - "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}]}" ] - } - } ], "org.keycloak.keys.KeyProvider" : [ { "id" : "5b1052d2-fb71-47d2-86f9-908c869c8d1b", "name" : "hmac-generated-hs512", @@ -2219,10 +2275,12 @@ "parRequestUriLifespan" : "60", "clientSessionMaxLifespan" : "0", "frontendUrl" : "", + "organizationsEnabled" : "false", "acr.loa.map" : "{}" }, - "keycloakVersion" : "24.0.5", + "keycloakVersion" : "26.0.4", "userManagedAccessAllowed" : false, + "organizationsEnabled" : false, "clientProfiles" : { "profiles" : [ ] }, diff --git a/dbrepo-data-service/Dockerfile b/dbrepo-data-service/Dockerfile index f4e2be5b967ca109e858d6f17099ec67d341ac12..9edf1375fb6c47f63dbd45f26bba0b3a6fe15255 100644 --- a/dbrepo-data-service/Dockerfile +++ b/dbrepo-data-service/Dockerfile @@ -8,7 +8,7 @@ LABEL org.opencontainers.image.authors="martin.weise@tuwien.ac.at" COPY ./pom.xml ./ -RUN mvn -fn -B dependency:go-offline +RUN mvn -fn dependency:go-offline COPY --from=dependency /root/.m2/repository/at/tuwien /root/.m2/repository/at/tuwien @@ -18,7 +18,7 @@ COPY ./rest-service ./rest-service COPY ./services ./services # Make sure it compiles -RUN mvn clean package -DskipTests +RUN mvn -fn clean package -DskipTests ###### THIRD STAGE ###### FROM amazoncorretto:17-alpine3.19 AS runtime diff --git a/dbrepo-data-service/pom.xml b/dbrepo-data-service/pom.xml index 884824994aff8a6e8f05bce24c44307ffe64c2b8..e2bfa739618b3a518aeabd623ea49718b9a06d5b 100644 --- a/dbrepo-data-service/pom.xml +++ b/dbrepo-data-service/pom.xml @@ -11,7 +11,7 @@ <groupId>at.tuwien</groupId> <artifactId>dbrepo-data-service</artifactId> <name>dbrepo-data-service</name> - <version>1.6.1</version> + <version>1.6.3</version> <description>Service that manages the data</description> diff --git a/dbrepo-data-service/querystore/pom.xml b/dbrepo-data-service/querystore/pom.xml index 943c115d117529adea091f02f77037367c12a32c..2905b5a935407cab65086def3f9c21d980ee329a 100644 --- a/dbrepo-data-service/querystore/pom.xml +++ b/dbrepo-data-service/querystore/pom.xml @@ -6,12 +6,12 @@ <parent> <groupId>at.tuwien</groupId> <artifactId>dbrepo-data-service</artifactId> - <version>1.6.1</version> + <version>1.6.3</version> </parent> <artifactId>dbrepo-data-service-querystore</artifactId> <name>dbrepo-data-service-querystore</name> - <version>1.6.1</version> + <version>1.6.3</version> <dependencies/> diff --git a/dbrepo-data-service/report/pom.xml b/dbrepo-data-service/report/pom.xml index ca03190a449b76f7217590283097978be9d8a0ab..4b230d55ebfbf084cfd00eea7cd7c568ac620d71 100644 --- a/dbrepo-data-service/report/pom.xml +++ b/dbrepo-data-service/report/pom.xml @@ -6,12 +6,12 @@ <parent> <groupId>at.tuwien</groupId> <artifactId>dbrepo-data-service</artifactId> - <version>1.6.1</version> + <version>1.6.3</version> </parent> <artifactId>report</artifactId> <name>dbrepo-data-service-report</name> - <version>1.6.1</version> + <version>1.6.3</version> <description> This module is only intended for the pipeline coverage report. See the detailed report in the respective modules diff --git a/dbrepo-data-service/rest-service/pom.xml b/dbrepo-data-service/rest-service/pom.xml index e72392c7071cb3083c894fbc3654266f34650f01..721cf1a254c8fff0927bffbd7d6ff27b3dcead8d 100644 --- a/dbrepo-data-service/rest-service/pom.xml +++ b/dbrepo-data-service/rest-service/pom.xml @@ -6,18 +6,18 @@ <parent> <groupId>at.tuwien</groupId> <artifactId>dbrepo-data-service</artifactId> - <version>1.6.1</version> + <version>1.6.3</version> </parent> <artifactId>rest-service</artifactId> <name>dbrepo-data-service-rest-service</name> - <version>1.6.1</version> + <version>1.6.3</version> <dependencies> <dependency> <groupId>at.tuwien</groupId> <artifactId>services</artifactId> - <version>1.6.1</version> + <version>1.6.3</version> </dependency> </dependencies> @@ -38,6 +38,14 @@ </execution> </executions> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>9</source> + <target>9</target> + </configuration> + </plugin> </plugins> </build> diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java index 7947e87a495595441c945e950453499c635aaac2..4d3803a1e1c7159903ae090515edf5d9f353b068 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java @@ -1,9 +1,9 @@ package at.tuwien.endpoints; -import at.tuwien.api.database.UpdateDatabaseAccessDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; +import at.tuwien.api.database.CreateAccessDto; +import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.api.user.internal.PrivilegedUserDto; +import at.tuwien.api.user.UserDto; import at.tuwien.exception.*; import at.tuwien.service.AccessService; import at.tuwien.service.CredentialService; @@ -29,7 +29,7 @@ import java.util.UUID; @RestController @CrossOrigin(origins = "*") @RequestMapping(path = "/api/database/{databaseId}/access") -public class AccessEndpoint extends AbstractEndpoint { +public class AccessEndpoint extends RestEndpoint { private final AccessService accessService; private final CredentialService credentialService; @@ -76,12 +76,12 @@ public class AccessEndpoint extends AbstractEndpoint { }) public ResponseEntity<Void> create(@NotNull @PathVariable("databaseId") Long databaseId, @PathVariable("userId") UUID userId, - @Valid @RequestBody UpdateDatabaseAccessDto data) + @Valid @RequestBody CreateAccessDto data) throws NotAllowedException, DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, DatabaseMalformedException, MetadataServiceException { log.debug("endpoint give access to database, databaseId={}, userId={}", databaseId, userId); - final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId); - final PrivilegedUserDto user = credentialService.getUser(userId); + final DatabaseDto database = credentialService.getDatabase(databaseId); + final UserDto user = credentialService.getUser(userId); if (database.getAccesses().stream().anyMatch(a -> a.getUser().getId().equals(userId))) { log.error("Failed to create access to user with id {}: already has access", userId); throw new NotAllowedException("Failed to create access to user with id " + userId + ": already has access"); @@ -132,13 +132,13 @@ public class AccessEndpoint extends AbstractEndpoint { }) public ResponseEntity<Void> update(@NotNull @PathVariable("databaseId") Long databaseId, @PathVariable("userId") UUID userId, - @Valid @RequestBody UpdateDatabaseAccessDto access) throws NotAllowedException, + @Valid @RequestBody CreateAccessDto access) throws NotAllowedException, DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, DatabaseMalformedException, MetadataServiceException { log.debug("endpoint modify access to database, databaseId={}, userId={}, access.type={}", databaseId, userId, access.getType()); - final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId); - final PrivilegedUserDto user = credentialService.getUser(userId); + final DatabaseDto database = credentialService.getDatabase(databaseId); + final UserDto user = credentialService.getUser(userId); if (database.getAccesses().stream().noneMatch(a -> a.getHuserid().equals(userId))) { log.error("Failed to update access to user with id {}: no access", userId); throw new NotAllowedException("Failed to update access to user with id " + userId + ": no access"); @@ -208,8 +208,8 @@ public class AccessEndpoint extends AbstractEndpoint { DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, DatabaseMalformedException, MetadataServiceException { log.debug("endpoint revoke access to database, databaseId={}, userId={}", databaseId, userId); - final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId); - final PrivilegedUserDto user = credentialService.getUser(userId); + final DatabaseDto database = credentialService.getDatabase(databaseId); + final UserDto user = credentialService.getUser(userId); if (database.getAccesses().stream().noneMatch(a -> a.getUser().getId().equals(userId))) { log.error("Failed to delete access to user with id {}: no access", userId); throw new NotAllowedException("Failed to delete access to user with id " + userId + ": no access"); diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java index d101a8c97393a41ecf4e76ea4e4fb4aa3c1f4993..27848cf517ca0187f8ccd69d5ec894a4a6121304 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java @@ -1,19 +1,17 @@ package at.tuwien.endpoints; -import at.tuwien.api.container.internal.PrivilegedContainerDto; +import at.tuwien.api.container.ContainerDto; import at.tuwien.api.database.AccessTypeDto; import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.internal.CreateDatabaseDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.api.user.internal.PrivilegedUserDto; +import at.tuwien.api.user.UserDto; import at.tuwien.api.user.internal.UpdateUserPasswordDto; import at.tuwien.exception.*; -import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.AccessService; +import at.tuwien.service.ContainerService; import at.tuwien.service.CredentialService; import at.tuwien.service.DatabaseService; -import at.tuwien.service.SubsetService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; @@ -35,21 +33,19 @@ import java.sql.SQLException; @RestController @CrossOrigin(origins = "*") @RequestMapping(path = "/api/database") -public class DatabaseEndpoint extends AbstractEndpoint { +public class DatabaseEndpoint extends RestEndpoint { - private final SubsetService queryService; private final AccessService accessService; - private final MetadataMapper metadataMapper; private final DatabaseService databaseService; + private final ContainerService containerService; private final CredentialService credentialService; @Autowired - public DatabaseEndpoint(SubsetService queryService, AccessService accessService, MetadataMapper metadataMapper, - DatabaseService databaseService, CredentialService credentialService) { - this.queryService = queryService; + public DatabaseEndpoint(AccessService accessService, DatabaseService databaseService, + ContainerService containerService, CredentialService credentialService) { this.accessService = accessService; - this.metadataMapper = metadataMapper; this.databaseService = databaseService; + this.containerService = containerService; this.credentialService = credentialService; } @@ -90,18 +86,18 @@ public class DatabaseEndpoint extends AbstractEndpoint { DatabaseMalformedException, QueryStoreCreateException, MetadataServiceException { log.debug("endpoint create database, data.containerId={}, data.internalName={}, data.username={}", data.getContainerId(), data.getInternalName(), data.getUsername()); - final PrivilegedContainerDto container = credentialService.getContainer(data.getContainerId()); + final ContainerDto container = credentialService.getContainer(data.getContainerId()); try { - final PrivilegedDatabaseDto database = databaseService.create(container, data); - queryService.createQueryStore(container, data.getInternalName()); - final PrivilegedUserDto user = PrivilegedUserDto.builder() + final DatabaseDto database = containerService.createDatabase(container, data); + containerService.createQueryStore(container, data.getInternalName()); + final UserDto user = UserDto.builder() .id(data.getUserId()) .username(data.getUsername()) .password(data.getPassword()) .build(); accessService.create(database, user, AccessTypeDto.WRITE_ALL); return ResponseEntity.status(HttpStatus.CREATED) - .body(metadataMapper.privilegedDatabaseDtoToDatabaseDto(database)); + .body(database); } catch (SQLException e) { log.error("Failed to establish connection to database: {}", e.getMessage()); throw new DatabaseUnavailableException("Failed to establish connection to database: " + e.getMessage(), e); @@ -138,7 +134,7 @@ public class DatabaseEndpoint extends AbstractEndpoint { DatabaseMalformedException, MetadataServiceException { log.debug("endpoint update user password in database, databaseId={}, data.username={}", databaseId, data.getUsername()); - final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId); + final DatabaseDto database = credentialService.getDatabase(databaseId); try { databaseService.update(database, data); return ResponseEntity.status(HttpStatus.ACCEPTED) diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AbstractEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/RestEndpoint.java similarity index 97% rename from dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AbstractEndpoint.java rename to dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/RestEndpoint.java index 87a4d32532c586c0f2517862f0cd3cc104f4f054..45cea4371c74f61d3cca69d70b08e8341c5e78d3 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/AbstractEndpoint.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/RestEndpoint.java @@ -11,7 +11,7 @@ import java.util.List; import java.util.Map; import java.util.UUID; -public abstract class AbstractEndpoint { +public abstract class RestEndpoint { public boolean hasRole(Principal principal, String role) { if (principal == null || role == null) { @@ -45,6 +45,7 @@ public abstract class AbstractEndpoint { return UUID.fromString(user.getId()); } + /* FIXME: Heap may run OOM */ public List<Map<String, Object>> transform(Dataset<Row> dataset) { return dataset.collectAsList() .stream() diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/SubsetEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/SubsetEndpoint.java index f30251a5ff09e895a7324a9857134c789f6b3c03..90cb9846b23f79ed4feb1d36e887886b88ad1a06 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/SubsetEndpoint.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/SubsetEndpoint.java @@ -1,14 +1,16 @@ package at.tuwien.endpoints; import at.tuwien.ExportResourceDto; +import at.tuwien.api.database.CreateViewDto; +import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.ViewColumnDto; import at.tuwien.api.database.ViewDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; import at.tuwien.api.database.query.ExecuteStatementDto; import at.tuwien.api.database.query.QueryDto; import at.tuwien.api.database.query.QueryPersistDto; import at.tuwien.api.error.ApiErrorDto; import at.tuwien.exception.*; +import at.tuwien.mapper.MariaDbMapper; import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.*; import at.tuwien.validation.EndpointValidator; @@ -46,25 +48,27 @@ import java.util.UUID; @RestController @CrossOrigin(origins = "*") @RequestMapping(path = "/api/database/{databaseId}/subset") -public class SubsetEndpoint extends AbstractEndpoint { +public class SubsetEndpoint extends RestEndpoint { - private final SchemaService schemaService; + private final MariaDbMapper mariaDbMapper; private final SubsetService subsetService; private final MetadataMapper metadataMapper; private final MetricsService metricsService; private final StorageService storageService; + private final DatabaseService databaseService; private final CredentialService credentialService; private final EndpointValidator endpointValidator; @Autowired - public SubsetEndpoint(SchemaService schemaService, SubsetService subsetService, MetadataMapper metadataMapper, - MetricsService metricsService, StorageService storageService, + public SubsetEndpoint(MariaDbMapper mariaDbMapper, SubsetService subsetService, MetadataMapper metadataMapper, + MetricsService metricsService, StorageService storageService, DatabaseService databaseService, CredentialService credentialService, EndpointValidator endpointValidator) { - this.schemaService = schemaService; + this.mariaDbMapper = mariaDbMapper; this.subsetService = subsetService; this.metadataMapper = metadataMapper; this.metricsService = metricsService; this.storageService = storageService; + this.databaseService = databaseService; this.credentialService = credentialService; this.endpointValidator = endpointValidator; } @@ -102,7 +106,7 @@ public class SubsetEndpoint extends AbstractEndpoint { throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, QueryNotFoundException, NotAllowedException, MetadataServiceException { log.debug("endpoint find subsets in database, databaseId={}, filterPersisted={}", databaseId, filterPersisted); - final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId); + final DatabaseDto database = credentialService.getDatabase(databaseId); endpointValidator.validateOnlyPrivateSchemaAccess(database, principal); final List<QueryDto> queries; try { @@ -160,11 +164,10 @@ public class SubsetEndpoint extends AbstractEndpoint { Principal principal) throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, QueryNotFoundException, FormatNotAvailableException, StorageUnavailableException, UserNotFoundException, - MetadataServiceException, TableNotFoundException, ViewMalformedException, QueryMalformedException, - NotAllowedException { + MetadataServiceException, TableNotFoundException, QueryMalformedException, NotAllowedException { log.debug("endpoint find subset in database, databaseId={}, subsetId={}, accept={}, timestamp={}", databaseId, subsetId, accept, timestamp); - final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId); + final DatabaseDto database = credentialService.getDatabase(databaseId); endpointValidator.validateOnlyPrivateSchemaAccess(database, principal); final QueryDto subset; try { @@ -188,20 +191,16 @@ public class SubsetEndpoint extends AbstractEndpoint { return ResponseEntity.ok(subset); case "text/csv": log.trace("accept header matches csv"); - try { - final Dataset<Row> dataset = subsetService.getData(database, subset, null, null); - metricsService.countSubsetGetData(databaseId, subsetId); - final ExportResourceDto resource = storageService.transformDataset(dataset); - final HttpHeaders headers = new HttpHeaders(); - headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\""); - log.trace("export table resulted in resource {}", resource); - return ResponseEntity.ok() - .headers(headers) - .body(resource.getResource()); - } catch (SQLException e) { - log.error("Failed to find data: {}", e.getMessage()); - throw new DatabaseUnavailableException("Failed to find data: " + e.getMessage(), e); - } + final String query = mariaDbMapper.rawSelectQuery(subset.getQuery(), timestamp, null, null); + final Dataset<Row> dataset = subsetService.getData(database, query, timestamp, null, null, null, null); + metricsService.countSubsetGetData(databaseId, subsetId); + final ExportResourceDto resource = storageService.transformDataset(dataset); + final HttpHeaders headers = new HttpHeaders(); + headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\""); + log.trace("export table resulted in resource {}", resource); + return ResponseEntity.ok() + .headers(headers) + .body(resource.getResource()); } throw new FormatNotAvailableException("Must provide either application/json or text/csv value for header 'Accept': provided " + accept + " instead"); } @@ -286,11 +285,11 @@ public class SubsetEndpoint extends AbstractEndpoint { log.debug("timestamp not set: default to {}", timestamp); } /* create */ - final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId); + final DatabaseDto database = credentialService.getDatabase(databaseId); endpointValidator.validateOnlyPrivateSchemaAccess(database, principal); try { final Long subsetId = subsetService.create(database, data.getStatement(), timestamp, userId); - return getData(databaseId, subsetId, principal, request, page, size); + return getData(databaseId, subsetId, principal, request, timestamp, page, size); } catch (SQLException e) { log.error("Failed to establish connection to database: {}", e.getMessage()); throw new DatabaseUnavailableException("Failed to establish connection to database: " + e.getMessage(), e); @@ -337,15 +336,16 @@ public class SubsetEndpoint extends AbstractEndpoint { @NotNull @PathVariable("subsetId") Long subsetId, Principal principal, @NotNull HttpServletRequest request, + @RequestParam(required = false) Instant timestamp, @RequestParam(required = false) Long page, @RequestParam(required = false) Long size) throws PaginationException, DatabaseNotFoundException, RemoteUnavailableException, NotAllowedException, QueryNotFoundException, DatabaseUnavailableException, TableMalformedException, QueryMalformedException, - UserNotFoundException, MetadataServiceException, TableNotFoundException, ViewMalformedException, ViewNotFoundException { + UserNotFoundException, MetadataServiceException, TableNotFoundException, ViewNotFoundException, ViewMalformedException { log.debug("endpoint get subset data, databaseId={}, subsetId={}, principal.name={} page={}, size={}", databaseId, subsetId, principal != null ? principal.getName() : null, page, size); endpointValidator.validateDataParams(page, size); - final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId); + final DatabaseDto database = credentialService.getDatabase(databaseId); if (!database.getIsPublic()) { if (principal == null) { log.error("Failed to re-execute query: no authentication found"); @@ -363,6 +363,10 @@ public class SubsetEndpoint extends AbstractEndpoint { size = 10L; log.debug("size not set: default to {}", size); } + if (timestamp == null) { + timestamp = Instant.now(); + log.debug("timestamp not set: default to {}", timestamp); + } try { final HttpHeaders headers = new HttpHeaders(); headers.set("X-Id", "" + subsetId); @@ -375,9 +379,17 @@ public class SubsetEndpoint extends AbstractEndpoint { .headers(headers) .build(); } - final Dataset<Row> dataset = subsetService.getData(database, subset, page, size); + final String query = mariaDbMapper.rawSelectQuery(subset.getQuery(), timestamp, page, size); + final Dataset<Row> dataset = subsetService.getData(database, query, timestamp, page, size, null, null); metricsService.countSubsetGetData(databaseId, subsetId); - final ViewDto view = schemaService.inspectView(database, metadataMapper.queryDtoToViewName(subset)); + final String viewName = metadataMapper.queryDtoToViewName(subset); + databaseService.createView(database, CreateViewDto.builder() + .name(viewName) + .isPublic(false) + .isSchemaPublic(false) + .query(query) + .build()); + final ViewDto view = databaseService.inspectView(database, viewName); headers.set("Access-Control-Expose-Headers", "X-Id X-Headers"); headers.set("X-Headers", String.join(",", view.getColumns().stream().map(ViewColumnDto::getInternalName).toList())); return ResponseEntity.status(request.getMethod().equals("POST") ? HttpStatus.CREATED : HttpStatus.OK) @@ -435,7 +447,7 @@ public class SubsetEndpoint extends AbstractEndpoint { DatabaseUnavailableException, QueryNotFoundException, UserNotFoundException, MetadataServiceException { log.debug("endpoint persist query, databaseId={}, queryId={}, data.persist={}, principal.name={}", databaseId, queryId, data.getPersist(), principal.getName()); - final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId); + final DatabaseDto database = credentialService.getDatabase(databaseId); credentialService.getAccess(databaseId, getId(principal)); try { subsetService.persist(database, queryId, data.getPersist()); diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java index f0ec00a035e729157726b65af9f3c85949581c4e..82ed0a96f7596e025301f11e6ebceed2cd393acc 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java @@ -3,15 +3,14 @@ package at.tuwien.endpoints; import at.tuwien.ExportResourceDto; import at.tuwien.api.database.DatabaseAccessDto; import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; import at.tuwien.api.database.query.ImportDto; import at.tuwien.api.database.table.*; import at.tuwien.api.database.table.columns.ColumnDto; -import at.tuwien.api.database.table.internal.PrivilegedTableDto; import at.tuwien.api.database.table.internal.TableCreateDto; import at.tuwien.api.error.ApiErrorDto; import at.tuwien.exception.*; import at.tuwien.gateway.MetadataServiceGateway; +import at.tuwien.mapper.MariaDbMapper; import at.tuwien.service.*; import at.tuwien.validation.EndpointValidator; import io.micrometer.observation.annotation.Observed; @@ -47,24 +46,29 @@ import java.util.Map; @RestController @CrossOrigin(origins = "*") @RequestMapping(path = "/api/database/{databaseId}/table") -public class TableEndpoint extends AbstractEndpoint { +public class TableEndpoint extends RestEndpoint { private final TableService tableService; - private final SchemaService schemaService; + private final MariaDbMapper mariaDbMapper; + private final SubsetService subsetService; private final MetricsService metricsService; private final StorageService storageService; + private final DatabaseService databaseService; private final CredentialService credentialService; private final EndpointValidator endpointValidator; private final MetadataServiceGateway metadataServiceGateway; @Autowired - public TableEndpoint(TableService tableService, SchemaService schemaService, MetricsService metricsService, - StorageService storageService, CredentialService credentialService, - EndpointValidator endpointValidator, MetadataServiceGateway metadataServiceGateway) { + public TableEndpoint(TableService tableService, MariaDbMapper mariaDbMapper, SubsetService subsetService, + MetricsService metricsService, StorageService storageService, DatabaseService databaseService, + CredentialService credentialService, EndpointValidator endpointValidator, + MetadataServiceGateway metadataServiceGateway) { this.tableService = tableService; - this.schemaService = schemaService; + this.mariaDbMapper = mariaDbMapper; + this.subsetService = subsetService; this.metricsService = metricsService; this.storageService = storageService; + this.databaseService = databaseService; this.credentialService = credentialService; this.endpointValidator = endpointValidator; this.metadataServiceGateway = metadataServiceGateway; @@ -113,11 +117,11 @@ public class TableEndpoint extends AbstractEndpoint { throw new TableMalformedException("Table must have a primary key"); } /* create */ - final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId); + final DatabaseDto database = credentialService.getDatabase(databaseId); try { - final TableDto table = tableService.createTable(database, data); + final TableDto table = databaseService.createTable(database, data); return ResponseEntity.status(HttpStatus.CREATED) - .body(schemaService.inspectTable(database, table.getInternalName())); + .body(databaseService.inspectTable(database, table.getInternalName())); } catch (SQLException e) { log.error("Failed to establish connection to database: {}", e.getMessage()); throw new DatabaseUnavailableException("Failed to establish connection to database: " + e.getMessage(), e); @@ -157,7 +161,7 @@ public class TableEndpoint extends AbstractEndpoint { TableMalformedException, DatabaseUnavailableException, TableNotFoundException, MetadataServiceException { log.debug("endpoint update table, databaseId={}, data.description={}", databaseId, data.getDescription()); /* create */ - final PrivilegedTableDto table = credentialService.getTable(databaseId, tableId); + final TableDto table = credentialService.getTable(databaseId, tableId); try { tableService.updateTable(table, data); return ResponseEntity.status(HttpStatus.ACCEPTED) @@ -200,7 +204,7 @@ public class TableEndpoint extends AbstractEndpoint { throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, QueryMalformedException, MetadataServiceException { log.debug("endpoint delete table, databaseId={}, tableId={}", databaseId, tableId); - final PrivilegedTableDto table = credentialService.getTable(databaseId, tableId); + final TableDto table = credentialService.getTable(databaseId, tableId); try { tableService.delete(table); return ResponseEntity.status(HttpStatus.ACCEPTED) @@ -253,7 +257,7 @@ public class TableEndpoint extends AbstractEndpoint { @NotNull HttpServletRequest request, Principal principal) throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, - PaginationException, MetadataServiceException, NotAllowedException { + PaginationException, MetadataServiceException, NotAllowedException, DatabaseNotFoundException { log.debug("endpoint get table data, databaseId={}, tableId={}, timestamp={}, page={}, size={}", databaseId, tableId, timestamp, page, size); endpointValidator.validateDataParams(page, size); @@ -270,7 +274,7 @@ public class TableEndpoint extends AbstractEndpoint { timestamp = Instant.now(); log.debug("timestamp not set: default to {}", timestamp); } - final PrivilegedTableDto table = credentialService.getTable(databaseId, tableId); + final TableDto table = credentialService.getTable(databaseId, tableId); if (!table.getIsPublic()) { if (principal == null) { log.error("Failed find table data: authentication required"); @@ -289,8 +293,10 @@ public class TableEndpoint extends AbstractEndpoint { } headers.set("Access-Control-Expose-Headers", "X-Headers"); headers.set("X-Headers", String.join(",", table.getColumns().stream().map(ColumnDto::getInternalName).toList())); - final Dataset<Row> dataset = tableService.getData(table.getDatabase(), table.getInternalName(), timestamp, - null, null, null, null); + final String query = mariaDbMapper.defaultRawSelectQuery(table.getDatabase().getInternalName(), + table.getInternalName(), timestamp, page, size); + final Dataset<Row> dataset = subsetService.getData(credentialService.getDatabase(table.getTdbid()), + query, timestamp, page, size, null, null); metricsService.countTableGetData(databaseId, tableId); return ResponseEntity.ok() .headers(headers) @@ -340,7 +346,7 @@ public class TableEndpoint extends AbstractEndpoint { TableMalformedException, QueryMalformedException, NotAllowedException, StorageUnavailableException, StorageNotFoundException, MetadataServiceException { log.debug("endpoint insert raw table data, databaseId={}, tableId={}", databaseId, tableId); - final PrivilegedTableDto table = credentialService.getTable(databaseId, tableId); + final TableDto table = credentialService.getTable(databaseId, tableId); final DatabaseAccessDto access = credentialService.getAccess(databaseId, getId(principal)); endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), getId(principal)); try { @@ -393,7 +399,7 @@ public class TableEndpoint extends AbstractEndpoint { TableMalformedException, QueryMalformedException, NotAllowedException, MetadataServiceException { log.debug("endpoint update raw table data, databaseId={}, tableId={}, data.keys={}", databaseId, tableId, data.getKeys()); - final PrivilegedTableDto table = credentialService.getTable(databaseId, tableId); + final TableDto table = credentialService.getTable(databaseId, tableId); final DatabaseAccessDto access = credentialService.getAccess(databaseId, getId(principal)); endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), getId(principal)); try { @@ -446,7 +452,7 @@ public class TableEndpoint extends AbstractEndpoint { TableMalformedException, QueryMalformedException, NotAllowedException, MetadataServiceException { log.debug("endpoint delete raw table data, databaseId={}, tableId={}, data.keys={}", databaseId, tableId, data.getKeys()); - final PrivilegedTableDto table = credentialService.getTable(databaseId, tableId); + final TableDto table = credentialService.getTable(databaseId, tableId); final DatabaseAccessDto access = credentialService.getAccess(databaseId, getId(principal)); endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), getId(principal)); try { @@ -506,7 +512,7 @@ public class TableEndpoint extends AbstractEndpoint { log.debug("size not set: default to 100L"); size = 100L; } - final PrivilegedTableDto table = credentialService.getTable(databaseId, tableId); + final TableDto table = credentialService.getTable(databaseId, tableId); if (!table.getIsPublic()) { if (principal == null) { log.error("Failed to find table history: no authentication found"); @@ -565,9 +571,9 @@ public class TableEndpoint extends AbstractEndpoint { throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, DatabaseMalformedException, TableNotFoundException, MetadataServiceException { log.debug("endpoint inspect table schemas, databaseId={}", databaseId); - final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId); + final DatabaseDto database = credentialService.getDatabase(databaseId); try { - return ResponseEntity.ok(tableService.getSchemas(database)); + return ResponseEntity.ok(databaseService.exploreTables(database)); } catch (SQLException e) { log.error("Failed to establish connection to database: {}", e.getMessage()); throw new DatabaseUnavailableException("Failed to establish connection to database: " + e.getMessage(), e); @@ -611,14 +617,14 @@ public class TableEndpoint extends AbstractEndpoint { @RequestParam(required = false) Instant timestamp, Principal principal) throws RemoteUnavailableException, TableNotFoundException, NotAllowedException, StorageUnavailableException, - QueryMalformedException, MetadataServiceException { + QueryMalformedException, MetadataServiceException, DatabaseNotFoundException { log.debug("endpoint export table data, databaseId={}, tableId={}, timestamp={}", databaseId, tableId, timestamp); /* parameters */ if (timestamp == null) { timestamp = Instant.now(); log.debug("timestamp not set: default to {}", timestamp); } - final PrivilegedTableDto table = credentialService.getTable(databaseId, tableId); + final TableDto table = credentialService.getTable(databaseId, tableId); if (!table.getIsPublic()) { if (principal == null) { log.error("Failed to export private table: principal is null"); @@ -626,8 +632,10 @@ public class TableEndpoint extends AbstractEndpoint { } credentialService.getAccess(databaseId, getId(principal)); } - final Dataset<Row> dataset = tableService.getData(table.getDatabase(), table.getInternalName(), timestamp, null, - null, null, null); + final String query = mariaDbMapper.defaultRawSelectQuery(table.getDatabase().getInternalName(), + table.getInternalName(), timestamp, null, null); + final Dataset<Row> dataset = subsetService.getData(credentialService.getDatabase(table.getTdbid()), + query, timestamp, null, null, null, null); metricsService.countTableGetData(databaseId, tableId); final ExportResourceDto resource = storageService.transformDataset(dataset); final HttpHeaders headers = new HttpHeaders(); @@ -677,7 +685,7 @@ public class TableEndpoint extends AbstractEndpoint { StorageNotFoundException, MalformedException, StorageUnavailableException, QueryMalformedException, DatabaseUnavailableException { log.debug("endpoint insert table data, databaseId={}, tableId={}, data.location={}", databaseId, tableId, data.getLocation()); - final PrivilegedTableDto table = credentialService.getTable(databaseId, tableId); + final TableDto table = credentialService.getTable(databaseId, tableId); final DatabaseAccessDto access = credentialService.getAccess(databaseId, getId(principal)); endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(access.getType(), table.getOwner().getId(), getId(principal)); if (data.getLineTermination() == null) { @@ -727,9 +735,9 @@ public class TableEndpoint extends AbstractEndpoint { throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, MetadataServiceException, TableMalformedException { log.debug("endpoint generate table statistic, databaseId={}, tableId={}", databaseId, tableId); - final PrivilegedTableDto table = credentialService.getTable(databaseId, tableId); try { - return ResponseEntity.ok(tableService.getStatistics(table)); + return ResponseEntity.ok(tableService.getStatistics( + credentialService.getTable(databaseId, tableId))); } catch (SQLException e) { log.error("Failed to establish connection to database: {}", e.getMessage()); throw new DatabaseUnavailableException("Failed to establish connection to database", e); diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java index 2b0463483d66429dfb0afd942bbc80ccdfb2fd26..25dfd50dd434df444a45c4f7850fcdd803f0e9de 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java @@ -1,13 +1,13 @@ package at.tuwien.endpoints; import at.tuwien.ExportResourceDto; +import at.tuwien.api.database.CreateViewDto; +import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.ViewColumnDto; -import at.tuwien.api.database.ViewCreateDto; import at.tuwien.api.database.ViewDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.database.internal.PrivilegedViewDto; import at.tuwien.api.error.ApiErrorDto; import at.tuwien.exception.*; +import at.tuwien.mapper.MariaDbMapper; import at.tuwien.service.*; import at.tuwien.validation.EndpointValidator; import io.micrometer.observation.annotation.Observed; @@ -42,23 +42,30 @@ import java.util.Map; @RestController @CrossOrigin(origins = "*") @RequestMapping(path = "/api/database/{databaseId}/view") -public class ViewEndpoint extends AbstractEndpoint { +public class ViewEndpoint extends RestEndpoint { private final ViewService viewService; private final TableService tableService; + private final MariaDbMapper mariaDbMapper; + private final SubsetService subsetService; private final MetricsService metricsService; private final StorageService storageService; + private final DatabaseService databaseService; private final CredentialService credentialService; private final EndpointValidator endpointValidator; @Autowired - public ViewEndpoint(ViewService viewService, TableService tableService, MetricsService metricsService, - StorageService storageService, CredentialService credentialService, + public ViewEndpoint(ViewService viewService, TableService tableService, MariaDbMapper mariaDbMapper, + SubsetService subsetService, MetricsService metricsService, StorageService storageService, + DatabaseService databaseService, CredentialService credentialService, EndpointValidator endpointValidator) { this.viewService = viewService; this.tableService = tableService; + this.mariaDbMapper = mariaDbMapper; + this.subsetService = subsetService; this.metricsService = metricsService; this.storageService = storageService; + this.databaseService = databaseService; this.credentialService = credentialService; this.endpointValidator = endpointValidator; } @@ -102,11 +109,11 @@ public class ViewEndpoint extends AbstractEndpoint { }) public ResponseEntity<List<ViewDto>> getSchema(@NotNull @PathVariable("databaseId") Long databaseId) throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, - ViewNotFoundException, DatabaseMalformedException, MetadataServiceException { + DatabaseMalformedException, MetadataServiceException, ViewNotFoundException { log.debug("endpoint inspect view schemas, databaseId={}", databaseId); - final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId); + final DatabaseDto database = credentialService.getDatabase(databaseId); try { - return ResponseEntity.ok(viewService.getSchemas(database)); + return ResponseEntity.ok(databaseService.exploreViews(database)); } catch (SQLException e) { log.error("Failed to establish connection to database: {}", e.getMessage()); throw new DatabaseUnavailableException("Failed to establish connection to database: " + e.getMessage(), e); @@ -146,13 +153,13 @@ public class ViewEndpoint extends AbstractEndpoint { schema = @Schema(implementation = ApiErrorDto.class))}), }) public ResponseEntity<ViewDto> create(@NotNull @PathVariable("databaseId") Long databaseId, - @Valid @RequestBody ViewCreateDto data) throws DatabaseUnavailableException, + @Valid @RequestBody CreateViewDto data) throws DatabaseUnavailableException, DatabaseNotFoundException, RemoteUnavailableException, ViewMalformedException, MetadataServiceException { log.debug("endpoint create view, databaseId={}, data.name={}", databaseId, data.getName()); - final PrivilegedDatabaseDto database = credentialService.getDatabase(databaseId); + final DatabaseDto database = credentialService.getDatabase(databaseId); try { return ResponseEntity.status(HttpStatus.CREATED) - .body(viewService.create(database, data)); + .body(databaseService.createView(database, data)); } catch (SQLException e) { log.error("Failed to establish connection to database: {}", e.getMessage()); throw new DatabaseUnavailableException("Failed to establish connection to database: " + e.getMessage(), e); @@ -193,9 +200,9 @@ public class ViewEndpoint extends AbstractEndpoint { throws DatabaseUnavailableException, RemoteUnavailableException, ViewNotFoundException, ViewMalformedException, MetadataServiceException { log.debug("endpoint delete view, databaseId={}, viewId={}", databaseId, viewId); - final PrivilegedViewDto view = credentialService.getView(databaseId, viewId); + final ViewDto view = credentialService.getView(databaseId, viewId); try { - viewService.delete(view.getDatabase(), view.getInternalName()); + viewService.delete(view); return ResponseEntity.status(HttpStatus.ACCEPTED) .build(); } catch (SQLException e) { @@ -207,7 +214,7 @@ public class ViewEndpoint extends AbstractEndpoint { @RequestMapping(value = "/{viewId}/data", method = {RequestMethod.GET, RequestMethod.HEAD}) @Observed(name = "dbrepo_view_data") @Operation(summary = "Get view data", - description = "Gets data from a view of a database. For private databases, the user needs at least *READ* access to the associated database. Requires role `view-database-view-data`.", + description = "Gets data from a view of a database. For private databases, the user needs at least *READ* access to the associated database.", security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")}) @ApiResponses(value = { @ApiResponse(responseCode = "200", @@ -251,7 +258,7 @@ public class ViewEndpoint extends AbstractEndpoint { @NotNull HttpServletRequest request, Principal principal) throws DatabaseUnavailableException, RemoteUnavailableException, ViewNotFoundException, PaginationException, - QueryMalformedException, NotAllowedException, MetadataServiceException, TableNotFoundException { + QueryMalformedException, NotAllowedException, MetadataServiceException, TableNotFoundException, DatabaseNotFoundException { log.debug("endpoint get view data, databaseId={}, viewId={}, page={}, size={}, timestamp={}", databaseId, viewId, page, size, timestamp); endpointValidator.validateDataParams(page, size); @@ -268,7 +275,7 @@ public class ViewEndpoint extends AbstractEndpoint { timestamp = Instant.now(); log.debug("timestamp not set: default to {}", timestamp); } - final PrivilegedViewDto view = credentialService.getView(databaseId, viewId); + final ViewDto view = credentialService.getView(databaseId, viewId); if (!view.getIsPublic()) { if (principal == null) { log.error("Failed to get data from view: unauthorized"); @@ -287,8 +294,10 @@ public class ViewEndpoint extends AbstractEndpoint { } headers.set("Access-Control-Expose-Headers", "X-Headers"); headers.set("X-Headers", String.join(",", view.getColumns().stream().map(ViewColumnDto::getInternalName).toList())); - final Dataset<Row> dataset = tableService.getData(view.getDatabase(), view.getInternalName(), timestamp, - page, size, null, null); + final String query = mariaDbMapper.defaultRawSelectQuery(view.getDatabase().getInternalName(), + view.getInternalName(), timestamp, page, size); + final Dataset<Row> dataset = subsetService.getData(credentialService.getDatabase(databaseId), + query, timestamp, page, size, null, null); metricsService.countViewGetData(databaseId, viewId); return ResponseEntity.ok() .headers(headers) @@ -336,7 +345,7 @@ public class ViewEndpoint extends AbstractEndpoint { @RequestParam(required = false) Instant timestamp, Principal principal) throws RemoteUnavailableException, ViewNotFoundException, NotAllowedException, MetadataServiceException, - StorageUnavailableException, QueryMalformedException, TableNotFoundException { + StorageUnavailableException, QueryMalformedException, TableNotFoundException, DatabaseNotFoundException { log.debug("endpoint export view data, databaseId={}, viewId={}", databaseId, viewId); /* parameters */ if (timestamp == null) { @@ -344,7 +353,7 @@ public class ViewEndpoint extends AbstractEndpoint { log.debug("timestamp not set: default to {}", timestamp); } /* parameters */ - final PrivilegedViewDto view = credentialService.getView(databaseId, viewId); + final ViewDto view = credentialService.getView(databaseId, viewId); if (!view.getIsPublic()) { if (principal == null) { log.error("Failed to export private view: principal is null"); @@ -352,8 +361,10 @@ public class ViewEndpoint extends AbstractEndpoint { } credentialService.getAccess(databaseId, getId(principal)); } - final Dataset<Row> dataset = tableService.getData(view.getDatabase(), view.getInternalName(), timestamp, null, - null, null, null); + final String query = mariaDbMapper.defaultRawSelectQuery(view.getDatabase().getInternalName(), + view.getInternalName(), timestamp, null, null); + final Dataset<Row> dataset = subsetService.getData(credentialService.getDatabase(databaseId), + query, timestamp, null, null, null, null); metricsService.countViewGetData(databaseId, viewId); final ExportResourceDto resource = storageService.transformDataset(dataset); final HttpHeaders headers = new HttpHeaders(); diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java index 25b858f51bd3f643f7879b9eac2dbb648b00aabb..9ad13f5be68bf6714f5d18fec4973fe9898b38f6 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java @@ -2,11 +2,11 @@ package at.tuwien.validation; import at.tuwien.api.database.AccessTypeDto; import at.tuwien.api.database.DatabaseAccessDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; +import at.tuwien.api.database.DatabaseDto; import at.tuwien.config.QueryConfig; -import at.tuwien.endpoints.AbstractEndpoint; +import at.tuwien.endpoints.RestEndpoint; import at.tuwien.exception.*; -import at.tuwien.gateway.MetadataServiceGateway; +import at.tuwien.service.CredentialService; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -21,15 +21,15 @@ import java.util.regex.Pattern; @Log4j2 @Component -public class EndpointValidator extends AbstractEndpoint { +public class EndpointValidator extends RestEndpoint { private final QueryConfig queryConfig; - private final MetadataServiceGateway metadataServiceGateway; + private final CredentialService credentialService; @Autowired - public EndpointValidator(QueryConfig queryConfig, MetadataServiceGateway metadataServiceGateway) { + public EndpointValidator(QueryConfig queryConfig, CredentialService credentialService) { this.queryConfig = queryConfig; - this.metadataServiceGateway = metadataServiceGateway; + this.credentialService = credentialService; } public void validateDataParams(Long page, Long size) throws PaginationException { @@ -48,12 +48,12 @@ public class EndpointValidator extends AbstractEndpoint { } } - public void validateOnlyPrivateSchemaAccess(PrivilegedDatabaseDto database, Principal principal) + public void validateOnlyPrivateSchemaAccess(DatabaseDto database, Principal principal) throws NotAllowedException, RemoteUnavailableException, MetadataServiceException { validateOnlyPrivateSchemaAccess(database, principal, false); } - public void validateOnlyPrivateSchemaAccess(PrivilegedDatabaseDto database, Principal principal, + public void validateOnlyPrivateSchemaAccess(DatabaseDto database, Principal principal, boolean writeAccessOnly) throws NotAllowedException, RemoteUnavailableException, MetadataServiceException { if (database.getIsSchemaPublic()) { @@ -63,7 +63,7 @@ public class EndpointValidator extends AbstractEndpoint { validateOnlyAccess(database, principal, writeAccessOnly); } - public void validateOnlyPrivateSchemaHasRole(PrivilegedDatabaseDto database, Principal principal, String role) + public void validateOnlyPrivateSchemaHasRole(DatabaseDto database, Principal principal, String role) throws NotAllowedException { if (database.getIsSchemaPublic()) { log.trace("database with id {} has public schema: no access needed", database.getId()); @@ -82,7 +82,7 @@ public class EndpointValidator extends AbstractEndpoint { log.trace("principal has role '{}': access granted", role); } - public void validateOnlyAccess(PrivilegedDatabaseDto database, Principal principal, boolean writeAccessOnly) + public void validateOnlyAccess(DatabaseDto database, Principal principal, boolean writeAccessOnly) throws NotAllowedException, RemoteUnavailableException, MetadataServiceException { if (principal == null) { throw new NotAllowedException("No principal provided"); @@ -90,7 +90,7 @@ public class EndpointValidator extends AbstractEndpoint { if (isSystem(principal)) { return; } - final DatabaseAccessDto access = metadataServiceGateway.getAccess(database.getId(), getId(principal)); + final DatabaseAccessDto access = credentialService.getAccess(database.getId(), getId(principal)); log.trace("found access: {}", access); if (writeAccessOnly && !(access.getType().equals(AccessTypeDto.WRITE_OWN) || access.getType().equals(AccessTypeDto.WRITE_ALL))) { log.error("Access not allowed: no write access"); diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java index a30ffb7b81ec455fc4eaa0ca11472eafa2c7aaf2..d4daa90741fa306a2d5c19093d5ad9ebe0d6ba2a 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/config/MariaDbConfig.java @@ -1,18 +1,14 @@ package at.tuwien.config; -import at.tuwien.api.container.internal.PrivilegedContainerDto; +import at.tuwien.api.container.ContainerDto; import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; import at.tuwien.api.database.query.QueryDto; -import at.tuwien.api.database.table.columns.ColumnTypeDto; -import at.tuwien.api.database.table.internal.PrivilegedTableDto; import lombok.extern.log4j.Log4j2; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; import java.sql.*; -import java.time.Instant; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -21,38 +17,7 @@ import java.util.regex.Pattern; @Configuration public class MariaDbConfig { - /** - * Inserts a query into a created database with given hostname and database name. The method uses the JDBC in-out - * notation <a href="#{@link}">{@link https://learn.microsoft.com/en-us/sql/connect/jdbc/using-sql-escape-sequences?view=sql-server-ver16#stored-procedure-calls}</a> - * - * @param database The database. - * @param query The query. - * @param username The connection username. - * @param password The connection password. - * @return The generated or retrieved query id. - * @throws SQLException The procedure did not succeed. - */ - public static Long mockSystemQueryInsert(PrivilegedDatabaseDto database, String query, String username, String password) - throws SQLException { - final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName(); - log.trace("connect to database {}", jdbc); - try (Connection connection = DriverManager.getConnection(jdbc, username, password)) { - final String call = "{call _store_query(?,?,?,?)}"; - log.trace("prepare procedure '{}'", call); - final CallableStatement statement = connection.prepareCall(call); - statement.setString(1, username); - statement.setString(2, query); - statement.setTimestamp(3, Timestamp.from(Instant.now())); - statement.registerOutParameter(4, Types.BIGINT); - statement.executeUpdate(); - final Long queryId = statement.getLong(4); - statement.close(); - log.debug("received queryId={}", queryId); - return queryId; - } - } - - public static void createDatabase(PrivilegedContainerDto container, String database) throws SQLException { + public static void createDatabase(ContainerDto container, String database) throws SQLException { final String jdbc = "jdbc:mariadb://" + container.getHost() + ":" + container.getPort(); log.trace("connect to database {}", jdbc); try (Connection connection = DriverManager.getConnection(jdbc, container.getUsername(), container.getPassword())) { @@ -65,7 +30,7 @@ public class MariaDbConfig { log.debug("created database {}", database); } - public static void createInitDatabase(PrivilegedContainerDto container, DatabaseDto database) throws SQLException { + public static void createInitDatabase(ContainerDto container, DatabaseDto database) throws SQLException { final String jdbc = "jdbc:mariadb://" + container.getHost() + ":" + container.getPort(); log.trace("connect to database {}", jdbc); try (Connection connection = DriverManager.getConnection(jdbc, container.getUsername(), container.getPassword())) { @@ -76,21 +41,7 @@ public class MariaDbConfig { log.debug("created init database {}", database.getInternalName()); } - public static void grantReadAccess(PrivilegedDatabaseDto database, String username) { - final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName(); - log.trace("connect to database {}", jdbc); - try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) { - connection.prepareStatement("GRANT SELECT ON *.* TO `" + username + "`@`%`;") - .executeUpdate(); - connection.prepareStatement("FLUSH PRIVILEGES;") - .executeUpdate(); - } catch (SQLException e) { - log.error("could not grant read access", e); - } - log.debug("granted read access to user {} in database {}", username, database.getInternalName()); - } - - public static void grantWriteAccess(PrivilegedDatabaseDto database, String username) { + public static void grantWriteAccess(DatabaseDto database, String username) { final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName(); log.trace("connect to database {}", jdbc); try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) { @@ -104,7 +55,7 @@ public class MariaDbConfig { log.debug("granted read access to user {} in database {}", username, database.getInternalName()); } - public static void dropAllDatabases(PrivilegedContainerDto container) { + public static void dropAllDatabases(ContainerDto container) { final String jdbc = "jdbc:mariadb://" + container.getHost() + ":" + container.getPort(); log.trace("connect to database {}", jdbc); try (Connection connection = DriverManager.getConnection(jdbc, container.getUsername(), container.getPassword())) { @@ -130,7 +81,7 @@ public class MariaDbConfig { log.debug("dropped all databases"); } - public static void dropDatabase(PrivilegedContainerDto container, String database) + public static void dropDatabase(ContainerDto container, String database) throws SQLException { final String jdbc = "jdbc:mariadb://" + container.getHost() + ":" + container.getPort(); log.trace("connect to database {}", jdbc); @@ -144,26 +95,7 @@ public class MariaDbConfig { log.debug("dropped database {}", database); } - public static List<String> getUsernames(String hostname, String database, String username, String password) - throws SQLException { - final String jdbc = "jdbc:mariadb://" + hostname + "/" + database; - log.trace("connect to database {}", jdbc); - final List<String> usernames = new LinkedList<>(); - try (Connection connection = DriverManager.getConnection(jdbc, username, password)) { - final String query = "SELECT User FROM mysql.user;"; - log.trace("prepare statement '{}'", query); - final PreparedStatement statement = connection.prepareStatement(query); - final ResultSet set = statement.executeQuery(); - statement.close(); - while (set.next()) { - usernames.add(set.getString("User")); - } - log.debug("received usernames={}", usernames); - return usernames; - } - } - - public static List<String> getPrivileges(PrivilegedDatabaseDto database, String username) throws SQLException { + public static List<String> getPrivileges(DatabaseDto database, String username) throws SQLException { final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName(); log.trace("connect to database {}", jdbc); try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) { @@ -185,7 +117,7 @@ public class MariaDbConfig { throw new SQLException("Failed to get privileges"); } - public static void dropTable(PrivilegedDatabaseDto database, String table) throws SQLException { + public static void dropTable(DatabaseDto database, String table) throws SQLException { final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName(); log.trace("connect to database {}", jdbc); try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) { @@ -209,50 +141,7 @@ public class MariaDbConfig { } } - /** - * Inserts a query into a created database with given hostname and database name. The method uses the JDBC in-out - * notation <a href="#{@link}">{@link https://learn.microsoft.com/en-us/sql/connect/jdbc/using-sql-escape-sequences?view=sql-server-ver16#stored-procedure-calls}</a> - * - * @param database The database. - * @param query The query. - * @param username The connection username. - * @param password The connection password. - * @return The generated or retrieved query id. - * @throws SQLException The procedure did not succeed. - */ - public static Long mockUserQueryInsert(PrivilegedDatabaseDto database, String query, String username, String password) - throws SQLException { - final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName(); - log.trace("connect to database: {}", jdbc); - try (Connection connection = DriverManager.getConnection(jdbc, username, password)) { - final String call = "{call store_query(?,?,?)}"; - log.trace("prepare procedure '{}'", call); - final CallableStatement statement = connection.prepareCall(call); - statement.setString(1, query); - statement.setTimestamp(2, Timestamp.from(Instant.now())); - statement.registerOutParameter(3, Types.BIGINT); - statement.executeUpdate(); - final Long queryId = statement.getLong(3); - statement.close(); - log.debug("received queryId={}", queryId); - return queryId; - } - } - - /** - * Inserts a query into a created database with given hostname and database name. The method uses the JDBC in-out - * notation <a href="#{@link}">{@link https://learn.microsoft.com/en-us/sql/connect/jdbc/using-sql-escape-sequences?view=sql-server-ver16#stored-procedure-calls}</a> - * - * @param database The database. - * @param query The query. - * @return The generated or retrieved query id. - * @throws SQLException The procedure did not succeed. - */ - public static Long mockSystemQueryInsert(PrivilegedDatabaseDto database, String query) throws SQLException { - return mockSystemQueryInsert(database, query, database.getContainer().getUsername(), database.getContainer().getPassword()); - } - - public static void insertQueryStore(PrivilegedDatabaseDto database, QueryDto query, UUID userId) throws SQLException { + public static void insertQueryStore(DatabaseDto database, QueryDto query, UUID userId) throws SQLException { final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName(); log.trace("connect to database: {}", jdbc); try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) { @@ -272,7 +161,7 @@ public class MariaDbConfig { } } - public static List<Map<String, Object>> listQueryStore(PrivilegedDatabaseDto database) throws SQLException { + public static List<Map<String, Object>> listQueryStore(DatabaseDto database) throws SQLException { final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName(); log.trace("connect to database {}", jdbc); try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) { @@ -297,7 +186,7 @@ public class MariaDbConfig { } } - public static List<Map<String, String>> selectQuery(PrivilegedDatabaseDto database, String query, Set<String> columns) + public static List<Map<String, String>> selectQuery(DatabaseDto database, String query, Set<String> columns) throws SQLException { final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName(); log.trace("connect to database {}", jdbc); @@ -318,7 +207,7 @@ public class MariaDbConfig { return rows; } - public static List<Map<String, byte[]>> selectQueryByteArr(PrivilegedDatabaseDto database, String query, Set<String> columns) + public static List<Map<String, byte[]>> selectQueryByteArr(DatabaseDto database, String query, Set<String> columns) throws SQLException { final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName(); log.trace("connect to database {}", jdbc); @@ -339,7 +228,7 @@ public class MariaDbConfig { return rows; } - public static void execute(PrivilegedDatabaseDto database, String query) + public static void execute(DatabaseDto database, String query) throws SQLException { final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName(); log.trace("connect to database {}", jdbc); @@ -349,17 +238,7 @@ public class MariaDbConfig { } } - public static void execute(PrivilegedContainerDto container, String query) - throws SQLException { - final String jdbc = "jdbc:mariadb://" + container.getHost() + ":" + container.getPort(); - log.trace("connect to database: {}", jdbc); - try (Connection connection = DriverManager.getConnection(jdbc, container.getUsername(), container.getPassword())) { - final Statement statement = connection.createStatement(); - statement.executeUpdate(query); - } - } - - public static void dropQueryStore(PrivilegedDatabaseDto database) + public static void dropQueryStore(DatabaseDto database) throws SQLException { final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName(); log.trace("connect to database: {}", jdbc); @@ -373,78 +252,4 @@ public class MariaDbConfig { } } - public static Map<String, List<Object>> describeTableSchema(PrivilegedTableDto table, String username, String password) - throws SQLException { - final String jdbc = "jdbc:mariadb://" + table.getDatabase().getContainer().getHost() + ":" + table.getDatabase().getContainer().getPort() + "/" + table.getDatabase().getInternalName(); - log.trace("connect to database {}", jdbc); - final Map<String, List<Object>> out = new HashMap<>(); - try (Connection connection = DriverManager.getConnection(jdbc, username, password)) { - final String query = "SHOW COLUMNS FROM `" + table.getInternalName() + "`;"; - log.trace("prepare statement '{}'", query); - final PreparedStatement statement = connection.prepareStatement(query); - final ResultSet resultSet = statement.executeQuery(); - statement.close(); - while (resultSet.next()) { - if (resultSet.getString("Field").equals("id")) { - continue; - } - out.put(resultSet.getString("Field"), List.of(resultSet.getString("Type"), resultSet.getString("Null"), resultSet.getString("Key"))); - } - return out; - } - } - - public static ColumnTypeDto typetoColumnTypeDto(String data) throws Exception { - if (data.toUpperCase().startsWith("TINYINT(1)")) { - /* boolean in MySQL */ - return ColumnTypeDto.BOOL; - } - final Matcher matcher = Pattern.compile("([A-Z]+)") - .matcher(data.toUpperCase()); - if (!matcher.find()) { - log.error("Failed to map type: does not match expected format"); - throw new Exception("Failed to map type: does not match expected format"); - } - final String type = matcher.group(1); - try { - return ColumnTypeDto.valueOf(type); - } catch (IllegalArgumentException e) { - if (type.startsWith("TINYINT")) { - /* boolean in MySQL */ - return ColumnTypeDto.BOOL; - } else if (type.startsWith("BOOL")) { - /* boolean */ - return ColumnTypeDto.BOOL; - } else if (type.startsWith("DOUBLE")) { - /* double precision */ - return ColumnTypeDto.DOUBLE; - } else if (type.startsWith("INT")) { - /* integer synonym */ - return ColumnTypeDto.INT; - } else if (type.startsWith("DEC")) { - /* decimal synonym */ - return ColumnTypeDto.DECIMAL; - } else if (type.startsWith("ENUM")) { - return ColumnTypeDto.ENUM; - } else if (type.startsWith("SET")) { - return ColumnTypeDto.SET; - } - } - log.error("Failed to map data {} and type {}", data, type); - throw new Exception("Failed to map data " + data + " and type " + type); - } - - public static boolean tableExists(PrivilegedDatabaseDto database, String tableName) - throws SQLException { - final String jdbc = "jdbc:mariadb://" + database.getContainer().getHost() + ":" + database.getContainer().getPort() + "/" + database.getInternalName(); - log.trace("connect to database {}", jdbc); - try (Connection connection = DriverManager.getConnection(jdbc, database.getContainer().getUsername(), database.getContainer().getPassword())) { - final Statement statement = connection.createStatement(); - final String query = "SHOW TABLES LIKE '" + tableName + "';"; - log.trace("execute query {}", query); - final ResultSet result = statement.executeQuery(query); - return result.next(); - } - } - } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/AccessEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/AccessEndpointUnitTest.java index 9fb4003dba35234f81cedf8334e74c8489268269..3cbdf09af1f7705b2dd3fa550c24770618ba99d1 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/AccessEndpointUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/AccessEndpointUnitTest.java @@ -1,8 +1,8 @@ package at.tuwien.endpoint; import at.tuwien.api.database.AccessTypeDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.user.internal.PrivilegedUserDto; +import at.tuwien.api.database.DatabaseDto; +import at.tuwien.api.user.UserDto; import at.tuwien.endpoints.AccessEndpoint; import at.tuwien.exception.*; import at.tuwien.service.AccessService; @@ -53,7 +53,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { when(credentialService.getDatabase(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); when(credentialService.getUser(USER_4_ID)) - .thenReturn(USER_4_PRIVILEGED_DTO); + .thenReturn(USER_4_DTO); /* test */ final ResponseEntity<Void> response = accessEndpoint.create(DATABASE_1_ID, USER_4_ID, UPDATE_DATABASE_ACCESS_READ_DTO); @@ -70,7 +70,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { when(credentialService.getDatabase(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); when(credentialService.getUser(USER_1_ID)) - .thenReturn(USER_1_PRIVILEGED_DTO); + .thenReturn(USER_1_DTO); /* test */ assertThrows(NotAllowedException.class, () -> { @@ -87,10 +87,10 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { when(credentialService.getDatabase(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); when(credentialService.getUser(USER_4_ID)) - .thenReturn(USER_4_PRIVILEGED_DTO); + .thenReturn(USER_4_DTO); doThrow(SQLException.class) .when(accessService) - .create(DATABASE_1_PRIVILEGED_DTO, USER_4_PRIVILEGED_DTO, AccessTypeDto.READ); + .create(DATABASE_1_PRIVILEGED_DTO, USER_4_DTO, AccessTypeDto.READ); /* test */ assertThrows(DatabaseUnavailableException.class, () -> { @@ -151,7 +151,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { when(credentialService.getDatabase(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); when(credentialService.getUser(USER_1_ID)) - .thenReturn(USER_1_PRIVILEGED_DTO); + .thenReturn(USER_1_DTO); /* test */ final ResponseEntity<Void> response = accessEndpoint.update(DATABASE_1_ID, USER_1_ID, UPDATE_DATABASE_ACCESS_READ_DTO); @@ -168,10 +168,10 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { when(credentialService.getDatabase(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); when(credentialService.getUser(USER_1_ID)) - .thenReturn(USER_1_PRIVILEGED_DTO); + .thenReturn(USER_1_DTO); doThrow(SQLException.class) .when(accessService) - .update(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO, AccessTypeDto.READ); + .update(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO, AccessTypeDto.READ); /* test */ assertThrows(DatabaseUnavailableException.class, () -> { @@ -188,7 +188,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { when(credentialService.getDatabase(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); when(credentialService.getUser(USER_4_ID)) - .thenReturn(USER_4_PRIVILEGED_DTO); + .thenReturn(USER_4_DTO); /* test */ assertThrows(NotAllowedException.class, () -> { @@ -250,10 +250,10 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { when(credentialService.getDatabase(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); when(credentialService.getUser(USER_1_ID)) - .thenReturn(USER_1_PRIVILEGED_DTO); + .thenReturn(USER_1_DTO); doNothing() .when(accessService) - .delete(any(PrivilegedDatabaseDto.class), any(PrivilegedUserDto.class)); + .delete(any(DatabaseDto.class), any(UserDto.class)); /* test */ final ResponseEntity<Void> response = accessEndpoint.revoke(DATABASE_1_ID, USER_1_ID); @@ -270,7 +270,7 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { when(credentialService.getDatabase(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); when(credentialService.getUser(USER_4_ID)) - .thenReturn(USER_4_PRIVILEGED_DTO); + .thenReturn(USER_4_DTO); /* test */ assertThrows(NotAllowedException.class, () -> { @@ -331,10 +331,10 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { when(credentialService.getDatabase(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); when(credentialService.getUser(USER_1_ID)) - .thenReturn(USER_1_PRIVILEGED_DTO); + .thenReturn(USER_1_DTO); doThrow(SQLException.class) .when(accessService) - .delete(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO); + .delete(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO); /* test */ assertThrows(DatabaseUnavailableException.class, () -> { diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java index c55442290ec1d17336dd73ac1dd4574f33e689a4..43f7b9353e0381a6bc001b1a563036e20e8daae1 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/DatabaseEndpointUnitTest.java @@ -2,13 +2,13 @@ package at.tuwien.endpoint; import at.tuwien.api.database.AccessTypeDto; import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.user.internal.PrivilegedUserDto; +import at.tuwien.api.user.UserDto; import at.tuwien.endpoints.DatabaseEndpoint; import at.tuwien.exception.*; import at.tuwien.service.AccessService; +import at.tuwien.service.ContainerService; import at.tuwien.service.CredentialService; import at.tuwien.service.DatabaseService; -import at.tuwien.service.SubsetService; import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; @@ -39,7 +39,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { private DatabaseEndpoint databaseEndpoint; @MockBean - private SubsetService queryService; + private ContainerService containerService; @MockBean private AccessService accessService; @@ -63,15 +63,15 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { /* mock */ when(credentialService.getContainer(CONTAINER_1_ID)) - .thenReturn(CONTAINER_1_PRIVILEGED_DTO); - when(databaseService.create(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL)) + .thenReturn(CONTAINER_1_DTO); + when(containerService.createDatabase(CONTAINER_1_DTO, DATABASE_1_CREATE_INTERNAL)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); doNothing() - .when(queryService) - .createQueryStore(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); + .when(containerService) + .createQueryStore(CONTAINER_1_DTO, DATABASE_1_INTERNALNAME); doNothing() .when(accessService) - .create(eq(DATABASE_1_PRIVILEGED_DTO), any(PrivilegedUserDto.class), any(AccessTypeDto.class)); + .create(eq(DATABASE_1_PRIVILEGED_DTO), any(UserDto.class), any(AccessTypeDto.class)); /* test */ final ResponseEntity<DatabaseDto> response = databaseEndpoint.create(DATABASE_1_CREATE_INTERNAL); @@ -85,15 +85,15 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { /* mock */ when(credentialService.getContainer(CONTAINER_1_ID)) - .thenReturn(CONTAINER_1_PRIVILEGED_DTO); - when(databaseService.create(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL)) + .thenReturn(CONTAINER_1_DTO); + when(containerService.createDatabase(CONTAINER_1_DTO, DATABASE_1_CREATE_INTERNAL)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); doNothing() - .when(queryService) - .createQueryStore(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); + .when(containerService) + .createQueryStore(CONTAINER_1_DTO, DATABASE_1_INTERNALNAME); doNothing() .when(accessService) - .create(eq(DATABASE_1_PRIVILEGED_DTO), any(PrivilegedUserDto.class), any(AccessTypeDto.class)); + .create(eq(DATABASE_1_PRIVILEGED_DTO), any(UserDto.class), any(AccessTypeDto.class)); /* test */ assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { @@ -108,10 +108,10 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { /* mock */ when(credentialService.getContainer(CONTAINER_1_ID)) - .thenReturn(CONTAINER_1_PRIVILEGED_DTO); + .thenReturn(CONTAINER_1_DTO); doThrow(SQLException.class) - .when(databaseService) - .create(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL); + .when(containerService) + .createDatabase(CONTAINER_1_DTO, DATABASE_1_CREATE_INTERNAL); /* test */ assertThrows(DatabaseUnavailableException.class, () -> { @@ -144,11 +144,11 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { doThrow(ContainerNotFoundException.class) .when(credentialService) .getContainer(CONTAINER_1_ID); - when(databaseService.create(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL)) + when(containerService.createDatabase(CONTAINER_1_DTO, DATABASE_1_CREATE_INTERNAL)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); doThrow(QueryStoreCreateException.class) - .when(queryService) - .createQueryStore(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); + .when(containerService) + .createQueryStore(CONTAINER_1_DTO, DATABASE_1_INTERNALNAME); /* test */ assertThrows(ContainerNotFoundException.class, () -> { diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/SubsetEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/SubsetEndpointUnitTest.java index 8a08f8231fe0de7babf1db995dc60786407425f8..8837ccb0d1c96f3dff61c0826fcabb956ecdc914 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/SubsetEndpointUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/SubsetEndpointUnitTest.java @@ -1,14 +1,14 @@ package at.tuwien.endpoint; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; +import at.tuwien.api.database.CreateViewDto; +import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.query.ExecuteStatementDto; import at.tuwien.api.database.query.QueryDto; import at.tuwien.api.database.query.QueryPersistDto; import at.tuwien.endpoints.SubsetEndpoint; import at.tuwien.exception.*; -import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.service.CredentialService; -import at.tuwien.service.SchemaService; +import at.tuwien.service.DatabaseService; import at.tuwien.service.StorageService; import at.tuwien.service.SubsetService; import at.tuwien.test.AbstractUnitTest; @@ -25,7 +25,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.security.test.context.support.WithAnonymousUser; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -53,12 +52,6 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @MockBean private SubsetService subsetService; - @MockBean - private SchemaService schemaService; - - @MockBean - private MetadataServiceGateway metadataServiceGateway; - @MockBean private HttpServletRequest httpServletRequest; @@ -66,10 +59,10 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { private StorageService storageService; @MockBean - private CredentialService credentialService; + private DatabaseService databaseService; @MockBean - private MockHttpServletRequest mockHttpServletRequest; + private CredentialService credentialService; @BeforeEach public void beforeEach() { @@ -98,6 +91,8 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { MetadataServiceException { /* mock */ + when(credentialService.getAccess(DATABASE_3_ID, USER_3_ID)) + .thenReturn(DATABASE_3_USER_1_READ_ACCESS_DTO); when(subsetService.findAll(DATABASE_3_PRIVILEGED_DTO, null)) .thenReturn(List.of(QUERY_1_DTO, QUERY_2_DTO, QUERY_3_DTO, QUERY_4_DTO, QUERY_5_DTO, QUERY_6_DTO)); @@ -136,14 +131,12 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser - public void findById_privateDataPrivateSchemaAnonymous_fails() throws DatabaseNotFoundException, SQLException, - RemoteUnavailableException, UserNotFoundException, QueryNotFoundException, MetadataServiceException { + public void findById_privateDataPrivateSchemaAnonymous_fails() throws DatabaseNotFoundException, + RemoteUnavailableException, MetadataServiceException { /* mock */ when(credentialService.getDatabase(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); - when(subsetService.findById(DATABASE_1_PRIVILEGED_DTO, QUERY_1_ID)) - .thenReturn(QUERY_1_DTO); /* test */ assertThrows(NotAllowedException.class, () -> { @@ -214,10 +207,10 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_1_PRIVILEGED_DTO); when(subsetService.findById(DATABASE_1_PRIVILEGED_DTO, QUERY_1_ID)) .thenReturn(QUERY_5_DTO); + when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(null), eq(null), eq(null), eq(null))) + .thenReturn(mock); when(storageService.transformDataset(any(Dataset.class))) .thenReturn(EXPORT_RESOURCE_DTO); - when(subsetService.getData(any(PrivilegedDatabaseDto.class), any(QueryDto.class), eq(null), eq(null))) - .thenReturn(mock); /* test */ generic_findById(DATABASE_1_ID, QUERY_1_ID, "text/csv", null, USER_1_PRINCIPAL); @@ -226,20 +219,11 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser public void findById_publicDataPrivateSchemaAnonymous_fails() throws DatabaseNotFoundException, - RemoteUnavailableException, UserNotFoundException, StorageUnavailableException, QueryMalformedException, - QueryNotFoundException, SQLException, MetadataServiceException, TableNotFoundException, - ViewMalformedException { - final Dataset<Row> mock = sparkSession.emptyDataFrame(); + RemoteUnavailableException, MetadataServiceException { /* mock */ when(credentialService.getDatabase(DATABASE_3_ID)) .thenReturn(DATABASE_3_PRIVILEGED_DTO); - when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID)) - .thenReturn(QUERY_5_DTO); - when(subsetService.getData(any(PrivilegedDatabaseDto.class), any(QueryDto.class), eq(null), eq(null))) - .thenReturn(mock); - when(storageService.transformDataset(any(Dataset.class))) - .thenReturn(EXPORT_RESOURCE_DTO); /* test */ assertThrows(NotAllowedException.class, () -> { @@ -251,7 +235,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void findById_publicDataPublicSchemaAnonymous_fails() throws DatabaseNotFoundException, SQLException, RemoteUnavailableException, UserNotFoundException, QueryMalformedException, StorageUnavailableException, - QueryNotFoundException, MetadataServiceException, TableNotFoundException, ViewMalformedException { + QueryNotFoundException, MetadataServiceException, TableNotFoundException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ @@ -259,7 +243,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_3_PRIVILEGED_DTO); when(subsetService.findById(DATABASE_4_PRIVILEGED_DTO, QUERY_5_ID)) .thenReturn(QUERY_5_DTO); - when(subsetService.getData(any(PrivilegedDatabaseDto.class), any(QueryDto.class), eq(null), eq(null))) + when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) .thenReturn(mock); when(storageService.transformDataset(any(Dataset.class))) .thenReturn(EXPORT_RESOURCE_DTO); @@ -304,29 +288,6 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { }); } - @Test - @WithMockUser(username = USER_1_USERNAME) - public void findById_publicDataPrivateSchemaUnavailableExport_fails() throws DatabaseNotFoundException, RemoteUnavailableException, - MetadataServiceException, SQLException, QueryMalformedException, UserNotFoundException, - QueryNotFoundException, TableNotFoundException, ViewMalformedException, StorageUnavailableException { - - /* mock */ - when(credentialService.getDatabase(DATABASE_3_ID)) - .thenReturn(DATABASE_3_PRIVILEGED_DTO); - when(subsetService.findById(DATABASE_3_PRIVILEGED_DTO, QUERY_5_ID)) - .thenReturn(QUERY_5_DTO); - when(storageService.transformDataset(any(Dataset.class))) - .thenReturn(EXPORT_RESOURCE_DTO); - doThrow(SQLException.class) - .when(subsetService) - .getData(eq(DATABASE_3_PRIVILEGED_DTO), eq(QUERY_5_DTO), eq(null), eq(null)); - - /* test */ - assertThrows(DatabaseUnavailableException.class, () -> { - generic_findById(DATABASE_3_ID, QUERY_5_ID, "text/csv", null, USER_1_PRINCIPAL); - }); - } - @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"execute-query"}) public void create_noAccess_succeeds() throws UserNotFoundException, QueryStoreInsertException, @@ -342,12 +303,12 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { /* mock */ when(credentialService.getDatabase(DATABASE_3_ID)) .thenReturn(DATABASE_3_PRIVILEGED_DTO); - when(subsetService.getData(eq(DATABASE_3_PRIVILEGED_DTO), any(QueryDto.class), eq(0L), eq(10L))) + when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) .thenReturn(mock); when(subsetService.findById(eq(DATABASE_3_PRIVILEGED_DTO), anyLong())) .thenReturn(QUERY_5_DTO); - when(schemaService.inspectView(eq(DATABASE_3_PRIVILEGED_DTO), anyString())) - .thenReturn(VIEW_5_DTO); + when(databaseService.inspectView(any(DatabaseDto.class), anyString())) + .thenReturn(QUERY_5_VIEW_DTO); when(httpServletRequest.getMethod()) .thenReturn("POST"); @@ -388,12 +349,16 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { /* mock */ when(credentialService.getDatabase(DATABASE_3_ID)) .thenReturn(DATABASE_3_PRIVILEGED_DTO); - when(schemaService.inspectView(eq(DATABASE_3_PRIVILEGED_DTO), anyString())) - .thenReturn(VIEW_5_DTO); - when(subsetService.findById(eq(DATABASE_3_PRIVILEGED_DTO), anyLong())) + when(subsetService.create(any(DatabaseDto.class), eq(QUERY_5_STATEMENT), any(Instant.class), eq(USER_1_ID))) + .thenReturn(QUERY_5_ID); + when(subsetService.findById(any(DatabaseDto.class), eq(QUERY_5_ID))) .thenReturn(QUERY_5_DTO); - when(subsetService.getData(eq(DATABASE_3_PRIVILEGED_DTO), any(QueryDto.class), eq(0L), eq(10L))) + when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) .thenReturn(mock); + when(databaseService.createView(any(DatabaseDto.class), any(CreateViewDto.class))) + .thenReturn(QUERY_5_VIEW_DTO); + when(databaseService.inspectView(any(DatabaseDto.class), anyString())) + .thenReturn(QUERY_5_VIEW_DTO); when(httpServletRequest.getMethod()) .thenReturn("POST"); @@ -401,38 +366,6 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { subsetEndpoint.create(DATABASE_3_ID, request, USER_1_PRINCIPAL, httpServletRequest, null, null, null); } - @Test - @WithMockUser(username = USER_1_USERNAME, authorities = {"execute-query"}) - public void create_unavailable_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, - SQLException, MetadataServiceException, QueryMalformedException, TableNotFoundException, - ViewMalformedException, UserNotFoundException, QueryNotFoundException, QueryStoreInsertException, - NotAllowedException { - final ExecuteStatementDto request = ExecuteStatementDto.builder() - .statement(QUERY_5_STATEMENT) - .build(); - - /* mock */ - when(credentialService.getDatabase(DATABASE_3_ID)) - .thenReturn(DATABASE_3_PRIVILEGED_DTO); - doThrow(SQLException.class) - .when(subsetService) - .getData(eq(DATABASE_3_PRIVILEGED_DTO), any(QueryDto.class), eq(null), eq(null)); - when(subsetService.findById(eq(DATABASE_3_PRIVILEGED_DTO), anyLong())) - .thenReturn(QUERY_5_DTO); - when(metadataServiceGateway.getAccess(DATABASE_3_ID, USER_1_ID)) - .thenReturn(DATABASE_3_USER_1_READ_ACCESS_DTO); - doThrow(SQLException.class) - .when(subsetService) - .create(eq(DATABASE_3_PRIVILEGED_DTO), eq(QUERY_5_STATEMENT), any(Instant.class), eq(USER_1_ID)); - when(httpServletRequest.getMethod()) - .thenReturn("POST"); - - /* test */ - assertThrows(DatabaseUnavailableException.class, () -> { - subsetEndpoint.create(DATABASE_3_ID, request, USER_1_PRINCIPAL, httpServletRequest, null, null, null); - }); - } - @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"execute-query"}) public void create_databaseNotFound_fails() throws RemoteUnavailableException, @@ -454,34 +387,6 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { }); } - @Test - @WithMockUser(username = USER_4_USERNAME) - public void create_noRole_fails() throws DatabaseNotFoundException, RemoteUnavailableException, - MetadataServiceException, UserNotFoundException, QueryStoreInsertException, TableMalformedException, - NotAllowedException, SQLException, QueryNotFoundException, DatabaseUnavailableException, - StorageUnavailableException, QueryMalformedException, QueryNotSupportedException, PaginationException, - StorageNotFoundException, TableNotFoundException, ViewMalformedException, ViewNotFoundException { - final Dataset<Row> mock = sparkSession.emptyDataFrame(); - final ExecuteStatementDto request = ExecuteStatementDto.builder() - .statement(QUERY_5_STATEMENT) - .build(); - - /* mock */ - when(credentialService.getDatabase(DATABASE_3_ID)) - .thenReturn(DATABASE_3_PRIVILEGED_DTO); - when(subsetService.getData(eq(DATABASE_3_PRIVILEGED_DTO), any(QueryDto.class), eq(0L), eq(10L))) - .thenReturn(mock); - when(subsetService.findById(eq(DATABASE_3_PRIVILEGED_DTO), anyLong())) - .thenReturn(QUERY_5_DTO); - when(schemaService.inspectView(eq(DATABASE_3_PRIVILEGED_DTO), anyString())) - .thenReturn(VIEW_5_DTO); - when(httpServletRequest.getMethod()) - .thenReturn("POST"); - - /* test */ - subsetEndpoint.create(DATABASE_3_ID, request, USER_4_PRINCIPAL, httpServletRequest, null, null, null); - } - @Test @WithAnonymousUser public void create_publicDataPublicSchemaAnonymous_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, @@ -499,10 +404,10 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_4_PRIVILEGED_DTO); when(subsetService.findById(eq(DATABASE_4_PRIVILEGED_DTO), anyLong())) .thenReturn(QUERY_5_DTO); - when(subsetService.getData(eq(DATABASE_4_PRIVILEGED_DTO), any(QueryDto.class), eq(0L), eq(10L))) + when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) .thenReturn(mock); - when(schemaService.inspectView(eq(DATABASE_4_PRIVILEGED_DTO), anyString())) - .thenReturn(VIEW_5_DTO); + when(databaseService.inspectView(any(DatabaseDto.class), anyString())) + .thenReturn(QUERY_5_VIEW_DTO); when(httpServletRequest.getMethod()) .thenReturn("POST"); @@ -527,10 +432,10 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_1_PRIVILEGED_DTO); when(subsetService.findById(eq(DATABASE_1_PRIVILEGED_DTO), anyLong())) .thenReturn(QUERY_1_DTO); - when(subsetService.getData(eq(DATABASE_1_PRIVILEGED_DTO), any(QueryDto.class), eq(0L), eq(10L))) + when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) .thenReturn(mock); - when(schemaService.inspectView(eq(DATABASE_1_PRIVILEGED_DTO), anyString())) - .thenReturn(VIEW_1_DTO); + when(databaseService.inspectView(any(DatabaseDto.class), anyString())) + .thenReturn(QUERY_1_VIEW_DTO); when(httpServletRequest.getMethod()) .thenReturn("POST"); @@ -542,7 +447,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void create_privateDataPublicSchemaAnonymous_fails() throws DatabaseNotFoundException, SQLException, MetadataServiceException, UserNotFoundException, QueryNotFoundException, QueryMalformedException, - TableNotFoundException, ViewMalformedException, ViewNotFoundException, RemoteUnavailableException { + TableNotFoundException, RemoteUnavailableException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); final ExecuteStatementDto request = ExecuteStatementDto.builder() .statement(QUERY_5_STATEMENT) @@ -553,10 +458,8 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_2_PRIVILEGED_DTO); when(subsetService.findById(eq(DATABASE_2_PRIVILEGED_DTO), anyLong())) .thenReturn(QUERY_2_DTO); - when(subsetService.getData(eq(DATABASE_2_PRIVILEGED_DTO), any(QueryDto.class), eq(0L), eq(10L))) + when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) .thenReturn(mock); - when(schemaService.inspectView(eq(DATABASE_2_PRIVILEGED_DTO), anyString())) - .thenReturn(VIEW_4_DTO); when(httpServletRequest.getMethod()) .thenReturn("POST"); @@ -570,7 +473,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { public void getData_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, NotAllowedException, SQLException, QueryNotFoundException, TableMalformedException, QueryMalformedException, DatabaseUnavailableException, PaginationException, MetadataServiceException, TableNotFoundException, - ViewMalformedException, ViewNotFoundException { + ViewNotFoundException, ViewMalformedException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ @@ -580,15 +483,15 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { .thenReturn(QUERY_5_DTO); when(subsetService.reExecuteCount(DATABASE_3_PRIVILEGED_DTO, QUERY_5_DTO)) .thenReturn(QUERY_5_RESULT_NUMBER); - when(subsetService.getData(eq(DATABASE_3_PRIVILEGED_DTO), any(QueryDto.class), eq(0L), eq(10L))) + when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) .thenReturn(mock); - when(schemaService.inspectView(eq(DATABASE_3_PRIVILEGED_DTO), anyString())) - .thenReturn(VIEW_5_DTO); + when(databaseService.inspectView(any(DatabaseDto.class), anyString())) + .thenReturn(QUERY_5_VIEW_DTO); when(httpServletRequest.getMethod()) .thenReturn("GET"); /* test */ - final ResponseEntity<List<Map<String, Object>>> response = subsetEndpoint.getData(DATABASE_3_ID, QUERY_5_ID, null, httpServletRequest, null, null); + final ResponseEntity<List<Map<String, Object>>> response = subsetEndpoint.getData(DATABASE_3_ID, QUERY_5_ID, null, httpServletRequest, null, null, null); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); } @@ -597,7 +500,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { public void getData_head_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, NotAllowedException, SQLException, QueryNotFoundException, TableMalformedException, QueryMalformedException, DatabaseUnavailableException, PaginationException, MetadataServiceException, - TableNotFoundException, ViewMalformedException, ViewNotFoundException { + TableNotFoundException, ViewNotFoundException, ViewMalformedException { /* mock */ when(credentialService.getDatabase(DATABASE_3_ID)) @@ -610,7 +513,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { .thenReturn("HEAD"); /* test */ - final ResponseEntity<List<Map<String, Object>>> response = subsetEndpoint.getData(DATABASE_3_ID, QUERY_5_ID, null, httpServletRequest, null, null); + final ResponseEntity<List<Map<String, Object>>> response = subsetEndpoint.getData(DATABASE_3_ID, QUERY_5_ID, null, httpServletRequest, null, null, null); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getHeaders().get("X-Count")); assertEquals(1, response.getHeaders().get("X-Count").size()); @@ -622,7 +525,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { public void getData_private_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, DatabaseUnavailableException, NotAllowedException, TableMalformedException, QueryMalformedException, QueryNotFoundException, PaginationException, SQLException, - MetadataServiceException, TableNotFoundException, ViewMalformedException, ViewNotFoundException { + MetadataServiceException, TableNotFoundException, ViewNotFoundException, ViewMalformedException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ @@ -632,15 +535,15 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { .thenReturn(QUERY_1_DTO); when(subsetService.reExecuteCount(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO)) .thenReturn(QUERY_1_RESULT_NUMBER); - when(subsetService.getData(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO, 0L, 10L)) + when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) .thenReturn(mock); - when(schemaService.inspectView(eq(DATABASE_1_PRIVILEGED_DTO), anyString())) - .thenReturn(VIEW_1_DTO); + when(databaseService.inspectView(any(DatabaseDto.class), anyString())) + .thenReturn(QUERY_1_VIEW_DTO); when(httpServletRequest.getMethod()) .thenReturn("GET"); /* test */ - final ResponseEntity<List<Map<String, Object>>> response = subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, null); + final ResponseEntity<List<Map<String, Object>>> response = subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, null, null); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); } @@ -656,7 +559,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, null, httpServletRequest, null, null); + subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, null, httpServletRequest, null, null, null); }); } @@ -674,7 +577,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { /* test */ assertThrows(NotAllowedException.class, () -> { - subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, null); + subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, null, null); }); } @@ -683,7 +586,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { public void getData_privateHead_succeeds() throws DatabaseNotFoundException, RemoteUnavailableException, UserNotFoundException, DatabaseUnavailableException, NotAllowedException, TableMalformedException, QueryMalformedException, QueryNotFoundException, PaginationException, SQLException, - MetadataServiceException, TableNotFoundException, ViewMalformedException, ViewNotFoundException { + MetadataServiceException, TableNotFoundException, ViewNotFoundException, ViewMalformedException { /* mock */ when(credentialService.getDatabase(DATABASE_1_ID)) @@ -696,36 +599,13 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { .thenReturn("HEAD"); /* test */ - final ResponseEntity<List<Map<String, Object>>> response = subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, null); + final ResponseEntity<List<Map<String, Object>>> response = subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, null, null); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getHeaders().get("X-Count")); assertEquals(1, response.getHeaders().get("X-Count").size()); assertEquals(QUERY_1_RESULT_NUMBER, Long.parseLong(response.getHeaders().get("X-Count").get(0))); } - @Test - @WithMockUser(username = USER_1_USERNAME) - public void getData_unavailable_fails() throws DatabaseNotFoundException, RemoteUnavailableException, SQLException, - UserNotFoundException, QueryNotFoundException, MetadataServiceException, QueryMalformedException, - TableNotFoundException, ViewMalformedException { - - /* mock */ - when(credentialService.getDatabase(DATABASE_1_ID)) - .thenReturn(DATABASE_1_PRIVILEGED_DTO); - when(subsetService.findById(DATABASE_1_PRIVILEGED_DTO, QUERY_1_ID)) - .thenReturn(QUERY_1_DTO); - when(httpServletRequest.getMethod()) - .thenReturn("GET"); - doThrow(SQLException.class) - .when(subsetService) - .getData(DATABASE_1_PRIVILEGED_DTO, QUERY_1_DTO, 0L, 10L); - - /* test */ - assertThrows(DatabaseUnavailableException.class, () -> { - subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, null); - }); - } - @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"persist-query"}) public void persist_succeeds() throws NotAllowedException, RemoteUnavailableException, DatabaseNotFoundException, @@ -825,7 +705,7 @@ public class SubsetEndpointUnitTest extends AbstractUnitTest { }); } - protected List<QueryDto> generic_list(Long databaseId, PrivilegedDatabaseDto database, Principal principal) + protected List<QueryDto> generic_list(Long databaseId, DatabaseDto database, Principal principal) throws NotAllowedException, DatabaseUnavailableException, QueryNotFoundException, DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException { diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java index e3171892a0be41f816feb749990a70aafc252f3d..b37007a0108946429481c7fa229eb575bc6e98f0 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/TableEndpointUnitTest.java @@ -1,14 +1,15 @@ package at.tuwien.endpoint; import at.tuwien.api.database.DatabaseAccessDto; +import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.query.ImportDto; import at.tuwien.api.database.table.*; -import at.tuwien.api.database.table.internal.PrivilegedTableDto; import at.tuwien.endpoints.TableEndpoint; import at.tuwien.exception.*; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.service.CredentialService; -import at.tuwien.service.SchemaService; +import at.tuwien.service.DatabaseService; +import at.tuwien.service.SubsetService; import at.tuwien.service.TableService; import at.tuwien.test.AbstractUnitTest; import jakarta.servlet.http.HttpServletRequest; @@ -61,7 +62,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest { private TableService tableService; @MockBean - private SchemaService schemaService; + private SubsetService subsetService; + + @MockBean + private DatabaseService databaseService; @MockBean private CredentialService credentialService; @@ -92,17 +96,17 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) - public void create_succeeds() throws DatabaseUnavailableException, TableMalformedException, + public void create_succeeds() throws DatabaseUnavailableException, TableMalformedException, ViewNotFoundException, DatabaseNotFoundException, TableExistsException, RemoteUnavailableException, SQLException, TableNotFoundException, QueryMalformedException, MetadataServiceException, ContainerNotFoundException { /* mock */ when(credentialService.getDatabase(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); - when(tableService.createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_CREATE_INTERNAL_DTO)) - .thenReturn(TABLE_4_DTO); - when(schemaService.inspectTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_INTERNALNAME)) - .thenReturn(TABLE_4_DTO); + when(databaseService.createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_CREATE_INTERNAL_DTO)) + .thenReturn(TABLE_4_PRIVILEGED_DTO); + when(databaseService.inspectTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_INTERNALNAME)) + .thenReturn(TABLE_4_PRIVILEGED_DTO); /* test */ final ResponseEntity<TableDto> response = tableEndpoint.create(DATABASE_1_ID, TABLE_4_CREATE_INTERNAL_DTO); @@ -144,7 +148,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { when(credentialService.getDatabase(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); doThrow(SQLException.class) - .when(tableService) + .when(databaseService) .createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_CREATE_INTERNAL_DTO); /* test */ @@ -171,7 +175,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* mock */ when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) .thenReturn(TABLE_8_PRIVILEGED_DTO); - when(tableService.getStatistics(any(PrivilegedTableDto.class))) + when(tableService.getStatistics(any(TableDto.class))) .thenReturn(TABLE_8_STATISTIC_DTO); /* test */ @@ -189,7 +193,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { .thenReturn(TABLE_8_PRIVILEGED_DTO); doThrow(SQLException.class) .when(tableService) - .getStatistics(any(PrivilegedTableDto.class)); + .getStatistics(any(TableDto.class)); /* test */ assertThrows(DatabaseUnavailableException.class, () -> { @@ -276,14 +280,17 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser - public void getData_succeeds() throws DatabaseUnavailableException, TableNotFoundException, QueryMalformedException, - RemoteUnavailableException, PaginationException, MetadataServiceException, NotAllowedException { + public void getData_publicDataPrivateSchema_succeeds() throws DatabaseUnavailableException, TableNotFoundException, QueryMalformedException, + RemoteUnavailableException, PaginationException, MetadataServiceException, NotAllowedException, + DatabaseNotFoundException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) .thenReturn(TABLE_8_PRIVILEGED_DTO); - when(tableService.getData(eq(DATABASE_3_PRIVILEGED_DTO), eq(TABLE_8_INTERNAL_NAME), any(Instant.class), eq(null), eq(null), eq(null), eq(null))) + when(credentialService.getDatabase(DATABASE_3_ID)) + .thenReturn(DATABASE_3_PRIVILEGED_DTO); + when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) .thenReturn(mock); when(httpServletRequest.getMethod()) .thenReturn("GET"); @@ -298,7 +305,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void getData_head_succeeds() throws DatabaseUnavailableException, TableNotFoundException, SQLException, QueryMalformedException, RemoteUnavailableException, PaginationException, - MetadataServiceException, NotAllowedException { + MetadataServiceException, NotAllowedException, DatabaseNotFoundException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ @@ -306,7 +313,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { .thenReturn(TABLE_8_PRIVILEGED_DTO); when(tableService.getCount(eq(TABLE_8_PRIVILEGED_DTO), any(Instant.class))) .thenReturn(3L); - when(tableService.getData(eq(DATABASE_3_PRIVILEGED_DTO), eq(TABLE_8_INTERNAL_NAME), any(Instant.class), eq(null), eq(null), eq(null), eq(null))) + when(subsetService.getData(eq(DATABASE_3_PRIVILEGED_DTO), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) .thenReturn(mock); when(httpServletRequest.getMethod()) .thenReturn("HEAD"); @@ -357,14 +364,16 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser public void getData_unavailable_fails() throws TableNotFoundException, RemoteUnavailableException, - MetadataServiceException, QueryMalformedException { + MetadataServiceException, QueryMalformedException, DatabaseNotFoundException { /* mock */ when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) .thenReturn(TABLE_8_PRIVILEGED_DTO); + when(credentialService.getDatabase(DATABASE_3_ID)) + .thenReturn(DATABASE_3_PRIVILEGED_DTO); doThrow(QueryMalformedException.class) - .when(tableService) - .getData(eq(DATABASE_3_PRIVILEGED_DTO), eq(TABLE_8_INTERNAL_NAME), any(Instant.class), eq(null), eq(null), eq(null), eq(null)); + .when(subsetService) + .getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null)); when(httpServletRequest.getMethod()) .thenReturn("GET"); @@ -397,15 +406,17 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @MethodSource("anyAccess_parameters") public void getData_private_succeeds(String name, DatabaseAccessDto access) throws DatabaseUnavailableException, TableNotFoundException, QueryMalformedException, RemoteUnavailableException, PaginationException, - MetadataServiceException, NotAllowedException { + MetadataServiceException, NotAllowedException, DatabaseNotFoundException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID)) .thenReturn(TABLE_1_PRIVILEGED_DTO); + when(credentialService.getDatabase(DATABASE_1_ID)) + .thenReturn(DATABASE_1_PRIVILEGED_DTO); when(credentialService.getAccess(DATABASE_1_ID, USER_2_ID)) .thenReturn(access); - when(tableService.getData(eq(DATABASE_1_PRIVILEGED_DTO), eq(TABLE_1_INTERNAL_NAME), any(Instant.class), eq(null), eq(null), eq(null), eq(null))) + when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) .thenReturn(mock); when(httpServletRequest.getMethod()) .thenReturn("GET"); @@ -1139,14 +1150,16 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser - public void exportData_succeeds() throws TableNotFoundException, NotAllowedException, - StorageUnavailableException, QueryMalformedException, RemoteUnavailableException, MetadataServiceException { + public void exportData_publicDataPrivateSchema_succeeds() throws TableNotFoundException, NotAllowedException, StorageUnavailableException, + QueryMalformedException, RemoteUnavailableException, MetadataServiceException, DatabaseNotFoundException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ when(credentialService.getTable(DATABASE_3_ID, TABLE_8_ID)) .thenReturn(TABLE_8_PRIVILEGED_DTO); - when(tableService.getData(eq(DATABASE_3_PRIVILEGED_DTO), eq(TABLE_8_INTERNAL_NAME), any(Instant.class), eq(null), eq(null), eq(null), eq(null))) + when(credentialService.getDatabase(DATABASE_3_ID)) + .thenReturn(DATABASE_3_PRIVILEGED_DTO); + when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(null), eq(null), eq(null), eq(null))) .thenReturn(mock); /* test */ @@ -1157,9 +1170,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @ParameterizedTest @WithMockUser(username = USER_2_USERNAME) @MethodSource("anyAccess_parameters") - public void exportData_private_succeeds(String name, DatabaseAccessDto access) throws TableNotFoundException, - NotAllowedException, StorageUnavailableException, QueryMalformedException, RemoteUnavailableException, - MetadataServiceException { + public void exportData_privateDataPrivateSchema_succeeds(String name, DatabaseAccessDto access) + throws TableNotFoundException, NotAllowedException, StorageUnavailableException, QueryMalformedException, + RemoteUnavailableException, MetadataServiceException, DatabaseNotFoundException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ @@ -1167,7 +1180,9 @@ public class TableEndpointUnitTest extends AbstractUnitTest { .thenReturn(TABLE_1_PRIVILEGED_DTO); when(credentialService.getAccess(DATABASE_1_ID, USER_2_ID)) .thenReturn(access); - when(tableService.getData(eq(DATABASE_1_PRIVILEGED_DTO), eq(TABLE_1_INTERNAL_NAME), any(Instant.class), eq(null), eq(null), eq(null), eq(null))) + when(credentialService.getDatabase(DATABASE_1_ID)) + .thenReturn(DATABASE_1_PRIVILEGED_DTO); + when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(null), eq(null), eq(null), eq(null))) .thenReturn(mock); /* test */ @@ -1202,8 +1217,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { /* mock */ when(credentialService.getDatabase(DATABASE_3_ID)) .thenReturn(DATABASE_3_PRIVILEGED_DTO); - when(tableService.getSchemas(DATABASE_3_PRIVILEGED_DTO)) - .thenReturn(List.of(TABLE_8_DTO)); + when(databaseService.exploreTables(DATABASE_3_PRIVILEGED_DTO)) + .thenReturn(List.of(TABLE_8_PRIVILEGED_DTO)); /* test */ final ResponseEntity<List<TableDto>> response = tableEndpoint.getSchema(DATABASE_3_ID); @@ -1239,8 +1254,8 @@ public class TableEndpointUnitTest extends AbstractUnitTest { when(credentialService.getDatabase(DATABASE_3_ID)) .thenReturn(DATABASE_3_PRIVILEGED_DTO); doThrow(SQLException.class) - .when(tableService) - .getSchemas(DATABASE_3_PRIVILEGED_DTO); + .when(databaseService) + .exploreTables(DATABASE_3_PRIVILEGED_DTO); /* test */ assertThrows(DatabaseUnavailableException.class, () -> { @@ -1329,7 +1344,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_3_USER_3_WRITE_ALL_ACCESS_DTO); doThrow(SQLException.class) .when(tableService) - .importDataset(any(PrivilegedTableDto.class), eq(request)); + .importDataset(any(TableDto.class), eq(request)); /* test */ assertThrows(DatabaseUnavailableException.class, () -> { @@ -1355,7 +1370,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_3_USER_3_WRITE_OWN_ACCESS_DTO); doThrow(SQLException.class) .when(tableService) - .importDataset(any(PrivilegedTableDto.class), eq(request)); + .importDataset(any(TableDto.class), eq(request)); /* test */ assertThrows(NotAllowedException.class, () -> { diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java index 5f580a2fc12156c6702b4b54e215dd979611b5f9..b003ebfb4fd427c0b6bd92aef0595915f5c2bdbd 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/endpoint/ViewEndpointUnitTest.java @@ -1,10 +1,12 @@ package at.tuwien.endpoint; +import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.ViewDto; import at.tuwien.endpoints.ViewEndpoint; import at.tuwien.exception.*; import at.tuwien.service.CredentialService; -import at.tuwien.service.TableService; +import at.tuwien.service.DatabaseService; +import at.tuwien.service.SubsetService; import at.tuwien.service.ViewService; import at.tuwien.test.AbstractUnitTest; import jakarta.servlet.http.HttpServletRequest; @@ -40,6 +42,9 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @MockBean private ViewService viewService; + @MockBean + private DatabaseService databaseService; + @MockBean private CredentialService credentialService; @@ -47,7 +52,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { private HttpServletRequest httpServletRequest; @MockBean - private TableService tableService; + private SubsetService subsetService; @Autowired private ViewEndpoint viewEndpoint; @@ -68,8 +73,8 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { /* mock */ when(credentialService.getDatabase(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); - when(viewService.create(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO)) - .thenReturn(VIEW_1_DTO); + when(databaseService.createView(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO)) + .thenReturn(VIEW_1_PRIVILEGED_DTO); /* test */ final ResponseEntity<ViewDto> response = viewEndpoint.create(DATABASE_1_ID, VIEW_1_CREATE_DTO); @@ -85,8 +90,8 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { when(credentialService.getDatabase(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); doThrow(SQLException.class) - .when(viewService) - .create(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO); + .when(databaseService) + .createView(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO); /* test */ assertThrows(DatabaseUnavailableException.class, () -> { @@ -102,8 +107,8 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { /* mock */ when(credentialService.getDatabase(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); - when(viewService.create(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO)) - .thenReturn(VIEW_1_DTO); + when(databaseService.createView(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO)) + .thenReturn(VIEW_1_PRIVILEGED_DTO); /* test */ assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { @@ -135,7 +140,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { /* mock */ when(credentialService.getDatabase(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); - when(viewService.getSchemas(DATABASE_1_PRIVILEGED_DTO)) + when(databaseService.exploreViews(DATABASE_1_PRIVILEGED_DTO)) .thenReturn(List.of(VIEW_1_DTO, VIEW_2_DTO, VIEW_3_DTO)); /* test */ @@ -178,8 +183,8 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { when(credentialService.getDatabase(DATABASE_1_ID)) .thenReturn(DATABASE_1_PRIVILEGED_DTO); doThrow(SQLException.class) - .when(viewService) - .getSchemas(DATABASE_1_PRIVILEGED_DTO); + .when(databaseService) + .exploreViews(DATABASE_1_PRIVILEGED_DTO); /* test */ assertThrows(DatabaseUnavailableException.class, () -> { @@ -207,7 +212,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { .thenReturn(VIEW_1_PRIVILEGED_DTO); doNothing() .when(viewService) - .delete(DATABASE_1_PRIVILEGED_DTO, VIEW_1_INTERNAL_NAME); + .delete(VIEW_1_PRIVILEGED_DTO); /* test */ final ResponseEntity<Void> response = viewEndpoint.delete(DATABASE_1_ID, VIEW_1_ID); @@ -224,7 +229,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { .thenReturn(VIEW_1_PRIVILEGED_DTO); doThrow(SQLException.class) .when(viewService) - .delete(DATABASE_1_PRIVILEGED_DTO, VIEW_1_INTERNAL_NAME); + .delete(VIEW_1_PRIVILEGED_DTO); /* test */ assertThrows(DatabaseUnavailableException.class, () -> { @@ -242,7 +247,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_1_PRIVILEGED_DTO); doNothing() .when(viewService) - .delete(DATABASE_1_PRIVILEGED_DTO, VIEW_1_INTERNAL_NAME); + .delete(VIEW_1_PRIVILEGED_DTO); /* test */ assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { @@ -268,17 +273,19 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"}) - public void getData_private_succeeds() throws RemoteUnavailableException, ViewNotFoundException, ViewMalformedException, + public void getData_privateDataPrivateSchema_succeeds() throws RemoteUnavailableException, ViewNotFoundException, SQLException, DatabaseUnavailableException, QueryMalformedException, PaginationException, - NotAllowedException, MetadataServiceException, TableNotFoundException { + NotAllowedException, MetadataServiceException, TableNotFoundException, DatabaseNotFoundException { final Dataset<Row> mock = sparkSession.emptyDataFrame(); /* mock */ when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID)) .thenReturn(VIEW_1_PRIVILEGED_DTO); + when(credentialService.getDatabase(DATABASE_1_ID)) + .thenReturn(DATABASE_1_PRIVILEGED_DTO); when(credentialService.getAccess(DATABASE_1_ID, USER_1_ID)) .thenReturn(DATABASE_1_USER_1_READ_ACCESS_DTO); - when(tableService.getData(eq(DATABASE_1_PRIVILEGED_DTO), eq(VIEW_1_INTERNAL_NAME), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) + when(subsetService.getData(any(DatabaseDto.class), anyString(), any(Instant.class), eq(0L), eq(10L), eq(null), eq(null))) .thenReturn(mock); when(httpServletRequest.getMethod()) .thenReturn("GET"); @@ -293,7 +300,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_1_USERNAME, authorities = {"view-database-view-data"}) public void getData_privateHead_succeeds() throws RemoteUnavailableException, ViewNotFoundException, SQLException, DatabaseUnavailableException, QueryMalformedException, PaginationException, - NotAllowedException, MetadataServiceException, TableNotFoundException { + NotAllowedException, MetadataServiceException, TableNotFoundException, DatabaseNotFoundException { /* mock */ when(credentialService.getView(DATABASE_1_ID, VIEW_3_ID)) @@ -323,17 +330,17 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { NotAllowedException, MetadataServiceException { /* mock */ - when(credentialService.getView(DATABASE_1_ID, VIEW_3_ID)) - .thenReturn(VIEW_3_PRIVILEGED_DTO); + when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID)) + .thenReturn(VIEW_1_PRIVILEGED_DTO); when(httpServletRequest.getMethod()) .thenReturn("GET"); doThrow(NotAllowedException.class) .when(credentialService) - .getAccess(DATABASE_1_ID, USER_1_ID); + .getAccess(DATABASE_1_ID, USER_4_ID); /* test */ assertThrows(NotAllowedException.class, () -> { - viewEndpoint.getData(DATABASE_1_ID, VIEW_3_ID, null, null, null, httpServletRequest, USER_1_PRINCIPAL); + viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, USER_4_PRINCIPAL); }); } @@ -359,15 +366,15 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { NotAllowedException, MetadataServiceException { /* mock */ - when(credentialService.getView(DATABASE_1_ID, VIEW_3_ID)) - .thenReturn(VIEW_3_PRIVILEGED_DTO); + when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID)) + .thenReturn(VIEW_1_PRIVILEGED_DTO); doThrow(NotAllowedException.class) .when(credentialService) - .getAccess(DATABASE_1_ID, USER_3_ID); + .getAccess(DATABASE_1_ID, USER_4_ID); /* test */ assertThrows(NotAllowedException.class, () -> { - viewEndpoint.getData(DATABASE_1_ID, VIEW_3_ID, null, null, null, httpServletRequest, USER_3_PRINCIPAL); + viewEndpoint.getData(DATABASE_1_ID, VIEW_1_ID, null, null, null, httpServletRequest, USER_4_PRINCIPAL); }); } @@ -377,15 +384,15 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { NotAllowedException, MetadataServiceException { /* mock */ - when(credentialService.getView(DATABASE_1_ID, VIEW_3_ID)) - .thenReturn(VIEW_3_PRIVILEGED_DTO); + when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID)) + .thenReturn(VIEW_1_PRIVILEGED_DTO); doThrow(NotAllowedException.class) .when(credentialService) - .getAccess(DATABASE_1_ID, USER_3_ID); + .getAccess(DATABASE_1_ID, USER_4_ID); /* test */ assertThrows(NotAllowedException.class, () -> { - viewEndpoint.exportDataset(DATABASE_1_ID, VIEW_3_ID, null, USER_3_PRINCIPAL); + viewEndpoint.exportDataset(DATABASE_1_ID, VIEW_1_ID, null, USER_4_PRINCIPAL); }); } @@ -411,15 +418,15 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { NotAllowedException, MetadataServiceException { /* mock */ - when(credentialService.getView(DATABASE_1_ID, VIEW_3_ID)) - .thenReturn(VIEW_3_PRIVILEGED_DTO); + when(credentialService.getView(DATABASE_1_ID, VIEW_1_ID)) + .thenReturn(VIEW_1_PRIVILEGED_DTO); doThrow(NotAllowedException.class) .when(credentialService) - .getAccess(DATABASE_1_ID, USER_1_ID); + .getAccess(DATABASE_1_ID, USER_4_ID); /* test */ assertThrows(NotAllowedException.class, () -> { - viewEndpoint.exportDataset(DATABASE_1_ID, VIEW_3_ID, null, USER_1_PRINCIPAL); + viewEndpoint.exportDataset(DATABASE_1_ID, VIEW_1_ID, null, USER_4_PRINCIPAL); }); } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/MetadataServiceGatewayUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/MetadataServiceGatewayUnitTest.java index f65de0707eec016f502d66f45e8f52b5811f042f..affb56208032bc818ce5f1dbe1d99008613ffa32 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/MetadataServiceGatewayUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/gateway/MetadataServiceGatewayUnitTest.java @@ -1,16 +1,12 @@ package at.tuwien.gateway; import at.tuwien.api.container.ContainerDto; -import at.tuwien.api.container.internal.PrivilegedContainerDto; import at.tuwien.api.database.DatabaseAccessDto; +import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.ViewDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.database.internal.PrivilegedViewDto; import at.tuwien.api.database.table.TableDto; -import at.tuwien.api.database.table.internal.PrivilegedTableDto; import at.tuwien.api.identifier.IdentifierBriefDto; import at.tuwien.api.user.UserDto; -import at.tuwien.api.user.internal.PrivilegedUserDto; import at.tuwien.exception.*; import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; @@ -40,10 +36,6 @@ import static org.mockito.Mockito.when; @ExtendWith(SpringExtension.class) public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { - @MockBean - @Qualifier("restTemplate") - private RestTemplate restTemplate; - @MockBean @Qualifier("internalRestTemplate") private RestTemplate internalRestTemplate; @@ -60,28 +52,22 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { public void getTableById_succeeds() throws TableNotFoundException, RemoteUnavailableException, MetadataServiceException { final HttpHeaders headers = new HttpHeaders(); - headers.set("X-Type", IMAGE_1_JDBC); - headers.set("X-Host", CONTAINER_1_HOST); - headers.set("X-Port", "" + CONTAINER_1_PORT); headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME); headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD); - headers.set("X-Database", DATABASE_1_INTERNALNAME); - headers.set("X-Table", TABLE_1_INTERNAL_NAME); /* mock */ when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableDto.class))) .thenReturn(ResponseEntity.status(HttpStatus.OK) .headers(headers) - .body(TABLE_1_DTO)); + .body(TABLE_1_PRIVILEGED_DTO)); /* test */ - final PrivilegedTableDto response = metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID); + final TableDto response = metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID); assertEquals(IMAGE_1_JDBC, response.getDatabase().getContainer().getImage().getJdbcMethod()); assertEquals(CONTAINER_1_HOST, response.getDatabase().getContainer().getHost()); assertEquals(CONTAINER_1_PORT, response.getDatabase().getContainer().getPort()); assertEquals(CONTAINER_1_PRIVILEGED_USERNAME, response.getDatabase().getContainer().getUsername()); assertEquals(CONTAINER_1_PRIVILEGED_PASSWORD, response.getDatabase().getContainer().getPassword()); - assertEquals(DATABASE_1_INTERNALNAME, response.getDatabase().getInternalName()); assertEquals(TABLE_1_INTERNAL_NAME, response.getInternalName()); } @@ -119,7 +105,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { /* mock */ when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableDto.class))) .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT) - .body(TABLE_1_DTO)); + .body(TABLE_1_PRIVILEGED_DTO)); /* test */ assertThrows(MetadataServiceException.class, () -> { @@ -129,7 +115,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { @Test public void getTableById_headerMissing_fails() { - final List<String> customHeaders = List.of("X-Type", "X-Host", "X-Port", "X-Username", "X-Password", "X-Database", "X-Sidecar-Host", "X-Sidecar-Port"); + final List<String> customHeaders = List.of("X-Username", "X-Password"); for (int i = 0; i < customHeaders.size(); i++) { final HttpHeaders headers = new HttpHeaders(); @@ -140,7 +126,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableDto.class))) .thenReturn(ResponseEntity.status(HttpStatus.OK) .headers(headers) - .body(TABLE_1_DTO)); + .body(TABLE_1_PRIVILEGED_DTO)); /* test */ assertThrows(MetadataServiceException.class, () -> { metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID); @@ -151,13 +137,8 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { @Test public void getTableById_emptyBody_fails() { final HttpHeaders headers = new HttpHeaders(); - headers.set("X-Type", IMAGE_1_JDBC); - headers.set("X-Host", CONTAINER_1_HOST); - headers.set("X-Port", "" + CONTAINER_1_PORT); headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME); headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD); - headers.set("X-Database", DATABASE_1_INTERNALNAME); - headers.set("X-Table", TABLE_1_INTERNAL_NAME); /* mock */ when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(TableDto.class))) @@ -177,17 +158,15 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { final HttpHeaders headers = new HttpHeaders(); headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME); headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD); - headers.set("X-Host", CONTAINER_1_HOST); - headers.set("X-Port", "" + CONTAINER_1_PORT); /* mock */ - when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto.class))) + when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(DatabaseDto.class))) .thenReturn(ResponseEntity.ok() .headers(headers) .body(DATABASE_1_PRIVILEGED_DTO)); /* test */ - final PrivilegedDatabaseDto response = metadataServiceGateway.getDatabaseById(DATABASE_1_ID); + final DatabaseDto response = metadataServiceGateway.getDatabaseById(DATABASE_1_ID); assertEquals(DATABASE_1_ID, response.getId()); } @@ -197,7 +176,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { /* mock */ doThrow(HttpServerErrorException.class) .when(internalRestTemplate) - .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto.class)); + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(DatabaseDto.class)); /* test */ assertThrows(RemoteUnavailableException.class, () -> { @@ -211,7 +190,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { /* mock */ doThrow(HttpClientErrorException.NotFound.class) .when(internalRestTemplate) - .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto.class)); + .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(DatabaseDto.class)); /* test */ assertThrows(DatabaseNotFoundException.class, () -> { @@ -223,7 +202,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { public void getDatabaseById_statusCode_fails() { /* mock */ - when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto.class))) + when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(DatabaseDto.class))) .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT) .build()); @@ -240,7 +219,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD); /* mock */ - when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto.class))) + when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(DatabaseDto.class))) .thenReturn(ResponseEntity.status(HttpStatus.OK) .headers(headers) .build()); @@ -261,7 +240,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { headers.add(customHeaders.get(j), ""); } /* mock */ - when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(PrivilegedDatabaseDto.class))) + when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(DatabaseDto.class))) .thenReturn(ResponseEntity.status(HttpStatus.OK) .headers(headers) .build()); @@ -285,7 +264,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { .body(CONTAINER_1_DTO)); /* test */ - final PrivilegedContainerDto response = metadataServiceGateway.getContainerById(CONTAINER_1_ID); + final ContainerDto response = metadataServiceGateway.getContainerById(CONTAINER_1_ID); assertEquals(CONTAINER_1_ID, response.getId()); } @@ -373,22 +352,17 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { @Test public void getViewById_succeeds() throws RemoteUnavailableException, ViewNotFoundException, MetadataServiceException { final HttpHeaders headers = new HttpHeaders(); - headers.set("X-Type", IMAGE_1_JDBC); - headers.set("X-Host", CONTAINER_1_HOST); - headers.set("X-Port", "" + CONTAINER_1_PORT); headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME); headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD); - headers.set("X-Database", DATABASE_1_INTERNALNAME); - headers.set("X-View", VIEW_1_INTERNAL_NAME); /* mock */ when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(ViewDto.class))) .thenReturn(ResponseEntity.ok() .headers(headers) - .body(VIEW_1_DTO)); + .body(VIEW_1_PRIVILEGED_DTO)); /* test */ - final PrivilegedViewDto response = metadataServiceGateway.getViewById(CONTAINER_1_ID, VIEW_1_ID); + final ViewDto response = metadataServiceGateway.getViewById(CONTAINER_1_ID, VIEW_1_ID); assertEquals(VIEW_1_ID, response.getId()); } @@ -458,12 +432,8 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { @Test public void getViewById_emptyBody_fails() { final HttpHeaders headers = new HttpHeaders(); - headers.set("X-Type", IMAGE_1_JDBC); - headers.set("X-Host", CONTAINER_1_HOST); - headers.set("X-Port", "" + CONTAINER_1_PORT); headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME); headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD); - headers.set("X-Database", DATABASE_1_INTERNALNAME); /* mock */ when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(ViewDto.class))) @@ -477,19 +447,6 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { }); } - @Test - public void getUserById_succeeds() throws RemoteUnavailableException, UserNotFoundException, MetadataServiceException { - - /* mock */ - when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class))) - .thenReturn(ResponseEntity.ok() - .body(USER_1_DTO)); - - /* test */ - final UserDto response = metadataServiceGateway.getUserById(USER_1_ID); - assertEquals(USER_1_ID, response.getId()); - } - @Test public void getUserById_unavailable_fails() { @@ -505,49 +462,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { } @Test - public void getUserById_notFound_fails() { - - /* mock */ - doThrow(HttpClientErrorException.NotFound.class) - .when(internalRestTemplate) - .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class)); - - /* test */ - assertThrows(UserNotFoundException.class, () -> { - metadataServiceGateway.getUserById(USER_1_ID); - }); - } - - @Test - public void getUserById_statusCode_fails() { - - /* mock */ - when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT) - .build()); - - /* test */ - assertThrows(MetadataServiceException.class, () -> { - metadataServiceGateway.getUserById(USER_1_ID); - }); - } - - @Test - public void getUserById_emptyBody_fails() { - - /* mock */ - when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class))) - .thenReturn(ResponseEntity.ok() - .build()); - - /* test */ - assertThrows(MetadataServiceException.class, () -> { - metadataServiceGateway.getUserById(USER_1_ID); - }); - } - - @Test - public void getPrivilegedUserById_succeeds() throws RemoteUnavailableException, UserNotFoundException, + public void getUserById_succeeds() throws RemoteUnavailableException, UserNotFoundException, MetadataServiceException { final HttpHeaders headers = new HttpHeaders(); headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME); @@ -560,28 +475,14 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { .body(USER_1_DTO)); /* test */ - final PrivilegedUserDto response = metadataServiceGateway.getPrivilegedUserById(USER_1_ID); + final UserDto response = metadataServiceGateway.getUserById(USER_1_ID); assertEquals(USER_1_ID, response.getId()); assertEquals(CONTAINER_1_PRIVILEGED_USERNAME, response.getUsername()); assertEquals(CONTAINER_1_PRIVILEGED_PASSWORD, response.getPassword()); } @Test - public void getPrivilegedUserById_unavailable_fails() { - - /* mock */ - doThrow(HttpServerErrorException.class) - .when(internalRestTemplate) - .exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class)); - - /* test */ - assertThrows(RemoteUnavailableException.class, () -> { - metadataServiceGateway.getPrivilegedUserById(USER_1_ID); - }); - } - - @Test - public void getPrivilegedUserById_notFound_fails() { + public void getUserById_notFound_fails() { /* mock */ doThrow(HttpClientErrorException.NotFound.class) @@ -590,12 +491,12 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { /* test */ assertThrows(UserNotFoundException.class, () -> { - metadataServiceGateway.getPrivilegedUserById(USER_1_ID); + metadataServiceGateway.getUserById(USER_1_ID); }); } @Test - public void getPrivilegedUserById_statusCode_fails() { + public void getUserById_statusCode_fails() { /* mock */ when(internalRestTemplate.exchange(anyString(), eq(HttpMethod.GET), eq(HttpEntity.EMPTY), eq(UserDto.class))) @@ -604,12 +505,12 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { /* test */ assertThrows(MetadataServiceException.class, () -> { - metadataServiceGateway.getPrivilegedUserById(USER_1_ID); + metadataServiceGateway.getUserById(USER_1_ID); }); } @Test - public void getPrivilegedUserById_headerMissing_fails() { + public void getUserById_headerMissing_fails() { final List<String> customHeaders = List.of("X-Username", "X-Password"); for (int i = 0; i < customHeaders.size(); i++) { @@ -624,13 +525,13 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { /* test */ assertThrows(MetadataServiceException.class, () -> { - metadataServiceGateway.getPrivilegedUserById(USER_1_ID); + metadataServiceGateway.getUserById(USER_1_ID); }); } } @Test - public void getPrivilegedUserById_emptyBody_fails() { + public void getUserById_emptyBody_fails() { final HttpHeaders headers = new HttpHeaders(); headers.set("X-Username", CONTAINER_1_PRIVILEGED_USERNAME); headers.set("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD); @@ -643,7 +544,7 @@ public class MetadataServiceGatewayUnitTest extends AbstractUnitTest { /* test */ assertThrows(MetadataServiceException.class, () -> { - metadataServiceGateway.getPrivilegedUserById(USER_1_ID); + metadataServiceGateway.getUserById(USER_1_ID); }); } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerIntegrationTest.java index 88bad7b06124df10f5a3cec690e993ac5b8ffcd5..bca5e1141082e320fe1bef132335fea7e30b7be3 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerIntegrationTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerIntegrationTest.java @@ -5,7 +5,7 @@ import at.tuwien.config.MariaDbContainerConfig; import at.tuwien.exception.MetadataServiceException; import at.tuwien.exception.RemoteUnavailableException; import at.tuwien.exception.TableNotFoundException; -import at.tuwien.gateway.MetadataServiceGateway; +import at.tuwien.service.CredentialService; import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; @@ -42,13 +42,13 @@ import static org.mockito.Mockito.when; public class DefaultListenerIntegrationTest extends AbstractUnitTest { @MockBean - private MetadataServiceGateway metadataServiceGateway; + private CredentialService credentialService; @Autowired private DefaultListener defaultListener; @Container - private static RabbitMQContainer rabbitContainer = new RabbitMQContainer("rabbitmq:3.10"); + private static RabbitMQContainer rabbitContainer = new RabbitMQContainer(RABBITMQ_IMAGE); @Container private static MariaDBContainer<?> mariaDBContainer = MariaDbContainerConfig.getContainer(); @@ -67,7 +67,7 @@ public class DefaultListenerIntegrationTest extends AbstractUnitTest { final Message request = buildMessage("dbrepo." + DATABASE_1_ID + "." + TABLE_1_ID, "{\"id\":4,\"date\":\"2023-10-03\",\"mintemp\":15.0,\"rainfall\":0.2}", new HashMap<>()); /* mock */ - when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) + when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID)) .thenReturn(TABLE_1_PRIVILEGED_DTO); /* test */ @@ -83,8 +83,8 @@ public class DefaultListenerIntegrationTest extends AbstractUnitTest { /* mock */ doThrow(TableNotFoundException.class) - .when(metadataServiceGateway) - .getTableById(DATABASE_1_ID, TABLE_1_ID); + .when(credentialService) + .getTable(DATABASE_1_ID, TABLE_1_ID); /* test */ defaultListener.onMessage(request); diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerUnitTest.java index 648e36caa938f11e564ce772b00c25ba24d18281..74042aa5788c38205d8b73abff31aadf162999e3 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/listener/DefaultListenerUnitTest.java @@ -5,7 +5,7 @@ import at.tuwien.config.MariaDbContainerConfig; import at.tuwien.exception.MetadataServiceException; import at.tuwien.exception.RemoteUnavailableException; import at.tuwien.exception.TableNotFoundException; -import at.tuwien.gateway.MetadataServiceGateway; +import at.tuwien.service.CredentialService; import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; @@ -38,7 +38,7 @@ import static org.mockito.Mockito.when; public class DefaultListenerUnitTest extends AbstractUnitTest { @MockBean - private MetadataServiceGateway metadataServiceGateway; + private CredentialService credentialService; @Autowired private DefaultListener defaultListener; @@ -51,9 +51,10 @@ public class DefaultListenerUnitTest extends AbstractUnitTest { @BeforeEach public void beforeEach() throws SQLException { + genesis(); /* metadata database */ MariaDbConfig.dropAllDatabases(CONTAINER_1_PRIVILEGED_DTO); - MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO); + MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_PRIVILEGED_DTO); } @Test @@ -80,7 +81,7 @@ public class DefaultListenerUnitTest extends AbstractUnitTest { final Message request = buildMessage("dbrepo.1.1", "{,}", new HashMap<>()); /* mock */ - when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) + when(credentialService.getTable(DATABASE_1_ID, TABLE_1_ID)) .thenReturn(TABLE_1_PRIVILEGED_DTO); /* test */ @@ -95,8 +96,8 @@ public class DefaultListenerUnitTest extends AbstractUnitTest { /* mock */ doThrow(TableNotFoundException.class) - .when(metadataServiceGateway) - .getTableById(DATABASE_1_ID, TABLE_1_ID); + .when(credentialService) + .getTable(DATABASE_1_ID, TABLE_1_ID); /* test */ defaultListener.onMessage(request); diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java index e48f0c048da2dd6c83934566e6e5d9956838ba62..120fe49d8f98f61e36840b69d8c33fa00bc27053 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java @@ -140,7 +140,7 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest { /* ignore */ } try { - subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, 0L, 10L); + subsetEndpoint.getData(DATABASE_1_ID, QUERY_1_ID, USER_1_PRINCIPAL, httpServletRequest, null, 0L, 10L); } catch (Exception e) { /* ignore */ } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/AccessServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/AccessServiceIntegrationTest.java index 5eccf50ed2568a40d868a0f819f763c026368d83..2c174e0a3da88a30e2e8ed8d739cf0200fd5a237 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/AccessServiceIntegrationTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/AccessServiceIntegrationTest.java @@ -45,14 +45,14 @@ public class AccessServiceIntegrationTest extends AbstractUnitTest { genesis(); /* metadata database */ MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); - MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO); + MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_PRIVILEGED_DTO); } @Test public void create_read_succeeds() throws SQLException, DatabaseMalformedException { /* test */ - accessService.create(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO, AccessTypeDto.READ); + accessService.create(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO, AccessTypeDto.READ); final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME); for (String privilege : grantDefaultRead.split(",")) { assertTrue(privileges.stream().anyMatch(p -> p.trim().equals(privilege.trim()))); @@ -63,7 +63,7 @@ public class AccessServiceIntegrationTest extends AbstractUnitTest { public void create_writeOwn_succeeds() throws SQLException, DatabaseMalformedException { /* test */ - accessService.create(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO, AccessTypeDto.WRITE_OWN); + accessService.create(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO, AccessTypeDto.WRITE_OWN); final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME); for (String privilege : grantDefaultWrite.split(",")) { assertTrue(privileges.stream().anyMatch(p -> p.trim().equals(privilege.trim()))); @@ -74,7 +74,7 @@ public class AccessServiceIntegrationTest extends AbstractUnitTest { public void create_writeAll_succeeds() throws SQLException, DatabaseMalformedException { /* test */ - accessService.create(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO, AccessTypeDto.WRITE_ALL); + accessService.create(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO, AccessTypeDto.WRITE_ALL); final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME); for (String privilege : grantDefaultWrite.split(",")) { assertTrue(privileges.stream().anyMatch(p -> p.trim().equals(privilege.trim()))); @@ -85,7 +85,7 @@ public class AccessServiceIntegrationTest extends AbstractUnitTest { public void update_read_succeeds() throws SQLException, DatabaseMalformedException { /* test */ - accessService.update(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO, AccessTypeDto.READ); + accessService.update(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO, AccessTypeDto.READ); final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME); for (String privilege : grantDefaultRead.split(",")) { assertTrue(privileges.stream().anyMatch(p -> p.trim().equals(privilege.trim()))); @@ -96,7 +96,7 @@ public class AccessServiceIntegrationTest extends AbstractUnitTest { public void update_writeOwn_succeeds() throws SQLException, DatabaseMalformedException { /* test */ - accessService.update(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO, AccessTypeDto.WRITE_OWN); + accessService.update(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO, AccessTypeDto.WRITE_OWN); final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME); for (String privilege : grantDefaultWrite.split(",")) { assertTrue(privileges.stream().anyMatch(p -> p.trim().equals(privilege.trim()))); @@ -107,7 +107,7 @@ public class AccessServiceIntegrationTest extends AbstractUnitTest { public void update_writeAll_succeeds() throws SQLException, DatabaseMalformedException { /* test */ - accessService.update(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO, AccessTypeDto.WRITE_ALL); + accessService.update(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO, AccessTypeDto.WRITE_ALL); final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME); for (String privilege : grantDefaultWrite.split(",")) { assertTrue(privileges.stream().anyMatch(p -> p.trim().equals(privilege.trim()))); @@ -119,7 +119,7 @@ public class AccessServiceIntegrationTest extends AbstractUnitTest { /* test */ assertThrows(DatabaseMalformedException.class, () -> { - accessService.update(DATABASE_1_PRIVILEGED_DTO, USER_5_PRIVILEGED_DTO, AccessTypeDto.WRITE_ALL); + accessService.update(DATABASE_1_PRIVILEGED_DTO, USER_5_DTO, AccessTypeDto.WRITE_ALL); }); } @@ -127,7 +127,7 @@ public class AccessServiceIntegrationTest extends AbstractUnitTest { public void delete_succeeds() throws SQLException, DatabaseMalformedException { /* test */ - accessService.delete(DATABASE_1_PRIVILEGED_DTO, USER_1_PRIVILEGED_DTO); + accessService.delete(DATABASE_1_PRIVILEGED_DTO, USER_1_DTO); final List<String> privileges = MariaDbConfig.getPrivileges(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME); assertEquals(1, privileges.size()); assertEquals("USAGE", privileges.get(0)); @@ -138,7 +138,7 @@ public class AccessServiceIntegrationTest extends AbstractUnitTest { /* test */ assertThrows(DatabaseMalformedException.class, () -> { - accessService.delete(DATABASE_1_PRIVILEGED_DTO, USER_5_PRIVILEGED_DTO); + accessService.delete(DATABASE_1_PRIVILEGED_DTO, USER_5_DTO); }); } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e1579fbe95d8d04cbdbe41f87f5dc066b874b26c --- /dev/null +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceIntegrationTest.java @@ -0,0 +1,95 @@ +package at.tuwien.service; + +import at.tuwien.api.database.DatabaseDto; +import at.tuwien.config.MariaDbConfig; +import at.tuwien.config.MariaDbContainerConfig; +import at.tuwien.exception.DatabaseMalformedException; +import at.tuwien.exception.QueryStoreCreateException; +import at.tuwien.test.AbstractUnitTest; +import lombok.extern.log4j.Log4j2; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.testcontainers.containers.MariaDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import java.sql.SQLException; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +@Log4j2 +@SpringBootTest +@ExtendWith(SpringExtension.class) +@Testcontainers +public class ContainerServiceIntegrationTest extends AbstractUnitTest { + + @Autowired + private ContainerService containerService; + + @Container + private static MariaDBContainer<?> mariaDBContainer = MariaDbContainerConfig.getContainer(); + + @BeforeAll + public static void beforeAll() throws InterruptedException { + Thread.sleep(1000) /* wait for test container some more */; + } + + @BeforeEach + public void beforeEach() throws SQLException, InterruptedException { + genesis(); + /* metadata database */ + MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); + MariaDbConfig.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); + Thread.sleep(1000) /* wait for test container some more */; + } + + @Test + public void create_succeeds() throws SQLException, DatabaseMalformedException { + + /* mock */ + MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); + + /* test */ + final DatabaseDto response = containerService.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL); + assertNull(response.getName()); + assertEquals(DATABASE_1_INTERNALNAME, response.getInternalName()); + assertEquals(EXCHANGE_DBREPO_NAME, response.getExchangeName()); + assertNotNull(response.getOwner()); + assertEquals(USER_1_ID, response.getOwner().getId()); + assertNotNull(response.getContact()); + assertEquals(USER_1_ID, response.getContact().getId()); + assertNotNull(response.getContainer()); + assertEquals(CONTAINER_1_ID, response.getContainer().getId()); + } + + @Test + public void create_exists_fails() { + + /* test */ + assertThrows(DatabaseMalformedException.class, () -> { + containerService.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL); + }); + } + + @Test + public void createQueryStore_succeeds() throws SQLException, QueryStoreCreateException, InterruptedException { + + /* test */ + createQueryStore_generic(DATABASE_1_INTERNALNAME); + } + + protected void createQueryStore_generic(String databaseName) throws SQLException, QueryStoreCreateException { + + /* test */ + containerService.createQueryStore(CONTAINER_1_PRIVILEGED_DTO, databaseName); + final List<Map<String, Object>> response = MariaDbConfig.listQueryStore(DATABASE_1_PRIVILEGED_DTO); + assertEquals(0, response.size()); + } +} diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/CredentialServiceUnitTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/CredentialServiceUnitTest.java index 160918bfaadbd5563dbf311e18f305efa9c6823f..07e283640a92bd68a774158d196578a0ab9fd23d 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/CredentialServiceUnitTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/CredentialServiceUnitTest.java @@ -1,11 +1,11 @@ package at.tuwien.service; -import at.tuwien.api.container.internal.PrivilegedContainerDto; +import at.tuwien.api.container.ContainerDto; import at.tuwien.api.database.DatabaseAccessDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.database.internal.PrivilegedViewDto; -import at.tuwien.api.database.table.internal.PrivilegedTableDto; -import at.tuwien.api.user.internal.PrivilegedUserDto; +import at.tuwien.api.database.DatabaseDto; +import at.tuwien.api.database.ViewDto; +import at.tuwien.api.database.table.TableDto; +import at.tuwien.api.user.UserDto; import at.tuwien.exception.*; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.service.impl.CredentialServiceImpl; @@ -51,7 +51,7 @@ public class CredentialServiceUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_1_PRIVILEGED_DTO); /* test */ - final PrivilegedDatabaseDto response = credentialService.getDatabase(DATABASE_1_ID); + final DatabaseDto response = credentialService.getDatabase(DATABASE_1_ID); assertNotNull(response); assertEquals(DATABASE_1_ID, response.getId()); } @@ -67,7 +67,7 @@ public class CredentialServiceUnitTest extends AbstractUnitTest { credentialService.getDatabase(DATABASE_1_ID); /* test */ - final PrivilegedDatabaseDto response = credentialService.getDatabase(DATABASE_1_ID); + final DatabaseDto response = credentialService.getDatabase(DATABASE_1_ID); assertNotNull(response); assertEquals(DATABASE_1_ID, response.getId()); } @@ -82,12 +82,12 @@ public class CredentialServiceUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_1_PRIVILEGED_DTO); /* pre-condition */ - final PrivilegedDatabaseDto tmp = credentialService.getDatabase(DATABASE_1_ID); + final DatabaseDto tmp = credentialService.getDatabase(DATABASE_1_ID); assertNotEquals(DATABASE_1_ID, tmp.getId()); Thread.sleep(5000); /* test */ - final PrivilegedDatabaseDto response = credentialService.getDatabase(DATABASE_1_ID); + final DatabaseDto response = credentialService.getDatabase(DATABASE_1_ID); assertNotNull(response); assertEquals(DATABASE_1_ID, response.getId()); } @@ -101,7 +101,7 @@ public class CredentialServiceUnitTest extends AbstractUnitTest { .thenReturn(CONTAINER_1_PRIVILEGED_DTO); /* test */ - final PrivilegedContainerDto response = credentialService.getContainer(CONTAINER_1_ID); + final ContainerDto response = credentialService.getContainer(CONTAINER_1_ID); assertNotNull(response); assertEquals(CONTAINER_1_ID, response.getId()); } @@ -112,12 +112,12 @@ public class CredentialServiceUnitTest extends AbstractUnitTest { /* mock */ when(metadataServiceGateway.getContainerById(CONTAINER_1_ID)) - .thenReturn(CONTAINER_1_PRIVILEGED_DTO) + .thenReturn(CONTAINER_1_DTO) .thenThrow(RuntimeException.class) /* should never be thrown */; credentialService.getContainer(CONTAINER_1_ID); /* test */ - final PrivilegedContainerDto response = credentialService.getContainer(CONTAINER_1_ID); + final ContainerDto response = credentialService.getContainer(CONTAINER_1_ID); assertNotNull(response); assertEquals(CONTAINER_1_ID, response.getId()); } @@ -132,12 +132,12 @@ public class CredentialServiceUnitTest extends AbstractUnitTest { .thenReturn(CONTAINER_1_PRIVILEGED_DTO); /* pre-condition */ - final PrivilegedContainerDto tmp = credentialService.getContainer(CONTAINER_1_ID); + final ContainerDto tmp = credentialService.getContainer(CONTAINER_1_ID); assertNotEquals(CONTAINER_1_ID, tmp.getId()); Thread.sleep(5000); /* test */ - final PrivilegedContainerDto response = credentialService.getContainer(CONTAINER_1_ID); + final ContainerDto response = credentialService.getContainer(CONTAINER_1_ID); assertNotNull(response); assertEquals(CONTAINER_1_ID, response.getId()); } @@ -147,11 +147,11 @@ public class CredentialServiceUnitTest extends AbstractUnitTest { UserNotFoundException { /* mock */ - when(metadataServiceGateway.getPrivilegedUserById(USER_1_ID)) - .thenReturn(USER_1_PRIVILEGED_DTO); + when(metadataServiceGateway.getUserById(USER_1_ID)) + .thenReturn(USER_1_DTO); /* test */ - final PrivilegedUserDto response = credentialService.getUser(USER_1_ID); + final UserDto response = credentialService.getUser(USER_1_ID); assertNotNull(response); assertEquals(USER_1_ID, response.getId()); } @@ -161,13 +161,13 @@ public class CredentialServiceUnitTest extends AbstractUnitTest { UserNotFoundException { /* mock */ - when(metadataServiceGateway.getPrivilegedUserById(USER_1_ID)) - .thenReturn(USER_1_PRIVILEGED_DTO) + when(metadataServiceGateway.getUserById(USER_1_ID)) + .thenReturn(USER_1_DTO) .thenThrow(RuntimeException.class) /* should never be thrown */; credentialService.getUser(USER_1_ID); /* test */ - final PrivilegedUserDto response = credentialService.getUser(USER_1_ID); + final UserDto response = credentialService.getUser(USER_1_ID); assertNotNull(response); assertEquals(USER_1_ID, response.getId()); } @@ -177,17 +177,17 @@ public class CredentialServiceUnitTest extends AbstractUnitTest { InterruptedException, UserNotFoundException { /* mock */ - when(metadataServiceGateway.getPrivilegedUserById(USER_1_ID)) - .thenReturn(USER_2_PRIVILEGED_DTO) /* needs to be different id for test case */ - .thenReturn(USER_1_PRIVILEGED_DTO); + when(metadataServiceGateway.getUserById(USER_1_ID)) + .thenReturn(USER_2_DTO) /* needs to be different id for test case */ + .thenReturn(USER_1_DTO); /* pre-condition */ - final PrivilegedUserDto tmp = credentialService.getUser(USER_1_ID); + final UserDto tmp = credentialService.getUser(USER_1_ID); assertNotEquals(USER_1_ID, tmp.getId()); Thread.sleep(5000); /* test */ - final PrivilegedUserDto response = credentialService.getUser(USER_1_ID); + final UserDto response = credentialService.getUser(USER_1_ID); assertNotNull(response); assertEquals(USER_1_ID, response.getId()); } @@ -254,7 +254,7 @@ public class CredentialServiceUnitTest extends AbstractUnitTest { .thenReturn(TABLE_1_PRIVILEGED_DTO); /* test */ - final PrivilegedTableDto response = credentialService.getTable(DATABASE_1_ID, TABLE_1_ID); + final TableDto response = credentialService.getTable(DATABASE_1_ID, TABLE_1_ID); assertNotNull(response); assertEquals(TABLE_1_ID, response.getId()); } @@ -270,7 +270,7 @@ public class CredentialServiceUnitTest extends AbstractUnitTest { credentialService.getTable(DATABASE_1_ID, TABLE_1_ID); /* test */ - final PrivilegedTableDto response = credentialService.getTable(DATABASE_1_ID, TABLE_1_ID); + final TableDto response = credentialService.getTable(DATABASE_1_ID, TABLE_1_ID); assertNotNull(response); assertEquals(TABLE_1_ID, response.getId()); } @@ -285,12 +285,12 @@ public class CredentialServiceUnitTest extends AbstractUnitTest { .thenReturn(TABLE_1_PRIVILEGED_DTO); /* pre-condition */ - final PrivilegedTableDto tmp = credentialService.getTable(DATABASE_1_ID, TABLE_1_ID); + final TableDto tmp = credentialService.getTable(DATABASE_1_ID, TABLE_1_ID); assertNotEquals(TABLE_1_ID, tmp.getId()); Thread.sleep(5000); /* test */ - final PrivilegedTableDto response = credentialService.getTable(DATABASE_1_ID, TABLE_1_ID); + final TableDto response = credentialService.getTable(DATABASE_1_ID, TABLE_1_ID); assertNotNull(response); assertEquals(TABLE_1_ID, response.getId()); } @@ -304,7 +304,7 @@ public class CredentialServiceUnitTest extends AbstractUnitTest { .thenReturn(VIEW_1_PRIVILEGED_DTO); /* test */ - final PrivilegedViewDto response = credentialService.getView(DATABASE_1_ID, VIEW_1_ID); + final ViewDto response = credentialService.getView(DATABASE_1_ID, VIEW_1_ID); assertNotNull(response); assertEquals(VIEW_1_ID, response.getId()); } @@ -319,7 +319,7 @@ public class CredentialServiceUnitTest extends AbstractUnitTest { credentialService.getView(DATABASE_1_ID, VIEW_1_ID); /* test */ - final PrivilegedViewDto response = credentialService.getView(DATABASE_1_ID, VIEW_1_ID); + final ViewDto response = credentialService.getView(DATABASE_1_ID, VIEW_1_ID); assertNotNull(response); assertEquals(VIEW_1_ID, response.getId()); } @@ -334,12 +334,12 @@ public class CredentialServiceUnitTest extends AbstractUnitTest { .thenReturn(VIEW_1_PRIVILEGED_DTO); /* pre-condition */ - final PrivilegedViewDto tmp = credentialService.getView(DATABASE_1_ID, VIEW_1_ID); + final ViewDto tmp = credentialService.getView(DATABASE_1_ID, VIEW_1_ID); assertNotEquals(VIEW_1_ID, tmp.getId()); Thread.sleep(5000); /* test */ - final PrivilegedViewDto response = credentialService.getView(DATABASE_1_ID, VIEW_1_ID); + final ViewDto response = credentialService.getView(DATABASE_1_ID, VIEW_1_ID); assertNotNull(response); assertEquals(VIEW_1_ID, response.getId()); } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java index 83d81715bd79a82b7306a3330d2d08e96bab82d0..6663a71d135033e5fb4a3b3810d04d54130e270a 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceIntegrationTest.java @@ -1,12 +1,29 @@ package at.tuwien.service; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; +import at.tuwien.api.database.ViewColumnDto; +import at.tuwien.api.database.ViewDto; +import at.tuwien.api.database.table.TableBriefDto; +import at.tuwien.api.database.table.TableDto; +import at.tuwien.api.database.table.columns.ColumnDto; +import at.tuwien.api.database.table.columns.ColumnTypeDto; +import at.tuwien.api.database.table.columns.CreateTableColumnDto; +import at.tuwien.api.database.table.constraints.ConstraintsDto; +import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto; +import at.tuwien.api.database.table.constraints.foreign.CreateForeignKeyDto; +import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto; +import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto; +import at.tuwien.api.database.table.constraints.foreign.ReferenceTypeDto; +import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto; +import at.tuwien.api.database.table.constraints.unique.UniqueDto; +import at.tuwien.api.database.table.internal.TableCreateDto; +import at.tuwien.api.identifier.IdentifierDto; import at.tuwien.api.user.internal.UpdateUserPasswordDto; import at.tuwien.config.MariaDbConfig; import at.tuwien.config.MariaDbContainerConfig; -import at.tuwien.exception.DatabaseMalformedException; +import at.tuwien.exception.*; import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -19,6 +36,9 @@ import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import java.sql.SQLException; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; import static org.junit.jupiter.api.Assertions.*; @@ -40,38 +60,47 @@ public class DatabaseServiceIntegrationTest extends AbstractUnitTest { } @BeforeEach - public void beforeEach() throws SQLException { + public void beforeEach() throws SQLException, InterruptedException { genesis(); /* metadata database */ MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); + MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO); + MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNALNAME); + MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_DTO); + Thread.sleep(1000) /* wait for test container some more */; } @Test - public void create_succeeds() throws SQLException, DatabaseMalformedException { + public void createView_succeeds() throws SQLException, ViewMalformedException { /* test */ - final PrivilegedDatabaseDto response = databaseService.create(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL); - assertNull(response.getName()); - assertEquals(DATABASE_1_INTERNALNAME, response.getInternalName()); - assertEquals(EXCHANGE_DBREPO_NAME, response.getExchangeName()); - assertNotNull(response.getOwner()); - assertEquals(USER_1_ID, response.getOwner().getId()); - assertNotNull(response.getContact()); - assertEquals(USER_1_ID, response.getContact().getId()); - assertNotNull(response.getContainer()); - assertEquals(CONTAINER_1_ID, response.getContainer().getId()); + databaseService.createView(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO); } @Test - public void create_exists_fails() throws SQLException { - - /* mock */ - MariaDbConfig.createDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); + public void exploreViews_succeeds() throws SQLException, ViewNotFoundException, DatabaseMalformedException { /* test */ - assertThrows(DatabaseMalformedException.class, () -> { - databaseService.create(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_CREATE_INTERNAL); - }); + final List<ViewDto> response = databaseService.exploreViews(DATABASE_1_PRIVILEGED_DTO); + final ViewDto view0 = response.get(0); + assertEquals("not_in_metadata_db2", view0.getName()); + assertEquals("not_in_metadata_db2", view0.getInternalName()); + assertEquals(DATABASE_1_ID, view0.getVdbid()); + assertEquals(USER_1_BRIEF_DTO, view0.getOwner()); + assertFalse(view0.getIsInitialView()); + assertEquals(DATABASE_1_PUBLIC, view0.getIsPublic()); + assertEquals(DATABASE_1_SCHEMA_PUBLIC, view0.getIsSchemaPublic()); + assertTrue(view0.getQuery().length() >= 69); + assertNotNull(view0.getQueryHash()); + assertEquals(4, view0.getColumns().size()); + final ViewColumnDto column0a = view0.getColumns().get(0); + assertEquals("date", column0a.getInternalName()); + final ViewColumnDto column1a = view0.getColumns().get(1); + assertEquals("location", column1a.getInternalName()); + final ViewColumnDto column2a = view0.getColumns().get(2); + assertEquals("MinTemp", column2a.getInternalName()); + final ViewColumnDto column3a = view0.getColumns().get(3); + assertEquals("Rainfall", column3a.getInternalName()); } @Test @@ -82,7 +111,6 @@ public class DatabaseServiceIntegrationTest extends AbstractUnitTest { .build(); /* mock */ - MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO); MariaDbConfig.grantWriteAccess(DATABASE_1_PRIVILEGED_DTO, USER_1_USERNAME); /* pre-condition */ @@ -100,19 +128,616 @@ public class DatabaseServiceIntegrationTest extends AbstractUnitTest { } @Test - public void update_notExists_fails() throws SQLException { + public void update_notExists_fails() { final UpdateUserPasswordDto request = UpdateUserPasswordDto.builder() .username("i_do_not_exist") .password(USER_1_PASSWORD) .build(); - /* mock */ - MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO); - /* test */ assertThrows(DatabaseMalformedException.class, () -> { databaseService.update(DATABASE_1_PRIVILEGED_DTO, request); }); } + @Test + public void inspectTable_sameNameDifferentDb_succeeds() throws TableNotFoundException, SQLException { + + /* mock */ + MariaDbConfig.execute(DATABASE_2_PRIVILEGED_DTO, "CREATE TABLE not_in_metadata_db (wrong_id BIGINT NOT NULL PRIMARY KEY, given_name VARCHAR(255) NOT NULL, middle_name VARCHAR(255), family_name VARCHAR(255) NOT NULL, age INT NOT NULL) WITH SYSTEM VERSIONING;"); + + /* test */ + final TableDto response = databaseService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "not_in_metadata_db"); + assertEquals("not_in_metadata_db", response.getInternalName()); + assertEquals("not_in_metadata_db", response.getName()); + assertEquals(DATABASE_1_ID, response.getTdbid()); + assertTrue(response.getIsVersioned()); + assertEquals(DATABASE_1_PUBLIC, response.getIsPublic()); + final List<ColumnDto> columns = response.getColumns(); + assertNotNull(columns); + assertEquals(5, columns.size()); + assertColumn(columns.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); + assertColumn(columns.get(1), null, null, DATABASE_1_ID, "given_name", "given_name", ColumnTypeDto.VARCHAR, 255L, null, false, null); + assertColumn(columns.get(2), null, null, DATABASE_1_ID, "middle_name", "middle_name", ColumnTypeDto.VARCHAR, 255L, null, true, null); + assertColumn(columns.get(3), null, null, DATABASE_1_ID, "family_name", "family_name", ColumnTypeDto.VARCHAR, 255L, null, false, null); + assertColumn(columns.get(4), null, null, DATABASE_1_ID, "age", "age", ColumnTypeDto.INT, 10L, 0L, false, null); + final ConstraintsDto constraints = response.getConstraints(); + assertNotNull(constraints); + final Set<PrimaryKeyDto> primaryKey = constraints.getPrimaryKey(); + assertEquals(1, primaryKey.size()); + final Set<String> checks = constraints.getChecks(); + assertEquals(1, checks.size()); + assertEquals(Set.of("`age` > 0 and `age` < 120"), checks); + final List<UniqueDto> uniques = constraints.getUniques(); + assertEquals(1, uniques.size()); + assertEquals(2, uniques.get(0).getColumns().size()); + assertEquals("not_in_metadata_db", uniques.get(0).getTable().getName()); + assertEquals("not_in_metadata_db", uniques.get(0).getTable().getInternalName()); + assertEquals("given_name", uniques.get(0).getColumns().get(0).getInternalName()); + assertEquals("family_name", uniques.get(0).getColumns().get(1).getInternalName()); + final List<ForeignKeyDto> foreignKeys = constraints.getForeignKeys(); + assertEquals(0, foreignKeys.size()); + } + + @Test + public void inspectTableEnum_succeeds() throws TableNotFoundException, SQLException { + + /* test */ + final TableDto response = databaseService.inspectTable(DATABASE_2_PRIVILEGED_DTO, "experiments"); + assertEquals("experiments", response.getInternalName()); + assertEquals("experiments", response.getName()); + assertEquals(DATABASE_2_ID, response.getTdbid()); + assertTrue(response.getIsVersioned()); + assertEquals(DATABASE_2_PUBLIC, response.getIsPublic()); + assertNotNull(response.getOwner()); + assertEquals(DATABASE_2_OWNER, response.getOwner().getId()); + assertEquals(USER_2_NAME, response.getOwner().getName()); + assertEquals(USER_2_USERNAME, response.getOwner().getUsername()); + assertEquals(USER_2_FIRSTNAME, response.getOwner().getFirstname()); + assertEquals(USER_2_LASTNAME, response.getOwner().getLastname()); + assertEquals(USER_2_QUALIFIED_NAME, response.getOwner().getQualifiedName()); + final List<IdentifierDto> identifiers = response.getIdentifiers(); + assertNotNull(identifiers); + assertEquals(0, identifiers.size()); + final List<ColumnDto> columns = response.getColumns(); + assertNotNull(columns); + assertEquals(3, columns.size()); + assertColumn(columns.get(0), null, null, DATABASE_2_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); + assertColumn(columns.get(1), null, null, DATABASE_2_ID, "mode", "mode", ColumnTypeDto.ENUM, 3L, null, false, null); + assertEquals(2, columns.get(1).getEnums().size()); + assertEquals(List.of("ABC", "DEF"), columns.get(1).getEnums()); + assertColumn(columns.get(2), null, null, DATABASE_2_ID, "seq", "seq", ColumnTypeDto.SET, 5L, null, true, null); + assertEquals(3, columns.get(2).getSets().size()); + assertEquals(List.of("1", "2", "3"), columns.get(2).getSets()); + /* ignore rest (constraints) */ + } + + @Test + public void inspectTableFullConstraints_succeeds() throws TableNotFoundException, SQLException { + + /* test */ + final TableDto response = databaseService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "weather_aus"); + assertEquals("weather_aus", response.getInternalName()); + assertEquals("weather_aus", response.getName()); + assertEquals(DATABASE_1_ID, response.getTdbid()); + assertTrue(response.getIsVersioned()); + assertEquals(DATABASE_1_PUBLIC, response.getIsPublic()); + assertNotNull(response.getOwner()); + assertEquals(USER_1_BRIEF_DTO, response.getOwner()); + assertEquals(USER_1_NAME, response.getOwner().getName()); + assertEquals(USER_1_USERNAME, response.getOwner().getUsername()); + assertEquals(USER_1_FIRSTNAME, response.getOwner().getFirstname()); + assertEquals(USER_1_LASTNAME, response.getOwner().getLastname()); + assertEquals(USER_1_QUALIFIED_NAME, response.getOwner().getQualifiedName()); + final List<IdentifierDto> identifiers = response.getIdentifiers(); + assertNotNull(identifiers); + assertEquals(0, identifiers.size()); + final List<ColumnDto> columns = response.getColumns(); + assertNotNull(columns); + assertEquals(5, columns.size()); + assertColumn(columns.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 20L, 0L, false, null); + assertColumn(columns.get(1), null, null, DATABASE_1_ID, "date", "date", ColumnTypeDto.DATE, null, null, false, null); + assertColumn(columns.get(2), null, null, DATABASE_1_ID, "location", "location", ColumnTypeDto.VARCHAR, 255L, null, true, "Closest city"); + assertColumn(columns.get(3), null, null, DATABASE_1_ID, "mintemp", "mintemp", ColumnTypeDto.DOUBLE, 22L, null, true, null); + assertColumn(columns.get(4), null, null, DATABASE_1_ID, "rainfall", "rainfall", ColumnTypeDto.DOUBLE, 22L, null, true, null); + final ConstraintsDto constraints = response.getConstraints(); + final List<PrimaryKeyDto> primaryKey = new LinkedList<>(constraints.getPrimaryKey()); + assertEquals(1, primaryKey.size()); + final PrimaryKeyDto pk0 = primaryKey.get(0); + assertNull(pk0.getId()); + assertNotNull(pk0.getTable()); + assertNull(pk0.getTable().getId()); + assertEquals("weather_aus", pk0.getTable().getName()); + assertEquals("weather_aus", pk0.getTable().getInternalName()); + assertEquals("Weather in Australia", pk0.getTable().getDescription()); + assertNotNull(pk0.getColumn()); + assertNull(pk0.getColumn().getId()); + assertNull(pk0.getColumn().getTableId()); + assertEquals(DATABASE_1_ID, pk0.getColumn().getDatabaseId()); + assertNull(pk0.getColumn().getAlias()); + assertEquals("id", pk0.getColumn().getName()); + assertEquals("id", pk0.getColumn().getInternalName()); + assertEquals(ColumnTypeDto.BIGINT, pk0.getColumn().getColumnType()); + final List<UniqueDto> uniques = constraints.getUniques(); + assertEquals(1, uniques.size()); + final UniqueDto unique0 = uniques.get(0); + assertNotNull(unique0.getTable()); + assertEquals("some_constraint", unique0.getName()); + assertNull(unique0.getTable().getId()); + assertEquals(TABLE_1_INTERNAL_NAME, unique0.getTable().getName()); + assertEquals(TABLE_1_INTERNAL_NAME, unique0.getTable().getInternalName()); + assertEquals(TABLE_1_DESCRIPTION, unique0.getTable().getDescription()); + assertTrue(unique0.getTable().getIsVersioned()); + assertNotNull(unique0.getColumns()); + assertEquals(1, unique0.getColumns().size()); + assertNull(unique0.getColumns().get(0).getId()); + assertNull(unique0.getColumns().get(0).getTableId()); + assertEquals("date", unique0.getColumns().get(0).getName()); + assertEquals("date", unique0.getColumns().get(0).getInternalName()); + final List<String> checks = new LinkedList<>(constraints.getChecks()); + assertEquals("`mintemp` > 0", checks.get(0)); + final List<ForeignKeyDto> foreignKeys = constraints.getForeignKeys(); + assertEquals(1, foreignKeys.size()); + final ForeignKeyDto fk0 = foreignKeys.get(0); + assertNotNull(fk0.getName()); + assertNotNull(fk0.getReferences()); + final ForeignKeyReferenceDto fk0ref0 = fk0.getReferences().get(0); + assertNull(fk0ref0.getId()); + assertNotNull(fk0ref0.getColumn()); + assertNotNull(fk0ref0.getReferencedColumn()); + assertNotNull(fk0ref0.getForeignKey()); + assertEquals(DATABASE_1_ID, fk0ref0.getColumn().getDatabaseId()); + assertNull(fk0ref0.getColumn().getId()); + assertNull(fk0ref0.getColumn().getTableId()); + assertEquals("location", fk0ref0.getColumn().getName()); + assertEquals("location", fk0ref0.getColumn().getInternalName()); + assertEquals(DATABASE_1_ID, fk0ref0.getReferencedColumn().getDatabaseId()); + assertNull(fk0ref0.getReferencedColumn().getId()); + assertNull(fk0ref0.getReferencedColumn().getTableId()); + assertEquals("location", fk0ref0.getReferencedColumn().getName()); + assertEquals("location", fk0ref0.getReferencedColumn().getInternalName()); + assertNotNull(fk0.getOnUpdate()); + assertEquals(ReferenceTypeDto.RESTRICT, fk0.getOnUpdate()); + assertNotNull(fk0.getOnDelete()); + assertEquals(ReferenceTypeDto.SET_NULL, fk0.getOnDelete()); + final TableBriefDto fk0table = fk0.getTable(); + assertNull(fk0table.getId()); + assertEquals(DATABASE_1_ID, fk0table.getDatabaseId()); + assertEquals(TABLE_1_INTERNAL_NAME, fk0table.getName()); + assertEquals(TABLE_1_INTERNAL_NAME, fk0table.getInternalName()); + assertNotNull(fk0.getOnDelete()); + assertNotNull(fk0.getOnUpdate()); + assertNotNull(fk0.getReferencedTable()); + assertEquals(TABLE_2_INTERNALNAME, fk0.getReferencedTable().getName()); + assertEquals(TABLE_2_INTERNALNAME, fk0.getReferencedTable().getInternalName()); + } + + @Test + public void inspectTable_multipleForeignKeyReferences_succeeds() throws TableNotFoundException, SQLException { + + /* test */ + final TableDto response = databaseService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "complex_foreign_keys"); + final ConstraintsDto constraints = response.getConstraints(); + final List<ForeignKeyDto> foreignKeys = constraints.getForeignKeys(); + assertEquals(1, foreignKeys.size()); + final ForeignKeyDto fk0 = foreignKeys.get(0); + assertNotNull(fk0.getName()); + assertNotNull(fk0.getReferences()); + final ForeignKeyReferenceDto fk0ref0 = fk0.getReferences().get(0); + assertNull(fk0ref0.getId()); + assertNotNull(fk0ref0.getColumn()); + assertNotNull(fk0ref0.getReferencedColumn()); + assertNotNull(fk0ref0.getForeignKey()); + assertEquals(DATABASE_1_ID, fk0ref0.getColumn().getDatabaseId()); + assertNull(fk0ref0.getColumn().getId()); + assertNull(fk0ref0.getColumn().getTableId()); + assertEquals("weather_id", fk0ref0.getColumn().getName()); + assertEquals("weather_id", fk0ref0.getColumn().getInternalName()); + assertEquals(DATABASE_1_ID, fk0ref0.getReferencedColumn().getDatabaseId()); + assertNull(fk0ref0.getReferencedColumn().getId()); + assertNull(fk0ref0.getReferencedColumn().getTableId()); + assertEquals("id", fk0ref0.getReferencedColumn().getName()); + assertEquals("id", fk0ref0.getReferencedColumn().getInternalName()); + final ForeignKeyReferenceDto fk0ref1 = fk0.getReferences().get(1); + assertNull(fk0ref1.getId()); + assertNotNull(fk0ref1.getColumn()); + assertNotNull(fk0ref1.getReferencedColumn()); + assertNotNull(fk0ref1.getForeignKey()); + assertEquals(DATABASE_1_ID, fk0ref1.getColumn().getDatabaseId()); + assertNull(fk0ref1.getColumn().getId()); + assertNull(fk0ref1.getColumn().getTableId()); + assertEquals("other_id", fk0ref1.getColumn().getName()); + assertEquals("other_id", fk0ref1.getColumn().getInternalName()); + assertEquals(DATABASE_1_ID, fk0ref1.getReferencedColumn().getDatabaseId()); + assertNull(fk0ref1.getReferencedColumn().getId()); + assertNull(fk0ref1.getReferencedColumn().getTableId()); + assertEquals("other_id", fk0ref1.getReferencedColumn().getName()); + assertEquals("other_id", fk0ref1.getReferencedColumn().getInternalName()); + final TableBriefDto fk0refT0 = fk0.getTable(); + assertNull(fk0refT0.getId()); + assertEquals(DATABASE_1_ID, fk0refT0.getDatabaseId()); + assertEquals("complex_foreign_keys", fk0refT0.getName()); + assertEquals("complex_foreign_keys", fk0refT0.getInternalName()); + assertNotNull(fk0.getReferencedTable()); + assertEquals("complex_primary_key", fk0.getReferencedTable().getName()); + assertEquals("complex_primary_key", fk0.getReferencedTable().getInternalName()); + assertNotNull(fk0.getOnDelete()); + assertNotNull(fk0.getOnUpdate()); + } + + @Test + public void inspectTable_multiplePrimaryKey_succeeds() throws TableNotFoundException, SQLException { + + /* test */ + final TableDto response = databaseService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "complex_primary_key"); + final ConstraintsDto constraints = response.getConstraints(); + final List<PrimaryKeyDto> primaryKey = new LinkedList<>(constraints.getPrimaryKey()); + assertEquals(2, primaryKey.size()); + final PrimaryKeyDto pk0 = primaryKey.get(0); + assertNull(pk0.getId()); + assertNotNull(pk0.getTable()); + assertNull(pk0.getTable().getId()); + assertEquals("complex_primary_key", pk0.getTable().getName()); + assertEquals("complex_primary_key", pk0.getTable().getInternalName()); + assertNotNull(pk0.getColumn()); + assertNull(pk0.getColumn().getId()); + assertNull(pk0.getColumn().getTableId()); + assertEquals(DATABASE_1_ID, pk0.getColumn().getDatabaseId()); + assertNull(pk0.getColumn().getAlias()); + assertEquals("id", pk0.getColumn().getName()); + assertEquals("id", pk0.getColumn().getInternalName()); + assertEquals(ColumnTypeDto.BIGINT, pk0.getColumn().getColumnType()); + final PrimaryKeyDto pk1 = primaryKey.get(1); + assertNull(pk1.getId()); + assertNotNull(pk1.getTable()); + assertNull(pk1.getTable().getId()); + assertEquals("complex_primary_key", pk1.getTable().getName()); + assertEquals("complex_primary_key", pk1.getTable().getInternalName()); + assertNotNull(pk1.getColumn()); + assertNull(pk1.getColumn().getId()); + assertNull(pk1.getColumn().getTableId()); + assertEquals(DATABASE_1_ID, pk1.getColumn().getDatabaseId()); + assertNull(pk1.getColumn().getAlias()); + assertEquals("other_id", pk1.getColumn().getName()); + assertEquals("other_id", pk1.getColumn().getInternalName()); + assertEquals(ColumnTypeDto.BIGINT, pk1.getColumn().getColumnType()); + } + + @Test + public void inspectTable_exoticBoolean_succeeds() throws TableNotFoundException, SQLException { + + /* test */ + final TableDto response = databaseService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "exotic_boolean"); + final ConstraintsDto constraints = response.getConstraints(); + final List<PrimaryKeyDto> primaryKey = new LinkedList<>(constraints.getPrimaryKey()); + assertEquals(1, primaryKey.size()); + final PrimaryKeyDto pk0 = primaryKey.get(0); + assertNull(pk0.getId()); + assertNotNull(pk0.getTable()); + assertNull(pk0.getTable().getId()); + assertEquals("exotic_boolean", pk0.getTable().getName()); + assertEquals("exotic_boolean", pk0.getTable().getInternalName()); + assertNotNull(pk0.getColumn()); + assertNull(pk0.getColumn().getId()); + assertNull(pk0.getColumn().getTableId()); + assertEquals(DATABASE_1_ID, pk0.getColumn().getDatabaseId()); + assertNull(pk0.getColumn().getAlias()); + assertEquals("bool_default", pk0.getColumn().getName()); + assertEquals("bool_default", pk0.getColumn().getInternalName()); + assertEquals(ColumnTypeDto.BOOL, pk0.getColumn().getColumnType()); + final List<ColumnDto> columns = response.getColumns(); + assertEquals(3, columns.size()); + assertColumn(columns.get(0), null, null, DATABASE_1_ID, "bool_default", "bool_default", ColumnTypeDto.BOOL, null, 0L, false, null); + assertColumn(columns.get(1), null, null, DATABASE_1_ID, "bool_tinyint", "bool_tinyint", ColumnTypeDto.BOOL, null, 0L, false, null); + assertColumn(columns.get(2), null, null, DATABASE_1_ID, "bool_tinyint_unsigned", "bool_tinyint_unsigned", ColumnTypeDto.BOOL, null, 0L, false, null); + } + + @Test + public void inspectView_succeeds() throws SQLException, ViewNotFoundException { + + /* test */ + final ViewDto response = databaseService.inspectView(DATABASE_1_PRIVILEGED_DTO, "not_in_metadata_db2"); + assertEquals("not_in_metadata_db2", response.getInternalName()); + assertEquals("not_in_metadata_db2", response.getName()); + assertEquals(DATABASE_1_ID, response.getVdbid()); + assertEquals(USER_1_BRIEF_DTO, response.getOwner()); + assertFalse(response.getIsInitialView()); + assertEquals(DATABASE_1_PUBLIC, response.getIsPublic()); + assertTrue(response.getQuery().length() >= 69); + assertNotNull(response.getQueryHash()); + assertEquals(4, response.getColumns().size()); + final ViewColumnDto column0 = response.getColumns().get(0); + assertNotNull(column0.getName()); + assertEquals("date", column0.getInternalName()); + assertEquals(DATABASE_1_ID, column0.getDatabaseId()); + final ViewColumnDto column1 = response.getColumns().get(1); + assertNotNull(column1.getName()); + assertEquals("location", column1.getInternalName()); + assertEquals(DATABASE_1_ID, column1.getDatabaseId()); + final ViewColumnDto column2 = response.getColumns().get(2); + assertNotNull(column2.getName()); + assertEquals("MinTemp", column2.getInternalName()); + assertEquals(DATABASE_1_ID, column2.getDatabaseId()); + final ViewColumnDto column3 = response.getColumns().get(3); + assertNotNull(column3.getName()); + assertEquals("Rainfall", column3.getInternalName()); + assertEquals(DATABASE_1_ID, column3.getDatabaseId()); + } + + @Test + public void getSchemas_succeeds() throws TableNotFoundException, SQLException, DatabaseMalformedException { + + /* test */ + final List<TableDto> response = databaseService.exploreTables(DATABASE_1_PRIVILEGED_DTO); + assertEquals(4, response.size()); + final TableDto table0 = response.get(0); + Assertions.assertEquals("complex_foreign_keys", table0.getInternalName()); + Assertions.assertEquals("complex_foreign_keys", table0.getName()); + Assertions.assertEquals(DATABASE_1_ID, table0.getTdbid()); + assertTrue(table0.getIsVersioned()); + Assertions.assertEquals(DATABASE_1_PUBLIC, table0.getIsPublic()); + final List<ColumnDto> columns0 = table0.getColumns(); + assertNotNull(columns0); + Assertions.assertEquals(3, columns0.size()); + assertColumn(columns0.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); + assertColumn(columns0.get(1), null, null, DATABASE_1_ID, "weather_id", "weather_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); + assertColumn(columns0.get(2), null, null, DATABASE_1_ID, "other_id", "other_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); + final ConstraintsDto constraints0 = table0.getConstraints(); + assertNotNull(constraints0); + assertEquals(1, constraints0.getPrimaryKey().size()); + final PrimaryKeyDto pk0 = new LinkedList<>(constraints0.getPrimaryKey()).get(0); + assertNull(pk0.getId()); + assertNull(pk0.getColumn().getId()); + assertEquals("id", pk0.getColumn().getName()); + assertEquals("id", pk0.getColumn().getInternalName()); + assertEquals(1, constraints0.getForeignKeys().size()); + final ForeignKeyDto fk0 = constraints0.getForeignKeys().get(0); + assertNotNull(fk0.getName()); + assertNull(fk0.getTable().getId()); + assertEquals("complex_foreign_keys", fk0.getTable().getName()); + assertEquals("complex_foreign_keys", fk0.getTable().getInternalName()); + assertNull(fk0.getReferencedTable().getId()); + assertEquals("complex_primary_key", fk0.getReferencedTable().getName()); + assertEquals("complex_primary_key", fk0.getReferencedTable().getInternalName()); + assertEquals(2, fk0.getReferences().size()); + final ForeignKeyReferenceDto fk0r0 = fk0.getReferences().get(0); + assertEquals("weather_id", fk0r0.getColumn().getName()); + assertEquals("weather_id", fk0r0.getColumn().getInternalName()); + assertNotNull(fk0r0.getColumn().getName()); + assertNotNull(fk0r0.getForeignKey()); + assertEquals("id", fk0r0.getReferencedColumn().getName()); + assertEquals("id", fk0r0.getReferencedColumn().getInternalName()); + final ForeignKeyReferenceDto fk0r1 = fk0.getReferences().get(1); + assertEquals("other_id", fk0r1.getColumn().getName()); + assertEquals("other_id", fk0r1.getColumn().getInternalName()); + assertNotNull(fk0r1.getColumn().getName()); + assertNotNull(fk0r1.getForeignKey()); + assertEquals("other_id", fk0r1.getReferencedColumn().getName()); + assertEquals("other_id", fk0r1.getReferencedColumn().getInternalName()); + assertEquals(0, constraints0.getChecks().size()); + assertEquals(0, constraints0.getUniques().size()); + /* table 1 */ + final TableDto table1 = response.get(1); + Assertions.assertEquals("complex_primary_key", table1.getInternalName()); + Assertions.assertEquals("complex_primary_key", table1.getName()); + Assertions.assertEquals(DATABASE_1_ID, table1.getTdbid()); + assertTrue(table1.getIsVersioned()); + Assertions.assertEquals(DATABASE_1_PUBLIC, table1.getIsPublic()); + final List<ColumnDto> columns1 = table1.getColumns(); + assertNotNull(columns1); + Assertions.assertEquals(2, columns1.size()); + assertColumn(columns1.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); + assertColumn(columns1.get(1), null, null, DATABASE_1_ID, "other_id", "other_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); + final ConstraintsDto constraints1 = table1.getConstraints(); + assertNotNull(constraints1); + assertEquals(2, constraints1.getPrimaryKey().size()); + final PrimaryKeyDto pk10 = new LinkedList<>(constraints1.getPrimaryKey()).get(0); + assertNull(pk10.getId()); + assertNull(pk10.getColumn().getId()); + assertEquals("id", pk10.getColumn().getName()); + assertEquals("id", pk10.getColumn().getInternalName()); + final PrimaryKeyDto pk11 = new LinkedList<>(constraints1.getPrimaryKey()).get(1); + assertNull(pk11.getId()); + assertNull(pk11.getColumn().getId()); + assertEquals("other_id", pk11.getColumn().getName()); + assertEquals("other_id", pk11.getColumn().getInternalName()); + assertEquals(0, constraints1.getForeignKeys().size()); + assertEquals(0, constraints1.getChecks().size()); + assertEquals(0, constraints1.getUniques().size()); + /* table 2 */ + final TableDto table2 = response.get(2); + Assertions.assertEquals("exotic_boolean", table2.getInternalName()); + Assertions.assertEquals("exotic_boolean", table2.getName()); + Assertions.assertEquals(DATABASE_1_ID, table2.getTdbid()); + assertTrue(table2.getIsVersioned()); + Assertions.assertEquals(DATABASE_1_PUBLIC, table2.getIsPublic()); + final List<ColumnDto> columns2 = table2.getColumns(); + assertNotNull(columns2); + Assertions.assertEquals(3, columns2.size()); + assertColumn(columns2.get(0), null, null, DATABASE_1_ID, "bool_default", "bool_default", ColumnTypeDto.BOOL, null, 0L, false, null); + assertColumn(columns2.get(1), null, null, DATABASE_1_ID, "bool_tinyint", "bool_tinyint", ColumnTypeDto.BOOL, null, 0L, false, null); + assertColumn(columns2.get(2), null, null, DATABASE_1_ID, "bool_tinyint_unsigned", "bool_tinyint_unsigned", ColumnTypeDto.BOOL, null, 0L, false, null); + final ConstraintsDto constraints2 = table2.getConstraints(); + assertNotNull(constraints2); + final Set<PrimaryKeyDto> primaryKey2 = constraints2.getPrimaryKey(); + Assertions.assertEquals(1, primaryKey2.size()); + final Set<String> checks2 = constraints2.getChecks(); + Assertions.assertEquals(0, checks2.size()); + final List<UniqueDto> uniques2 = constraints2.getUniques(); + Assertions.assertEquals(0, uniques2.size()); + /* table 3 */ + final TableDto table3 = response.get(3); + Assertions.assertEquals("not_in_metadata_db", table3.getInternalName()); + Assertions.assertEquals("not_in_metadata_db", table3.getName()); + Assertions.assertEquals(DATABASE_1_ID, table3.getTdbid()); + assertTrue(table3.getIsVersioned()); + Assertions.assertEquals(DATABASE_1_PUBLIC, table3.getIsPublic()); + final List<ColumnDto> columns3 = table3.getColumns(); + assertNotNull(columns3); + Assertions.assertEquals(5, columns3.size()); + assertColumn(columns3.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); + assertColumn(columns3.get(1), null, null, DATABASE_1_ID, "given_name", "given_name", ColumnTypeDto.VARCHAR, 255L, null, false, null); + assertColumn(columns3.get(2), null, null, DATABASE_1_ID, "middle_name", "middle_name", ColumnTypeDto.VARCHAR, 255L, null, true, null); + assertColumn(columns3.get(3), null, null, DATABASE_1_ID, "family_name", "family_name", ColumnTypeDto.VARCHAR, 255L, null, false, null); + assertColumn(columns3.get(4), null, null, DATABASE_1_ID, "age", "age", ColumnTypeDto.INT, 10L, 0L, false, null); + final ConstraintsDto constraints3 = table3.getConstraints(); + assertNotNull(constraints3); + final Set<PrimaryKeyDto> primaryKey3 = constraints3.getPrimaryKey(); + Assertions.assertEquals(1, primaryKey3.size()); + final Set<String> checks3 = constraints3.getChecks(); + Assertions.assertEquals(1, checks3.size()); + Assertions.assertEquals(Set.of("`age` > 0 and `age` < 120"), checks3); + final List<UniqueDto> uniques3 = constraints3.getUniques(); + Assertions.assertEquals(1, uniques3.size()); + Assertions.assertEquals(2, uniques3.get(0).getColumns().size()); + Assertions.assertEquals("not_in_metadata_db", uniques3.get(0).getTable().getInternalName()); + Assertions.assertEquals("given_name", uniques3.get(0).getColumns().get(0).getInternalName()); + Assertions.assertEquals("family_name", uniques3.get(0).getColumns().get(1).getInternalName()); + } + + @Test + public void createTable_succeeds() throws TableNotFoundException, TableMalformedException, SQLException, + TableExistsException { + + /* test */ + final TableDto response = databaseService.createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_CREATE_INTERNAL_DTO); + assertEquals(TABLE_4_INTERNALNAME, response.getName()); + assertEquals(TABLE_4_INTERNALNAME, response.getInternalName()); + final List<ColumnDto> columns = response.getColumns(); + assertEquals(TABLE_4_COLUMNS.size(), columns.size()); + assertColumn(columns.get(0), null, null, DATABASE_1_ID, "timestamp", "timestamp", ColumnTypeDto.TIMESTAMP, null, null, false, null); + assertColumn(columns.get(1), null, null, DATABASE_1_ID, "value", "value", ColumnTypeDto.DECIMAL, 10L, 10L, true, null); + final ConstraintsDto constraints = response.getConstraints(); + assertNotNull(constraints); + final Set<PrimaryKeyDto> primaryKey = constraints.getPrimaryKey(); + Assertions.assertEquals(1, primaryKey.size()); + final Set<String> checks = constraints.getChecks(); + Assertions.assertEquals(0, checks.size()); + } + + @Test + public void createTable_malformed_fails() { + final at.tuwien.api.database.table.internal.TableCreateDto request = TableCreateDto.builder() + .name("missing_foreign_key") + .columns(List.of()) + .constraints(CreateTableConstraintsDto.builder() + .foreignKeys(List.of(CreateForeignKeyDto.builder() + .columns(List.of("i_do_not_exist")) + .referencedTable("neither_do_i") + .referencedColumns(List.of("behold")) + .build())) + .build()) + .build(); + + /* test */ + assertThrows(TableMalformedException.class, () -> { + databaseService.createTable(DATABASE_1_PRIVILEGED_DTO, request); + }); + } + + @Test + public void createTable_compositePrimaryKey_fails() throws TableNotFoundException, TableMalformedException, SQLException, + TableExistsException { + final at.tuwien.api.database.table.internal.TableCreateDto request = TableCreateDto.builder() + .name("composite_primary_key") + .columns(List.of(CreateTableColumnDto.builder() + .name("name") + .type(ColumnTypeDto.VARCHAR) + .size(255L) + .nullAllowed(false) + .build(), + CreateTableColumnDto.builder() + .name("lat") + .type(ColumnTypeDto.DECIMAL) + .size(10L) + .d(10L) + .nullAllowed(false) + .build(), + CreateTableColumnDto.builder() + .name("lng") + .type(ColumnTypeDto.DECIMAL) + .size(10L) + .d(10L) + .nullAllowed(false) + .build())) + .constraints(CreateTableConstraintsDto.builder() + .primaryKey(Set.of("lat", "lng")) + .foreignKeys(List.of()) + .checks(Set.of()) + .uniques(List.of()) + .build()) + .build(); + + /* test */ + final TableDto response = databaseService.createTable(DATABASE_1_PRIVILEGED_DTO, request); + assertEquals("composite_primary_key", response.getName()); + assertEquals("composite_primary_key", response.getInternalName()); + final List<ColumnDto> columns = response.getColumns(); + assertEquals(3, columns.size()); + assertColumn(columns.get(0), null, null, DATABASE_1_ID, "name", "name", ColumnTypeDto.VARCHAR, 255L, null, false, null); + assertColumn(columns.get(1), null, null, DATABASE_1_ID, "lat", "lat", ColumnTypeDto.DECIMAL, 10L, 10L, false, null); + assertColumn(columns.get(2), null, null, DATABASE_1_ID, "lng", "lng", ColumnTypeDto.DECIMAL, 10L, 10L, false, null); + final ConstraintsDto constraints = response.getConstraints(); + assertNotNull(constraints); + final Set<String> checks = constraints.getChecks(); + assertNotNull(checks); + assertEquals(0, checks.size()); + final List<PrimaryKeyDto> primaryKeys = new LinkedList<>(constraints.getPrimaryKey()); + assertNotNull(primaryKeys); + assertEquals(2, primaryKeys.size()); + assertEquals("lat", primaryKeys.get(0).getColumn().getInternalName()); + assertEquals("lng", primaryKeys.get(1).getColumn().getInternalName()); + final List<ForeignKeyDto> foreignKeys = constraints.getForeignKeys(); + assertNotNull(foreignKeys); + assertEquals(0, foreignKeys.size()); + final List<UniqueDto> uniques = constraints.getUniques(); + assertNotNull(uniques); + assertEquals(0, uniques.size()); + } + + @Test + public void createTable_needSequence_succeeds() throws TableNotFoundException, TableMalformedException, SQLException, + TableExistsException { + + /* mock */ + MariaDbConfig.dropTable(DATABASE_1_PRIVILEGED_DTO, TABLE_1_INTERNAL_NAME); + + /* test */ + final TableDto response = databaseService.createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_1_CREATE_INTERNAL_DTO); + assertEquals(TABLE_1_INTERNAL_NAME, response.getName()); + assertEquals(TABLE_1_INTERNAL_NAME, response.getInternalName()); + assertEquals(TABLE_1_COLUMNS.size(), response.getColumns().size()); + } + + protected static void assertViewColumn(ViewColumnDto column, ViewColumnDto other) { + assertNotNull(column); + assertNotNull(other); + assertEquals(column.getId(), other.getId()); + assertEquals(column.getDatabaseId(), other.getDatabaseId()); + assertEquals(column.getName(), other.getName()); + assertEquals(column.getInternalName(), other.getInternalName()); + assertEquals(column.getColumnType(), other.getColumnType()); + assertEquals(column.getSize(), other.getSize()); + assertEquals(column.getD(), other.getD()); + assertEquals(column.getIsNullAllowed(), other.getIsNullAllowed()); + assertEquals(column.getDescription(), other.getDescription()); + } + + protected static void assertColumn(ColumnDto column, Long id, Long tableId, Long databaseId, String name, + String internalName, ColumnTypeDto type, Long size, Long d, Boolean nullAllowed, + String description) { + log.trace("assert column: {}", internalName); + assertNotNull(column); + assertEquals(id, column.getId()); + assertEquals(tableId, column.getTableId()); + assertEquals(databaseId, column.getDatabaseId()); + assertEquals(name, column.getName()); + assertEquals(internalName, column.getInternalName()); + assertEquals(type, column.getColumnType()); + assertEquals(size, column.getSize()); + assertEquals(d, column.getD()); + assertEquals(nullAllowed, column.getIsNullAllowed()); + assertEquals(description, column.getDescription()); + } + } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java index bd57eafacc47a1107e309be0fba94de75371bc95..18b2dd8e01bc8d8e10f1de9bea9798846868bc6d 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/QueueServiceIntegrationTest.java @@ -53,7 +53,7 @@ public class QueueServiceIntegrationTest extends AbstractUnitTest { genesis(); /* metadata database */ MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); - MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO); + MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_PRIVILEGED_DTO); } @Test diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java deleted file mode 100644 index 2a0ad624dbbb8399cf9d360148c96bd0524c8453..0000000000000000000000000000000000000000 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java +++ /dev/null @@ -1,416 +0,0 @@ -package at.tuwien.service; - -import at.tuwien.api.database.ViewColumnDto; -import at.tuwien.api.database.ViewDto; -import at.tuwien.api.database.table.TableBriefDto; -import at.tuwien.api.database.table.TableDto; -import at.tuwien.api.database.table.columns.ColumnDto; -import at.tuwien.api.database.table.columns.ColumnTypeDto; -import at.tuwien.api.database.table.constraints.ConstraintsDto; -import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto; -import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto; -import at.tuwien.api.database.table.constraints.foreign.ReferenceTypeDto; -import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto; -import at.tuwien.api.database.table.constraints.unique.UniqueDto; -import at.tuwien.api.identifier.IdentifierDto; -import at.tuwien.config.MariaDbConfig; -import at.tuwien.config.MariaDbContainerConfig; -import at.tuwien.exception.TableNotFoundException; -import at.tuwien.exception.ViewNotFoundException; -import at.tuwien.test.AbstractUnitTest; -import lombok.extern.log4j.Log4j2; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.testcontainers.containers.MariaDBContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; - -import java.sql.SQLException; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - -import static org.junit.jupiter.api.Assertions.*; - -@Log4j2 -@SpringBootTest -@ExtendWith(SpringExtension.class) -@Testcontainers -public class SchemaServiceIntegrationTest extends AbstractUnitTest { - - @Autowired - private SchemaService schemaService; - - @Container - private static MariaDBContainer<?> mariaDBContainer = MariaDbContainerConfig.getContainer(); - - @BeforeEach - public void beforeEach() throws SQLException { - genesis(); - /* metadata database */ - MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); - MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNALNAME); - MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO); - MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_DTO); - } - - @Test - public void inspectTable_sameNameDifferentDb_succeeds() throws TableNotFoundException, SQLException { - - /* mock */ - MariaDbConfig.execute(DATABASE_2_PRIVILEGED_DTO, "CREATE TABLE not_in_metadata_db (wrong_id BIGINT NOT NULL PRIMARY KEY, given_name VARCHAR(255) NOT NULL, middle_name VARCHAR(255), family_name VARCHAR(255) NOT NULL, age INT NOT NULL) WITH SYSTEM VERSIONING;"); - - /* test */ - final TableDto response = schemaService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "not_in_metadata_db"); - assertEquals("not_in_metadata_db", response.getInternalName()); - assertEquals("not_in_metadata_db", response.getName()); - assertEquals(DATABASE_1_ID, response.getTdbid()); - assertTrue(response.getIsVersioned()); - assertEquals(DATABASE_1_PUBLIC, response.getIsPublic()); - final List<ColumnDto> columns = response.getColumns(); - assertNotNull(columns); - assertEquals(5, columns.size()); - assertColumn(columns.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); - assertColumn(columns.get(1), null, null, DATABASE_1_ID, "given_name", "given_name", ColumnTypeDto.VARCHAR, 255L, null, false, null); - assertColumn(columns.get(2), null, null, DATABASE_1_ID, "middle_name", "middle_name", ColumnTypeDto.VARCHAR, 255L, null, true, null); - assertColumn(columns.get(3), null, null, DATABASE_1_ID, "family_name", "family_name", ColumnTypeDto.VARCHAR, 255L, null, false, null); - assertColumn(columns.get(4), null, null, DATABASE_1_ID, "age", "age", ColumnTypeDto.INT, 10L, 0L, false, null); - final ConstraintsDto constraints = response.getConstraints(); - assertNotNull(constraints); - final Set<PrimaryKeyDto> primaryKey = constraints.getPrimaryKey(); - assertEquals(1, primaryKey.size()); - final Set<String> checks = constraints.getChecks(); - assertEquals(1, checks.size()); - assertEquals(Set.of("`age` > 0 and `age` < 120"), checks); - final List<UniqueDto> uniques = constraints.getUniques(); - assertEquals(1, uniques.size()); - assertEquals(2, uniques.get(0).getColumns().size()); - assertEquals("not_in_metadata_db", uniques.get(0).getTable().getName()); - assertEquals("not_in_metadata_db", uniques.get(0).getTable().getInternalName()); - assertEquals("given_name", uniques.get(0).getColumns().get(0).getInternalName()); - assertEquals("family_name", uniques.get(0).getColumns().get(1).getInternalName()); - final List<ForeignKeyDto> foreignKeys = constraints.getForeignKeys(); - assertEquals(0, foreignKeys.size()); - } - - @Test - public void inspectTableEnum_succeeds() throws TableNotFoundException, SQLException { - - /* test */ - final TableDto response = schemaService.inspectTable(DATABASE_2_PRIVILEGED_DTO, "experiments"); - assertEquals("experiments", response.getInternalName()); - assertEquals("experiments", response.getName()); - assertEquals(DATABASE_2_ID, response.getTdbid()); - assertTrue(response.getIsVersioned()); - assertEquals(DATABASE_2_PUBLIC, response.getIsPublic()); - assertNotNull(response.getOwner()); - assertEquals(DATABASE_2_OWNER, response.getOwner().getId()); - assertEquals(USER_2_NAME, response.getOwner().getName()); - assertEquals(USER_2_USERNAME, response.getOwner().getUsername()); - assertEquals(USER_2_FIRSTNAME, response.getOwner().getFirstname()); - assertEquals(USER_2_LASTNAME, response.getOwner().getLastname()); - assertEquals(USER_2_QUALIFIED_NAME, response.getOwner().getQualifiedName()); - final List<IdentifierDto> identifiers = response.getIdentifiers(); - assertNotNull(identifiers); - assertEquals(0, identifiers.size()); - final List<ColumnDto> columns = response.getColumns(); - assertNotNull(columns); - assertEquals(3, columns.size()); - assertColumn(columns.get(0), null, null, DATABASE_2_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); - assertColumn(columns.get(1), null, null, DATABASE_2_ID, "mode", "mode", ColumnTypeDto.ENUM, 3L, null, false, null); - assertEquals(2, columns.get(1).getEnums().size()); - assertEquals(List.of("ABC", "DEF"), columns.get(1).getEnums()); - assertColumn(columns.get(2), null, null, DATABASE_2_ID, "seq", "seq", ColumnTypeDto.SET, 5L, null, true, null); - assertEquals(3, columns.get(2).getSets().size()); - assertEquals(List.of("1", "2", "3"), columns.get(2).getSets()); - /* ignore rest (constraints) */ - } - - @Test - public void inspectTableFullConstraints_succeeds() throws TableNotFoundException, SQLException { - - /* test */ - final TableDto response = schemaService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "weather_aus"); - assertEquals("weather_aus", response.getInternalName()); - assertEquals("weather_aus", response.getName()); - assertEquals(DATABASE_1_ID, response.getTdbid()); - assertTrue(response.getIsVersioned()); - assertEquals(DATABASE_1_PUBLIC, response.getIsPublic()); - assertNotNull(response.getOwner()); - assertEquals(DATABASE_1_OWNER, response.getOwner().getId()); - assertEquals(USER_1_NAME, response.getOwner().getName()); - assertEquals(USER_1_USERNAME, response.getOwner().getUsername()); - assertEquals(USER_1_FIRSTNAME, response.getOwner().getFirstname()); - assertEquals(USER_1_LASTNAME, response.getOwner().getLastname()); - assertEquals(USER_1_QUALIFIED_NAME, response.getOwner().getQualifiedName()); - final List<IdentifierDto> identifiers = response.getIdentifiers(); - assertNotNull(identifiers); - assertEquals(0, identifiers.size()); - final List<ColumnDto> columns = response.getColumns(); - assertNotNull(columns); - assertEquals(5, columns.size()); - assertColumn(columns.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 20L, 0L, false, null); - assertColumn(columns.get(1), null, null, DATABASE_1_ID, "date", "date", ColumnTypeDto.DATE, null, null, false, null); - assertColumn(columns.get(2), null, null, DATABASE_1_ID, "location", "location", ColumnTypeDto.VARCHAR, 255L, null, true, "Closest city"); - assertColumn(columns.get(3), null, null, DATABASE_1_ID, "mintemp", "mintemp", ColumnTypeDto.DOUBLE, 22L, null, true, null); - assertColumn(columns.get(4), null, null, DATABASE_1_ID, "rainfall", "rainfall", ColumnTypeDto.DOUBLE, 22L, null, true, null); - final ConstraintsDto constraints = response.getConstraints(); - final List<PrimaryKeyDto> primaryKey = new LinkedList<>(constraints.getPrimaryKey()); - assertEquals(1, primaryKey.size()); - final PrimaryKeyDto pk0 = primaryKey.get(0); - assertNull(pk0.getId()); - assertNotNull(pk0.getTable()); - assertNull(pk0.getTable().getId()); - assertEquals("weather_aus", pk0.getTable().getName()); - assertEquals("weather_aus", pk0.getTable().getInternalName()); - assertEquals("Weather in Australia", pk0.getTable().getDescription()); - assertNotNull(pk0.getColumn()); - assertNull(pk0.getColumn().getId()); - assertNull(pk0.getColumn().getTableId()); - assertEquals(DATABASE_1_ID, pk0.getColumn().getDatabaseId()); - assertNull(pk0.getColumn().getAlias()); - assertEquals("id", pk0.getColumn().getName()); - assertEquals("id", pk0.getColumn().getInternalName()); - assertEquals(ColumnTypeDto.BIGINT, pk0.getColumn().getColumnType()); - final List<UniqueDto> uniques = constraints.getUniques(); - assertEquals(1, uniques.size()); - final UniqueDto unique0 = uniques.get(0); - assertNotNull(unique0.getTable()); - assertEquals("some_constraint", unique0.getName()); - assertNull(unique0.getTable().getId()); - assertEquals(TABLE_1_INTERNAL_NAME, unique0.getTable().getName()); - assertEquals(TABLE_1_INTERNAL_NAME, unique0.getTable().getInternalName()); - assertEquals(TABLE_1_DESCRIPTION, unique0.getTable().getDescription()); - assertTrue(unique0.getTable().getIsVersioned()); - assertNotNull(unique0.getColumns()); - assertEquals(1, unique0.getColumns().size()); - assertNull(unique0.getColumns().get(0).getId()); - assertNull(unique0.getColumns().get(0).getTableId()); - assertEquals("date", unique0.getColumns().get(0).getName()); - assertEquals("date", unique0.getColumns().get(0).getInternalName()); - final List<String> checks = new LinkedList<>(constraints.getChecks()); - assertEquals("`mintemp` > 0", checks.get(0)); - final List<ForeignKeyDto> foreignKeys = constraints.getForeignKeys(); - assertEquals(1, foreignKeys.size()); - final ForeignKeyDto fk0 = foreignKeys.get(0); - assertNotNull(fk0.getName()); - assertNotNull(fk0.getReferences()); - final ForeignKeyReferenceDto fk0ref0 = fk0.getReferences().get(0); - assertNull(fk0ref0.getId()); - assertNotNull(fk0ref0.getColumn()); - assertNotNull(fk0ref0.getReferencedColumn()); - assertNotNull(fk0ref0.getForeignKey()); - assertEquals(DATABASE_1_ID, fk0ref0.getColumn().getDatabaseId()); - assertNull(fk0ref0.getColumn().getId()); - assertNull(fk0ref0.getColumn().getTableId()); - assertEquals("location", fk0ref0.getColumn().getName()); - assertEquals("location", fk0ref0.getColumn().getInternalName()); - assertEquals(DATABASE_1_ID, fk0ref0.getReferencedColumn().getDatabaseId()); - assertNull(fk0ref0.getReferencedColumn().getId()); - assertNull(fk0ref0.getReferencedColumn().getTableId()); - assertEquals("location", fk0ref0.getReferencedColumn().getName()); - assertEquals("location", fk0ref0.getReferencedColumn().getInternalName()); - assertNotNull(fk0.getOnUpdate()); - assertEquals(ReferenceTypeDto.RESTRICT, fk0.getOnUpdate()); - assertNotNull(fk0.getOnDelete()); - assertEquals(ReferenceTypeDto.SET_NULL, fk0.getOnDelete()); - final TableBriefDto fk0table = fk0.getTable(); - assertNull(fk0table.getId()); - assertEquals(DATABASE_1_ID, fk0table.getDatabaseId()); - assertEquals(TABLE_1_INTERNAL_NAME, fk0table.getName()); - assertEquals(TABLE_1_INTERNAL_NAME, fk0table.getInternalName()); - assertNotNull(fk0.getOnDelete()); - assertNotNull(fk0.getOnUpdate()); - assertNotNull(fk0.getReferencedTable()); - assertEquals(TABLE_2_INTERNALNAME, fk0.getReferencedTable().getName()); - assertEquals(TABLE_2_INTERNALNAME, fk0.getReferencedTable().getInternalName()); - } - - @Test - public void inspectTable_multipleForeignKeyReferences_succeeds() throws TableNotFoundException, SQLException { - - /* test */ - final TableDto response = schemaService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "complex_foreign_keys"); - final ConstraintsDto constraints = response.getConstraints(); - final List<ForeignKeyDto> foreignKeys = constraints.getForeignKeys(); - assertEquals(1, foreignKeys.size()); - final ForeignKeyDto fk0 = foreignKeys.get(0); - assertNotNull(fk0.getName()); - assertNotNull(fk0.getReferences()); - final ForeignKeyReferenceDto fk0ref0 = fk0.getReferences().get(0); - assertNull(fk0ref0.getId()); - assertNotNull(fk0ref0.getColumn()); - assertNotNull(fk0ref0.getReferencedColumn()); - assertNotNull(fk0ref0.getForeignKey()); - assertEquals(DATABASE_1_ID, fk0ref0.getColumn().getDatabaseId()); - assertNull(fk0ref0.getColumn().getId()); - assertNull(fk0ref0.getColumn().getTableId()); - assertEquals("weather_id", fk0ref0.getColumn().getName()); - assertEquals("weather_id", fk0ref0.getColumn().getInternalName()); - assertEquals(DATABASE_1_ID, fk0ref0.getReferencedColumn().getDatabaseId()); - assertNull(fk0ref0.getReferencedColumn().getId()); - assertNull(fk0ref0.getReferencedColumn().getTableId()); - assertEquals("id", fk0ref0.getReferencedColumn().getName()); - assertEquals("id", fk0ref0.getReferencedColumn().getInternalName()); - final ForeignKeyReferenceDto fk0ref1 = fk0.getReferences().get(1); - assertNull(fk0ref1.getId()); - assertNotNull(fk0ref1.getColumn()); - assertNotNull(fk0ref1.getReferencedColumn()); - assertNotNull(fk0ref1.getForeignKey()); - assertEquals(DATABASE_1_ID, fk0ref1.getColumn().getDatabaseId()); - assertNull(fk0ref1.getColumn().getId()); - assertNull(fk0ref1.getColumn().getTableId()); - assertEquals("other_id", fk0ref1.getColumn().getName()); - assertEquals("other_id", fk0ref1.getColumn().getInternalName()); - assertEquals(DATABASE_1_ID, fk0ref1.getReferencedColumn().getDatabaseId()); - assertNull(fk0ref1.getReferencedColumn().getId()); - assertNull(fk0ref1.getReferencedColumn().getTableId()); - assertEquals("other_id", fk0ref1.getReferencedColumn().getName()); - assertEquals("other_id", fk0ref1.getReferencedColumn().getInternalName()); - final TableBriefDto fk0refT0 = fk0.getTable(); - assertNull(fk0refT0.getId()); - assertEquals(DATABASE_1_ID, fk0refT0.getDatabaseId()); - assertEquals("complex_foreign_keys", fk0refT0.getName()); - assertEquals("complex_foreign_keys", fk0refT0.getInternalName()); - assertNotNull(fk0.getReferencedTable()); - assertEquals("complex_primary_key", fk0.getReferencedTable().getName()); - assertEquals("complex_primary_key", fk0.getReferencedTable().getInternalName()); - assertNotNull(fk0.getOnDelete()); - assertNotNull(fk0.getOnUpdate()); - } - - @Test - public void inspectTable_multiplePrimaryKey_succeeds() throws TableNotFoundException, SQLException { - - /* test */ - final TableDto response = schemaService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "complex_primary_key"); - final ConstraintsDto constraints = response.getConstraints(); - final List<PrimaryKeyDto> primaryKey = new LinkedList<>(constraints.getPrimaryKey()); - assertEquals(2, primaryKey.size()); - final PrimaryKeyDto pk0 = primaryKey.get(0); - assertNull(pk0.getId()); - assertNotNull(pk0.getTable()); - assertNull(pk0.getTable().getId()); - assertEquals("complex_primary_key", pk0.getTable().getName()); - assertEquals("complex_primary_key", pk0.getTable().getInternalName()); - assertNotNull(pk0.getColumn()); - assertNull(pk0.getColumn().getId()); - assertNull(pk0.getColumn().getTableId()); - assertEquals(DATABASE_1_ID, pk0.getColumn().getDatabaseId()); - assertNull(pk0.getColumn().getAlias()); - assertEquals("id", pk0.getColumn().getName()); - assertEquals("id", pk0.getColumn().getInternalName()); - assertEquals(ColumnTypeDto.BIGINT, pk0.getColumn().getColumnType()); - final PrimaryKeyDto pk1 = primaryKey.get(1); - assertNull(pk1.getId()); - assertNotNull(pk1.getTable()); - assertNull(pk1.getTable().getId()); - assertEquals("complex_primary_key", pk1.getTable().getName()); - assertEquals("complex_primary_key", pk1.getTable().getInternalName()); - assertNotNull(pk1.getColumn()); - assertNull(pk1.getColumn().getId()); - assertNull(pk1.getColumn().getTableId()); - assertEquals(DATABASE_1_ID, pk1.getColumn().getDatabaseId()); - assertNull(pk1.getColumn().getAlias()); - assertEquals("other_id", pk1.getColumn().getName()); - assertEquals("other_id", pk1.getColumn().getInternalName()); - assertEquals(ColumnTypeDto.BIGINT, pk1.getColumn().getColumnType()); - } - - @Test - public void inspectTable_exoticBoolean_succeeds() throws TableNotFoundException, SQLException { - - /* test */ - final TableDto response = schemaService.inspectTable(DATABASE_1_PRIVILEGED_DTO, "exotic_boolean"); - final ConstraintsDto constraints = response.getConstraints(); - final List<PrimaryKeyDto> primaryKey = new LinkedList<>(constraints.getPrimaryKey()); - assertEquals(1, primaryKey.size()); - final PrimaryKeyDto pk0 = primaryKey.get(0); - assertNull(pk0.getId()); - assertNotNull(pk0.getTable()); - assertNull(pk0.getTable().getId()); - assertEquals("exotic_boolean", pk0.getTable().getName()); - assertEquals("exotic_boolean", pk0.getTable().getInternalName()); - assertNotNull(pk0.getColumn()); - assertNull(pk0.getColumn().getId()); - assertNull(pk0.getColumn().getTableId()); - assertEquals(DATABASE_1_ID, pk0.getColumn().getDatabaseId()); - assertNull(pk0.getColumn().getAlias()); - assertEquals("bool_default", pk0.getColumn().getName()); - assertEquals("bool_default", pk0.getColumn().getInternalName()); - assertEquals(ColumnTypeDto.BOOL, pk0.getColumn().getColumnType()); - final List<ColumnDto> columns = response.getColumns(); - assertEquals(3, columns.size()); - assertColumn(columns.get(0), null, null, DATABASE_1_ID, "bool_default", "bool_default", ColumnTypeDto.BOOL, null, 0L, false, null); - assertColumn(columns.get(1), null, null, DATABASE_1_ID, "bool_tinyint", "bool_tinyint", ColumnTypeDto.BOOL, null, 0L, false, null); - assertColumn(columns.get(2), null, null, DATABASE_1_ID, "bool_tinyint_unsigned", "bool_tinyint_unsigned", ColumnTypeDto.BOOL, null, 0L, false, null); - } - - @Test - public void inspectView_succeeds() throws SQLException, ViewNotFoundException { - - /* test */ - final ViewDto response = schemaService.inspectView(DATABASE_1_PRIVILEGED_DTO, "not_in_metadata_db2"); - assertEquals("not_in_metadata_db2", response.getInternalName()); - assertEquals("not_in_metadata_db2", response.getName()); - assertEquals(DATABASE_1_ID, response.getVdbid()); - assertEquals(DATABASE_1_OWNER, response.getOwner().getId()); - assertFalse(response.getIsInitialView()); - assertEquals(DATABASE_1_PUBLIC, response.getIsPublic()); - assertTrue(response.getQuery().length() >= 69); - assertNotNull(response.getQueryHash()); - assertEquals(4, response.getColumns().size()); - final ViewColumnDto column0 = response.getColumns().get(0); - assertNotNull(column0.getName()); - assertEquals("date", column0.getInternalName()); - assertEquals(DATABASE_1_ID, column0.getDatabaseId()); - final ViewColumnDto column1 = response.getColumns().get(1); - assertNotNull(column1.getName()); - assertEquals("location", column1.getInternalName()); - assertEquals(DATABASE_1_ID, column1.getDatabaseId()); - final ViewColumnDto column2 = response.getColumns().get(2); - assertNotNull(column2.getName()); - assertEquals("MinTemp", column2.getInternalName()); - assertEquals(DATABASE_1_ID, column2.getDatabaseId()); - final ViewColumnDto column3 = response.getColumns().get(3); - assertNotNull(column3.getName()); - assertEquals("Rainfall", column3.getInternalName()); - assertEquals(DATABASE_1_ID, column3.getDatabaseId()); - } - - protected static void assertViewColumn(ViewColumnDto column, ViewColumnDto other) { - assertNotNull(column); - assertNotNull(other); - assertEquals(column.getId(), other.getId()); - assertEquals(column.getDatabaseId(), other.getDatabaseId()); - assertEquals(column.getName(), other.getName()); - assertEquals(column.getInternalName(), other.getInternalName()); - assertEquals(column.getColumnType(), other.getColumnType()); - assertEquals(column.getSize(), other.getSize()); - assertEquals(column.getD(), other.getD()); - assertEquals(column.getIsNullAllowed(), other.getIsNullAllowed()); - assertEquals(column.getDescription(), other.getDescription()); - } - - protected static void assertColumn(ColumnDto column, Long id, Long tableId, Long databaseId, String name, - String internalName, ColumnTypeDto type, Long size, Long d, Boolean nullAllowed, - String description) { - log.trace("assert column: {}", internalName); - assertNotNull(column); - assertEquals(id, column.getId()); - assertEquals(tableId, column.getTableId()); - assertEquals(databaseId, column.getDatabaseId()); - assertEquals(name, column.getName()); - assertEquals(internalName, column.getInternalName()); - assertEquals(type, column.getColumnType()); - assertEquals(size, column.getSize()); - assertEquals(d, column.getD()); - assertEquals(nullAllowed, column.getIsNullAllowed()); - assertEquals(description, column.getDescription()); - } - -} diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SubsetServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SubsetServiceIntegrationTest.java index 0eab9c6ff3e012950dd011f472ca65e67c4912e9..56115690b503ce3c71bb241fdd84704710a0bb0b 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SubsetServiceIntegrationTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SubsetServiceIntegrationTest.java @@ -21,7 +21,6 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.sql.SQLException; import java.util.List; -import java.util.Map; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.when; @@ -46,7 +45,7 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { genesis(); /* metadata database */ MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); - MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO); + MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_PRIVILEGED_DTO); } @Test @@ -129,25 +128,6 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { assertFalse(response.getIsPersisted()); } - @Test - public void createQueryStore_succeeds() throws SQLException, QueryStoreCreateException, InterruptedException { - - /* mock */ - MariaDbConfig.dropQueryStore(DATABASE_1_PRIVILEGED_DTO); - - /* test */ - createQueryStore_generic(DATABASE_1_INTERNALNAME); - } - - @Test - public void createQueryStore_fails() { - - /* test */ - assertThrows(QueryStoreCreateException.class, () -> { - createQueryStore_generic(DATABASE_1_INTERNALNAME); - }); - } - protected void findById_generic(Long queryId) throws RemoteUnavailableException, SQLException, UserNotFoundException, QueryNotFoundException, MetadataServiceException, DatabaseNotFoundException, InterruptedException { @@ -201,16 +181,4 @@ public class SubsetServiceIntegrationTest extends AbstractUnitTest { queryService.persist(DATABASE_1_PRIVILEGED_DTO, queryId, persist); } - protected void createQueryStore_generic(String databaseName) throws SQLException, QueryStoreCreateException, - InterruptedException { - - /* pre-condition */ - Thread.sleep(1000) /* wait for test container some more */; - - /* test */ - queryService.createQueryStore(CONTAINER_1_PRIVILEGED_DTO, databaseName); - final List<Map<String, Object>> response = MariaDbConfig.listQueryStore(DATABASE_1_PRIVILEGED_DTO); - assertEquals(0, response.size()); - } - } diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java index 383c44770f251876836190f7729834c6d8ba84b5..f235f39d63a905e34017933bcc6365c85a299442 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/TableServiceIntegrationTest.java @@ -2,31 +2,21 @@ package at.tuwien.service; import at.tuwien.api.database.query.ImportDto; import at.tuwien.api.database.table.*; -import at.tuwien.api.database.table.columns.ColumnCreateDto; -import at.tuwien.api.database.table.columns.ColumnDto; import at.tuwien.api.database.table.columns.ColumnStatisticDto; -import at.tuwien.api.database.table.columns.ColumnTypeDto; -import at.tuwien.api.database.table.constraints.ConstraintsCreateDto; -import at.tuwien.api.database.table.constraints.ConstraintsDto; -import at.tuwien.api.database.table.constraints.foreign.ForeignKeyCreateDto; -import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto; -import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto; -import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto; -import at.tuwien.api.database.table.constraints.unique.UniqueDto; -import at.tuwien.api.database.table.internal.TableCreateDto; import at.tuwien.config.MariaDbConfig; import at.tuwien.config.MariaDbContainerConfig; import at.tuwien.config.S3Config; import at.tuwien.exception.*; -import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.test.AbstractUnitTest; import com.google.common.io.Files; import lombok.extern.log4j.Log4j2; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -44,11 +34,12 @@ import java.io.IOException; import java.math.BigDecimal; import java.sql.SQLException; import java.time.Instant; -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; -import static at.tuwien.service.SchemaServiceIntegrationTest.assertColumn; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.when; @Log4j2 @SpringBootTest @@ -65,9 +56,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { @Autowired private S3Config s3Config; - @MockBean - private MetadataServiceGateway metadataServiceGateway; - @Container private static MariaDBContainer<?> mariaDBContainer = MariaDbContainerConfig.getContainer(); @@ -91,8 +79,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_2_INTERNALNAME); MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_3_INTERNALNAME); - MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO); - MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_3_DTO); + MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_PRIVILEGED_DTO); + MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_3_PRIVILEGED_DTO); /* s3 */ if (s3Client.listBuckets().buckets().stream().noneMatch(b -> b.name().equals(s3Config.getS3Bucket()))) { s3Client.createBucket(CreateBucketRequest.builder() @@ -107,8 +95,7 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { } @Test - public void updateTuple_succeeds() throws SQLException, RemoteUnavailableException, ContainerNotFoundException, - TableNotFoundException, TableMalformedException, QueryMalformedException, MetadataServiceException { + public void updateTuple_succeeds() throws SQLException, TableMalformedException, QueryMalformedException { /* modify row based on primary key */ final TupleUpdateDto request = TupleUpdateDto.builder() .data(new HashMap<>() {{ @@ -122,12 +109,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { }}) .build(); - /* mock */ - when(metadataServiceGateway.getContainerById(CONTAINER_1_ID)) - .thenReturn(CONTAINER_1_PRIVILEGED_DTO); - when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) - .thenReturn(TABLE_1_PRIVILEGED_DTO); - /* test */ tableService.updateTuple(TABLE_1_PRIVILEGED_DTO, request); final List<Map<String, String>> result = MariaDbConfig.selectQuery(DATABASE_1_PRIVILEGED_DTO, "SELECT id, `date`, location, mintemp, rainfall FROM weather_aus WHERE id = 1", Set.of("id", "date", "location", "mintemp", "rainfall")); @@ -139,9 +120,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { } @Test - public void updateTuple_modifyPrimaryKey_succeeds() throws SQLException, RemoteUnavailableException, - ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException, - MetadataServiceException { + public void updateTuple_modifyPrimaryKey_succeeds() throws SQLException, TableMalformedException, + QueryMalformedException { /* modify row primary key based on primary key */ final TupleUpdateDto request = TupleUpdateDto.builder() .data(new HashMap<>() {{ @@ -156,12 +136,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { }}) .build(); - /* mock */ - when(metadataServiceGateway.getContainerById(CONTAINER_1_ID)) - .thenReturn(CONTAINER_1_PRIVILEGED_DTO); - when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) - .thenReturn(TABLE_1_PRIVILEGED_DTO); - /* test */ tableService.updateTuple(TABLE_1_PRIVILEGED_DTO, request); final List<Map<String, String>> result = MariaDbConfig.selectQuery(DATABASE_1_PRIVILEGED_DTO, "SELECT id, `date`, location, mintemp, rainfall FROM weather_aus WHERE id = 4", Set.of("id", "date", "location", "mintemp", "rainfall")); @@ -173,9 +147,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { } @Test - public void updateTuple_missingPrimaryKey_succeeds() throws SQLException, RemoteUnavailableException, - ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException, - MetadataServiceException { + public void updateTuple_missingPrimaryKey_succeeds() throws SQLException, TableMalformedException, + QueryMalformedException { /* modify row based on non-primary key column */ final TupleUpdateDto request = TupleUpdateDto.builder() .data(new HashMap<>() {{ @@ -189,12 +162,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { }}) .build(); - /* mock */ - when(metadataServiceGateway.getContainerById(CONTAINER_1_ID)) - .thenReturn(CONTAINER_1_PRIVILEGED_DTO); - when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) - .thenReturn(TABLE_1_PRIVILEGED_DTO); - /* test */ tableService.updateTuple(TABLE_1_PRIVILEGED_DTO, request); final List<Map<String, String>> result = MariaDbConfig.selectQuery(DATABASE_1_PRIVILEGED_DTO, "SELECT id, `date`, location, mintemp, rainfall FROM weather_aus WHERE id = 1", Set.of("id", "date", "location", "mintemp", "rainfall")); @@ -206,9 +173,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { } @Test - public void updateTuple_notInOrder_succeeds() throws SQLException, RemoteUnavailableException, - ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException, - MetadataServiceException { + public void updateTuple_notInOrder_succeeds() throws SQLException, TableMalformedException, + QueryMalformedException { /* modify row based on non-primary key column */ final TupleUpdateDto request = TupleUpdateDto.builder() .data(new HashMap<>() {{ @@ -222,12 +188,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { }}) .build(); - /* mock */ - when(metadataServiceGateway.getContainerById(CONTAINER_1_ID)) - .thenReturn(CONTAINER_1_PRIVILEGED_DTO); - when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) - .thenReturn(TABLE_1_PRIVILEGED_DTO); - /* test */ tableService.updateTuple(TABLE_1_PRIVILEGED_DTO, request); final List<Map<String, String>> result = MariaDbConfig.selectQuery(DATABASE_1_PRIVILEGED_DTO, "SELECT id, `date`, location, mintemp, rainfall FROM weather_aus WHERE id = 1", Set.of("id", "date", "location", "mintemp", "rainfall")); @@ -239,9 +199,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { } @Test - public void createTuple_succeeds() throws SQLException, RemoteUnavailableException, ContainerNotFoundException, - TableNotFoundException, TableMalformedException, QueryMalformedException, StorageUnavailableException, - StorageNotFoundException, MetadataServiceException { + public void createTuple_succeeds() throws SQLException, TableMalformedException, QueryMalformedException, + StorageUnavailableException, StorageNotFoundException { /* add row with primary key */ final TupleDto request = TupleDto.builder() .data(new HashMap<>() {{ @@ -253,12 +212,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { }}) .build(); - /* mock */ - when(metadataServiceGateway.getContainerById(CONTAINER_1_ID)) - .thenReturn(CONTAINER_1_PRIVILEGED_DTO); - when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) - .thenReturn(TABLE_1_PRIVILEGED_DTO); - /* test */ tableService.createTuple(TABLE_1_PRIVILEGED_DTO, request); final List<Map<String, String>> result = MariaDbConfig.selectQuery(DATABASE_1_PRIVILEGED_DTO, "SELECT id, `date`, location, mintemp, rainfall FROM weather_aus WHERE id = 4", Set.of("id", "date", "location", "mintemp", "rainfall")); @@ -270,9 +223,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { } @Test - public void createTuple_autogeneratedBlob_succeeds() throws SQLException, RemoteUnavailableException, ContainerNotFoundException, - TableNotFoundException, TableMalformedException, QueryMalformedException, StorageUnavailableException, - StorageNotFoundException, MetadataServiceException, IOException { + public void createTuple_autogeneratedBlob_succeeds() throws SQLException, TableMalformedException, + QueryMalformedException, StorageUnavailableException, StorageNotFoundException, IOException { /* add row with primary key */ final TupleDto request = TupleDto.builder() .data(new HashMap<>() {{ @@ -282,10 +234,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { .build(); /* mock */ - when(metadataServiceGateway.getContainerById(CONTAINER_1_ID)) - .thenReturn(CONTAINER_1_PRIVILEGED_DTO); - when(metadataServiceGateway.getTableById(DATABASE_3_ID, TABLE_8_ID)) - .thenReturn(TABLE_8_PRIVILEGED_DTO); s3Client.putObject(PutObjectRequest.builder() .key("s3key") .bucket(s3Config.getS3Bucket()) @@ -299,9 +247,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { } @Test - public void createTuple_notInOrder_succeeds() throws SQLException, RemoteUnavailableException, - ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException, - StorageUnavailableException, StorageNotFoundException, MetadataServiceException { + public void createTuple_notInOrder_succeeds() throws SQLException, TableMalformedException, QueryMalformedException, + StorageUnavailableException, StorageNotFoundException { /* add row with primary key */ final TupleDto request = TupleDto.builder() .data(new HashMap<>() {{ @@ -313,12 +260,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { }}) .build(); - /* mock */ - when(metadataServiceGateway.getContainerById(CONTAINER_1_ID)) - .thenReturn(CONTAINER_1_PRIVILEGED_DTO); - when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) - .thenReturn(TABLE_1_PRIVILEGED_DTO); - /* test */ tableService.createTuple(TABLE_1_PRIVILEGED_DTO, request); final List<Map<String, String>> result = MariaDbConfig.selectQuery(DATABASE_1_PRIVILEGED_DTO, "SELECT id, `date`, location, mintemp, rainfall FROM weather_aus WHERE id = 4", Set.of("id", "date", "location", "mintemp", "rainfall")); @@ -330,8 +271,7 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { } @Test - public void deleteTuple_succeeds() throws SQLException, RemoteUnavailableException, ContainerNotFoundException, - TableNotFoundException, TableMalformedException, QueryMalformedException, MetadataServiceException { + public void deleteTuple_succeeds() throws SQLException, TableMalformedException, QueryMalformedException { /* delete row based on primary key */ final TupleDeleteDto request = TupleDeleteDto.builder() .keys(new HashMap<>() {{ @@ -339,12 +279,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { }}) .build(); - /* mock */ - when(metadataServiceGateway.getContainerById(CONTAINER_1_ID)) - .thenReturn(CONTAINER_1_PRIVILEGED_DTO); - when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) - .thenReturn(TABLE_1_PRIVILEGED_DTO); - /* test */ tableService.deleteTuple(TABLE_1_PRIVILEGED_DTO, request); final List<Map<String, String>> result = MariaDbConfig.selectQuery(DATABASE_1_PRIVILEGED_DTO, "SELECT id FROM weather_aus WHERE id = 1", Set.of("id")); @@ -352,9 +286,8 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { } @Test - public void deleteTuple_withoutPrimaryKey_succeeds() throws SQLException, RemoteUnavailableException, - ContainerNotFoundException, TableNotFoundException, TableMalformedException, QueryMalformedException, - MetadataServiceException { + public void deleteTuple_withoutPrimaryKey_succeeds() throws SQLException, TableMalformedException, + QueryMalformedException { /* remove row based on non-primary key */ final TupleDeleteDto request = TupleDeleteDto.builder() .keys(new HashMap<>() {{ @@ -363,169 +296,12 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { }}) .build(); - /* mock */ - when(metadataServiceGateway.getContainerById(CONTAINER_1_ID)) - .thenReturn(CONTAINER_1_PRIVILEGED_DTO); - when(metadataServiceGateway.getTableById(DATABASE_1_ID, TABLE_1_ID)) - .thenReturn(TABLE_1_PRIVILEGED_DTO); - /* test */ tableService.deleteTuple(TABLE_1_PRIVILEGED_DTO, request); final List<Map<String, String>> result = MariaDbConfig.selectQuery(DATABASE_1_PRIVILEGED_DTO, "SELECT id FROM weather_aus WHERE id = 1", Set.of("id")); assertEquals(0, result.size()); } - @Test - public void getSchemas_succeeds() throws TableNotFoundException, SQLException, DatabaseMalformedException { - - /* test */ - final List<TableDto> response = tableService.getSchemas(DATABASE_1_PRIVILEGED_DTO); - assertEquals(4, response.size()); - final TableDto table0 = response.get(0); - Assertions.assertEquals("complex_foreign_keys", table0.getInternalName()); - Assertions.assertEquals("complex_foreign_keys", table0.getName()); - Assertions.assertEquals(DATABASE_1_ID, table0.getTdbid()); - assertTrue(table0.getIsVersioned()); - Assertions.assertEquals(DATABASE_1_PUBLIC, table0.getIsPublic()); - final List<ColumnDto> columns0 = table0.getColumns(); - assertNotNull(columns0); - Assertions.assertEquals(3, columns0.size()); - assertColumn(columns0.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); - assertColumn(columns0.get(1), null, null, DATABASE_1_ID, "weather_id", "weather_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); - assertColumn(columns0.get(2), null, null, DATABASE_1_ID, "other_id", "other_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); - final ConstraintsDto constraints0 = table0.getConstraints(); - assertNotNull(constraints0); - assertEquals(1, constraints0.getPrimaryKey().size()); - final PrimaryKeyDto pk0 = new LinkedList<>(constraints0.getPrimaryKey()).get(0); - assertNull(pk0.getId()); - assertNull(pk0.getColumn().getId()); - assertEquals("id", pk0.getColumn().getName()); - assertEquals("id", pk0.getColumn().getInternalName()); - assertEquals(1, constraints0.getForeignKeys().size()); - final ForeignKeyDto fk0 = constraints0.getForeignKeys().get(0); - assertNotNull(fk0.getName()); - assertNull(fk0.getTable().getId()); - assertEquals("complex_foreign_keys", fk0.getTable().getName()); - assertEquals("complex_foreign_keys", fk0.getTable().getInternalName()); - assertNull(fk0.getReferencedTable().getId()); - assertEquals("complex_primary_key", fk0.getReferencedTable().getName()); - assertEquals("complex_primary_key", fk0.getReferencedTable().getInternalName()); - assertEquals(2, fk0.getReferences().size()); - final ForeignKeyReferenceDto fk0r0 = fk0.getReferences().get(0); - assertEquals("weather_id", fk0r0.getColumn().getName()); - assertEquals("weather_id", fk0r0.getColumn().getInternalName()); - assertNotNull(fk0r0.getColumn().getName()); - assertNotNull(fk0r0.getForeignKey()); - assertEquals("id", fk0r0.getReferencedColumn().getName()); - assertEquals("id", fk0r0.getReferencedColumn().getInternalName()); - final ForeignKeyReferenceDto fk0r1 = fk0.getReferences().get(1); - assertEquals("other_id", fk0r1.getColumn().getName()); - assertEquals("other_id", fk0r1.getColumn().getInternalName()); - assertNotNull(fk0r1.getColumn().getName()); - assertNotNull(fk0r1.getForeignKey()); - assertEquals("other_id", fk0r1.getReferencedColumn().getName()); - assertEquals("other_id", fk0r1.getReferencedColumn().getInternalName()); - assertEquals(0, constraints0.getChecks().size()); - assertEquals(0, constraints0.getUniques().size()); - /* table 1 */ - final TableDto table1 = response.get(1); - Assertions.assertEquals("complex_primary_key", table1.getInternalName()); - Assertions.assertEquals("complex_primary_key", table1.getName()); - Assertions.assertEquals(DATABASE_1_ID, table1.getTdbid()); - assertTrue(table1.getIsVersioned()); - Assertions.assertEquals(DATABASE_1_PUBLIC, table1.getIsPublic()); - final List<ColumnDto> columns1 = table1.getColumns(); - assertNotNull(columns1); - Assertions.assertEquals(2, columns1.size()); - assertColumn(columns1.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); - assertColumn(columns1.get(1), null, null, DATABASE_1_ID, "other_id", "other_id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); - final ConstraintsDto constraints1 = table1.getConstraints(); - assertNotNull(constraints1); - assertEquals(2, constraints1.getPrimaryKey().size()); - final PrimaryKeyDto pk10 = new LinkedList<>(constraints1.getPrimaryKey()).get(0); - assertNull(pk10.getId()); - assertNull(pk10.getColumn().getId()); - assertEquals("id", pk10.getColumn().getName()); - assertEquals("id", pk10.getColumn().getInternalName()); - final PrimaryKeyDto pk11 = new LinkedList<>(constraints1.getPrimaryKey()).get(1); - assertNull(pk11.getId()); - assertNull(pk11.getColumn().getId()); - assertEquals("other_id", pk11.getColumn().getName()); - assertEquals("other_id", pk11.getColumn().getInternalName()); - assertEquals(0, constraints1.getForeignKeys().size()); - assertEquals(0, constraints1.getChecks().size()); - assertEquals(0, constraints1.getUniques().size()); - /* table 2 */ - final TableDto table2 = response.get(2); - Assertions.assertEquals("exotic_boolean", table2.getInternalName()); - Assertions.assertEquals("exotic_boolean", table2.getName()); - Assertions.assertEquals(DATABASE_1_ID, table2.getTdbid()); - assertTrue(table2.getIsVersioned()); - Assertions.assertEquals(DATABASE_1_PUBLIC, table2.getIsPublic()); - final List<ColumnDto> columns2 = table2.getColumns(); - assertNotNull(columns2); - Assertions.assertEquals(3, columns2.size()); - assertColumn(columns2.get(0), null, null, DATABASE_1_ID, "bool_default", "bool_default", ColumnTypeDto.BOOL, null, 0L, false, null); - assertColumn(columns2.get(1), null, null, DATABASE_1_ID, "bool_tinyint", "bool_tinyint", ColumnTypeDto.BOOL, null, 0L, false, null); - assertColumn(columns2.get(2), null, null, DATABASE_1_ID, "bool_tinyint_unsigned", "bool_tinyint_unsigned", ColumnTypeDto.BOOL, null, 0L, false, null); - final ConstraintsDto constraints2 = table2.getConstraints(); - assertNotNull(constraints2); - final Set<PrimaryKeyDto> primaryKey2 = constraints2.getPrimaryKey(); - Assertions.assertEquals(1, primaryKey2.size()); - final Set<String> checks2 = constraints2.getChecks(); - Assertions.assertEquals(0, checks2.size()); - final List<UniqueDto> uniques2 = constraints2.getUniques(); - Assertions.assertEquals(0, uniques2.size()); - /* table 3 */ - final TableDto table3 = response.get(3); - Assertions.assertEquals("not_in_metadata_db", table3.getInternalName()); - Assertions.assertEquals("not_in_metadata_db", table3.getName()); - Assertions.assertEquals(DATABASE_1_ID, table3.getTdbid()); - assertTrue(table3.getIsVersioned()); - Assertions.assertEquals(DATABASE_1_PUBLIC, table3.getIsPublic()); - final List<ColumnDto> columns3 = table3.getColumns(); - assertNotNull(columns3); - Assertions.assertEquals(5, columns3.size()); - assertColumn(columns3.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); - assertColumn(columns3.get(1), null, null, DATABASE_1_ID, "given_name", "given_name", ColumnTypeDto.VARCHAR, 255L, null, false, null); - assertColumn(columns3.get(2), null, null, DATABASE_1_ID, "middle_name", "middle_name", ColumnTypeDto.VARCHAR, 255L, null, true, null); - assertColumn(columns3.get(3), null, null, DATABASE_1_ID, "family_name", "family_name", ColumnTypeDto.VARCHAR, 255L, null, false, null); - assertColumn(columns3.get(4), null, null, DATABASE_1_ID, "age", "age", ColumnTypeDto.INT, 10L, 0L, false, null); - final ConstraintsDto constraints3 = table3.getConstraints(); - assertNotNull(constraints3); - final Set<PrimaryKeyDto> primaryKey3 = constraints3.getPrimaryKey(); - Assertions.assertEquals(1, primaryKey3.size()); - final Set<String> checks3 = constraints3.getChecks(); - Assertions.assertEquals(1, checks3.size()); - Assertions.assertEquals(Set.of("`age` > 0 and `age` < 120"), checks3); - final List<UniqueDto> uniques3 = constraints3.getUniques(); - Assertions.assertEquals(1, uniques3.size()); - Assertions.assertEquals(2, uniques3.get(0).getColumns().size()); - Assertions.assertEquals("not_in_metadata_db", uniques3.get(0).getTable().getInternalName()); - Assertions.assertEquals("given_name", uniques3.get(0).getColumns().get(0).getInternalName()); - Assertions.assertEquals("family_name", uniques3.get(0).getColumns().get(1).getInternalName()); - } - - @Test - public void create_succeeds() throws TableNotFoundException, TableMalformedException, SQLException, - TableExistsException { - - /* test */ - final TableDto response = tableService.createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_4_CREATE_INTERNAL_DTO); - assertEquals(TABLE_4_NAME, response.getName()); - assertEquals(TABLE_4_INTERNALNAME, response.getInternalName()); - final List<ColumnDto> columns = response.getColumns(); - assertEquals(TABLE_4_COLUMNS.size(), columns.size()); - assertColumn(columns.get(0), null, null, DATABASE_1_ID, "timestamp", "timestamp", ColumnTypeDto.TIMESTAMP, null, null, false, null); - assertColumn(columns.get(1), null, null, DATABASE_1_ID, "value", "value", ColumnTypeDto.DECIMAL, 10L, 10L, true, null); - final ConstraintsDto constraints = response.getConstraints(); - assertNotNull(constraints); - final Set<PrimaryKeyDto> primaryKey = constraints.getPrimaryKey(); - Assertions.assertEquals(1, primaryKey.size()); - final Set<String> checks = constraints.getChecks(); - Assertions.assertEquals(0, checks.size()); - } - @Test @Disabled("Not stable CI/CD") public void getStatistics_succeeds() throws TableMalformedException, SQLException, TableNotFoundException { @@ -556,100 +332,6 @@ public class TableServiceIntegrationTest extends AbstractUnitTest { assertNotNull(column4.getStdDev()); } - @Test - public void create_malformed_fails() { - final at.tuwien.api.database.table.internal.TableCreateDto request = TableCreateDto.builder() - .name("missing_foreign_key") - .columns(List.of()) - .constraints(ConstraintsCreateDto.builder() - .foreignKeys(List.of(ForeignKeyCreateDto.builder() - .columns(List.of("i_do_not_exist")) - .referencedTable("neither_do_i") - .referencedColumns(List.of("behold")) - .build())) - .build()) - .build(); - - /* test */ - assertThrows(TableMalformedException.class, () -> { - tableService.createTable(DATABASE_1_PRIVILEGED_DTO, request); - }); - } - - @Test - public void create_compositePrimaryKey_fails() throws TableNotFoundException, TableMalformedException, SQLException, - TableExistsException { - final at.tuwien.api.database.table.internal.TableCreateDto request = TableCreateDto.builder() - .name("composite_primary_key") - .columns(List.of(ColumnCreateDto.builder() - .name("name") - .type(ColumnTypeDto.VARCHAR) - .size(255L) - .nullAllowed(false) - .build(), - ColumnCreateDto.builder() - .name("lat") - .type(ColumnTypeDto.DECIMAL) - .size(10L) - .d(10L) - .nullAllowed(false) - .build(), - ColumnCreateDto.builder() - .name("lng") - .type(ColumnTypeDto.DECIMAL) - .size(10L) - .d(10L) - .nullAllowed(false) - .build())) - .constraints(ConstraintsCreateDto.builder() - .primaryKey(Set.of("lat", "lng")) - .foreignKeys(List.of()) - .checks(Set.of()) - .uniques(List.of()) - .build()) - .build(); - - /* test */ - final TableDto response = tableService.createTable(DATABASE_1_PRIVILEGED_DTO, request); - assertEquals("composite_primary_key", response.getName()); - assertEquals("composite_primary_key", response.getInternalName()); - final List<ColumnDto> columns = response.getColumns(); - assertEquals(3, columns.size()); - assertColumn(columns.get(0), null, null, DATABASE_1_ID, "name", "name", ColumnTypeDto.VARCHAR, 255L, null, false, null); - assertColumn(columns.get(1), null, null, DATABASE_1_ID, "lat", "lat", ColumnTypeDto.DECIMAL, 10L, 10L, false, null); - assertColumn(columns.get(2), null, null, DATABASE_1_ID, "lng", "lng", ColumnTypeDto.DECIMAL, 10L, 10L, false, null); - final ConstraintsDto constraints = response.getConstraints(); - assertNotNull(constraints); - final Set<String> checks = constraints.getChecks(); - assertNotNull(checks); - assertEquals(0, checks.size()); - final List<PrimaryKeyDto> primaryKeys = new LinkedList<>(constraints.getPrimaryKey()); - assertNotNull(primaryKeys); - assertEquals(2, primaryKeys.size()); - assertEquals("lat", primaryKeys.get(0).getColumn().getInternalName()); - assertEquals("lng", primaryKeys.get(1).getColumn().getInternalName()); - final List<ForeignKeyDto> foreignKeys = constraints.getForeignKeys(); - assertNotNull(foreignKeys); - assertEquals(0, foreignKeys.size()); - final List<UniqueDto> uniques = constraints.getUniques(); - assertNotNull(uniques); - assertEquals(0, uniques.size()); - } - - @Test - public void create_needSequence_succeeds() throws TableNotFoundException, TableMalformedException, SQLException, - TableExistsException { - - /* mock */ - MariaDbConfig.dropTable(DATABASE_1_PRIVILEGED_DTO, TABLE_1_INTERNAL_NAME); - - /* test */ - final TableDto response = tableService.createTable(DATABASE_1_PRIVILEGED_DTO, TABLE_1_CREATE_INTERNAL_DTO); - assertEquals(TABLE_1_NAME, response.getName()); - assertEquals(TABLE_1_INTERNAL_NAME, response.getInternalName()); - assertEquals(TABLE_1_COLUMNS.size(), response.getColumns().size()); - } - @Test public void delete_succeeds() throws SQLException, QueryMalformedException { diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java index b5555611c666f60f0af6e2d8a122dc11ec3264dd..2edf7f5f28a2e607ba55eb38ca82547f112a60f5 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/ViewServiceIntegrationTest.java @@ -1,12 +1,8 @@ package at.tuwien.service; -import at.tuwien.api.database.ViewColumnDto; -import at.tuwien.api.database.ViewDto; import at.tuwien.config.MariaDbConfig; import at.tuwien.config.MariaDbContainerConfig; -import at.tuwien.exception.DatabaseMalformedException; import at.tuwien.exception.ViewMalformedException; -import at.tuwien.exception.ViewNotFoundException; import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; @@ -20,9 +16,6 @@ import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import java.sql.SQLException; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; @Log4j2 @SpringBootTest @@ -41,46 +34,14 @@ public class ViewServiceIntegrationTest extends AbstractUnitTest { genesis(); /* metadata database */ MariaDbConfig.dropDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_INTERNALNAME); - MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_DTO); + MariaDbConfig.createInitDatabase(CONTAINER_1_PRIVILEGED_DTO, DATABASE_1_PRIVILEGED_DTO); } @Test public void delete_succeeds() throws SQLException, ViewMalformedException { /* test */ - viewService.delete(DATABASE_1_PRIVILEGED_DTO, VIEW_1_INTERNAL_NAME); - } - - @Test - public void create_succeeds() throws SQLException, ViewMalformedException { - - /* test */ - viewService.create(DATABASE_1_PRIVILEGED_DTO, VIEW_1_CREATE_DTO); - } - - @Test - public void getSchemas_succeeds() throws SQLException, ViewNotFoundException, DatabaseMalformedException { - - /* test */ - final List<ViewDto> response = viewService.getSchemas(DATABASE_1_PRIVILEGED_DTO); - final ViewDto view0 = response.get(0); - assertEquals("not_in_metadata_db2", view0.getName()); - assertEquals("not_in_metadata_db2", view0.getInternalName()); - assertEquals(DATABASE_1_ID, view0.getVdbid()); - assertEquals(DATABASE_1_OWNER, view0.getOwner().getId()); - assertFalse(view0.getIsInitialView()); - assertEquals(DATABASE_1_PUBLIC, view0.getIsPublic()); - assertTrue(view0.getQuery().length() >= 69); - assertNotNull(view0.getQueryHash()); - assertEquals(4, view0.getColumns().size()); - final ViewColumnDto column0a = view0.getColumns().get(0); - assertEquals("date", column0a.getInternalName()); - final ViewColumnDto column1a = view0.getColumns().get(1); - assertEquals("location", column1a.getInternalName()); - final ViewColumnDto column2a = view0.getColumns().get(2); - assertEquals("MinTemp", column2a.getInternalName()); - final ViewColumnDto column3a = view0.getColumns().get(3); - assertEquals("Rainfall", column3a.getInternalName()); + viewService.delete(VIEW_1_PRIVILEGED_DTO); } } diff --git a/dbrepo-data-service/services/pom.xml b/dbrepo-data-service/services/pom.xml index 666cda76a43da22b1993729bf9df8c58ca4d75e9..04ddee3c59536698ac1fb63cd094f93410941328 100644 --- a/dbrepo-data-service/services/pom.xml +++ b/dbrepo-data-service/services/pom.xml @@ -6,18 +6,18 @@ <parent> <groupId>at.tuwien</groupId> <artifactId>dbrepo-data-service</artifactId> - <version>1.6.1</version> + <version>1.6.3</version> </parent> <artifactId>services</artifactId> <name>dbrepo-data-service-services</name> - <version>1.6.1</version> + <version>1.6.3</version> <dependencies> <dependency> <groupId>at.tuwien</groupId> <artifactId>dbrepo-data-service-querystore</artifactId> - <version>1.6.1</version> + <version>1.6.3</version> </dependency> </dependencies> diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/config/CacheConfig.java b/dbrepo-data-service/services/src/main/java/at/tuwien/config/CacheConfig.java index 45654157d1a7564d6504e08bd6d6d5fa5d24b206..c798537b5b378822a82119b2ffcb7ec4c7bf1384 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/config/CacheConfig.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/config/CacheConfig.java @@ -1,11 +1,11 @@ package at.tuwien.config; -import at.tuwien.api.container.internal.PrivilegedContainerDto; +import at.tuwien.api.container.ContainerDto; import at.tuwien.api.database.DatabaseAccessDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.database.internal.PrivilegedViewDto; -import at.tuwien.api.database.table.internal.PrivilegedTableDto; -import at.tuwien.api.user.internal.PrivilegedUserDto; +import at.tuwien.api.database.DatabaseDto; +import at.tuwien.api.database.ViewDto; +import at.tuwien.api.database.table.TableDto; +import at.tuwien.api.user.UserDto; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import org.springframework.beans.factory.annotation.Value; @@ -22,13 +22,13 @@ public class CacheConfig { private Long credentialCacheTimeout; @Bean - public Cache<UUID, PrivilegedUserDto> userCache() { - return new ExpiryCache<UUID, PrivilegedUserDto>().build(); + public Cache<UUID, UserDto> userCache() { + return new ExpiryCache<UUID, UserDto>().build(); } @Bean - public Cache<Long, PrivilegedViewDto> viewCache() { - return new ExpiryCache<Long, PrivilegedViewDto>().build(); + public Cache<Long, ViewDto> viewCache() { + return new ExpiryCache<Long, ViewDto>().build(); } @Bean @@ -37,18 +37,18 @@ public class CacheConfig { } @Bean - public Cache<Long, PrivilegedTableDto> tableCache() { - return new ExpiryCache<Long, PrivilegedTableDto>().build(); + public Cache<Long, TableDto> tableCache() { + return new ExpiryCache<Long, TableDto>().build(); } @Bean - public Cache<Long, PrivilegedDatabaseDto> databaseCache() { - return new ExpiryCache<Long, PrivilegedDatabaseDto>().build(); + public Cache<Long, DatabaseDto> databaseCache() { + return new ExpiryCache<Long, DatabaseDto>().build(); } @Bean - public Cache<Long, PrivilegedContainerDto> containerCache() { - return new ExpiryCache<Long, PrivilegedContainerDto>().build(); + public Cache<Long, ContainerDto> containerCache() { + return new ExpiryCache<Long, ContainerDto>().build(); } class ExpiryCache<K, T> { diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/MetadataServiceGateway.java b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/MetadataServiceGateway.java index e2851071dad176ca44a9f2d0952a0392101ad2eb..f7fe2f207512791b17144cea27cedcc5f7bfd2b9 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/MetadataServiceGateway.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/MetadataServiceGateway.java @@ -1,13 +1,12 @@ package at.tuwien.gateway; -import at.tuwien.api.container.internal.PrivilegedContainerDto; +import at.tuwien.api.container.ContainerDto; import at.tuwien.api.database.DatabaseAccessDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.database.internal.PrivilegedViewDto; -import at.tuwien.api.database.table.internal.PrivilegedTableDto; +import at.tuwien.api.database.DatabaseDto; +import at.tuwien.api.database.ViewDto; +import at.tuwien.api.database.table.TableDto; import at.tuwien.api.identifier.IdentifierBriefDto; import at.tuwien.api.user.UserDto; -import at.tuwien.api.user.internal.PrivilegedUserDto; import at.tuwien.exception.*; import jakarta.validation.constraints.NotNull; @@ -20,12 +19,12 @@ public interface MetadataServiceGateway { * Get a container with given id from the metadata service. * * @param containerId The container id - * @return The container with privileged connection information, if successful. + * @return The container with connection information, if successful. * @throws ContainerNotFoundException The table was not found in the metadata service. * @throws RemoteUnavailableException The remote service is not available. * @throws MetadataServiceException The remote service returned invalid data. */ - PrivilegedContainerDto getContainerById(Long containerId) throws RemoteUnavailableException, + ContainerDto getContainerById(Long containerId) throws RemoteUnavailableException, ContainerNotFoundException, MetadataServiceException; /** @@ -37,7 +36,7 @@ public interface MetadataServiceGateway { * @throws RemoteUnavailableException The remote service is not available. * @throws MetadataServiceException The remote service returned invalid data. */ - PrivilegedDatabaseDto getDatabaseById(Long id) throws DatabaseNotFoundException, RemoteUnavailableException, + DatabaseDto getDatabaseById(Long id) throws DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException; /** @@ -50,7 +49,7 @@ public interface MetadataServiceGateway { * @throws RemoteUnavailableException The remote service is not available. * @throws MetadataServiceException The remote service returned invalid data. */ - PrivilegedTableDto getTableById(Long databaseId, Long id) throws TableNotFoundException, RemoteUnavailableException, + TableDto getTableById(Long databaseId, Long id) throws TableNotFoundException, RemoteUnavailableException, MetadataServiceException; /** @@ -63,7 +62,7 @@ public interface MetadataServiceGateway { * @throws RemoteUnavailableException The remote service is not available. * @throws MetadataServiceException The remote service returned invalid data. */ - PrivilegedViewDto getViewById(Long databaseId, Long id) throws RemoteUnavailableException, ViewNotFoundException, + ViewDto getViewById(Long databaseId, Long id) throws RemoteUnavailableException, ViewNotFoundException, MetadataServiceException; /** @@ -77,18 +76,6 @@ public interface MetadataServiceGateway { */ UserDto getUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException, MetadataServiceException; - /** - * Get a user with given user id from the metadata service. - * - * @param userId The user id. - * @return The user, if successful. - * @throws RemoteUnavailableException The remote service is not available and invalid data was returned. - * @throws UserNotFoundException The user was not found in the metadata service. - * @throws MetadataServiceException The remote service returned invalid data. - */ - PrivilegedUserDto getPrivilegedUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException, - MetadataServiceException; - /** * Get database access for a given user and database id from the metadata service. * diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/MetadataServiceGatewayImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/MetadataServiceGatewayImpl.java index 7d834992cc73b689bc990b6639061ae1ca2ddb71..7b02192b7ed0209bae55614808e5c236d03da6ef 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/MetadataServiceGatewayImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/gateway/impl/MetadataServiceGatewayImpl.java @@ -1,17 +1,12 @@ package at.tuwien.gateway.impl; import at.tuwien.api.container.ContainerDto; -import at.tuwien.api.container.image.ImageDto; -import at.tuwien.api.container.internal.PrivilegedContainerDto; import at.tuwien.api.database.DatabaseAccessDto; +import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.ViewDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.database.internal.PrivilegedViewDto; import at.tuwien.api.database.table.TableDto; -import at.tuwien.api.database.table.internal.PrivilegedTableDto; import at.tuwien.api.identifier.IdentifierBriefDto; import at.tuwien.api.user.UserDto; -import at.tuwien.api.user.internal.PrivilegedUserDto; import at.tuwien.config.GatewayConfig; import at.tuwien.exception.*; import at.tuwien.gateway.MetadataServiceGateway; @@ -36,27 +31,24 @@ import java.util.UUID; @Service public class MetadataServiceGatewayImpl implements MetadataServiceGateway { - private final RestTemplate restTemplate; private final RestTemplate internalRestTemplate; private final GatewayConfig gatewayConfig; private final MetadataMapper metadataMapper; @Autowired public MetadataServiceGatewayImpl(@Qualifier("internalRestTemplate") RestTemplate internalRestTemplate, - RestTemplate restTemplate, GatewayConfig gatewayConfig, - MetadataMapper metadataMapper) { - this.restTemplate = restTemplate; + GatewayConfig gatewayConfig, MetadataMapper metadataMapper) { this.internalRestTemplate = internalRestTemplate; this.gatewayConfig = gatewayConfig; this.metadataMapper = metadataMapper; } @Override - public PrivilegedContainerDto getContainerById(Long containerId) throws RemoteUnavailableException, + public ContainerDto getContainerById(Long containerId) throws RemoteUnavailableException, ContainerNotFoundException, MetadataServiceException { final ResponseEntity<ContainerDto> response; final String url = "/api/container/" + containerId; - log.debug("get privileged container info from metadata service: {}", url); + log.debug("get container info from metadata service: {}", url); try { response = internalRestTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, ContainerDto.class); @@ -73,16 +65,16 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway { } final List<String> expectedHeaders = List.of("X-Username", "X-Password"); if (!response.getHeaders().keySet().containsAll(expectedHeaders)) { - log.error("Failed to find all privileged container headers"); + log.error("Failed to find all container headers"); log.debug("expected headers: {}", expectedHeaders); log.debug("found headers: {}", response.getHeaders().keySet()); - throw new MetadataServiceException("Failed to find all privileged container headers"); + throw new MetadataServiceException("Failed to find all container headers"); } if (response.getBody() == null) { log.error("Failed to find container with id {}: body is empty", containerId); throw new MetadataServiceException("Failed to find container with id " + containerId + ": body is empty"); } - final PrivilegedContainerDto container = metadataMapper.containerDtoToPrivilegedContainerDto(response.getBody()); + final ContainerDto container = metadataMapper.containerDtoToContainerDto(response.getBody()); container.setUsername(response.getHeaders().get("X-Username").get(0)); container.setPassword(response.getHeaders().get("X-Password").get(0)); container.setLastRetrieved(Instant.now()); @@ -90,13 +82,13 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway { } @Override - public PrivilegedDatabaseDto getDatabaseById(Long id) throws DatabaseNotFoundException, RemoteUnavailableException, + public DatabaseDto getDatabaseById(Long id) throws DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException { - final ResponseEntity<PrivilegedDatabaseDto> response; + final ResponseEntity<DatabaseDto> response; final String url = "/api/database/" + id; - log.debug("get privileged database info from metadata service: {}", url); + log.debug("get database info from metadata service: {}", url); try { - response = internalRestTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, PrivilegedDatabaseDto.class); + response = internalRestTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, DatabaseDto.class); } catch (ResourceAccessException | HttpServerErrorException e) { log.error("Failed to find database with id {}: {}", id, e.getMessage()); throw new RemoteUnavailableException("Failed to find database: " + e.getMessage(), e); @@ -108,32 +100,30 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway { log.error("Failed to find database with id {}: service responded unsuccessful: {}", id, response.getStatusCode()); throw new MetadataServiceException("Failed to find database: service responded unsuccessful: " + response.getStatusCode()); } - final List<String> expectedHeaders = List.of("X-Username", "X-Password", "X-Host", "X-Port"); + final List<String> expectedHeaders = List.of("X-Username", "X-Password"); if (!response.getHeaders().keySet().containsAll(expectedHeaders)) { - log.error("Failed to find all privileged database headers"); + log.error("Failed to find all database headers"); log.debug("expected headers: {}", expectedHeaders); log.debug("found headers: {}", response.getHeaders().keySet()); - throw new MetadataServiceException("Failed to find all privileged database headers"); + throw new MetadataServiceException("Failed to find all database headers"); } if (response.getBody() == null) { log.error("Failed to find database with id {}: body is empty", id); throw new MetadataServiceException("Failed to find database with id " + id + ": body is empty"); } - final PrivilegedDatabaseDto database = response.getBody(); + final DatabaseDto database = response.getBody(); database.getContainer().setUsername(response.getHeaders().get("X-Username").get(0)); database.getContainer().setPassword(response.getHeaders().get("X-Password").get(0)); - database.getContainer().setHost(response.getHeaders().get("X-Host").get(0)); - database.getContainer().setPort(Integer.parseInt(response.getHeaders().get("X-Port").get(0))); database.setLastRetrieved(Instant.now()); return database; } @Override - public PrivilegedTableDto getTableById(Long databaseId, Long id) throws TableNotFoundException, + public TableDto getTableById(Long databaseId, Long id) throws TableNotFoundException, RemoteUnavailableException, MetadataServiceException { final ResponseEntity<TableDto> response; final String url = "/api/database/" + databaseId + "/table/" + id; - log.debug("get privileged table info from metadata service: {}", url); + log.debug("get table info from metadata service: {}", url); try { response = internalRestTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, TableDto.class); } catch (ResourceAccessException | HttpServerErrorException e) { @@ -147,35 +137,30 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway { log.error("Failed to find table with id {}: service responded unsuccessful: {}", id, response.getStatusCode()); throw new MetadataServiceException("Failed to find table: service responded unsuccessful: " + response.getStatusCode()); } - final List<String> expectedHeaders = List.of("X-Type", "X-Host", "X-Port", "X-Username", "X-Password", "X-Database", "X-Table"); + final List<String> expectedHeaders = List.of("X-Username", "X-Password"); if (!response.getHeaders().keySet().containsAll(expectedHeaders)) { - log.error("Failed to find all privileged table headers"); + log.error("Failed to find all table headers"); log.debug("expected headers: {}", expectedHeaders); log.debug("found headers: {}", response.getHeaders().keySet()); - throw new MetadataServiceException("Failed to find all privileged table headers"); + throw new MetadataServiceException("Failed to find all table headers"); } if (response.getBody() == null) { log.error("Failed to find table with id {}: body is empty", id); throw new MetadataServiceException("Failed to find table with id " + id + ": body is empty"); } - final PrivilegedTableDto table = metadataMapper.tableDtoToPrivilegedTableDto(response.getBody()); - table.getDatabase().getContainer().getImage().setJdbcMethod(response.getHeaders().get("X-Type").get(0)); - table.getDatabase().getContainer().setHost(response.getHeaders().get("X-Host").get(0)); - table.getDatabase().getContainer().setPort(Integer.parseInt(response.getHeaders().get("X-Port").get(0))); + final TableDto table = metadataMapper.tableDtoToTableDto(response.getBody()); table.getDatabase().getContainer().setUsername(response.getHeaders().get("X-Username").get(0)); table.getDatabase().getContainer().setPassword(response.getHeaders().get("X-Password").get(0)); - table.getDatabase().setInternalName(response.getHeaders().get("X-Database").get(0)); - table.setInternalName(response.getHeaders().get("X-Table").get(0)); table.setLastRetrieved(Instant.now()); return table; } @Override - public PrivilegedViewDto getViewById(Long databaseId, Long id) throws RemoteUnavailableException, + public ViewDto getViewById(Long databaseId, Long id) throws RemoteUnavailableException, ViewNotFoundException, MetadataServiceException { final ResponseEntity<ViewDto> response; final String url = "/api/database/" + databaseId + "/view/" + id; - log.debug("get privileged view info from metadata service: {}", url); + log.debug("get view info from metadata service: {}", url); try { response = internalRestTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, ViewDto.class); } catch (ResourceAccessException | HttpServerErrorException e) { @@ -189,31 +174,20 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway { log.error("Failed to find view with id {}: service responded unsuccessful: {}", id, response.getStatusCode()); throw new MetadataServiceException("Failed to find view: service responded unsuccessful: " + response.getStatusCode()); } - final List<String> expectedHeaders = List.of("X-Type", "X-Host", "X-Port", "X-Username", "X-Password", "X-Database", "X-View"); + final List<String> expectedHeaders = List.of("X-Username", "X-Password"); if (!response.getHeaders().keySet().containsAll(expectedHeaders)) { - log.error("Failed to find all privileged view headers"); + log.error("Failed to find all view headers"); log.debug("expected headers: {}", expectedHeaders); log.debug("found headers: {}", response.getHeaders().keySet()); - throw new MetadataServiceException("Failed to find all privileged view headers"); + throw new MetadataServiceException("Failed to find all view headers"); } if (response.getBody() == null) { log.error("Failed to find view with id {}: body is empty", id); throw new MetadataServiceException("Failed to find view with id " + id + ": body is empty"); } - final PrivilegedViewDto view = metadataMapper.viewDtoToPrivilegedViewDto(response.getBody()); - view.setDatabase(PrivilegedDatabaseDto.builder() - .internalName(response.getHeaders().get("X-Database").get(0)) - .container(PrivilegedContainerDto.builder() - .host(response.getHeaders().get("X-Host").get(0)) - .port(Integer.parseInt(response.getHeaders().get("X-Port").get(0))) - .username(response.getHeaders().get("X-Username").get(0)) - .password(response.getHeaders().get("X-Password").get(0)) - .image(ImageDto.builder() - .jdbcMethod(response.getHeaders().get("X-Type").get(0)) - .build()) - .build()) - .build()); - view.setInternalName(response.getHeaders().get("X-View").get(0)); + final ViewDto view = metadataMapper.viewDtoToViewDto(response.getBody()); + view.getDatabase().getContainer().setUsername(response.getHeaders().get("X-Username").get(0)); + view.getDatabase().getContainer().setPassword(response.getHeaders().get("X-Password").get(0)); view.setLastRetrieved(Instant.now()); return view; } @@ -223,33 +197,7 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway { MetadataServiceException { final ResponseEntity<UserDto> response; final String url = "/api/user/" + userId; - log.debug("get user info from metadata service: {}", url); - try { - response = internalRestTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, UserDto.class); - } catch (ResourceAccessException | HttpServerErrorException e) { - log.error("Failed to find user with id {}: {}", userId, e.getMessage()); - throw new RemoteUnavailableException("Failed to find user: " + e.getMessage(), e); - } catch (HttpClientErrorException.NotFound e) { - log.error("Failed to find user with id {}: not found: {}", userId, e.getMessage()); - throw new UserNotFoundException("Failed to find user: " + e.getMessage(), e); - } - if (!response.getStatusCode().equals(HttpStatus.OK)) { - log.error("Failed to find user with id {}: service responded unsuccessful: {}", userId, response.getStatusCode()); - throw new MetadataServiceException("Failed to find user: service responded unsuccessful: " + response.getStatusCode()); - } - if (response.getBody() == null) { - log.error("Failed to find user with id {}: body is empty", userId); - throw new MetadataServiceException("Failed to find user with id " + userId + ": body is empty"); - } - return response.getBody(); - } - - @Override - public PrivilegedUserDto getPrivilegedUserById(UUID userId) throws RemoteUnavailableException, UserNotFoundException, - MetadataServiceException { - final ResponseEntity<UserDto> response; - final String url = "/api/user/" + userId; - log.debug("get privileged user info from metadata service: {}", url); + log.debug("get user info from metadata service: {}", url); try { response = internalRestTemplate.exchange(url, HttpMethod.GET, HttpEntity.EMPTY, UserDto.class); } catch (ResourceAccessException | HttpServerErrorException e) { @@ -265,16 +213,16 @@ public class MetadataServiceGatewayImpl implements MetadataServiceGateway { } final List<String> expectedHeaders = List.of("X-Username", "X-Password"); if (!response.getHeaders().keySet().containsAll(expectedHeaders)) { - log.error("Failed to find all privileged user headers"); + log.error("Failed to find all user headers"); log.debug("expected headers: {}", expectedHeaders); log.debug("found headers: {}", response.getHeaders().keySet()); - throw new MetadataServiceException("Failed to find all privileged user headers"); + throw new MetadataServiceException("Failed to find all user headers"); } if (response.getBody() == null) { log.error("Failed to find user with id {}: body is empty", userId); throw new MetadataServiceException("Failed to find user with id " + userId + ": body is empty"); } - final PrivilegedUserDto user = metadataMapper.userDtoToPrivilegedUserDto(response.getBody()); + final UserDto user = metadataMapper.userDtoToUserDto(response.getBody()); user.setUsername(response.getHeaders().get("X-Username").get(0)); user.setPassword(response.getHeaders().get("X-Password").get(0)); user.setLastRetrieved(Instant.now()); diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/listener/DefaultListener.java b/dbrepo-data-service/services/src/main/java/at/tuwien/listener/DefaultListener.java index fac47a3d80f6030f5e7d4d561c4262123e9feea7..d2a66ab548d44192638801189f0bd36294f6c321 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/listener/DefaultListener.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/listener/DefaultListener.java @@ -1,8 +1,10 @@ package at.tuwien.listener; -import at.tuwien.api.database.table.internal.PrivilegedTableDto; -import at.tuwien.exception.*; -import at.tuwien.gateway.MetadataServiceGateway; +import at.tuwien.api.database.table.TableDto; +import at.tuwien.exception.MetadataServiceException; +import at.tuwien.exception.RemoteUnavailableException; +import at.tuwien.exception.TableNotFoundException; +import at.tuwien.service.CredentialService; import at.tuwien.service.QueueService; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; @@ -26,14 +28,13 @@ public class DefaultListener implements MessageListener { private final ObjectMapper objectMapper; private final QueueService queueService; - private final MetadataServiceGateway metadataServiceGateway; + private final CredentialService credentialService; @Autowired - public DefaultListener(ObjectMapper objectMapper, QueueService queueService, - MetadataServiceGateway metadataServiceGateway) { + public DefaultListener(ObjectMapper objectMapper, QueueService queueService, CredentialService credentialService) { this.objectMapper = objectMapper; this.queueService = queueService; - this.metadataServiceGateway = metadataServiceGateway; + this.credentialService = credentialService; } @Override @@ -57,7 +58,7 @@ public class DefaultListener implements MessageListener { log.trace("received message for table with id {} of database id {}: {} bytes", tableId, databaseId, message.getMessageProperties().getContentLength()); final Map<String, Object> body; try { - final PrivilegedTableDto table = metadataServiceGateway.getTableById(databaseId, tableId); + final TableDto table = credentialService.getTable(databaseId, tableId); body = objectMapper.readValue(message.getBody(), typeRef); queueService.insert(table, body); } catch (IOException e) { diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/DataMapper.java b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/DataMapper.java index 5b96a5934b83e2c4636590f7515f70c04aef5826..956d50b0dd8705d8dd3f783b2c73270d10cf2398 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/DataMapper.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/DataMapper.java @@ -99,6 +99,7 @@ public interface DataMapper { .vdbid(database.getId()) .isInitialView(false) .isPublic(database.getIsPublic()) + .isSchemaPublic(database.getIsSchemaPublic()) .query(resultSet.getString(9)) .queryHash(Hashing.sha256() .hashString(resultSet.getString(9), StandardCharsets.UTF_8) @@ -176,7 +177,6 @@ public interface DataMapper { default ViewDto resultSetToTable(ResultSet resultSet, ViewDto view, QueryConfig queryConfig) throws SQLException { final ViewColumnDto column = ViewColumnDto.builder() .ordinalPosition(resultSet.getInt(1) - 1) /* start at zero */ - .autoGenerated(resultSet.getString(2) != null && resultSet.getString(2).startsWith("nextval")) .isNullAllowed(resultSet.getString(3).equals("YES")) .columnType(ColumnTypeDto.valueOf(resultSet.getString(4).toUpperCase())) .d(resultSet.getString(7) != null ? resultSet.getLong(7) : null) @@ -256,7 +256,7 @@ public interface DataMapper { if (optional2.isPresent()) { optional2.get() .getColumns() - .add(column); + .add(columnDtoToColumnBriefDto(column)); return table; } if (type.equals("UNIQUE")) { @@ -264,7 +264,7 @@ public interface DataMapper { .getUniques() .add(UniqueDto.builder() .name(name) - .columns(new LinkedList<>(List.of(column))) + .columns(new LinkedList<>(List.of(columnDtoToColumnBriefDto(column)))) .build()); return table; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java index db848cab7ef8b59f1bfaac58aa5d7c008410732f..8be9ef68e3dff7246a061664d10273eee95d24f0 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java @@ -1,12 +1,12 @@ package at.tuwien.mapper; +import at.tuwien.api.database.table.TableDto; import at.tuwien.api.database.table.TupleDeleteDto; import at.tuwien.api.database.table.TupleDto; import at.tuwien.api.database.table.TupleUpdateDto; -import at.tuwien.api.database.table.columns.ColumnCreateDto; import at.tuwien.api.database.table.columns.ColumnDto; import at.tuwien.api.database.table.columns.ColumnTypeDto; -import at.tuwien.api.database.table.internal.PrivilegedTableDto; +import at.tuwien.api.database.table.columns.CreateTableColumnDto; import at.tuwien.exception.QueryMalformedException; import at.tuwien.exception.TableMalformedException; import at.tuwien.utils.MariaDbUtil; @@ -231,19 +231,13 @@ public interface MariaDbMapper { return statement.toString(); } - default String tableCreateDtoToSequenceName(at.tuwien.api.database.table.internal.TableCreateDto data) { - final String name = "seq_" + nameToInternalName(data.getName()) + "_id"; - log.trace("mapped table name {} to sequence name {}", data.getName(), name); - return name; - } - /** * Maps the desired data type to a MySQL string with the default MySQL 8 values for each * * @param data The column definition. * @return The MySQL string. */ - default String columnTypeDtoToDataType(ColumnCreateDto data) { + default String columnTypeDtoToDataType(CreateTableColumnDto data) { return switch (data.getType()) { case CHAR -> "CHAR(" + Objects.requireNonNullElse(data.getSize(), "1") + ")"; case VARCHAR -> "VARCHAR(" + Objects.requireNonNullElse(data.getSize(), "255") + ")"; @@ -266,7 +260,7 @@ public interface MariaDbMapper { }; } - default String columnCreateDtoToPrimaryKeyLengthSpecification(ColumnCreateDto data) { + default String columnCreateDtoToPrimaryKeyLengthSpecification(CreateTableColumnDto data) { if (EnumSet.of(ColumnTypeDto.BLOB, ColumnTypeDto.TEXT).contains(data.getType())) { return "(" + Objects.requireNonNullElse(data.getIndexLength(), 255) + ")"; } @@ -315,7 +309,7 @@ public interface MariaDbMapper { .append("` ("); log.trace("primary key column(s) exist: {}", data.getConstraints().getPrimaryKey()); final int[] idx = {0}; - for (ColumnCreateDto column : data.getColumns()) { + for (CreateTableColumnDto column : data.getColumns()) { stringBuilder.append(idx[0]++ > 0 ? ", " : "") .append("`") .append(nameToInternalName(column.getName())) @@ -342,11 +336,11 @@ public interface MariaDbMapper { .getPrimaryKey() .stream() .map(c -> { - final Optional<ColumnCreateDto> optional = data.getColumns() + final Optional<CreateTableColumnDto> optional = data.getColumns() .stream() .filter(cc -> cc.getName().equals(c)) .findFirst(); - log.trace("lookup {} in columns: {}", c, data.getColumns().stream().map(ColumnCreateDto::getName).toList()); + log.trace("lookup {} in columns: {}", c, data.getColumns().stream().map(CreateTableColumnDto::getName).toList()); return "`" + nameToInternalName(c) + "`" + columnCreateDtoToPrimaryKeyLengthSpecification(optional.get()); }) .toArray(String[]::new))) @@ -519,7 +513,7 @@ public interface MariaDbMapper { return statement.toString(); } - default String tupleToRawDeleteQuery(PrivilegedTableDto table, TupleDeleteDto data) throws TableMalformedException { + default String tupleToRawDeleteQuery(TableDto table, TupleDeleteDto data) throws TableMalformedException { log.trace("table csv to delete query, table.id={}, data.keys={}", table.getId(), data.getKeys()); if (table.getColumns().isEmpty()) { throw new TableMalformedException("Columns are not known"); @@ -540,7 +534,7 @@ public interface MariaDbMapper { return statement.toString(); } - default String tupleToRawUpdateQuery(PrivilegedTableDto table, TupleUpdateDto data) + default String tupleToRawUpdateQuery(TableDto table, TupleUpdateDto data) throws TableMalformedException { if (table.getColumns().isEmpty()) { throw new TableMalformedException("Columns are not known"); @@ -579,7 +573,7 @@ public interface MariaDbMapper { return statement.toString(); } - default String tupleToRawCreateQuery(PrivilegedTableDto table, TupleDto data) throws TableMalformedException { + default String tupleToRawCreateQuery(TableDto table, TupleDto data) throws TableMalformedException { if (table.getColumns().isEmpty()) { throw new TableMalformedException("Columns are not known"); } @@ -731,27 +725,54 @@ public interface MariaDbMapper { } } - default String selectRawSelectQuery(String query, Instant timestamp, Long page, Long size) { - query = query.toLowerCase(Locale.ROOT) - .trim(); - if (query.matches(";$")) { - /* remove last semicolon */ - query = query.substring(0, query.length() - 1); - } + default String rawSelectQuery(String query, Instant timestamp, Long page, Long size) { /* query check (this is enforced by the db also) */ final StringBuilder statement = new StringBuilder("SELECT * FROM (") - .append(query) - .append(") FOR SYSTEM_TIME AS OF TIMESTAMP '") - .append(mariaDbFormatter.format(timestamp)) - .append("' as tbl"); + .append(query); + statement.append(")"); + if (timestamp != null) { + statement.append(" FOR SYSTEM_TIME AS OF TIMESTAMP '") + .append(mariaDbFormatter.format(timestamp)) + .append("'"); + } + statement.append(" as tbl"); /* pagination */ - log.trace("pagination size/limit of {}", size); - statement.append(" LIMIT ") - .append(size); - log.trace("pagination page/offset of {}", page); - statement.append(" OFFSET ") - .append(page * size); - statement.append(";"); + if (size != null && page != null) { + log.trace("pagination size/limit of {}", size); + statement.append(" LIMIT ") + .append(size); + log.trace("pagination page/offset of {}", page); + statement.append(" OFFSET ") + .append(page * size); + } + log.trace("mapped select query: {}", statement); + return statement.toString(); + } + + default String defaultRawSelectQuery(String databaseName, String tableOrViewName, Instant timestamp, Long page, + Long size) { + /* query check (this is enforced by the db also) */ + final StringBuilder statement = new StringBuilder("SELECT * FROM (SELECT * FROM `") + .append(databaseName) + .append("`.`") + .append(tableOrViewName) + .append("`"); + if (timestamp != null) { + statement.append(" FOR SYSTEM_TIME AS OF TIMESTAMP '") + .append(mariaDbFormatter.format(timestamp)) + .append("'"); + } + statement.append(" as tbl"); + /* pagination */ + if (size != null && page != null) { + log.trace("pagination size/limit of {}", size); + statement.append(" LIMIT ") + .append(size); + log.trace("pagination page/offset of {}", page); + statement.append(" OFFSET ") + .append(page * size); + } + statement.append(") as tbl2"); log.trace("mapped select query: {}", statement); return statement.toString(); } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MetadataMapper.java b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MetadataMapper.java index 0adfafa8f96c1c63dafea3a8edd6f45230f88a3d..116737e2ed01bbcfb890174881d9abb14f5e1614 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MetadataMapper.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MetadataMapper.java @@ -2,28 +2,23 @@ package at.tuwien.mapper; import at.tuwien.api.container.ContainerDto; import at.tuwien.api.container.image.ImageDto; -import at.tuwien.api.container.internal.PrivilegedContainerDto; import at.tuwien.api.database.DatabaseBriefDto; import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.ViewColumnDto; import at.tuwien.api.database.ViewDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.database.internal.PrivilegedViewDto; import at.tuwien.api.database.query.QueryDto; import at.tuwien.api.database.table.TableBriefDto; import at.tuwien.api.database.table.TableDto; import at.tuwien.api.database.table.columns.ColumnDto; -import at.tuwien.api.database.table.internal.PrivilegedTableDto; import at.tuwien.api.identifier.IdentifierBriefDto; import at.tuwien.api.identifier.IdentifierDto; import at.tuwien.api.user.UserBriefDto; import at.tuwien.api.user.UserDto; -import at.tuwien.api.user.internal.PrivilegedUserDto; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.Mappings; -@Mapper(componentModel = "spring", imports = {PrivilegedDatabaseDto.class, PrivilegedContainerDto.class, ImageDto.class}) +@Mapper(componentModel = "spring", imports = {DatabaseDto.class, ContainerDto.class, ImageDto.class}) public interface MetadataMapper { org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MetadataMapper.class); @@ -32,28 +27,21 @@ public interface MetadataMapper { return subset.getQueryHash(); } - PrivilegedContainerDto containerDtoToPrivilegedContainerDto(ContainerDto data); + ContainerDto containerDtoToContainerDto(ContainerDto data); - DatabaseDto privilegedDatabaseDtoToDatabaseDto(PrivilegedDatabaseDto data); - - DatabaseBriefDto privilegedDatabaseDtoToDatabaseBriefDto(PrivilegedDatabaseDto data); - - TableDto privilegedTableDtoToTableDto(PrivilegedTableDto data); + DatabaseBriefDto databaseDtoToDatabaseBriefDto(DatabaseDto data); ColumnDto viewColumnDtoToColumnDto(ViewColumnDto data); ViewColumnDto columnDtoToViewColumnDto(ColumnDto data); - @Mappings({ - @Mapping(target = "database", expression = "java(PrivilegedDatabaseDto.builder().container(PrivilegedContainerDto.builder().image(new ImageDto()).build()).build())") - }) - PrivilegedTableDto tableDtoToPrivilegedTableDto(TableDto data); + TableDto tableDtoToTableDto(TableDto data); - PrivilegedViewDto viewDtoToPrivilegedViewDto(ViewDto data); + ViewDto viewDtoToViewDto(ViewDto data); - ContainerDto privilegedContainerDtoToContainerDto(PrivilegedContainerDto data); + ContainerDto ContainerDtoToContainerDto(ContainerDto data); - PrivilegedUserDto userDtoToPrivilegedUserDto(UserDto data); + UserDto userDtoToUserDto(UserDto data); UserBriefDto userDtoToUserBriefDto(UserDto data); diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/AccessService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/AccessService.java index 89707ce8f2a834ca8aee1acd7d57ac238dfe9fb9..c42fc28101ba6498e2723f4b02acca6c6d6c2a1b 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/AccessService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/AccessService.java @@ -1,8 +1,8 @@ package at.tuwien.service; import at.tuwien.api.database.AccessTypeDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.user.internal.PrivilegedUserDto; +import at.tuwien.api.database.DatabaseDto; +import at.tuwien.api.user.UserDto; import at.tuwien.exception.DatabaseMalformedException; import java.sql.SQLException; @@ -18,7 +18,7 @@ public interface AccessService { * @throws SQLException The connection to the database could not be established. * @throws DatabaseMalformedException The database schema is malformed. */ - void create(PrivilegedDatabaseDto database, PrivilegedUserDto user, AccessTypeDto access) throws SQLException, + void create(DatabaseDto database, UserDto user, AccessTypeDto access) throws SQLException, DatabaseMalformedException; /** @@ -30,7 +30,7 @@ public interface AccessService { * @throws SQLException The connection to the database could not be established. * @throws DatabaseMalformedException The database schema is malformed. */ - void update(PrivilegedDatabaseDto database, PrivilegedUserDto user, AccessTypeDto access) throws SQLException, + void update(DatabaseDto database, UserDto user, AccessTypeDto access) throws SQLException, DatabaseMalformedException; /** @@ -41,6 +41,5 @@ public interface AccessService { * @throws SQLException The connection to the database could not be established. * @throws DatabaseMalformedException The database schema is malformed. */ - void delete(PrivilegedDatabaseDto database, PrivilegedUserDto user) throws SQLException, - DatabaseMalformedException; + void delete(DatabaseDto database, UserDto user) throws SQLException, DatabaseMalformedException; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/ContainerService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/ContainerService.java new file mode 100644 index 0000000000000000000000000000000000000000..4f9e92ed7899149b518ef6018bade9818e1a4bc5 --- /dev/null +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/ContainerService.java @@ -0,0 +1,33 @@ +package at.tuwien.service; + +import at.tuwien.api.container.ContainerDto; +import at.tuwien.api.database.DatabaseDto; +import at.tuwien.api.database.internal.CreateDatabaseDto; +import at.tuwien.exception.DatabaseMalformedException; +import at.tuwien.exception.QueryStoreCreateException; + +import java.sql.SQLException; + +public interface ContainerService { + + /** + * Creates a database in the given container. + * @param container The container. + * @param data The database metadata. + * @return The created database, if successful. + * @throws SQLException The connection to the database could not be established. + * @throws DatabaseMalformedException The database schema is malformed. + */ + DatabaseDto createDatabase(ContainerDto container, CreateDatabaseDto data) throws SQLException, + DatabaseMalformedException; + + /** + * Creates the query store in the container and database. + * + * @param container The container. + * @param databaseName The database name. + * @throws SQLException The connection to the database could not be established. + * @throws QueryStoreCreateException The query store could not be created. + */ + void createQueryStore(ContainerDto container, String databaseName) throws SQLException, QueryStoreCreateException; +} diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/CredentialService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/CredentialService.java index ff09d6672fe23904181d1e7600a263b847146e0d..fe3df343dba29ca489a8559e1cc741b7cc03359c 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/CredentialService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/CredentialService.java @@ -1,11 +1,11 @@ package at.tuwien.service; -import at.tuwien.api.container.internal.PrivilegedContainerDto; +import at.tuwien.api.container.ContainerDto; import at.tuwien.api.database.DatabaseAccessDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.database.internal.PrivilegedViewDto; -import at.tuwien.api.database.table.internal.PrivilegedTableDto; -import at.tuwien.api.user.internal.PrivilegedUserDto; +import at.tuwien.api.database.DatabaseDto; +import at.tuwien.api.database.ViewDto; +import at.tuwien.api.database.table.TableDto; +import at.tuwien.api.user.UserDto; import at.tuwien.exception.*; import java.util.UUID; @@ -22,7 +22,7 @@ public interface CredentialService { * @throws RemoteUnavailableException The remote service is not available. * @throws MetadataServiceException The remote service returned invalid data. */ - PrivilegedDatabaseDto getDatabase(Long id) throws DatabaseNotFoundException, RemoteUnavailableException, + DatabaseDto getDatabase(Long id) throws DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException; /** @@ -35,7 +35,7 @@ public interface CredentialService { * @throws RemoteUnavailableException The remote service is not available. * @throws MetadataServiceException The remote service returned invalid data. */ - PrivilegedContainerDto getContainer(Long id) throws ContainerNotFoundException, RemoteUnavailableException, + ContainerDto getContainer(Long id) throws ContainerNotFoundException, RemoteUnavailableException, MetadataServiceException; /** @@ -49,7 +49,7 @@ public interface CredentialService { * @throws RemoteUnavailableException The remote service is not available. * @throws MetadataServiceException The remote service returned invalid data. */ - PrivilegedTableDto getTable(Long databaseId, Long tableId) throws RemoteUnavailableException, + TableDto getTable(Long databaseId, Long tableId) throws RemoteUnavailableException, MetadataServiceException, TableNotFoundException; /** @@ -63,7 +63,7 @@ public interface CredentialService { * @throws RemoteUnavailableException The remote service is not available. * @throws MetadataServiceException The remote service returned invalid data. */ - PrivilegedViewDto getView(Long databaseId, Long viewId) throws RemoteUnavailableException, + ViewDto getView(Long databaseId, Long viewId) throws RemoteUnavailableException, MetadataServiceException, ViewNotFoundException; /** @@ -76,7 +76,7 @@ public interface CredentialService { * @throws RemoteUnavailableException The remote service is not available. * @throws MetadataServiceException The remote service returned invalid data. */ - PrivilegedUserDto getUser(UUID id) throws RemoteUnavailableException, MetadataServiceException, + UserDto getUser(UUID id) throws RemoteUnavailableException, MetadataServiceException, UserNotFoundException; /** diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/DatabaseService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/DatabaseService.java index 271b2abb82918027053a357c648a1d2ac1926278..c325d7b33a06b9dd5d773262d79a512893b67643 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/DatabaseService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/DatabaseService.java @@ -1,27 +1,89 @@ package at.tuwien.service; -import at.tuwien.api.container.internal.PrivilegedContainerDto; +import at.tuwien.api.database.CreateViewDto; import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.internal.CreateDatabaseDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; +import at.tuwien.api.database.ViewDto; +import at.tuwien.api.database.table.TableDto; +import at.tuwien.api.database.table.internal.TableCreateDto; import at.tuwien.api.user.internal.UpdateUserPasswordDto; import at.tuwien.exception.*; import java.sql.SQLException; +import java.util.List; public interface DatabaseService { /** - * Creates a database in the given container. - * @param container The container. - * @param data The database metadata. - * @return The created database, if successful. + * Inspects the schema (columns with names, data types) of a view with given name in the given database. + * @param database The database. + * @param viewName The view name. + * @return The inspected view if successful. * @throws SQLException The connection to the database could not be established. - * @throws DatabaseMalformedException The database schema is malformed. + * @throws ViewNotFoundException The view was not found in the given database. + */ + ViewDto inspectView(DatabaseDto database, String viewName) throws SQLException, ViewNotFoundException; + + /** + * Creates a table in given data database with table definition. + * + * @param database The data database object. + * @param data The table definition. + * @return The generated table. + * @throws SQLException Query statement is malformed. + * @throws TableMalformedException The table schema is malformed. + * @throws TableExistsException The table name already exists in the information_schema. + * @throws TableNotFoundException The table could not be inspected in the metadata database. + */ + TableDto createTable(DatabaseDto database, TableCreateDto data) throws SQLException, + TableMalformedException, TableExistsException, TableNotFoundException; + + /** + * Creates a view in given data database with view definition. + * @param database The data database object. + * @param data The view definition. + * @return The generated view. + * @throws SQLException + * @throws ViewMalformedException + */ + ViewDto createView(DatabaseDto database, CreateViewDto data) throws SQLException, + ViewMalformedException; + + /** + * Gets the metadata schema for a given database. + * + * @param database The database. + * @return The list of view metadata. + * @throws SQLException The connection to the data database was unsuccessful. + * @throws DatabaseMalformedException The columns that are referenced in the views are unknown to the Metadata Database. Call {@link TableService#getSchemas(DatabaseDto)} beforehand. + * @throws ViewNotFoundException The view with given name was not found. + */ + List<ViewDto> exploreViews(DatabaseDto database) throws SQLException, DatabaseMalformedException, + ViewNotFoundException; + + /** + * Get table schemas from the information_schema in the data database. + * + * @param database The data database object. + * @return List of tables, if successful. + * @throws SQLException Failed to parse SQL query, contains invalid syntax. + * @throws TableNotFoundException The table could not be inspected in the data database. + * @throws DatabaseMalformedException The database inspection was unsuccessful, likely due to a bug in the mapping. */ - PrivilegedDatabaseDto create(PrivilegedContainerDto container, CreateDatabaseDto data) throws SQLException, + List<TableDto> exploreTables(DatabaseDto database) throws SQLException, TableNotFoundException, DatabaseMalformedException; + /** + * Inspects the schema (columns with names, data types, unique-, check-, primary- and foreign key constraints) of + * a table with given name in the given database. + * + * @param database The database. + * @param tableName The table name. + * @return The inspected table if successful. + * @throws SQLException The connection to the database could not be established. + * @throws TableNotFoundException The table was not found in the given database. + */ + TableDto inspectTable(DatabaseDto database, String tableName) throws SQLException, TableNotFoundException; + /** * Updates a user's password in a given database. * @param database The database. @@ -29,6 +91,6 @@ public interface DatabaseService { * @throws SQLException The connection to the database could not be established. * @throws DatabaseMalformedException The database schema is malformed. */ - void update(PrivilegedDatabaseDto database, UpdateUserPasswordDto data) throws SQLException, + void update(DatabaseDto database, UpdateUserPasswordDto data) throws SQLException, DatabaseMalformedException; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/QueueService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/QueueService.java index 79a23932b5aee74da800c0b41023a7257fa4d32b..6a03f5d767115314f6683ae726caaaf26538ebf9 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/QueueService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/QueueService.java @@ -1,6 +1,6 @@ package at.tuwien.service; -import at.tuwien.api.database.table.internal.PrivilegedTableDto; +import at.tuwien.api.database.table.TableDto; import java.sql.SQLException; import java.util.Map; @@ -14,5 +14,5 @@ public interface QueueService { * @param data The data. * @throws SQLException The connection to the database could not be established. */ - void insert(PrivilegedTableDto table, Map<String, Object> data) throws SQLException; + void insert(TableDto table, Map<String, Object> data) throws SQLException; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/SchemaService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/SchemaService.java deleted file mode 100644 index f5ef05b44aed27a8fb43dbd123b5096e36c2283d..0000000000000000000000000000000000000000 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/SchemaService.java +++ /dev/null @@ -1,33 +0,0 @@ -package at.tuwien.service; - -import at.tuwien.api.database.ViewDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.database.table.TableDto; -import at.tuwien.exception.*; - -import java.sql.SQLException; - -public interface SchemaService { - - /** - * Inspects the schema (columns with names, data types, unique-, check-, primary- and foreign key constraints) of - * a table with given name in the given database. - * @param database The database. - * @param tableName The table name. - * @return The inspected table if successful. - * @throws SQLException The connection to the database could not be established. - * @throws TableNotFoundException The table was not found in the given database. - */ - TableDto inspectTable(PrivilegedDatabaseDto database, String tableName) throws SQLException, - TableNotFoundException; - - /** - * Inspects the schema (columns with names, data types) of a view with given name in the given database. - * @param database The database. - * @param viewName The table name. - * @return The inspected view if successful. - * @throws SQLException The connection to the database could not be established. - * @throws ViewNotFoundException The view was not found in the given database. - */ - ViewDto inspectView(PrivilegedDatabaseDto database, String viewName) throws SQLException, ViewNotFoundException; -} diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/SubsetService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/SubsetService.java index 4a3455fbc4e10f9632148fbe12e92f4298973f9d..e2fc56002799d26e75fc05ca496cb76d330cdb07 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/SubsetService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/SubsetService.java @@ -1,7 +1,7 @@ package at.tuwien.service; -import at.tuwien.api.container.internal.PrivilegedContainerDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; +import at.tuwien.api.SortTypeDto; +import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.query.QueryDto; import at.tuwien.exception.*; import org.apache.spark.sql.Dataset; @@ -14,33 +14,6 @@ import java.util.UUID; public interface SubsetService { - /** - * Creates the query store in the container and database. - * - * @param container The container. - * @param databaseName The database name. - * @throws SQLException The connection to the database could not be established. - * @throws QueryStoreCreateException The query store could not be created. - */ - void createQueryStore(PrivilegedContainerDto container, String databaseName) throws SQLException, - QueryStoreCreateException; - - /** - * Retrieve data from a subset in a database and optionally paginate with number of page and size of results. - * - * @param database The database. - * @param subset The subset. - * @param page The page number. - * @param size Te result size. - * @return The data. - * @throws ViewMalformedException The view is malformed. - * @throws SQLException The connection to the database could not be established. - * @throws QueryMalformedException The mapped query produced a database error. - * @throws TableNotFoundException The database table is malformed. - */ - Dataset<Row> getData(PrivilegedDatabaseDto database, QueryDto subset, Long page, Long size) - throws ViewMalformedException, SQLException, QueryMalformedException, TableNotFoundException; - /** * Creates a subset from the given statement at given time in the given database. * @@ -52,7 +25,7 @@ public interface SubsetService { * @throws QueryStoreInsertException The query store refused to insert the query. * @throws SQLException The connection to the database could not be established. */ - Long create(PrivilegedDatabaseDto database, String statement, Instant timestamp, UUID userId) + Long create(DatabaseDto database, String statement, Instant timestamp, UUID userId) throws QueryStoreInsertException, SQLException; /** @@ -64,9 +37,24 @@ public interface SubsetService { * @throws TableMalformedException The table is malformed. * @throws SQLException The connection to the database could not be established. */ - Long reExecuteCount(PrivilegedDatabaseDto database, QueryDto query) throws TableMalformedException, + Long reExecuteCount(DatabaseDto database, QueryDto query) throws TableMalformedException, SQLException, QueryMalformedException; + /** + * Retrieve data from a subset in a database and optionally paginate with number of page and size of results. + * + * @param database The database. + * @param query The query statements. + * @param page The page number. + * @param size Te result size. + * @return The data. + * @throws QueryMalformedException The mapped query produced a database error. + * @throws TableNotFoundException The database table is malformed. + */ + Dataset<Row> getData(DatabaseDto database, String query, Instant timestamp, Long page, Long size, + SortTypeDto sortDirection, String sortColumn) throws QueryMalformedException, + TableNotFoundException; + /** * Finds all queries in the query store of the given database id and query id. * @@ -75,11 +63,11 @@ public interface SubsetService { * @return The list of queries. * @throws SQLException The connection to the database could not be established. * @throws QueryNotFoundException The query was not found for re-execution. - * @throws RemoteUnavailableException The privileged database information could not be found in the Metadata Service. + * @throws RemoteUnavailableException The database information could not be found in the Metadata Service. * @throws DatabaseNotFoundException The database was not found in the Metadata Service. * @throws MetadataServiceException The Metadata Service responded unexpected. */ - List<QueryDto> findAll(PrivilegedDatabaseDto database, Boolean filterPersisted) throws SQLException, + List<QueryDto> findAll(DatabaseDto database, Boolean filterPersisted) throws SQLException, QueryNotFoundException, RemoteUnavailableException, DatabaseNotFoundException, MetadataServiceException; /** @@ -93,7 +81,7 @@ public interface SubsetService { * @throws QueryMalformedException The mapped query produced a database error. * @throws TableMalformedException The database table is malformed. */ - Long executeCountNonPersistent(PrivilegedDatabaseDto database, String statement, Instant timestamp) + Long executeCountNonPersistent(DatabaseDto database, String statement, Instant timestamp) throws SQLException, QueryMalformedException, TableMalformedException; /** @@ -104,12 +92,12 @@ public interface SubsetService { * @return The query. * @throws QueryNotFoundException The query store did not return a query. * @throws SQLException The connection to the database could not be established. - * @throws RemoteUnavailableException The privileged database information could not be found in the Metadata Service. + * @throws RemoteUnavailableException The database information could not be found in the Metadata Service. * @throws UserNotFoundException The user that created the query was not found in the Metadata Service. * @throws DatabaseNotFoundException The database metadata was not found in the Metadata Service. * @throws MetadataServiceException Communication with the Metadata Service failed. */ - QueryDto findById(PrivilegedDatabaseDto database, Long queryId) throws QueryNotFoundException, SQLException, + QueryDto findById(DatabaseDto database, Long queryId) throws QueryNotFoundException, SQLException, RemoteUnavailableException, UserNotFoundException, DatabaseNotFoundException, MetadataServiceException; /** @@ -122,7 +110,7 @@ public interface SubsetService { * @throws SQLException The connection to the database could not be established. * @throws QueryStoreInsertException The query store failed to insert the query. */ - Long storeQuery(PrivilegedDatabaseDto database, String query, Instant timestamp, UUID userId) throws SQLException, + Long storeQuery(DatabaseDto database, String query, Instant timestamp, UUID userId) throws SQLException, QueryStoreInsertException; /** @@ -134,7 +122,7 @@ public interface SubsetService { * @throws SQLException The connection to the database could not be established. * @throws QueryStorePersistException The query store failed to persist/unpersist the query. */ - void persist(PrivilegedDatabaseDto database, Long queryId, Boolean persist) throws SQLException, + void persist(DatabaseDto database, Long queryId, Boolean persist) throws SQLException, QueryStorePersistException; /** @@ -144,5 +132,5 @@ public interface SubsetService { * @throws SQLException The connection to the database could not be established. * @throws QueryStoreGCException The query store failed to delete stale queries. */ - void deleteStaleQueries(PrivilegedDatabaseDto database) throws SQLException, QueryStoreGCException; + void deleteStaleQueries(DatabaseDto database) throws SQLException, QueryStoreGCException; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java index 0564639874b53e07ba5c900d85688af14552ec39..f664a82cf32050512f5eeb7d9e2b206289153568 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java @@ -1,14 +1,8 @@ package at.tuwien.service; -import at.tuwien.api.SortTypeDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; import at.tuwien.api.database.query.ImportDto; import at.tuwien.api.database.table.*; -import at.tuwien.api.database.table.internal.PrivilegedTableDto; -import at.tuwien.api.database.table.internal.TableCreateDto; import at.tuwien.exception.*; -import org.apache.spark.sql.Dataset; -import org.apache.spark.sql.Row; import java.sql.SQLException; import java.time.Instant; @@ -16,18 +10,6 @@ import java.util.List; public interface TableService { - /** - * Get table schemas from the information_schema in the data database. - * - * @param database The data database privileged object. - * @return List of tables, if successful. - * @throws SQLException Failed to parse SQL query, contains invalid syntax. - * @throws TableNotFoundException The table could not be inspected in the data database. - * @throws DatabaseMalformedException The database inspection was unsuccessful, likely due to a bug in the mapping. - */ - List<TableDto> getSchemas(PrivilegedDatabaseDto database) throws SQLException, TableNotFoundException, - DatabaseMalformedException; - /** * Generate table statistic for a given table. Only numerical columns are calculated. * @@ -37,36 +19,9 @@ public interface TableService { * @throws TableMalformedException The table statistic generation was unsuccessful, likely due to a bug in the mapping. * @throws TableNotFoundException The table could not be inspected in the data database. */ - TableStatisticDto getStatistics(PrivilegedTableDto table) throws SQLException, TableMalformedException, + TableStatisticDto getStatistics(TableDto table) throws SQLException, TableMalformedException, TableNotFoundException; - /** - * Finds a table with given data database and table name. - * - * @param database The data database. - * @param tableName The table name. - * @return The table, if successful. - * @throws TableNotFoundException The table could not be inspected in the data database. - * @throws SQLException Failed to parse SQL query, contains invalid syntax. - * @throws QueryMalformedException The inspection query is malformed. - */ - TableDto find(PrivilegedDatabaseDto database, String tableName) throws TableNotFoundException, SQLException, - QueryMalformedException; - - /** - * Creates a table in given data database with table definition. - * - * @param database The data database privileged object. - * @param data The table definition. - * @return The created table, if successful. - * @throws SQLException Query statement is malformed. - * @throws TableMalformedException The table schema is malformed. - * @throws TableExistsException The table name already exists in the information_schema. - * @throws TableNotFoundException The table could not be inspected in the metadata database. - */ - TableDto createTable(PrivilegedDatabaseDto database, TableCreateDto data) throws SQLException, - TableMalformedException, TableExistsException, TableNotFoundException; - /** * Updating table description. * @@ -76,7 +31,7 @@ public interface TableService { * @throws TableMalformedException The table schema is malformed. * @throws TableNotFoundException The table could not be inspected in the metadata database. */ - void updateTable(PrivilegedTableDto table, TableUpdateDto data) throws SQLException, + void updateTable(TableDto table, TableUpdateDto data) throws SQLException, TableMalformedException, TableNotFoundException; /** @@ -86,7 +41,7 @@ public interface TableService { * @throws SQLException Failed to parse SQL query, contains invalid syntax. * @throws QueryMalformedException The drop table query is malformed. */ - void delete(PrivilegedTableDto table) throws SQLException, QueryMalformedException; + void delete(TableDto table) throws SQLException, QueryMalformedException; /** * Obtains the table history for a given table object. @@ -97,7 +52,7 @@ public interface TableService { * @throws SQLException Failed to parse SQL query, contains invalid syntax. * @throws TableNotFoundException The table could not be found in the data database. */ - List<TableHistoryDto> history(PrivilegedTableDto table, Long size) throws SQLException, TableNotFoundException; + List<TableHistoryDto> history(TableDto table, Long size) throws SQLException, TableNotFoundException; /** * Obtains the table data tuples count at time. @@ -108,7 +63,7 @@ public interface TableService { * @throws SQLException Failed to parse SQL query, contains invalid syntax. * @throws QueryMalformedException The count query is malformed, likely due to a bug in the application. */ - Long getCount(PrivilegedTableDto table, Instant timestamp) throws SQLException, + Long getCount(TableDto table, Instant timestamp) throws SQLException, QueryMalformedException; /** @@ -123,7 +78,7 @@ public interface TableService { * @throws SQLException Failed to parse SQL query, contains invalid syntax. * @throws QueryMalformedException The import query is malformed, likely due to a bug in the application. */ - void importDataset(PrivilegedTableDto table, ImportDto data) throws MalformedException, StorageNotFoundException, + void importDataset(TableDto table, ImportDto data) throws MalformedException, StorageNotFoundException, StorageUnavailableException, SQLException, QueryMalformedException, TableMalformedException; /** @@ -135,7 +90,7 @@ public interface TableService { * @throws TableMalformedException The tuple is malformed and does not fit the table schema. * @throws QueryMalformedException The delete query is malformed, likely due to a bug in the application. */ - void deleteTuple(PrivilegedTableDto table, TupleDeleteDto data) throws SQLException, + void deleteTuple(TableDto table, TupleDeleteDto data) throws SQLException, TableMalformedException, QueryMalformedException; /** @@ -149,7 +104,7 @@ public interface TableService { * @throws StorageUnavailableException Failed to establish a connection with the Storage Service. * @throws StorageNotFoundException The storage service was not able to find the dataset for import. */ - void createTuple(PrivilegedTableDto table, TupleDto data) throws SQLException, + void createTuple(TableDto table, TupleDto data) throws SQLException, QueryMalformedException, TableMalformedException, StorageUnavailableException, StorageNotFoundException; /** @@ -161,10 +116,6 @@ public interface TableService { * @throws QueryMalformedException The update query is malformed, likely due to a bug in the application. * @throws TableMalformedException The tuple is malformed and does not fit the table schema. */ - void updateTuple(PrivilegedTableDto table, TupleUpdateDto data) throws SQLException, + void updateTuple(TableDto table, TupleUpdateDto data) throws SQLException, QueryMalformedException, TableMalformedException; - - Dataset<Row> getData(PrivilegedDatabaseDto database, String tableOrView, Instant timestamp, - Long page, Long size, SortTypeDto sortDirection, String sortColumn) - throws QueryMalformedException, TableNotFoundException; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java index ec7a723261372d1414f0590e74ef915bb62264f4..8f721f9974b0a35d5158fba0d67f9bf7a95faf70 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java @@ -1,66 +1,22 @@ package at.tuwien.service; -import at.tuwien.api.database.ViewCreateDto; import at.tuwien.api.database.ViewDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.database.internal.PrivilegedViewDto; -import at.tuwien.api.database.query.QueryDto; -import at.tuwien.exception.DatabaseMalformedException; import at.tuwien.exception.QueryMalformedException; import at.tuwien.exception.ViewMalformedException; -import at.tuwien.exception.ViewNotFoundException; import java.sql.SQLException; import java.time.Instant; -import java.util.List; public interface ViewService { - Boolean existsByName(PrivilegedDatabaseDto database, String name) throws SQLException, - QueryMalformedException; - - /** - * Gets the metadata schema for a given database. - * - * @param database The database. - * @return The list of view metadata. - * @throws SQLException The connection to the data database was unsuccessful. - * @throws DatabaseMalformedException The columns that are referenced in the views are unknown to the Metadata Database. Call {@link TableService#getSchemas(PrivilegedDatabaseDto)} beforehand. - * @throws ViewNotFoundException The view with given name was not found. - */ - List<ViewDto> getSchemas(PrivilegedDatabaseDto database) throws SQLException, DatabaseMalformedException, - ViewNotFoundException; - - /** - * Creates a view if not already exists. - * @param database - * @param subset - * @return - * @throws ViewMalformedException - * @throws SQLException - */ - ViewDto create(PrivilegedDatabaseDto database, QueryDto subset) throws ViewMalformedException, SQLException; - - /** - * Creates a view in the given data database. - * - * @param database The data database. - * @param data The view. - * @throws SQLException The connection to the data database was unsuccessful. - * @throws ViewMalformedException The query is malformed and was rejected by the data database. - */ - ViewDto create(PrivilegedDatabaseDto database, ViewCreateDto data) throws SQLException, - ViewMalformedException; - /** * Deletes a view. * - * @param database The database. - * @param viewName The view name. + * @param view The view. * @throws SQLException The connection to the data database was unsuccessful. * @throws ViewMalformedException The query is malformed and was rejected by the data database. */ - void delete(PrivilegedDatabaseDto database, String viewName) throws SQLException, ViewMalformedException; + void delete(ViewDto view) throws SQLException, ViewMalformedException; /** * Counts tuples in a view at system-versioned timestamp. @@ -71,5 +27,5 @@ public interface ViewService { * @throws SQLException The connection to the data database was unsuccessful. * @throws QueryMalformedException The query is malformed and was rejected by the data database. */ - Long count(PrivilegedViewDto view, Instant timestamp) throws SQLException, QueryMalformedException; + Long count(ViewDto view, Instant timestamp) throws SQLException, QueryMalformedException; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/AccessServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/AccessServiceMariaDbImpl.java index c50ac2f0d6bc9f298dfc0a334d524f5e15a91170..be049663b7eb0e3ff2e0f10ccee8e3ee2fc5b759 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/AccessServiceMariaDbImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/AccessServiceMariaDbImpl.java @@ -1,8 +1,8 @@ package at.tuwien.service.impl; import at.tuwien.api.database.AccessTypeDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.user.internal.PrivilegedUserDto; +import at.tuwien.api.database.DatabaseDto; +import at.tuwien.api.user.UserDto; import at.tuwien.exception.DatabaseMalformedException; import at.tuwien.mapper.MariaDbMapper; import at.tuwien.service.AccessService; @@ -17,7 +17,7 @@ import java.sql.SQLException; @Log4j2 @Service -public class AccessServiceMariaDbImpl extends HibernateConnector implements AccessService { +public class AccessServiceMariaDbImpl extends DataConnector implements AccessService { @Value("${dbrepo.grant.default.read}") private String grantDefaultRead; @@ -33,9 +33,9 @@ public class AccessServiceMariaDbImpl extends HibernateConnector implements Acce } @Override - public void create(PrivilegedDatabaseDto database, PrivilegedUserDto user, AccessTypeDto access) + public void create(DatabaseDto database, UserDto user, AccessTypeDto access) throws SQLException, DatabaseMalformedException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); + final ComboPooledDataSource dataSource = getDataSource(database); final Connection connection = dataSource.getConnection(); try { /* create user if not exists */ @@ -71,9 +71,9 @@ public class AccessServiceMariaDbImpl extends HibernateConnector implements Acce } @Override - public void update(PrivilegedDatabaseDto database, PrivilegedUserDto user, AccessTypeDto access) + public void update(DatabaseDto database, UserDto user, AccessTypeDto access) throws DatabaseMalformedException, SQLException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); + final ComboPooledDataSource dataSource = getDataSource(database); final Connection connection = dataSource.getConnection(); try { /* grant access */ @@ -96,9 +96,9 @@ public class AccessServiceMariaDbImpl extends HibernateConnector implements Acce } @Override - public void delete(PrivilegedDatabaseDto database, PrivilegedUserDto user) throws DatabaseMalformedException, + public void delete(DatabaseDto database, UserDto user) throws DatabaseMalformedException, SQLException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); + final ComboPooledDataSource dataSource = getDataSource(database); final Connection connection = dataSource.getConnection(); try { /* revoke access */ @@ -109,7 +109,7 @@ public class AccessServiceMariaDbImpl extends HibernateConnector implements Acce /* apply access rights */ start = System.currentTimeMillis(); connection.prepareStatement(mariaDbMapper.databaseFlushPrivilegesQuery()) - .execute(); + .execute(); log.trace("executed statement in {} ms", System.currentTimeMillis() - start); connection.commit(); } catch (SQLException e) { diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceMariaDbImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..aedba1aed2902b35b424832d117e200dcc02aca9 --- /dev/null +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceMariaDbImpl.java @@ -0,0 +1,103 @@ +package at.tuwien.service.impl; + +import at.tuwien.api.container.ContainerDto; +import at.tuwien.api.database.DatabaseDto; +import at.tuwien.api.database.internal.CreateDatabaseDto; +import at.tuwien.api.user.UserBriefDto; +import at.tuwien.config.RabbitConfig; +import at.tuwien.exception.DatabaseMalformedException; +import at.tuwien.exception.QueryStoreCreateException; +import at.tuwien.mapper.MariaDbMapper; +import at.tuwien.service.ContainerService; +import com.mchange.v2.c3p0.ComboPooledDataSource; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.sql.Connection; +import java.sql.SQLException; + +@Log4j2 +@Service +public class ContainerServiceMariaDbImpl extends DataConnector implements ContainerService { + + private final RabbitConfig rabbitConfig; + private final MariaDbMapper mariaDbMapper; + + @Autowired + public ContainerServiceMariaDbImpl(RabbitConfig rabbitConfig, MariaDbMapper mariaDbMapper) { + this.rabbitConfig = rabbitConfig; + this.mariaDbMapper = mariaDbMapper; + } + + @Override + public DatabaseDto createDatabase(ContainerDto container, CreateDatabaseDto data) throws SQLException, + DatabaseMalformedException { + final ComboPooledDataSource dataSource = getDataSource(container); + final Connection connection = dataSource.getConnection(); + try { + /* create database if not exists */ + final long start = System.currentTimeMillis(); + connection.prepareStatement(mariaDbMapper.databaseCreateDatabaseQuery(data.getInternalName())) + .execute(); + log.trace("executed statement in {} ms", System.currentTimeMillis() - start); + connection.commit(); + } catch (SQLException e) { + connection.rollback(); + log.error("Failed to create database access: {}", e.getMessage()); + throw new DatabaseMalformedException("Failed to create database access: " + e.getMessage(), e); + } finally { + dataSource.close(); + } + log.info("Created database with name {}", data.getInternalName()); + return DatabaseDto.builder() + .internalName(data.getInternalName()) + .exchangeName(rabbitConfig.getExchangeName()) + .owner(UserBriefDto.builder() + .id(data.getUserId()) + .build()) + .contact(UserBriefDto.builder() + .id(data.getUserId()) + .build()) + .container(container) + .build(); + } + + @Override + public void createQueryStore(ContainerDto container, String databaseName) throws SQLException, + QueryStoreCreateException { + final ComboPooledDataSource dataSource = getDataSource(container, databaseName); + final Connection connection = dataSource.getConnection(); + try { + /* create query store */ + long start = System.currentTimeMillis(); + connection.prepareStatement(mariaDbMapper.queryStoreCreateSequenceRawQuery()) + .execute(); + log.trace("executed statement in {} ms", System.currentTimeMillis() - start); + start = System.currentTimeMillis(); + connection.prepareStatement(mariaDbMapper.queryStoreCreateTableRawQuery()) + .execute(); + log.trace("executed statement in {} ms", System.currentTimeMillis() - start); + start = System.currentTimeMillis(); + connection.prepareStatement(mariaDbMapper.queryStoreCreateHashTableProcedureRawQuery()) + .execute(); + log.trace("executed statement in {} ms", System.currentTimeMillis() - start); + start = System.currentTimeMillis(); + connection.prepareStatement(mariaDbMapper.queryStoreCreateStoreQueryProcedureRawQuery()) + .execute(); + log.trace("executed statement in {} ms", System.currentTimeMillis() - start); + start = System.currentTimeMillis(); + connection.prepareStatement(mariaDbMapper.queryStoreCreateInternalStoreQueryProcedureRawQuery()) + .execute(); + log.trace("executed statement in {} ms", System.currentTimeMillis() - start); + connection.commit(); + } catch (SQLException e) { + connection.rollback(); + log.error("Failed to create query store: {}", e.getMessage()); + throw new QueryStoreCreateException("Failed to create query store: " + e.getMessage(), e); + } finally { + dataSource.close(); + } + log.info("Created query store in database with name {}", databaseName); + } +} diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/CredentialServiceImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/CredentialServiceImpl.java index 05b9e0a3feec4930111b5cdad5f839c132daaeac..fbc800bf4719bee556dc597ad593de93b8e9e0be 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/CredentialServiceImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/CredentialServiceImpl.java @@ -1,11 +1,11 @@ package at.tuwien.service.impl; -import at.tuwien.api.container.internal.PrivilegedContainerDto; +import at.tuwien.api.container.ContainerDto; import at.tuwien.api.database.DatabaseAccessDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.database.internal.PrivilegedViewDto; -import at.tuwien.api.database.table.internal.PrivilegedTableDto; -import at.tuwien.api.user.internal.PrivilegedUserDto; +import at.tuwien.api.database.DatabaseDto; +import at.tuwien.api.database.ViewDto; +import at.tuwien.api.database.table.TableDto; +import at.tuwien.api.user.UserDto; import at.tuwien.exception.*; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.service.CredentialService; @@ -21,19 +21,19 @@ import java.util.UUID; public class CredentialServiceImpl implements CredentialService { private final MetadataServiceGateway gateway; - private final Cache<UUID, PrivilegedUserDto> userCache; - private final Cache<Long, PrivilegedViewDto> viewCache; + private final Cache<UUID, UserDto> userCache; + private final Cache<Long, ViewDto> viewCache; private final Cache<Long, DatabaseAccessDto> accessCache; - private final Cache<Long, PrivilegedTableDto> tableCache; - private final Cache<Long, PrivilegedDatabaseDto> databaseCache; - private final Cache<Long, PrivilegedContainerDto> containerCache; + private final Cache<Long, TableDto> tableCache; + private final Cache<Long, DatabaseDto> databaseCache; + private final Cache<Long, ContainerDto> containerCache; @Autowired - public CredentialServiceImpl(MetadataServiceGateway gateway, Cache<UUID, PrivilegedUserDto> userCache, - Cache<Long, PrivilegedViewDto> viewCache, Cache<Long, DatabaseAccessDto> accessCache, - Cache<Long, PrivilegedTableDto> tableCache, - Cache<Long, PrivilegedDatabaseDto> databaseCache, - Cache<Long, PrivilegedContainerDto> containerCache) { + public CredentialServiceImpl(MetadataServiceGateway gateway, Cache<UUID, UserDto> userCache, + Cache<Long, ViewDto> viewCache, Cache<Long, DatabaseAccessDto> accessCache, + Cache<Long, TableDto> tableCache, + Cache<Long, DatabaseDto> databaseCache, + Cache<Long, ContainerDto> containerCache) { this.gateway = gateway; this.userCache = userCache; this.viewCache = viewCache; @@ -44,29 +44,29 @@ public class CredentialServiceImpl implements CredentialService { } @Override - public PrivilegedDatabaseDto getDatabase(Long id) throws DatabaseNotFoundException, RemoteUnavailableException, + public DatabaseDto getDatabase(Long id) throws DatabaseNotFoundException, RemoteUnavailableException, MetadataServiceException { - final PrivilegedDatabaseDto cacheDatabase = databaseCache.getIfPresent(id); + final DatabaseDto cacheDatabase = databaseCache.getIfPresent(id); if (cacheDatabase != null) { log.trace("found database with id {} in cache", id); return cacheDatabase; } log.debug("database with id {} not it cache (anymore): reload from metadata service", id); - final PrivilegedDatabaseDto database = gateway.getDatabaseById(id); + final DatabaseDto database = gateway.getDatabaseById(id); databaseCache.put(id, database); return database; } @Override - public PrivilegedTableDto getTable(Long databaseId, Long tableId) throws RemoteUnavailableException, + public TableDto getTable(Long databaseId, Long tableId) throws RemoteUnavailableException, MetadataServiceException, TableNotFoundException { - final PrivilegedTableDto cacheTable = tableCache.getIfPresent(tableId); + final TableDto cacheTable = tableCache.getIfPresent(tableId); if (cacheTable != null) { log.trace("found table with id {} in cache", tableId); return cacheTable; } log.debug("table with id {} not it cache (anymore): reload from metadata service", tableId); - final PrivilegedTableDto table = gateway.getTableById(databaseId, tableId); + final TableDto table = gateway.getTableById(databaseId, tableId); tableCache.put(tableId, table); return table; } @@ -78,43 +78,43 @@ public class CredentialServiceImpl implements CredentialService { } @Override - public PrivilegedContainerDto getContainer(Long id) throws RemoteUnavailableException, MetadataServiceException, + public ContainerDto getContainer(Long id) throws RemoteUnavailableException, MetadataServiceException, ContainerNotFoundException { - final PrivilegedContainerDto cacheContainer = containerCache.getIfPresent(id); + final ContainerDto cacheContainer = containerCache.getIfPresent(id); if (cacheContainer != null) { log.trace("found container with id {} in cache", id); return cacheContainer; } log.debug("container with id {} not it cache (anymore): reload from metadata service", id); - final PrivilegedContainerDto container = gateway.getContainerById(id); + final ContainerDto container = gateway.getContainerById(id); containerCache.put(id, container); return container; } @Override - public PrivilegedViewDto getView(Long databaseId, Long viewId) throws RemoteUnavailableException, + public ViewDto getView(Long databaseId, Long viewId) throws RemoteUnavailableException, MetadataServiceException, ViewNotFoundException { - final PrivilegedViewDto cacheView = viewCache.getIfPresent(viewId); + final ViewDto cacheView = viewCache.getIfPresent(viewId); if (cacheView != null) { log.trace("found view with id {} in cache", viewId); return cacheView; } log.debug("view with id {} not it cache (anymore): reload from metadata service", viewId); - final PrivilegedViewDto view = gateway.getViewById(databaseId, viewId); + final ViewDto view = gateway.getViewById(databaseId, viewId); viewCache.put(viewId, view); return view; } @Override - public PrivilegedUserDto getUser(UUID id) throws RemoteUnavailableException, MetadataServiceException, + public UserDto getUser(UUID id) throws RemoteUnavailableException, MetadataServiceException, UserNotFoundException { - final PrivilegedUserDto cacheUser = userCache.getIfPresent(id); + final UserDto cacheUser = userCache.getIfPresent(id); if (cacheUser != null) { log.trace("found user with id {} in cache", id); return cacheUser; } log.debug("user with id {} not it cache (anymore): reload from metadata service", id); - final PrivilegedUserDto user = gateway.getPrivilegedUserById(id); + final UserDto user = gateway.getUserById(id); userCache.put(id, user); return user; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/DataConnector.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/DataConnector.java new file mode 100644 index 0000000000000000000000000000000000000000..37a345426ae560aee202d5acbcc4d62d79f85f2b --- /dev/null +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/DataConnector.java @@ -0,0 +1,74 @@ +package at.tuwien.service.impl; + +import at.tuwien.api.container.ContainerDto; +import at.tuwien.api.database.DatabaseDto; +import at.tuwien.api.database.ViewDto; +import at.tuwien.api.database.table.TableDto; +import com.mchange.v2.c3p0.ComboPooledDataSource; +import lombok.extern.log4j.Log4j2; +import org.springframework.stereotype.Service; + +@Log4j2 +@Service +public abstract class DataConnector { + + public ComboPooledDataSource getDataSource(ContainerDto container, String databaseName) { + final ComboPooledDataSource dataSource = new ComboPooledDataSource(); + dataSource.setJdbcUrl(getJdbcUrl(container, databaseName)); + dataSource.setUser(container.getUsername()); + dataSource.setPassword(container.getPassword()); + dataSource.setInitialPoolSize(5); + dataSource.setMinPoolSize(5); + dataSource.setAcquireIncrement(5); + dataSource.setMaxPoolSize(20); + dataSource.setMaxStatements(100); + return dataSource; + } + + public ComboPooledDataSource getDataSource(ViewDto view) { + return getDataSource(view.getDatabase().getContainer(), view.getDatabase().getInternalName()); + } + + public ComboPooledDataSource getDataSource(TableDto table) { + return getDataSource(table.getDatabase().getContainer(), table.getDatabase().getInternalName()); + } + + public ComboPooledDataSource getDataSource(ContainerDto container) { + return getDataSource(container, null); + } + + public ComboPooledDataSource getDataSource(DatabaseDto database) { + return getDataSource(database.getContainer(), database.getInternalName()); + } + + public String getSparkUrl(ContainerDto container, String databaseName) { + final StringBuilder sb = new StringBuilder(getJdbcUrl(container, databaseName)) + .append("?sessionVariables=sql_mode='ANSI_QUOTES'"); + log.trace("mapped container to spark url: {}", sb.toString()); + return sb.toString(); + } + + public String getSparkUrl(TableDto table) { + return getSparkUrl(table.getDatabase().getContainer(), table.getDatabase().getInternalName()); + } + + public String getSparkUrl(DatabaseDto databaseDto) { + return getSparkUrl(databaseDto.getContainer(), databaseDto.getInternalName()); + } + + public String getJdbcUrl(ContainerDto container, String databaseName) { + final StringBuilder stringBuilder = new StringBuilder("jdbc:") + .append(container.getImage().getJdbcMethod()) + .append("://") + .append(container.getHost()) + .append(":") + .append(container.getPort()); + if (databaseName != null) { + stringBuilder.append("/") + .append(databaseName); + } + log.trace("mapped jdbc url: {}", stringBuilder); + return stringBuilder.toString(); + } + +} diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceMariaDbImpl.java index a15c22f55e9c7731de47e81d114431961114877d..4d899c99782f99813c3618dd4c051a2a2a0f2da8 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceMariaDbImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceMariaDbImpl.java @@ -1,72 +1,320 @@ package at.tuwien.service.impl; -import at.tuwien.api.container.internal.PrivilegedContainerDto; -import at.tuwien.api.database.internal.CreateDatabaseDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.user.UserBriefDto; +import at.tuwien.api.database.CreateViewDto; +import at.tuwien.api.database.DatabaseDto; +import at.tuwien.api.database.ViewDto; +import at.tuwien.api.database.table.TableDto; +import at.tuwien.api.database.table.constraints.unique.UniqueDto; +import at.tuwien.api.database.table.internal.TableCreateDto; import at.tuwien.api.user.internal.UpdateUserPasswordDto; -import at.tuwien.config.RabbitConfig; -import at.tuwien.exception.DatabaseMalformedException; +import at.tuwien.config.QueryConfig; +import at.tuwien.exception.*; +import at.tuwien.mapper.DataMapper; import at.tuwien.mapper.MariaDbMapper; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.DatabaseService; +import com.google.common.hash.Hashing; import com.mchange.v2.c3p0.ComboPooledDataSource; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.nio.charset.StandardCharsets; import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; +import java.util.LinkedList; +import java.util.List; @Log4j2 @Service -public class DatabaseServiceMariaDbImpl extends HibernateConnector implements DatabaseService { +public class DatabaseServiceMariaDbImpl extends DataConnector implements DatabaseService { - private final RabbitConfig rabbitConfig; + private final DataMapper dataMapper; + private final QueryConfig queryConfig; private final MariaDbMapper mariaDbMapper; + private final MetadataMapper metadataMapper; @Autowired - public DatabaseServiceMariaDbImpl(RabbitConfig rabbitConfig, MariaDbMapper mariaDbMapper) { - this.rabbitConfig = rabbitConfig; + public DatabaseServiceMariaDbImpl(DataMapper dataMapper, QueryConfig queryConfig, MariaDbMapper mariaDbMapper, + MetadataMapper metadataMapper) { + this.dataMapper = dataMapper; + this.queryConfig = queryConfig; this.mariaDbMapper = mariaDbMapper; + this.metadataMapper = metadataMapper; } @Override - public PrivilegedDatabaseDto create(PrivilegedContainerDto container, CreateDatabaseDto data) throws SQLException, - DatabaseMalformedException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(container, null); + public ViewDto inspectView(DatabaseDto database, String viewName) throws SQLException, ViewNotFoundException { + final ComboPooledDataSource dataSource = getDataSource(database); final Connection connection = dataSource.getConnection(); try { - /* create database if not exists */ + /* obtain only view metadata */ + long start = System.currentTimeMillis(); + final PreparedStatement statement1 = connection.prepareStatement(mariaDbMapper.databaseViewSelectRawQuery()); + statement1.setString(1, database.getInternalName()); + statement1.setString(2, viewName); + log.trace("1={}, 2={}", database.getInternalName(), viewName); + final ResultSet resultSet1 = statement1.executeQuery(); + log.trace("executed statement in {} ms", System.currentTimeMillis() - start); + if (!resultSet1.next()) { + throw new ViewNotFoundException("Failed to find view in the information schema"); + } + final ViewDto view = dataMapper.schemaResultSetToView(database, resultSet1); + view.setVdbid(database.getId()); + view.setOwner(database.getOwner()); + /* obtain view columns */ + start = System.currentTimeMillis(); + final PreparedStatement statement2 = connection.prepareStatement(mariaDbMapper.databaseTableColumnsSelectRawQuery()); + statement2.setString(1, database.getInternalName()); + statement2.setString(2, view.getInternalName()); + log.trace("1={}, 2={}", database.getInternalName(), view.getInternalName()); + final ResultSet resultSet2 = statement2.executeQuery(); + log.trace("executed statement in {} ms", System.currentTimeMillis() - start); + TableDto tmp = TableDto.builder() + .columns(new LinkedList<>()) + .build(); + while (resultSet2.next()) { + tmp = dataMapper.resultSetToTable(resultSet2, tmp); + } + view.setColumns(tmp.getColumns() + .stream() + .map(metadataMapper::columnDtoToViewColumnDto) + .toList()); + view.getColumns() + .forEach(column -> column.setDatabaseId(database.getId())); + log.debug("obtained metadata for view {}.{}", database.getInternalName(), view.getInternalName()); + return view; + } finally { + dataSource.close(); + } + } + + @Override + public TableDto createTable(DatabaseDto database, TableCreateDto data) throws SQLException, + TableMalformedException, TableExistsException, TableNotFoundException { + final String tableName = mariaDbMapper.nameToInternalName(data.getName()); + final ComboPooledDataSource dataSource = getDataSource(database); + final Connection connection = dataSource.getConnection(); + try { + /* create table if not exists */ final long start = System.currentTimeMillis(); - connection.prepareStatement(mariaDbMapper.databaseCreateDatabaseQuery(data.getInternalName())) + connection.prepareStatement(mariaDbMapper.tableCreateDtoToCreateTableRawQuery(data)) .execute(); log.trace("executed statement in {} ms", System.currentTimeMillis() - start); connection.commit(); } catch (SQLException e) { connection.rollback(); - log.error("Failed to create database access: {}", e.getMessage()); - throw new DatabaseMalformedException("Failed to create database access: " + e.getMessage(), e); + if (e.getMessage().contains("already exists")) { + log.error("Failed to create table: already exists"); + throw new TableExistsException("Failed to create table: already exists", e); + } + log.error("Failed to create table: {}", e.getMessage()); + throw new TableMalformedException("Failed to create table: " + e.getMessage(), e); } finally { dataSource.close(); } - log.info("Created database with name {}", data.getInternalName()); - return PrivilegedDatabaseDto.builder() - .internalName(data.getInternalName()) - .exchangeName(rabbitConfig.getExchangeName()) - .owner(UserBriefDto.builder() - .id(data.getUserId()) - .build()) - .contact(UserBriefDto.builder() - .id(data.getUserId()) - .build()) - .container(container) + log.info("Created table with name {}", tableName); + final TableDto table = inspectTable(database, tableName); + return table; + } + + @Override + public ViewDto createView(DatabaseDto database, CreateViewDto data) throws SQLException, + ViewMalformedException { + final ComboPooledDataSource dataSource = getDataSource(database); + final Connection connection = dataSource.getConnection(); + ViewDto view = ViewDto.builder() + .name(data.getName()) + .internalName(mariaDbMapper.nameToInternalName(data.getName())) + .query(data.getQuery()) + .queryHash(Hashing.sha256() + .hashString(data.getQuery(), StandardCharsets.UTF_8) + .toString()) + .isPublic(database.getIsPublic()) + .owner(database.getOwner()) + .identifiers(new LinkedList<>()) + .isInitialView(false) + .vdbid(database.getId()) + .columns(new LinkedList<>()) .build(); + try { + /* create view if not exists */ + final long start = System.currentTimeMillis(); + connection.prepareStatement(mariaDbMapper.viewCreateRawQuery(view.getInternalName(), data.getQuery())) + .execute(); + log.trace("executed statement in {} ms", System.currentTimeMillis() - start); + /* select view columns */ + final PreparedStatement statement2 = connection.prepareStatement(mariaDbMapper.databaseTableColumnsSelectRawQuery()); + statement2.setString(1, database.getInternalName()); + statement2.setString(2, view.getInternalName()); + final ResultSet resultSet2 = statement2.executeQuery(); + while (resultSet2.next()) { + view = dataMapper.resultSetToTable(resultSet2, view, queryConfig); + } + connection.commit(); + } catch (SQLException e) { + connection.rollback(); + log.error("Failed to create view: {}", e.getMessage()); + throw new ViewMalformedException("Failed to create view: " + e.getMessage(), e); + } finally { + dataSource.close(); + } + log.info("Created view with name {}", view.getName()); + return view; + } + + @Override + public List<ViewDto> exploreViews(DatabaseDto database) throws SQLException, DatabaseMalformedException, + ViewNotFoundException { + final ComboPooledDataSource dataSource = getDataSource(database); + final Connection connection = dataSource.getConnection(); + final List<ViewDto> views = new LinkedList<>(); + try { + /* inspect tables before views */ + final PreparedStatement statement = connection.prepareStatement(mariaDbMapper.databaseViewsSelectRawQuery()); + statement.setString(1, database.getInternalName()); + final long start = System.currentTimeMillis(); + final ResultSet resultSet1 = statement.executeQuery(); + log.trace("executed statement in {} ms", System.currentTimeMillis() - start); + while (resultSet1.next()) { + final String viewName = resultSet1.getString(1); + if (viewName.length() == 64) { + log.trace("view {}.{} seems to be a subset view (name length = 64), skip.", database.getInternalName(), viewName); + continue; + } + if (database.getViews().stream().anyMatch(v -> v.getInternalName().equals(viewName))) { + log.trace("view {}.{} already known to metadata database, skip.", database.getInternalName(), viewName); + continue; + } + if (database.getTables().stream().noneMatch(t -> t.getInternalName().equals(viewName))) { + views.add(inspectView(database, viewName)); + } + } + } catch (SQLException e) { + log.error("Failed to get view schemas: {}", e.getMessage()); + throw new DatabaseMalformedException("Failed to get view schemas: " + e.getMessage(), e); + } finally { + dataSource.close(); + } + log.info("Found {} view schema(s)", views.size()); + return views; + } + + @Override + public List<TableDto> exploreTables(DatabaseDto database) throws SQLException, TableNotFoundException, + DatabaseMalformedException { + final ComboPooledDataSource dataSource = getDataSource(database); + final Connection connection = dataSource.getConnection(); + final List<TableDto> tables = new LinkedList<>(); + try { + /* inspect tables before views */ + final long start = System.currentTimeMillis(); + final PreparedStatement statement = connection.prepareStatement(mariaDbMapper.databaseTablesSelectRawQuery()); + statement.setString(1, database.getInternalName()); + final ResultSet resultSet1 = statement.executeQuery(); + log.trace("executed statement in {} ms", System.currentTimeMillis() - start); + while (resultSet1.next()) { + final String tableName = resultSet1.getString(1); + if (database.getTables().stream().anyMatch(t -> t.getInternalName().equals(tableName))) { + log.trace("view {}.{} already known to metadata database, skip.", database.getInternalName(), tableName); + continue; + } + final TableDto table = inspectTable(database, tableName); + if (database.getTables().stream().noneMatch(t -> t.getInternalName().equals(tableName))) { + tables.add(table); + } + } + } catch (SQLException e) { + log.error("Failed to get table schemas: {}", e.getMessage()); + throw new DatabaseMalformedException("Failed to get table schemas: " + e.getMessage(), e); + } finally { + dataSource.close(); + } + log.info("Found {} table schema(s)", tables.size()); + return tables; + } + + @Override + public TableDto inspectTable(DatabaseDto database, String tableName) throws SQLException, TableNotFoundException { + log.trace("inspecting table: {}.{}", database.getInternalName(), tableName); + final ComboPooledDataSource dataSource = getDataSource(database); + final Connection connection = dataSource.getConnection(); + try { + /* obtain only table metadata */ + long start = System.currentTimeMillis(); + final PreparedStatement statement1 = connection.prepareStatement(mariaDbMapper.databaseTableSelectRawQuery()); + statement1.setString(1, database.getInternalName()); + statement1.setString(2, tableName); + log.trace("1={}, 2={}", database.getInternalName(), tableName); + TableDto table = dataMapper.schemaResultSetToTable(database, statement1.executeQuery()); + log.trace("executed statement in {} ms", System.currentTimeMillis() - start); + /* obtain columns metadata */ + start = System.currentTimeMillis(); + final PreparedStatement statement2 = connection.prepareStatement(mariaDbMapper.databaseTableColumnsSelectRawQuery()); + statement2.setString(1, database.getInternalName()); + statement2.setString(2, tableName); + log.trace("1={}, 2={}", database.getInternalName(), tableName); + final ResultSet resultSet2 = statement2.executeQuery(); + log.trace("executed statement in {} ms", System.currentTimeMillis() - start); + while (resultSet2.next()) { + table = dataMapper.resultSetToTable(resultSet2, table); + } + /* obtain check constraints metadata */ + start = System.currentTimeMillis(); + final PreparedStatement statement3 = connection.prepareStatement(mariaDbMapper.columnsCheckConstraintSelectRawQuery()); + statement3.setString(1, database.getInternalName()); + statement3.setString(2, tableName); + log.trace("1={}, 2={}", database.getInternalName(), tableName); + final ResultSet resultSet3 = statement3.executeQuery(); + log.trace("executed statement in {} ms", System.currentTimeMillis() - start); + while (resultSet3.next()) { + final String clause = resultSet3.getString(1); + table.getConstraints() + .getChecks() + .add(clause); + log.trace("found check clause: {}", clause); + } + /* obtain column constraints metadata */ + start = System.currentTimeMillis(); + final PreparedStatement statement4 = connection.prepareStatement(mariaDbMapper.databaseTableConstraintsSelectRawQuery()); + statement4.setString(1, database.getInternalName()); + statement4.setString(2, tableName); + log.trace("1={}, 2={}", database.getInternalName(), tableName); + final ResultSet resultSet4 = statement4.executeQuery(); + log.trace("executed statement in {} ms", System.currentTimeMillis() - start); + while (resultSet4.next()) { + table = dataMapper.resultSetToConstraint(resultSet4, table); + for (UniqueDto uk : table.getConstraints().getUniques()) { + uk.setTable(metadataMapper.tableDtoToTableBriefDto(table)); + final TableDto tmpTable = table; + uk.getColumns() + .forEach(column -> { + column.setTableId(tmpTable.getId()); + column.setDatabaseId(database.getId()); + }); + } + } + table.setTdbid(database.getId()); + table.setOwner(database.getOwner()); + final TableDto tmpTable = table; + tmpTable.getColumns() + .forEach(column -> { + column.setTableId(tmpTable.getId()); + column.setDatabaseId(database.getId()); + }); + log.debug("obtained metadata for table {}.{}", database.getInternalName(), tableName); + return tmpTable; + } finally { + dataSource.close(); + } } @Override - public void update(PrivilegedDatabaseDto database, UpdateUserPasswordDto data) throws SQLException, + public void update(DatabaseDto database, UpdateUserPasswordDto data) throws SQLException, DatabaseMalformedException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); + final ComboPooledDataSource dataSource = getDataSource(database); final Connection connection = dataSource.getConnection(); try { /* update user password */ diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java deleted file mode 100644 index 242cefd557cfd68ef95a0b06b5ac4efb91ed83f1..0000000000000000000000000000000000000000 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java +++ /dev/null @@ -1,53 +0,0 @@ -package at.tuwien.service.impl; - -import at.tuwien.api.container.internal.PrivilegedContainerDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import com.mchange.v2.c3p0.ComboPooledDataSource; -import lombok.extern.log4j.Log4j2; -import org.springframework.stereotype.Service; - -@Log4j2 -@Service -public abstract class HibernateConnector { - - public ComboPooledDataSource getPrivilegedDataSource(PrivilegedContainerDto container, String databaseName) { - final long start = System.currentTimeMillis(); - final ComboPooledDataSource dataSource = new ComboPooledDataSource(); - dataSource.setJdbcUrl(url(container, databaseName)); - dataSource.setUser(container.getUsername()); - dataSource.setPassword(container.getPassword()); - dataSource.setInitialPoolSize(5); - dataSource.setMinPoolSize(5); - dataSource.setAcquireIncrement(5); - dataSource.setMaxPoolSize(20); - dataSource.setMaxStatements(100); - log.trace("created pooled data source {} in {} ms, user={}", url(container, databaseName), System.currentTimeMillis() - start, container.getUsername()); - return dataSource; - } - - public ComboPooledDataSource getPrivilegedDataSource(PrivilegedDatabaseDto database) { - return getPrivilegedDataSource(database.getContainer(), database.getInternalName()); - } - - public String getSparkUrl(PrivilegedContainerDto container, String databaseName) { - final StringBuilder sb = new StringBuilder(url(container, databaseName)) - .append("?sessionVariables=sql_mode='ANSI_QUOTES'"); - log.trace("mapped container to spark url: {}", sb.toString()); - return sb.toString(); - } - - private String url(PrivilegedContainerDto container, String databaseName) { - final StringBuilder stringBuilder = new StringBuilder("jdbc:") - .append(container.getImage().getJdbcMethod()) - .append("://") - .append(container.getHost()) - .append(":") - .append(container.getPort()); - if (databaseName != null) { - stringBuilder.append("/") - .append(databaseName); - } - return stringBuilder.toString(); - } - -} diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/QueueServiceRabbitMqImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/QueueServiceRabbitMqImpl.java index d5127e050e521b69e5130c4af836680ffaae013d..4db29335fbfc4cbdbb8086a2009cb588613d1969 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/QueueServiceRabbitMqImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/QueueServiceRabbitMqImpl.java @@ -1,7 +1,7 @@ package at.tuwien.service.impl; +import at.tuwien.api.database.table.TableDto; import at.tuwien.api.database.table.columns.ColumnDto; -import at.tuwien.api.database.table.internal.PrivilegedTableDto; import at.tuwien.mapper.DataMapper; import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.QueueService; @@ -18,7 +18,7 @@ import java.util.Optional; @Log4j2 @Service -public class QueueServiceRabbitMqImpl extends HibernateConnector implements QueueService { +public class QueueServiceRabbitMqImpl extends DataConnector implements QueueService { private final DataMapper dataMapper; private final MetadataMapper metadataMapper; @@ -30,13 +30,13 @@ public class QueueServiceRabbitMqImpl extends HibernateConnector implements Queu } @Override - public void insert(PrivilegedTableDto table, Map<String, Object> data) throws SQLException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase()); + public void insert(TableDto table, Map<String, Object> data) throws SQLException { + final ComboPooledDataSource dataSource = getDataSource(table); final Connection connection = dataSource.getConnection(); try { final int[] idx = new int[]{1}; final PreparedStatement preparedStatement = connection.prepareStatement( - dataMapper.rabbitMqTupleToInsertOrUpdateQuery(metadataMapper.privilegedTableDtoToTableDto(table), data)); + dataMapper.rabbitMqTupleToInsertOrUpdateQuery(metadataMapper.tableDtoToTableDto(table), data)); for (Map.Entry<String, Object> entry : data.entrySet()) { final Optional<ColumnDto> optional = table.getColumns().stream().filter(c -> c.getInternalName().equals(entry.getKey())).findFirst(); if (optional.isEmpty()) { diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SchemaServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SchemaServiceMariaDbImpl.java deleted file mode 100644 index e2b0c984e0f53c68bf9d384a301ab62ad67bbff7..0000000000000000000000000000000000000000 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SchemaServiceMariaDbImpl.java +++ /dev/null @@ -1,164 +0,0 @@ -package at.tuwien.service.impl; - -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.ViewDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.database.table.TableDto; -import at.tuwien.api.database.table.constraints.unique.UniqueDto; -import at.tuwien.exception.TableNotFoundException; -import at.tuwien.exception.ViewNotFoundException; -import at.tuwien.mapper.DataMapper; -import at.tuwien.mapper.MariaDbMapper; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.service.SchemaService; -import com.mchange.v2.c3p0.ComboPooledDataSource; -import lombok.extern.log4j.Log4j2; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.LinkedList; - -@Log4j2 -@Service -public class SchemaServiceMariaDbImpl extends HibernateConnector implements SchemaService { - - private final DataMapper dataMapper; - private final MariaDbMapper mariaDbMapper; - private final MetadataMapper metadataMapper; - - @Autowired - public SchemaServiceMariaDbImpl(DataMapper dataMapper, MariaDbMapper mariaDbMapper, MetadataMapper metadataMapper) { - this.dataMapper = dataMapper; - this.mariaDbMapper = mariaDbMapper; - this.metadataMapper = metadataMapper; - } - - @Override - public TableDto inspectTable(PrivilegedDatabaseDto database, String tableName) throws SQLException, - TableNotFoundException { - log.trace("inspecting table: {}.{}", database.getInternalName(), tableName); - final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); - final Connection connection = dataSource.getConnection(); - try { - /* obtain only table metadata */ - long start = System.currentTimeMillis(); - final PreparedStatement statement1 = connection.prepareStatement(mariaDbMapper.databaseTableSelectRawQuery()); - statement1.setString(1, database.getInternalName()); - statement1.setString(2, tableName); - log.trace("1={}, 2={}", database.getInternalName(), tableName); - TableDto table = dataMapper.schemaResultSetToTable(metadataMapper.privilegedDatabaseDtoToDatabaseDto(database), statement1.executeQuery()); - log.trace("executed statement in {} ms", System.currentTimeMillis() - start); - /* obtain columns metadata */ - start = System.currentTimeMillis(); - final PreparedStatement statement2 = connection.prepareStatement(mariaDbMapper.databaseTableColumnsSelectRawQuery()); - statement2.setString(1, database.getInternalName()); - statement2.setString(2, tableName); - log.trace("1={}, 2={}", database.getInternalName(), tableName); - final ResultSet resultSet2 = statement2.executeQuery(); - log.trace("executed statement in {} ms", System.currentTimeMillis() - start); - while (resultSet2.next()) { - table = dataMapper.resultSetToTable(resultSet2, table); - } - /* obtain check constraints metadata */ - start = System.currentTimeMillis(); - final PreparedStatement statement3 = connection.prepareStatement(mariaDbMapper.columnsCheckConstraintSelectRawQuery()); - statement3.setString(1, database.getInternalName()); - statement3.setString(2, tableName); - log.trace("1={}, 2={}", database.getInternalName(), tableName); - final ResultSet resultSet3 = statement3.executeQuery(); - log.trace("executed statement in {} ms", System.currentTimeMillis() - start); - while (resultSet3.next()) { - final String clause = resultSet3.getString(1); - table.getConstraints() - .getChecks() - .add(clause); - log.trace("found check clause: {}", clause); - } - /* obtain column constraints metadata */ - start = System.currentTimeMillis(); - final PreparedStatement statement4 = connection.prepareStatement(mariaDbMapper.databaseTableConstraintsSelectRawQuery()); - statement4.setString(1, database.getInternalName()); - statement4.setString(2, tableName); - log.trace("1={}, 2={}", database.getInternalName(), tableName); - final ResultSet resultSet4 = statement4.executeQuery(); - log.trace("executed statement in {} ms", System.currentTimeMillis() - start); - while (resultSet4.next()) { - table = dataMapper.resultSetToConstraint(resultSet4, table); - for (UniqueDto uk : table.getConstraints().getUniques()) { - uk.setTable(metadataMapper.tableDtoToTableBriefDto(table)); - final TableDto tmpTable = table; - uk.getColumns() - .forEach(column -> { - column.setTableId(tmpTable.getId()); - column.setDatabaseId(database.getId()); - }); - } - } - table.setTdbid(database.getId()); - table.setOwner(database.getOwner()); - final TableDto tmpTable = table; - tmpTable.getColumns() - .forEach(column -> { - column.setTableId(tmpTable.getId()); - column.setDatabaseId(database.getId()); - }); - log.debug("obtained metadata for table {}.{}", database.getInternalName(), tableName); - return tmpTable; - } finally { - dataSource.close(); - } - } - - @Override - public ViewDto inspectView(PrivilegedDatabaseDto privilegedDatabase, String viewName) throws SQLException, - ViewNotFoundException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(privilegedDatabase); - final Connection connection = dataSource.getConnection(); - final DatabaseDto database = metadataMapper.privilegedDatabaseDtoToDatabaseDto(privilegedDatabase); - try { - /* obtain only view metadata */ - long start = System.currentTimeMillis(); - final PreparedStatement statement1 = connection.prepareStatement(mariaDbMapper.databaseViewSelectRawQuery()); - statement1.setString(1, database.getInternalName()); - statement1.setString(2, viewName); - log.trace("1={}, 2={}", database.getInternalName(), viewName); - final ResultSet resultSet1 = statement1.executeQuery(); - log.trace("executed statement in {} ms", System.currentTimeMillis() - start); - if (!resultSet1.next()) { - throw new ViewNotFoundException("Failed to find view in the information schema"); - } - ViewDto view = dataMapper.schemaResultSetToView(database, resultSet1); - view.setVdbid(database.getId()); - view.setOwner(database.getOwner()); - /* obtain view columns */ - start = System.currentTimeMillis(); - final PreparedStatement statement2 = connection.prepareStatement(mariaDbMapper.databaseTableColumnsSelectRawQuery()); - statement2.setString(1, database.getInternalName()); - statement2.setString(2, viewName); - log.trace("1={}, 2={}", database.getInternalName(), viewName); - final ResultSet resultSet2 = statement2.executeQuery(); - log.trace("executed statement in {} ms", System.currentTimeMillis() - start); - TableDto tmp = TableDto.builder() - .columns(new LinkedList<>()) - .build(); - while (resultSet2.next()) { - tmp = dataMapper.resultSetToTable(resultSet2, tmp); - } - view.setColumns(tmp.getColumns() - .stream() - .map(metadataMapper::columnDtoToViewColumnDto) - .toList()); - view.getColumns() - .forEach(column -> column.setDatabaseId(database.getId())); - log.debug("obtained metadata for view {}.{}", database.getInternalName(), viewName); - return view; - } finally { - dataSource.close(); - } - } - -} diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SubsetServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SubsetServiceMariaDbImpl.java index fb244bb30113ab90f4f2209bf4e80b5d11cd9185..bdfdb14838a608ce87b40a94faebe52a27546a63 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SubsetServiceMariaDbImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/SubsetServiceMariaDbImpl.java @@ -1,7 +1,7 @@ package at.tuwien.service.impl; -import at.tuwien.api.container.internal.PrivilegedContainerDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; +import at.tuwien.api.SortTypeDto; +import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.query.QueryDto; import at.tuwien.api.identifier.IdentifierBriefDto; import at.tuwien.api.identifier.IdentifierTypeDto; @@ -9,14 +9,13 @@ import at.tuwien.exception.*; import at.tuwien.gateway.MetadataServiceGateway; import at.tuwien.mapper.DataMapper; import at.tuwien.mapper.MariaDbMapper; -import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.SubsetService; -import at.tuwien.service.TableService; -import at.tuwien.service.ViewService; import com.mchange.v2.c3p0.ComboPooledDataSource; import lombok.extern.log4j.Log4j2; import org.apache.spark.sql.Dataset; import org.apache.spark.sql.Row; +import org.apache.spark.sql.SparkSession; +import org.apache.spark.sql.catalyst.ExtendedAnalysisException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -28,95 +27,63 @@ import java.util.UUID; @Log4j2 @Service -public class SubsetServiceMariaDbImpl extends HibernateConnector implements SubsetService { +public class SubsetServiceMariaDbImpl extends DataConnector implements SubsetService { private final DataMapper dataMapper; - private final ViewService viewService; - private final TableService tableService; + private final SparkSession sparkSession; private final MariaDbMapper mariaDbMapper; - private final MetadataMapper metadataMapper; private final MetadataServiceGateway metadataServiceGateway; @Autowired - public SubsetServiceMariaDbImpl(DataMapper dataMapper, ViewService viewService, TableService tableService, - MariaDbMapper mariaDbMapper, MetadataMapper metadataMapper, + public SubsetServiceMariaDbImpl(DataMapper dataMapper, MariaDbMapper mariaDbMapper, SparkSession sparkSession, MetadataServiceGateway metadataServiceGateway) { this.dataMapper = dataMapper; - this.viewService = viewService; - this.tableService = tableService; + this.sparkSession = sparkSession; this.mariaDbMapper = mariaDbMapper; - this.metadataMapper = metadataMapper; this.metadataServiceGateway = metadataServiceGateway; } @Override - public void createQueryStore(PrivilegedContainerDto container, String databaseName) throws SQLException, - QueryStoreCreateException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(container, databaseName); - final Connection connection = dataSource.getConnection(); + public Dataset<Row> getData(DatabaseDto database, String query, Instant timestamp, Long page, Long size, + SortTypeDto sortDirection, String sortColumn) + throws QueryMalformedException, TableNotFoundException { try { - /* create query store */ - long start = System.currentTimeMillis(); - connection.prepareStatement(mariaDbMapper.queryStoreCreateSequenceRawQuery()) - .execute(); - log.trace("executed statement in {} ms", System.currentTimeMillis() - start); - start = System.currentTimeMillis(); - connection.prepareStatement(mariaDbMapper.queryStoreCreateTableRawQuery()) - .execute(); - log.trace("executed statement in {} ms", System.currentTimeMillis() - start); - start = System.currentTimeMillis(); - connection.prepareStatement(mariaDbMapper.queryStoreCreateHashTableProcedureRawQuery()) - .execute(); - log.trace("executed statement in {} ms", System.currentTimeMillis() - start); - start = System.currentTimeMillis(); - connection.prepareStatement(mariaDbMapper.queryStoreCreateStoreQueryProcedureRawQuery()) - .execute(); - log.trace("executed statement in {} ms", System.currentTimeMillis() - start); - start = System.currentTimeMillis(); - connection.prepareStatement(mariaDbMapper.queryStoreCreateInternalStoreQueryProcedureRawQuery()) - .execute(); - log.trace("executed statement in {} ms", System.currentTimeMillis() - start); - connection.commit(); - } catch (SQLException e) { - connection.rollback(); - log.error("Failed to create query store: {}", e.getMessage()); - throw new QueryStoreCreateException("Failed to create query store: " + e.getMessage(), e); - } finally { - dataSource.close(); - } - log.info("Created query store in database with name {}", databaseName); - } - - @Override - public Dataset<Row> getData(PrivilegedDatabaseDto database, QueryDto subset, Long page, Long size) - throws ViewMalformedException, SQLException, QueryMalformedException, TableNotFoundException { - final String viewName = metadataMapper.queryDtoToViewName(subset); - if (!viewService.existsByName(database, viewName)) { - log.warn("Missing internal view {} for subset with id {}: create it from subset query", viewName, subset.getId()); - viewService.create(database, subset); - } else { - log.debug("internal view {}.{} for subset with id {} exists", database.getInternalName(), viewName, subset.getId()); + return sparkSession.read() + .format("jdbc") + .option("user", database.getContainer().getUsername()) + .option("password", database.getContainer().getPassword()) + .option("url", getSparkUrl(database)) + .option("query", query) + .load(); + } catch (Exception e) { + if (e instanceof ExtendedAnalysisException exception) { + if (exception.getSimpleMessage().contains("TABLE_OR_VIEW_NOT_FOUND")) { + log.error("Failed to find named reference: {}", exception.getSimpleMessage()); + throw new TableNotFoundException("Failed to find named reference: " + exception.getSimpleMessage()) /* remove throwable on purpose, clutters the output */; + } + } + log.error("Malformed query: {}", e.getMessage()); + throw new QueryMalformedException("Malformed query: " + e.getMessage(), e); } - return tableService.getData(database, viewName, subset.getExecution(), page, size, null, null); } @Override - public Long create(PrivilegedDatabaseDto database, String statement, Instant timestamp, UUID userId) + public Long create(DatabaseDto database, String statement, Instant timestamp, UUID userId) throws QueryStoreInsertException, SQLException { return storeQuery(database, statement, timestamp, userId); } @Override - public Long reExecuteCount(PrivilegedDatabaseDto database, QueryDto query) throws TableMalformedException, + public Long reExecuteCount(DatabaseDto database, QueryDto query) throws TableMalformedException, SQLException, QueryMalformedException { return executeCountNonPersistent(database, query.getQuery(), query.getExecution()); } @Override - public List<QueryDto> findAll(PrivilegedDatabaseDto database, Boolean filterPersisted) throws SQLException, + public List<QueryDto> findAll(DatabaseDto database, Boolean filterPersisted) throws SQLException, QueryNotFoundException, RemoteUnavailableException, DatabaseNotFoundException, MetadataServiceException { final List<IdentifierBriefDto> identifiers = metadataServiceGateway.getIdentifiers(database.getId(), null); - final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); + final ComboPooledDataSource dataSource = getDataSource(database); final Connection connection = dataSource.getConnection(); try { final long start = System.currentTimeMillis(); @@ -147,9 +114,9 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs } @Override - public Long executeCountNonPersistent(PrivilegedDatabaseDto database, String statement, Instant timestamp) + public Long executeCountNonPersistent(DatabaseDto database, String statement, Instant timestamp) throws SQLException, QueryMalformedException, TableMalformedException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); + final ComboPooledDataSource dataSource = getDataSource(database); final Connection connection = dataSource.getConnection(); try { final long start = System.currentTimeMillis(); @@ -166,9 +133,9 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs } @Override - public QueryDto findById(PrivilegedDatabaseDto database, Long queryId) throws QueryNotFoundException, SQLException, + public QueryDto findById(DatabaseDto database, Long queryId) throws QueryNotFoundException, SQLException, RemoteUnavailableException, DatabaseNotFoundException, MetadataServiceException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); + final ComboPooledDataSource dataSource = getDataSource(database); final Connection connection = dataSource.getConnection(); try { final long start = System.currentTimeMillis(); @@ -193,11 +160,11 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs } @Override - public Long storeQuery(PrivilegedDatabaseDto database, String query, Instant timestamp, UUID userId) throws SQLException, + public Long storeQuery(DatabaseDto database, String query, Instant timestamp, UUID userId) throws SQLException, QueryStoreInsertException { /* save */ final Long queryId; - final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); + final ComboPooledDataSource dataSource = getDataSource(database); final Connection connection = dataSource.getConnection(); try { /* insert query into query store */ @@ -228,9 +195,9 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs } @Override - public void persist(PrivilegedDatabaseDto database, Long queryId, Boolean persist) throws SQLException, + public void persist(DatabaseDto database, Long queryId, Boolean persist) throws SQLException, QueryStorePersistException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); + final ComboPooledDataSource dataSource = getDataSource(database); final Connection connection = dataSource.getConnection(); try { /* update query */ @@ -250,8 +217,8 @@ public class SubsetServiceMariaDbImpl extends HibernateConnector implements Subs } @Override - public void deleteStaleQueries(PrivilegedDatabaseDto database) throws SQLException, QueryStoreGCException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); + public void deleteStaleQueries(DatabaseDto database) throws SQLException, QueryStoreGCException { + final ComboPooledDataSource dataSource = getDataSource(database); final Connection connection = dataSource.getConnection(); try { final long start = System.currentTimeMillis(); diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java index c34f057e0129bd1c65277648adf3b5985952235c..466f7539fd250666962d08a75ffffd5aa61480fa 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/TableServiceMariaDbImpl.java @@ -1,25 +1,23 @@ package at.tuwien.service.impl; -import at.tuwien.api.SortTypeDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; import at.tuwien.api.database.query.ImportDto; import at.tuwien.api.database.table.*; import at.tuwien.api.database.table.columns.ColumnDto; import at.tuwien.api.database.table.columns.ColumnStatisticDto; import at.tuwien.api.database.table.columns.ColumnTypeDto; -import at.tuwien.api.database.table.internal.PrivilegedTableDto; -import at.tuwien.api.database.table.internal.TableCreateDto; import at.tuwien.exception.*; import at.tuwien.mapper.DataMapper; import at.tuwien.mapper.MariaDbMapper; -import at.tuwien.service.SchemaService; +import at.tuwien.service.DatabaseService; import at.tuwien.service.StorageService; import at.tuwien.service.TableService; import at.tuwien.utils.MariaDbUtil; import com.mchange.v2.c3p0.ComboPooledDataSource; import lombok.extern.log4j.Log4j2; -import org.apache.spark.sql.*; -import org.apache.spark.sql.catalyst.ExtendedAnalysisException; +import org.apache.spark.sql.AnalysisException; +import org.apache.spark.sql.Dataset; +import org.apache.spark.sql.Row; +import org.apache.spark.sql.SaveMode; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -28,66 +26,33 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.time.Instant; -import java.util.*; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; @Log4j2 @Service -public class TableServiceMariaDbImpl extends HibernateConnector implements TableService { +public class TableServiceMariaDbImpl extends DataConnector implements TableService { private final DataMapper dataMapper; - private final SparkSession sparkSession; private final MariaDbMapper mariaDbMapper; - private final SchemaService schemaService; private final StorageService storageService; + private final DatabaseService databaseService; @Autowired - public TableServiceMariaDbImpl(DataMapper dataMapper, SparkSession sparkSession, MariaDbMapper mariaDbMapper, - SchemaService schemaService, StorageService storageService) { + public TableServiceMariaDbImpl(DataMapper dataMapper, MariaDbMapper mariaDbMapper, StorageService storageService, + DatabaseService databaseService) { this.dataMapper = dataMapper; - this.sparkSession = sparkSession; this.mariaDbMapper = mariaDbMapper; - this.schemaService = schemaService; this.storageService = storageService; + this.databaseService = databaseService; } @Override - public List<TableDto> getSchemas(PrivilegedDatabaseDto database) throws SQLException, TableNotFoundException, - DatabaseMalformedException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); - final Connection connection = dataSource.getConnection(); - final List<TableDto> tables = new LinkedList<>(); - try { - /* inspect tables before views */ - final long start = System.currentTimeMillis(); - final PreparedStatement statement = connection.prepareStatement(mariaDbMapper.databaseTablesSelectRawQuery()); - statement.setString(1, database.getInternalName()); - final ResultSet resultSet1 = statement.executeQuery(); - log.trace("executed statement in {} ms", System.currentTimeMillis() - start); - while (resultSet1.next()) { - final String tableName = resultSet1.getString(1); - if (database.getTables().stream().anyMatch(t -> t.getInternalName().equals(tableName))) { - log.trace("view {}.{} already known to metadata database, skip.", database.getInternalName(), tableName); - continue; - } - final TableDto table = schemaService.inspectTable(database, tableName); - if (database.getTables().stream().noneMatch(t -> t.getInternalName().equals(table.getInternalName()))) { - tables.add(table); - } - } - } catch (SQLException e) { - log.error("Failed to get table schemas: {}", e.getMessage()); - throw new DatabaseMalformedException("Failed to get table schemas: " + e.getMessage(), e); - } finally { - dataSource.close(); - } - log.info("Found {} table schema(s)", tables.size()); - return tables; - } - - @Override - public TableStatisticDto getStatistics(PrivilegedTableDto table) throws SQLException, TableMalformedException, + public TableStatisticDto getStatistics(TableDto table) throws SQLException, TableMalformedException, TableNotFoundException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase()); + final ComboPooledDataSource dataSource = getDataSource(table); final Connection connection = dataSource.getConnection(); final TableStatisticDto statistic; try { @@ -102,7 +67,7 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table .executeQuery(); log.trace("executed statement in {} ms", System.currentTimeMillis() - start); statistic = dataMapper.resultSetToTableStatistic(resultSet); - final TableDto tmpTable = schemaService.inspectTable(table.getDatabase(), table.getInternalName()); + final TableDto tmpTable = databaseService.inspectTable(table.getDatabase(), table.getInternalName()); statistic.setAvgRowLength(tmpTable.getAvgRowLength()); statistic.setDataLength(tmpTable.getDataLength()); statistic.setMaxDataLength(tmpTable.getMaxDataLength()); @@ -126,44 +91,9 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table } @Override - public TableDto find(PrivilegedDatabaseDto database, String tableName) throws TableNotFoundException, SQLException { - return schemaService.inspectTable(database, tableName); - } - - @Override - public TableDto createTable(PrivilegedDatabaseDto database, TableCreateDto data) throws SQLException, - TableMalformedException, TableExistsException, TableNotFoundException { - final String tableName = mariaDbMapper.nameToInternalName(data.getName()); - final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); - final Connection connection = dataSource.getConnection(); - try { - /* create table if not exists */ - final long start = System.currentTimeMillis(); - connection.prepareStatement(mariaDbMapper.tableCreateDtoToCreateTableRawQuery(data)) - .execute(); - log.trace("executed statement in {} ms", System.currentTimeMillis() - start); - connection.commit(); - } catch (SQLException e) { - connection.rollback(); - if (e.getMessage().contains("already exists")) { - log.error("Failed to create table: already exists"); - throw new TableExistsException("Failed to create table: already exists", e); - } - log.error("Failed to create table: {}", e.getMessage()); - throw new TableMalformedException("Failed to create table: " + e.getMessage(), e); - } finally { - dataSource.close(); - } - log.info("Created table with name {}", tableName); - final TableDto table = find(database, tableName); - table.setName(data.getName()); - return table; - } - - @Override - public void updateTable(PrivilegedTableDto table, TableUpdateDto data) throws SQLException, + public void updateTable(TableDto table, TableUpdateDto data) throws SQLException, TableMalformedException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase()); + final ComboPooledDataSource dataSource = getDataSource(table.getDatabase()); final Connection connection = dataSource.getConnection(); try { /* create table if not exists */ @@ -189,14 +119,13 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table } @Override - public void delete(PrivilegedTableDto table) throws SQLException, QueryMalformedException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase()); - final String tableName = mariaDbMapper.nameToInternalName(table.getInternalName()); + public void delete(TableDto table) throws SQLException, QueryMalformedException { + final ComboPooledDataSource dataSource = getDataSource(table.getDatabase()); final Connection connection = dataSource.getConnection(); try { /* create table if not exists */ final long start = System.currentTimeMillis(); - connection.prepareStatement(mariaDbMapper.dropTableRawQuery(tableName)) + connection.prepareStatement(mariaDbMapper.dropTableRawQuery(table.getInternalName())) .execute(); log.trace("executed statement in {} ms", System.currentTimeMillis() - start); connection.commit(); @@ -207,13 +136,13 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table } finally { dataSource.close(); } - log.info("Deleted table with name {}", tableName); + log.info("Deleted table with name {}", table.getInternalName()); } @Override - public List<TableHistoryDto> history(PrivilegedTableDto table, Long size) throws SQLException, + public List<TableHistoryDto> history(TableDto table, Long size) throws SQLException, TableNotFoundException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase()); + final ComboPooledDataSource dataSource = getDataSource(table.getDatabase()); final Connection connection = dataSource.getConnection(); final List<TableHistoryDto> history; try { @@ -227,19 +156,19 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table connection.commit(); } catch (SQLException e) { connection.rollback(); - log.error("Failed to find history for table {}.{}: {}", table.getDatabase().getInternalName(), table.getInternalName(), e.getMessage()); - throw new TableNotFoundException("Failed to find history for table " + table.getDatabase().getInternalName() + "." + table.getInternalName() + ": " + e.getMessage(), e); + log.error("Failed to find history for table {}.{}: {}", table.getDatabase(), table.getInternalName(), e.getMessage()); + throw new TableNotFoundException("Failed to find history for table " + table.getDatabase() + "." + table.getInternalName() + ": " + e.getMessage(), e); } finally { dataSource.close(); } - log.info("Find history for table {}.{}", table.getDatabase().getInternalName(), table.getInternalName()); + log.info("Find history for table {}.{}", table.getDatabase(), table.getInternalName()); return history; } @Override - public Long getCount(PrivilegedTableDto table, Instant timestamp) throws SQLException, + public Long getCount(TableDto table, Instant timestamp) throws SQLException, QueryMalformedException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase()); + final ComboPooledDataSource dataSource = getDataSource(table.getDatabase()); final Connection connection = dataSource.getConnection(); final Long queryResult; try { @@ -253,17 +182,17 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table connection.commit(); } catch (SQLException e) { connection.rollback(); - log.error("Failed to find row count from table {}.{}: {}", table.getDatabase().getInternalName(), table.getInternalName(), e.getMessage()); - throw new QueryMalformedException("Failed to find row count from table " + table.getDatabase().getInternalName() + "." + table.getInternalName() + ": " + e.getMessage(), e); + log.error("Failed to find row count from table {}.{}: {}", table.getDatabase(), table.getInternalName(), e.getMessage()); + throw new QueryMalformedException("Failed to find row count from table " + table.getDatabase() + "." + table.getInternalName() + ": " + e.getMessage(), e); } finally { dataSource.close(); } - log.info("Find row count from table {}.{}", table.getDatabase().getInternalName(), table.getInternalName()); + log.info("Find row count from table {}.{}", table.getDatabase(), table.getInternalName()); return queryResult; } @Override - public void importDataset(PrivilegedTableDto table, ImportDto data) throws MalformedException, + public void importDataset(TableDto table, ImportDto data) throws MalformedException, StorageNotFoundException, StorageUnavailableException, SQLException, QueryMalformedException, TableMalformedException { final List<String> columns = table.getColumns() @@ -282,8 +211,7 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table .mode(SaveMode.Overwrite) .option("header", data.getHeader()) .option("inferSchema", "true") - .jdbc(getSparkUrl(table.getDatabase().getContainer(), table.getDatabase().getInternalName()), - temporaryTable, properties); + .jdbc(getSparkUrl(table), temporaryTable, properties); } catch (Exception e) { if (e instanceof AnalysisException exception) { final String message = exception.getSimpleMessage() @@ -295,7 +223,7 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table throw new MalformedException("Failed to write dataset: " + e.getMessage()) /* remove throwable on purpose, clutters the output */; } /* import .csv from sidecar to database */ - final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase()); + final ComboPooledDataSource dataSource = getDataSource(table); final Connection connection = dataSource.getConnection(); try { /* import tuple */ @@ -314,15 +242,15 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table connection.commit(); dataSource.close(); } - log.info("Imported dataset into table: {}.{}", table.getDatabase().getInternalName(), table.getInternalName()); + log.info("Imported dataset into table: {}.{}", table.getDatabase(), table.getInternalName()); } @Override - public void deleteTuple(PrivilegedTableDto table, TupleDeleteDto data) throws SQLException, + public void deleteTuple(TableDto table, TupleDeleteDto data) throws SQLException, TableMalformedException, QueryMalformedException { log.trace("delete tuple: {}", data); /* prepare the statement */ - final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase()); + final ComboPooledDataSource dataSource = getDataSource(table); final Connection connection = dataSource.getConnection(); try { /* import tuple */ @@ -344,11 +272,11 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table } finally { dataSource.close(); } - log.info("Deleted tuple(s) from table: {}.{}", table.getDatabase().getInternalName(), table.getInternalName()); + log.info("Deleted tuple(s) from table: {}.{}", table.getDatabase(), table.getInternalName()); } @Override - public void createTuple(PrivilegedTableDto table, TupleDto data) throws SQLException, QueryMalformedException, + public void createTuple(TableDto table, TupleDto data) throws SQLException, QueryMalformedException, TableMalformedException, StorageUnavailableException, StorageNotFoundException { log.trace("create tuple: {}", data); /* for each LOB-like data-column, retrieve the bytes and replace the value */ @@ -366,7 +294,7 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table .replace(key, blob); } /* prepare the statement */ - final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase()); + final ComboPooledDataSource dataSource = getDataSource(table); final Connection connection = dataSource.getConnection(); try { /* create tuple */ @@ -388,15 +316,15 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table } finally { dataSource.close(); } - log.info("Created tuple(s) in table: {}.{}", table.getDatabase().getInternalName(), table.getInternalName()); + log.info("Created tuple(s) in table: {}.{}", table.getDatabase(), table.getInternalName()); } @Override - public void updateTuple(PrivilegedTableDto table, TupleUpdateDto data) throws SQLException, + public void updateTuple(TableDto table, TupleUpdateDto data) throws SQLException, QueryMalformedException, TableMalformedException { log.trace("update tuple: {}", data); /* prepare the statement */ - final ComboPooledDataSource dataSource = getPrivilegedDataSource(table.getDatabase()); + final ComboPooledDataSource dataSource = getDataSource(table); final Connection connection = dataSource.getConnection(); try { final int[] idx = new int[]{1}; @@ -424,7 +352,7 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table } finally { dataSource.close(); } - log.info("Updated tuple(s) from table: {}.{}", table.getDatabase().getInternalName(), table.getInternalName()); + log.info("Updated tuple(s) from table: {}.{}", table.getDatabase(), table.getInternalName()); } public ColumnTypeDto getColumnType(List<ColumnDto> columns, String name) throws QueryMalformedException { @@ -438,26 +366,4 @@ public class TableServiceMariaDbImpl extends HibernateConnector implements Table .getColumnType(); } - @Override - public Dataset<Row> getData(PrivilegedDatabaseDto database, String tableOrView, Instant timestamp, - Long page, Long size, SortTypeDto sortDirection, String sortColumn) - throws QueryMalformedException, TableNotFoundException { - try { - final Properties properties = new Properties(); - properties.setProperty("user", database.getContainer().getUsername()); - properties.setProperty("password", database.getContainer().getPassword()); - return sparkSession.read() - .jdbc(getSparkUrl(database.getContainer(), database.getInternalName()), tableOrView, properties); - } catch (Exception e) { - if (e instanceof ExtendedAnalysisException exception) { - if (exception.getSimpleMessage().contains("TABLE_OR_VIEW_NOT_FOUND")) { - log.error("Failed to find named reference: {}", exception.getSimpleMessage()); - throw new TableNotFoundException("Failed to find named reference: " + exception.getSimpleMessage()) /* remove throwable on purpose, clutters the output */; - } - } - log.error("Failed to find get data from query statement: {}", e.getMessage()); - throw new QueryMalformedException("Failed to find get data from query statement: " + e.getMessage(), e); - } - } - } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java index d85bdc53ac235a3a95bb8b3543bddcfdd143dc6d..fff524047e10b575f773fe23656f86944514843a 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java @@ -1,182 +1,39 @@ package at.tuwien.service.impl; -import at.tuwien.api.database.ViewCreateDto; import at.tuwien.api.database.ViewDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.database.internal.PrivilegedViewDto; -import at.tuwien.api.database.query.QueryDto; -import at.tuwien.config.QueryConfig; -import at.tuwien.exception.DatabaseMalformedException; import at.tuwien.exception.QueryMalformedException; import at.tuwien.exception.ViewMalformedException; -import at.tuwien.exception.ViewNotFoundException; -import at.tuwien.mapper.DataMapper; import at.tuwien.mapper.MariaDbMapper; -import at.tuwien.mapper.MetadataMapper; -import at.tuwien.service.SchemaService; import at.tuwien.service.ViewService; -import com.google.common.hash.Hashing; import com.mchange.v2.c3p0.ComboPooledDataSource; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.nio.charset.StandardCharsets; import java.sql.Connection; -import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.time.Instant; -import java.util.LinkedList; -import java.util.List; @Log4j2 @Service -public class ViewServiceMariaDbImpl extends HibernateConnector implements ViewService { +public class ViewServiceMariaDbImpl extends DataConnector implements ViewService { - private final DataMapper dataMapper; - private final QueryConfig queryConfig; - private final SchemaService schemaService; private final MariaDbMapper mariaDbMapper; - private final MetadataMapper metadataMapper; @Autowired - public ViewServiceMariaDbImpl(DataMapper dataMapper, QueryConfig queryConfig, SchemaService schemaService, - MariaDbMapper mariaDbMapper, MetadataMapper metadataMapper) { - this.dataMapper = dataMapper; - this.queryConfig = queryConfig; - this.schemaService = schemaService; + public ViewServiceMariaDbImpl(MariaDbMapper mariaDbMapper) { this.mariaDbMapper = mariaDbMapper; - this.metadataMapper = metadataMapper; } @Override - public Boolean existsByName(PrivilegedDatabaseDto database, String name) throws SQLException, - QueryMalformedException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); - final Connection connection = dataSource.getConnection(); - final Boolean queryResult; - try { - /* find view data */ - final long start = System.currentTimeMillis(); - final PreparedStatement statement = connection.prepareStatement(mariaDbMapper.selectExistsTableOrViewRawQuery()); - statement.setString(1, database.getInternalName()); - statement.setString(2, name); - final ResultSet resultSet = statement.executeQuery(); - log.trace("executed statement in {} ms", System.currentTimeMillis() - start); - queryResult = mariaDbMapper.resultSetToBoolean(resultSet); - } catch (SQLException e) { - log.error("Failed to prepare statement {}", e.getMessage()); - throw new QueryMalformedException("Failed to prepare statement: " + e.getMessage(), e); - } finally { - dataSource.close(); - } - return queryResult; - } - - @Override - public List<ViewDto> getSchemas(PrivilegedDatabaseDto database) throws SQLException, DatabaseMalformedException, - ViewNotFoundException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); - final Connection connection = dataSource.getConnection(); - final List<ViewDto> views = new LinkedList<>(); - try { - /* inspect tables before views */ - final PreparedStatement statement = connection.prepareStatement(mariaDbMapper.databaseViewsSelectRawQuery()); - statement.setString(1, database.getInternalName()); - final long start = System.currentTimeMillis(); - final ResultSet resultSet1 = statement.executeQuery(); - log.trace("executed statement in {} ms", System.currentTimeMillis() - start); - while (resultSet1.next()) { - final String viewName = resultSet1.getString(1); - if (viewName.length() == 64) { - log.trace("view {}.{} seems to be a subset view (name length = 64), skip.", database.getInternalName(), viewName); - continue; - } - if (database.getViews().stream().anyMatch(v -> v.getInternalName().equals(viewName))) { - log.trace("view {}.{} already known to metadata database, skip.", database.getInternalName(), viewName); - continue; - } - final ViewDto view; - view = schemaService.inspectView(database, viewName); - if (database.getTables().stream().noneMatch(t -> t.getInternalName().equals(view.getInternalName()))) { - views.add(view); - } - } - } catch (SQLException e) { - log.error("Failed to get view schemas: {}", e.getMessage()); - throw new DatabaseMalformedException("Failed to get view schemas: " + e.getMessage(), e); - } finally { - dataSource.close(); - } - log.info("Found {} view schema(s)", views.size()); - return views; - } - - @Override - public ViewDto create(PrivilegedDatabaseDto database, QueryDto subset) throws ViewMalformedException, - SQLException { - final ViewCreateDto data = ViewCreateDto.builder() - .name(metadataMapper.queryDtoToViewName(subset)) - .query(subset.getQuery()) - .isPublic(false) - .build(); - return create(database, data); - } - - @Override - public ViewDto create(PrivilegedDatabaseDto database, ViewCreateDto data) throws SQLException, - ViewMalformedException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); - final Connection connection = dataSource.getConnection(); - ViewDto view = ViewDto.builder() - .name(data.getName()) - .internalName(mariaDbMapper.nameToInternalName(data.getName())) - .query(data.getQuery()) - .queryHash(Hashing.sha256() - .hashString(data.getQuery(), StandardCharsets.UTF_8) - .toString()) - .isPublic(database.getIsPublic()) - .owner(database.getOwner()) - .identifiers(new LinkedList<>()) - .isInitialView(false) - .vdbid(database.getId()) - .columns(new LinkedList<>()) - .build(); - try { - /* create view if not exists */ - final long start = System.currentTimeMillis(); - connection.prepareStatement(mariaDbMapper.viewCreateRawQuery(view.getInternalName(), data.getQuery())) - .execute(); - log.trace("executed statement in {} ms", System.currentTimeMillis() - start); - /* select view columns */ - final PreparedStatement statement2 = connection.prepareStatement(mariaDbMapper.databaseTableColumnsSelectRawQuery()); - statement2.setString(1, database.getInternalName()); - statement2.setString(2, view.getInternalName()); - final ResultSet resultSet2 = statement2.executeQuery(); - while (resultSet2.next()) { - view = dataMapper.resultSetToTable(resultSet2, view, queryConfig); - } - connection.commit(); - } catch (SQLException e) { - connection.rollback(); - log.error("Failed to create view: {}", e.getMessage()); - throw new ViewMalformedException("Failed to create view: " + e.getMessage(), e); - } finally { - dataSource.close(); - } - log.info("Created view with name {}", view.getName()); - return view; - } - - @Override - public void delete(PrivilegedDatabaseDto database, String viewName) throws SQLException, ViewMalformedException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); + public void delete(ViewDto view) throws SQLException, ViewMalformedException { + final ComboPooledDataSource dataSource = getDataSource(view); final Connection connection = dataSource.getConnection(); try { /* drop view if exists */ final long start = System.currentTimeMillis(); - connection.prepareStatement(mariaDbMapper.dropViewRawQuery(viewName)) + connection.prepareStatement(mariaDbMapper.dropViewRawQuery(view.getInternalName())) .execute(); log.trace("executed statement in {} ms", System.currentTimeMillis() - start); connection.commit(); @@ -187,14 +44,13 @@ public class ViewServiceMariaDbImpl extends HibernateConnector implements ViewSe } finally { dataSource.close(); } - log.info("Deleted view {}.{}", database.getInternalName(), viewName); + log.info("Deleted view {}.{}", view.getDatabase(), view.getInternalName()); } - @Override - public Long count(PrivilegedViewDto view, Instant timestamp) throws SQLException, + public Long count(ViewDto view, Instant timestamp) throws SQLException, QueryMalformedException { - final ComboPooledDataSource dataSource = getPrivilegedDataSource(view.getDatabase()); + final ComboPooledDataSource dataSource = getDataSource(view); final Connection connection = dataSource.getConnection(); final Long queryResult; try { @@ -208,12 +64,12 @@ public class ViewServiceMariaDbImpl extends HibernateConnector implements ViewSe connection.commit(); } catch (SQLException e) { connection.rollback(); - log.error("Failed to find row count from view {}.{}: {}", view.getDatabase().getInternalName(), view.getInternalName(), e.getMessage()); - throw new QueryMalformedException("Failed to find row count from view " + view.getDatabase().getInternalName() + "." + view.getInternalName() + ": " + e.getMessage(), e); + log.error("Failed to find row count from view {}.{}: {}", view.getDatabase(), view.getInternalName(), e.getMessage()); + throw new QueryMalformedException("Failed to find row count from view " + view.getDatabase() + "." + view.getInternalName() + ": " + e.getMessage(), e); } finally { dataSource.close(); } - log.info("Find row count from view {}.{}", view.getDatabase().getInternalName(), view.getInternalName()); + log.info("Find row count from view {}.{}", view.getDatabase(), view.getInternalName()); return queryResult; } diff --git a/dbrepo-gateway-service/dbrepo.conf b/dbrepo-gateway-service/dbrepo.conf index fd66cf805ef4bc7d5e7bb5e93ee54381015e88f6..68778de757bf331e183e7258755c6f3ef210d6ec 100644 --- a/dbrepo-gateway-service/dbrepo.conf +++ b/dbrepo-gateway-service/dbrepo.conf @@ -40,6 +40,10 @@ upstream dashboard-service { server dashboard-service:3000; } +upstream auth-service { + server auth-service:8080; +} + server { listen 8080 default_server; server_name _; @@ -67,6 +71,26 @@ server { proxy_read_timeout 90; } + # Proxy Keycloak OIDC connections, c.f. https://www.keycloak.org/server/reverseproxy#_exposed_path_recommendations + location /realms { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_pass http://auth-service; + proxy_read_timeout 90; + } + + # Proxy Keycloak assets, c.f. https://www.keycloak.org/server/reverseproxy#_exposed_path_recommendations + location /resources { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_pass http://auth-service; + proxy_read_timeout 90; + } + location /api/search { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; diff --git a/dbrepo-metadata-db/1_setup-schema.sql b/dbrepo-metadata-db/1_setup-schema.sql index c9ce89d1be71f4791c5e55dbb7c24f46e979355a..e2bde25ed6d64f69c4f8d6e897a49a672e3f9a71 100644 --- a/dbrepo-metadata-db/1_setup-schema.sql +++ b/dbrepo-metadata-db/1_setup-schema.sql @@ -3,10 +3,10 @@ BEGIN; CREATE TABLE IF NOT EXISTS `mdb_users` ( id character varying(36) NOT NULL, + keycloak_id character varying(36) NOT NULL, username character varying(255) NOT NULL, firstname character varying(255), lastname character varying(255), - email character varying(255) NOT NULL, orcid character varying(255), affiliation character varying(255), is_internal BOOLEAN NOT NULL DEFAULT FALSE, @@ -14,8 +14,8 @@ CREATE TABLE IF NOT EXISTS `mdb_users` theme character varying(255) NOT NULL default ('light'), language character varying(3) NOT NULL default ('en'), PRIMARY KEY (id), - UNIQUE (username), - UNIQUE (email) + UNIQUE (keycloak_id), + UNIQUE (username) ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_images` diff --git a/dbrepo-metadata-service/Dockerfile b/dbrepo-metadata-service/Dockerfile index 843c334a9acb3d24e061c42c72cb75c6068ef954..fa92b799eeaac75f9daea7b5a1eec11560b04647 100644 --- a/dbrepo-metadata-service/Dockerfile +++ b/dbrepo-metadata-service/Dockerfile @@ -12,7 +12,7 @@ COPY ./rest-service/pom.xml ./rest-service/ COPY ./services/pom.xml ./services/ COPY ./test/pom.xml ./test/ -RUN mvn verify -B -fn +RUN mvn dependency:go-offline COPY ./api ./api COPY ./entities ./entities diff --git a/dbrepo-metadata-service/api/pom.xml b/dbrepo-metadata-service/api/pom.xml index 9baf18ff69870ee00658f67dc5fa5e43bab49581..0d534105f8a12d52201e2437d31360903292f657 100644 --- a/dbrepo-metadata-service/api/pom.xml +++ b/dbrepo-metadata-service/api/pom.xml @@ -6,18 +6,18 @@ <parent> <groupId>at.tuwien</groupId> <artifactId>dbrepo-metadata-service</artifactId> - <version>1.6.1</version> + <version>1.6.3</version> </parent> <artifactId>dbrepo-metadata-service-api</artifactId> <name>dbrepo-metadata-service-api</name> - <version>1.6.1</version> + <version>1.6.3</version> <dependencies> <dependency> <groupId>at.tuwien</groupId> <artifactId>dbrepo-metadata-service-entities</artifactId> - <version>1.6.1</version> + <version>1.6.3</version> <scope>compile</scope> </dependency> </dependencies> diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/PrivilegedObjectDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/CacheableDto.java similarity index 59% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/PrivilegedObjectDto.java rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/CacheableDto.java index c88fcabccfba67130fbc4a230d98fb749d5857dd..e947ece6320820e926a3674834310c785042603d 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/PrivilegedObjectDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/CacheableDto.java @@ -1,6 +1,8 @@ package at.tuwien.api; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; import lombok.ToString; @@ -9,10 +11,12 @@ import java.time.Instant; @Getter @Setter +@EqualsAndHashCode @ToString -public abstract class PrivilegedObjectDto { +public abstract class CacheableDto { @JsonProperty("last_retrieved") + @Schema(example = "2025-01-23T12:09:01") private Instant lastRetrieved; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/CreateUserDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/CreateUserDto.java index 0beb8a379491869edef613a594616beb21d1da83..16f45aec4d625639f1188e0e853b3a81bd71811f 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/CreateUserDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/CreateUserDto.java @@ -1,13 +1,13 @@ package at.tuwien.api.auth; +import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; -import java.util.List; +import java.util.UUID; @Getter @Setter @@ -20,23 +20,27 @@ import java.util.List; public class CreateUserDto { @NotNull - @Schema(example = "true") - private Boolean enabled; + @Schema(example = "3b91bc36-3eae-4662-a4be-8993624ab0cb", description = "The user id generated by Keycloak") + private UUID id; + + @NotNull + @JsonProperty("ldap_id") + @Schema(example = "ea022d6d-b4a4-42f3-836f-ff4e596a527a", description = "The user id generated by OpenLDAP") + private UUID ldapId; @NotBlank @Schema(example = "user") private String username; - @NotBlank - @Email - @Schema(example = "user@example.com") - private String email; + @JsonProperty("given_name") + @Schema(example = "foo") + private String givenName; - private String firstName; + @JsonProperty("family_name") + @Schema(example = "bar") + private String familyName; - private String lastName; - - @NotNull - private List<CredentialDto> credentials; + @Schema(example = "foo.bar@example.com") + private String email; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/SignupRequestDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/SignupRequestDto.java deleted file mode 100644 index c9110e041aaf1187675c58d2365cf63e1f1f2003..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/auth/SignupRequestDto.java +++ /dev/null @@ -1,35 +0,0 @@ -package at.tuwien.api.auth; - -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Pattern; -import lombok.*; -import lombok.extern.jackson.Jacksonized; - -@Getter -@Setter -@Builder -@EqualsAndHashCode -@NoArgsConstructor -@AllArgsConstructor -@Jacksonized -@ToString -public class SignupRequestDto { - - @NotBlank - @Pattern(regexp = "^[a-z0-9]{3,}$") - @Schema(example = "user") - private String username; - - @NotBlank - @Email - @Schema(example = "user@example.com") - private String email; - - @NotNull - @ToString.Exclude - private String password; - -} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java index 9b1f8fcd4791d018970cb8559b5a7dcd1b1d7210..71e7601b164bbda3a1efd21557d9695322ad0715 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerBriefDto.java @@ -22,6 +22,7 @@ import java.time.Instant; public class ContainerBriefDto { @NotNull + @Schema(example = "4") private Long id; @NotNull diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerDto.java index 9928c8e54d39287fc7a19bf84b6a99c7429f69bd..913ab26d9d4469fb3335d5dc1da8463c9afc0bd6 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerDto.java @@ -1,7 +1,7 @@ package at.tuwien.api.container; +import at.tuwien.api.CacheableDto; import at.tuwien.api.container.image.ImageDto; -import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; @@ -14,13 +14,15 @@ import java.time.Instant; @Getter @Setter @Builder +@EqualsAndHashCode(callSuper = true) @NoArgsConstructor @AllArgsConstructor @Jacksonized @ToString -public class ContainerDto { +public class ContainerDto extends CacheableDto { @NotNull + @Schema(example = "4") private Long id; @NotBlank @@ -29,19 +31,21 @@ public class ContainerDto { @NotBlank @JsonProperty("internal_name") - @Schema(example = "data-db") + @Schema(example = "air_quality") private String internalName; - @NotBlank + @Schema(example = "data-db") private String host; - @NotNull + @Schema(example = "3306") private Integer port; @JsonProperty("ui_host") + @Schema(example = "example.com") private String uiHost; @JsonProperty("ui_port") + @Schema(example = "3306") private Integer uiPort; @NotNull @@ -55,4 +59,18 @@ public class ContainerDto { @Schema(example = "10") private Long count; + @ToString.Exclude + @Schema(example = "username") + private String username; + + @ToString.Exclude + @Schema(example = "p4ssw0rd") + private String password; + + /* lombok limitations prevent from convenient builder functions */ + + @JsonProperty("last_retrieved") + @Schema(example = "2025-01-23T12:09:01") + private Instant lastRetrieved; + } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/CreateContainerDto.java similarity index 68% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerCreateDto.java rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/CreateContainerDto.java index 86b50bea70209334a41458c47610c07f44f1799f..23062ffd9082098f13524ddd283b39310ecf39d5 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/ContainerCreateDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/CreateContainerDto.java @@ -14,7 +14,7 @@ import lombok.extern.jackson.Jacksonized; @AllArgsConstructor @Jacksonized @ToString -public class ContainerCreateDto { +public class CreateContainerDto { @NotBlank @Schema(example = "Air Quality") @@ -22,20 +22,22 @@ public class ContainerCreateDto { @NotNull @JsonProperty("image_id") - @Schema(description = "Image ID") + @Schema(example = "1", description = "Image ID") private Long imageId; @NotBlank - @Schema(description = "Hostname of container") + @Schema(example = "data-db2", description = "Hostname of container") private String host; - @Schema(description = "Port of container") + @Schema(example = "3306", description = "Port of container") private Integer port; @JsonProperty("ui_host") + @Schema(example = "example.com") private String uiHost; @JsonProperty("ui_port") + @Schema(example = "3306") private Integer uiPort; @NotNull @@ -44,11 +46,11 @@ public class ContainerCreateDto { @NotBlank @JsonProperty("privileged_username") - @Schema(description = "Username of privileged user", example = "root") + @Schema(example = "root", description = "Username of privileged user") private String privilegedUsername; @NotBlank @JsonProperty("privileged_password") - @Schema(description = "Password of privileged user") + @Schema(example = "dbrepo", description = "Password of privileged user") private String privilegedPassword; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageBriefDto.java index 880db11fbd9818ed432f8dab7a910c48a51bf72e..6a9a970c0f5b3931bbcab7f53be099138d568c12 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageBriefDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageBriefDto.java @@ -18,6 +18,7 @@ import lombok.extern.jackson.Jacksonized; public class ImageBriefDto { @NotNull + @Schema(example = "5") private Long id; @NotBlank diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDto.java index 3baa76171b1ad00ab575a0fafa403c675e16f640..a9c37fb8485db0e90b4b5d56b91b53ad4ec47940 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/ImageDto.java @@ -20,6 +20,7 @@ import java.util.List; public class ImageDto { @NotNull + @Schema(example = "1") private Long id; @NotBlank diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/internal/PrivilegedContainerDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/internal/PrivilegedContainerDto.java deleted file mode 100644 index 9c414e5ef1f0201da252e58494048d537996bb56..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/internal/PrivilegedContainerDto.java +++ /dev/null @@ -1,60 +0,0 @@ -package at.tuwien.api.container.internal; - -import at.tuwien.api.PrivilegedObjectDto; -import at.tuwien.api.container.image.ImageDto; -import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import lombok.*; -import lombok.extern.jackson.Jacksonized; - -import java.time.Instant; - -@Getter -@Setter -@Builder -@NoArgsConstructor -@AllArgsConstructor -@Jacksonized -@ToString -public class PrivilegedContainerDto extends PrivilegedObjectDto { - - @NotNull - private Long id; - - @NotBlank - @Schema(example = "Air Quality") - private String name; - - @NotBlank - @JsonProperty("internal_name") - @Schema(example = "data-db") - private String internalName; - - @NotBlank - private String host; - - @NotNull - private Integer port; - - @JsonProperty("ui_host") - private String uiHost; - - @JsonProperty("ui_port") - private Integer uiPort; - - @NotNull - private ImageDto image; - - @ToString.Exclude - private String username; - - @ToString.Exclude - private String password; - - @JsonProperty("last_retrieved") - private Instant lastRetrieved; - -} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/AccessTypeDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/AccessTypeDto.java index a93e89ec96fd19a78767f135366422301d42d959..fa0f6fea49e0aaf1823ba26f70aa918ecd96d98d 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/AccessTypeDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/AccessTypeDto.java @@ -1,9 +1,11 @@ package at.tuwien.api.database; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; @Getter +@Schema public enum AccessTypeDto { @JsonProperty("read") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/UpdateDatabaseAccessDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateAccessDto.java similarity index 72% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/UpdateDatabaseAccessDto.java rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateAccessDto.java index 32084c865feafc27fd1ae0a1a534229b347d3538..965e10afd50884605ca8788a4653b2b2dc3b9f09 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/UpdateDatabaseAccessDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateAccessDto.java @@ -1,5 +1,6 @@ package at.tuwien.api.database; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; @@ -12,9 +13,10 @@ import lombok.extern.jackson.Jacksonized; @AllArgsConstructor @Jacksonized @ToString -public class UpdateDatabaseAccessDto { +public class CreateAccessDto { @NotNull + @Schema(example = "read") private AccessTypeDto type; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateDatabaseDto.java similarity index 96% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseCreateDto.java rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateDatabaseDto.java index f87673764ea55479e86ede7e3f2b70c94cd16b9a..c10d6b0b5e2618a6c3854e591d99e477be952035 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseCreateDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateDatabaseDto.java @@ -15,7 +15,7 @@ import lombok.extern.jackson.Jacksonized; @AllArgsConstructor @Jacksonized @ToString -public class DatabaseCreateDto { +public class CreateDatabaseDto { @NotNull @JsonProperty("container_id") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateViewDto.java similarity index 96% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewCreateDto.java rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateViewDto.java index 142a751ec4cc8eaceee7a9402af2c711d1acaa19..366845d08304881519c80f4984106626bf52a01a 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewCreateDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/CreateViewDto.java @@ -16,7 +16,7 @@ import lombok.extern.jackson.Jacksonized; @AllArgsConstructor @Jacksonized @ToString -public class ViewCreateDto { +public class CreateViewDto { @NotBlank @Size(min = 1, max = 63) diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseAccessDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseAccessDto.java index 7e929eb74843d7ad5589652c269f59d8bd7db498..d065a5892afb0cb342c12975f562820d1eeb6b10 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseAccessDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseAccessDto.java @@ -3,6 +3,7 @@ package at.tuwien.api.database; import at.tuwien.api.user.UserBriefDto; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; @@ -31,6 +32,7 @@ public class DatabaseAccessDto { private UserBriefDto user; @NotNull + @Schema(example = "read") private AccessTypeDto type; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java index 46072e83dc14af22d09923d3e9462a53506aa4f8..4cff48db18b1b337de7ae9d3a50c986e4c329028 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseBriefDto.java @@ -23,6 +23,7 @@ import java.util.UUID; public class DatabaseBriefDto { @NotNull + @Schema(example = "3") private Long id; @NotBlank @@ -47,6 +48,7 @@ public class DatabaseBriefDto { @Schema(example = "true") private Boolean isSchemaPublic; + @NotNull private List<IdentifierBriefDto> identifiers; @NotNull @@ -54,6 +56,10 @@ public class DatabaseBriefDto { @NotNull @JsonProperty("owner_id") + @Schema(example = "2f45ef7a-7f9b-4667-9156-152c87fe1ca5") private UUID ownerId; + @JsonProperty("preview_image") + private String previewImage; + } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseDto.java index 5fc253c4335044a1eaabbb43d02f7ae07510178b..d6ea2bff9e2203439891e3a1a6aec6f17afc86a6 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/DatabaseDto.java @@ -1,8 +1,9 @@ package at.tuwien.api.database; -import at.tuwien.api.container.ContainerBriefDto; -import at.tuwien.api.database.table.TableBriefDto; -import at.tuwien.api.identifier.IdentifierBriefDto; +import at.tuwien.api.CacheableDto; +import at.tuwien.api.container.ContainerDto; +import at.tuwien.api.database.table.TableDto; +import at.tuwien.api.identifier.IdentifierDto; import at.tuwien.api.user.UserBriefDto; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; @@ -11,19 +12,21 @@ import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; +import java.time.Instant; import java.util.List; @Getter @Setter @Builder -@EqualsAndHashCode +@EqualsAndHashCode(callSuper = true) @NoArgsConstructor @AllArgsConstructor @Jacksonized @ToString -public class DatabaseDto { +public class DatabaseDto extends CacheableDto { @NotNull + @Schema(example = "3") private Long id; @NotBlank @@ -47,9 +50,11 @@ public class DatabaseDto { @Schema(example = "Air Quality") private String description; - private List<TableBriefDto> tables; + @NotNull + private List<TableDto> tables; - private List<ViewBriefDto> views; + @NotNull + private List<ViewDto> views; @NotNull @JsonProperty("is_public") @@ -61,14 +66,16 @@ public class DatabaseDto { @Schema(example = "true") private Boolean isSchemaPublic; - @NotNull - private ContainerBriefDto container; + private ContainerDto container; + @NotNull private List<DatabaseAccessDto> accesses; - private List<IdentifierBriefDto> identifiers; + @NotNull + private List<IdentifierDto> identifiers; - private List<IdentifierBriefDto> subsets; + @NotNull + private List<IdentifierDto> subsets; @NotNull private UserBriefDto contact; @@ -79,4 +86,10 @@ public class DatabaseDto { @JsonProperty("preview_image") private String previewImage; + /* lombok limitations prevent from convenient builder functions */ + + @JsonProperty("last_retrieved") + @Schema(example = "2025-01-23T12:09:01") + private Instant lastRetrieved; + } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewBriefDto.java index 9b7c9fca89472a956b5d142e69c498c616fce81a..f68067e8a870f01b402b23a3b27bd0a065e186fd 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewBriefDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewBriefDto.java @@ -20,10 +20,12 @@ import java.util.UUID; public class ViewBriefDto { @NotNull + @Schema(example = "4") private Long id; @NotNull @JsonProperty("database_id") + @Schema(example = "1") private Long vdbid; @NotBlank @@ -31,8 +33,8 @@ public class ViewBriefDto { private String name; @NotBlank - @JsonProperty("internal_name") @Schema(example = "air_quality") + @JsonProperty("internal_name") private String internalName; @JsonProperty("is_public") @@ -57,6 +59,7 @@ public class ViewBriefDto { private String queryHash; @JsonProperty("owned_by") + @Schema(example = "ac750fcf-ea02-4fce-85ac-d73857e18b35") private UUID ownedBy; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java index 4005433afedbd5440b939d97bcd874f570a56c29..24cca8e4cc7325904c83845d42d060814753d171 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java @@ -20,42 +20,41 @@ import lombok.extern.jackson.Jacksonized; public class ViewColumnDto { @NotNull + @Schema(example = "12") private Long id; @NotNull @JsonProperty("database_id") + @Schema(example = "1") private Long databaseId; @NotNull - @Schema(example = "0") @JsonProperty("ord") + @Schema(example = "0") private Integer ordinalPosition; @NotBlank @Size(max = 64) - @Schema(example = "Date") + @Schema(example = "Given Name") private String name; @NotBlank @Size(max = 64) @JsonProperty("internal_name") - @Schema(example = "mdb_date") + @Schema(example = "given_name") private String internalName; - @NotNull - @JsonProperty("auto_generated") - @Schema(example = "false") - private Boolean autoGenerated; - @JsonProperty("index_length") + @Schema(example = "255") private Long indexLength; @JsonProperty("length") + @Schema(example = "255") private Long length; @NotNull @JsonProperty("type") - @Schema(example = "string") + @Schema(example = "varchar") private ColumnTypeDto columnType; @Schema(example = "255") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewDto.java index d1ee156e9b95c09a9dd31c1ddf01926818f75879..82a7081e16f08a2cc2c3a7c02a28760adc7ef9d1 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewDto.java @@ -1,5 +1,6 @@ package at.tuwien.api.database; +import at.tuwien.api.CacheableDto; import at.tuwien.api.identifier.IdentifierDto; import at.tuwien.api.user.UserBriefDto; import com.fasterxml.jackson.annotation.JsonProperty; @@ -9,29 +10,33 @@ import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; +import java.time.Instant; import java.util.List; @Getter @Setter @Builder -@EqualsAndHashCode +@EqualsAndHashCode(callSuper = true) @NoArgsConstructor @AllArgsConstructor @Jacksonized @ToString -public class ViewDto { +public class ViewDto extends CacheableDto { @NotNull + @Schema(example = "4") private Long id; @NotNull @JsonProperty("database_id") + @Schema(example = "1") private Long vdbid; @NotBlank @Schema(example = "Air Quality") private String name; + @NotNull private List<IdentifierDto> identifiers; @NotBlank @@ -60,10 +65,20 @@ public class ViewDto { @Schema(example = "7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916") private String queryHash; + @ToString.Exclude + @EqualsAndHashCode.Exclude + private DatabaseDto database; + @NotNull private UserBriefDto owner; @NotNull private List<ViewColumnDto> columns; + /* lombok limitations prevent from convenient builder functions */ + + @JsonProperty("last_retrieved") + @Schema(example = "2025-01-23T12:09:01") + private Instant lastRetrieved; + } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/internal/PrivilegedDatabaseDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/internal/PrivilegedDatabaseDto.java deleted file mode 100644 index 2335ea39baf1a2e8f1461b56c844409f8e21b207..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/internal/PrivilegedDatabaseDto.java +++ /dev/null @@ -1,88 +0,0 @@ -package at.tuwien.api.database.internal; - -import at.tuwien.api.PrivilegedObjectDto; -import at.tuwien.api.container.internal.PrivilegedContainerDto; -import at.tuwien.api.database.DatabaseAccessDto; -import at.tuwien.api.database.ViewDto; -import at.tuwien.api.database.table.TableDto; -import at.tuwien.api.identifier.IdentifierDto; -import at.tuwien.api.user.UserBriefDto; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import lombok.*; -import lombok.extern.jackson.Jacksonized; - -import java.time.Instant; -import java.util.List; - -@Getter -@Setter -@Builder -@NoArgsConstructor -@AllArgsConstructor -@Jacksonized -@ToString -public class PrivilegedDatabaseDto extends PrivilegedObjectDto { - - @NotNull - private Long id; - - @NotBlank - @Schema(example = "Air Quality") - private String name; - - @NotBlank - @JsonProperty("exchange_name") - @Schema(example = "dbrepo") - private String exchangeName; - - @JsonProperty("exchange_type") - @Schema(example = "topic") - private String exchangeType; - - @NotBlank - @JsonProperty("internal_name") - @Schema(example = "air_quality") - private String internalName; - - @Schema(example = "Air Quality") - private String description; - - private List<TableDto> tables; - - private List<ViewDto> views; - - @NotNull - @JsonProperty("is_public") - @Schema(example = "true") - private Boolean isPublic; - - @NotNull - @JsonProperty("is_schema_public") - @Schema(example = "true") - private Boolean isSchemaPublic; - - @NotNull - private PrivilegedContainerDto container; - - private List<DatabaseAccessDto> accesses; - - private List<IdentifierDto> identifiers; - - private List<IdentifierDto> subsets; - - @NotNull - private UserBriefDto contact; - - @NotNull - private UserBriefDto owner; - - @JsonProperty("preview_image") - private String previewImage; - - @JsonProperty("last_retrieved") - private Instant lastRetrieved; - -} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/internal/PrivilegedViewDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/internal/PrivilegedViewDto.java deleted file mode 100644 index bda575f45d05f21a29a7be3d9da6cdfe1511d855..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/internal/PrivilegedViewDto.java +++ /dev/null @@ -1,77 +0,0 @@ -package at.tuwien.api.database.internal; - -import at.tuwien.api.PrivilegedObjectDto; -import at.tuwien.api.database.ViewColumnDto; -import at.tuwien.api.identifier.IdentifierDto; -import at.tuwien.api.user.UserBriefDto; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import lombok.*; -import lombok.extern.jackson.Jacksonized; - -import java.time.Instant; -import java.util.List; - -@Getter -@Setter -@Builder -@NoArgsConstructor -@AllArgsConstructor -@Jacksonized -@ToString -public class PrivilegedViewDto extends PrivilegedObjectDto { - - @NotNull - private Long id; - - @NotNull - @JsonProperty("database_id") - private Long vdbid; - - @NotNull - private PrivilegedDatabaseDto database; - - @NotBlank - @Schema(example = "Air Quality") - private String name; - - private List<IdentifierDto> identifiers; - - @NotBlank - @Schema(example = "air_quality") - @JsonProperty("internal_name") - private String internalName; - - @JsonProperty("is_public") - @Schema(example = "true") - private Boolean isPublic; - - @JsonProperty("is_schema_public") - @Schema(example = "true") - private Boolean isSchemaPublic; - - @JsonProperty("initial_view") - @Schema(example = "true", description = "True if it is the default view for the database") - private Boolean isInitialView; - - @NotNull - @Schema(example = "SELECT `id` FROM `air_quality` ORDER BY `value` DESC") - private String query; - - @NotNull - @JsonProperty("query_hash") - @Schema(example = "7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916") - private String queryHash; - - @NotNull - private UserBriefDto owner; - - @NotNull - private List<ViewColumnDto> columns; - - @JsonProperty("last_retrieved") - private Instant lastRetrieved; - -} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportDto.java index 39cb6683a1cb2d5250054b8dd555bffbad929fad..20817e017622ff5619cf1eaf284f238ba02dff4b 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/ImportDto.java @@ -22,7 +22,7 @@ public class ImportDto { private String location; @NotNull - @Schema(description = "If true, the first line contains the column names, otherwise it contains only data") + @Schema(example = "true", description = "If true, the first line contains the column names, otherwise it contains only data") private Boolean header; @NotNull diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryDto.java index cd1659e73c6a1e0a13e220e4a83aaaf5b5aacc2f..41cb641a5d8cdf8ccc6187c2f083447e4cdb4714 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryDto.java @@ -24,10 +24,12 @@ import java.util.List; public class QueryDto { @NotNull + @Schema(example = "4") private Long id; @NotNull @JsonProperty("database_id") + @Schema(example = "1") private Long databaseId; @NotNull diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryTypeDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryTypeDto.java index afc03ab97f9742d5d4d639b546ae983fa7525f35..4df28733cdba0830b0e1579805284a92581c42bb 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryTypeDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/query/QueryTypeDto.java @@ -1,7 +1,9 @@ package at.tuwien.api.database.query; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +@Schema public enum QueryTypeDto { @JsonProperty("query") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/CreateTableDto.java similarity index 77% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableCreateDto.java rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/CreateTableDto.java index 7c3defcc0b69dc47e20c4e9aa9931fdfad1143b0..15a798ee2d6bd237a6f578678d8885ca3b0f87dd 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableCreateDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/CreateTableDto.java @@ -1,7 +1,7 @@ package at.tuwien.api.database.table; -import at.tuwien.api.database.table.columns.ColumnCreateDto; -import at.tuwien.api.database.table.constraints.ConstraintsCreateDto; +import at.tuwien.api.database.table.columns.CreateTableColumnDto; +import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; @@ -20,7 +20,7 @@ import java.util.List; @AllArgsConstructor @Jacksonized @ToString -public class TableCreateDto { +public class CreateTableDto { @NotBlank @Size(min = 1, max = 64) @@ -42,8 +42,8 @@ public class TableCreateDto { private Boolean isSchemaPublic; @NotNull - private List<ColumnCreateDto> columns; + private List<CreateTableColumnDto> columns; @NotNull - private ConstraintsCreateDto constraints; + private CreateTableConstraintsDto constraints; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableBriefDto.java index 29531012f1f2912cc7d7f0c326661cee868ec72d..98932f30a294febdc3df41290888c0d6d3ae7e5d 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableBriefDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableBriefDto.java @@ -20,10 +20,12 @@ import java.util.UUID; public class TableBriefDto { @NotNull + @Schema(example = "3") private Long id; @NotNull @JsonProperty("database_id") + @Schema(example = "2") private Long databaseId; @NotBlank @@ -55,5 +57,6 @@ public class TableBriefDto { @NotNull @JsonProperty("owned_by") + @Schema(example = "78337b80-5699-45db-8111-cec86439ab6b") private UUID ownedBy; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableDto.java index 67087d438daedf60cd0236a8f5427310b06464e4..1021d167ca1364eb63b06d321040e708c4f7d6e2 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TableDto.java @@ -1,9 +1,13 @@ package at.tuwien.api.database.table; +import at.tuwien.api.CacheableDto; +import at.tuwien.api.container.ContainerDto; +import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.table.columns.ColumnDto; import at.tuwien.api.database.table.constraints.ConstraintsDto; import at.tuwien.api.identifier.IdentifierDto; import at.tuwien.api.user.UserBriefDto; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; @@ -12,23 +16,26 @@ import jakarta.validation.constraints.Size; import lombok.*; import lombok.extern.jackson.Jacksonized; +import java.time.Instant; import java.util.List; @Getter @Setter @Builder -@EqualsAndHashCode +@EqualsAndHashCode(callSuper = true) @NoArgsConstructor @AllArgsConstructor @Jacksonized @ToString -public class TableDto { +public class TableDto extends CacheableDto { @NotNull + @Schema(example = "3") private Long id; @NotNull @JsonProperty("database_id") + @Schema(example = "2") private Long tdbid; @NotBlank @@ -40,7 +47,7 @@ public class TableDto { @Schema(example = "air_quality") private String internalName; - @Schema + @Schema(example = "a") private String alias; private List<IdentifierDto> identifiers; @@ -100,7 +107,17 @@ public class TableDto { @NotNull private List<ColumnDto> columns; + @ToString.Exclude + @EqualsAndHashCode.Exclude + private DatabaseDto database; + @NotNull private ConstraintsDto constraints; + /* lombok limitations prevent from convenient builder functions */ + + @JsonProperty("last_retrieved") + @Schema(example = "2025-01-23T12:09:01") + private Instant lastRetrieved; + } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDeleteDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDeleteDto.java index 6c3a946e1257dd2a9a90175a1904d88cf2f1a339..f74ffb3d89a1cfc5582be30e89ff0cb6a573f8c5 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDeleteDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDeleteDto.java @@ -1,5 +1,6 @@ package at.tuwien.api.database.table; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; @@ -17,6 +18,7 @@ import java.util.Map; public class TupleDeleteDto { @NotNull + @Schema(example = "{\"id\": 1}") private Map<String, Object> keys; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDto.java index 62f57434b67dfe69e95bd212afb795f004da87d7..13dc2b9723e763a5b255c762f1d94974ef90d074 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleDto.java @@ -1,5 +1,6 @@ package at.tuwien.api.database.table; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; @@ -17,6 +18,7 @@ import java.util.Map; public class TupleDto { @NotNull + @Schema(example = "{\"key\": \"value\"}") private Map<String, Object> data; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleUpdateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleUpdateDto.java index be50791b944db8eada4316ca6ee975dedf95a113..ab3f1ae8758c69a9bfa0958e9a53e5326d8c91a9 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleUpdateDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/TupleUpdateDto.java @@ -1,5 +1,6 @@ package at.tuwien.api.database.table; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; @@ -17,9 +18,11 @@ import java.util.Map; public class TupleUpdateDto { @NotNull + @Schema(example = "{\"key\": \"value\"}") private Map<String, Object> data; @NotNull + @Schema(example = "{\"id\": 1}") private Map<String, Object> keys; } \ No newline at end of file diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnBriefDto.java index 4dee5f0837148f9c2d1095fdbe12d6ab664672ef..bc13700bdd83dfac5fe23c133509c0184834b7a9 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnBriefDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnBriefDto.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.*; import lombok.extern.jackson.Jacksonized; @@ -18,31 +19,36 @@ import lombok.extern.jackson.Jacksonized; public class ColumnBriefDto { @NotNull + @Schema(example = "1") private Long id; - @JsonProperty("database_id") @NotNull + @Schema(example = "2") + @JsonProperty("database_id") private Long databaseId; - @JsonProperty("table_id") @NotNull + @Schema(example = "3") + @JsonProperty("table_id") private Long tableId; @NotBlank - @Schema(example = "date") + @Size(max = 64) + @Schema(example = "Given Name") private String name; @NotBlank + @Size(max = 64) @JsonProperty("internal_name") - @Schema(example = "mdb_date") + @Schema(example = "given_name") private String internalName; - @Schema + @Schema(example = "firstname") private String alias; @NotNull - @JsonProperty("column_type") - @Schema(example = "date") + @JsonProperty("type") + @Schema(example = "varchar") private ColumnTypeDto columnType; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java index 1f8d3b046e7c6fc6512fc68e53095822a3513061..462821b53c0a8a01a7acb36f15a25641ac895cd8 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java @@ -25,44 +25,49 @@ import java.util.List; public class ColumnDto { @NotNull + @Schema(example = "1") private Long id; @NotNull @JsonProperty("database_id") + @Schema(example = "2") private Long databaseId; @NotNull @JsonProperty("table_id") + @Schema(example = "3") private Long tableId; @NotNull - @Schema(example = "0") @JsonProperty("ord") + @Schema(example = "0") private Integer ordinalPosition; @NotBlank @Size(max = 64) - @Schema(example = "Date") + @Schema(example = "Given Name") private String name; @NotBlank @Size(max = 64) @JsonProperty("internal_name") - @Schema(example = "mdb_date") + @Schema(example = "given_name") private String internalName; - @Schema + @Schema(example = "firstname") private String alias; @JsonProperty("index_length") + @Schema(example = "255") private Long indexLength; @JsonProperty("length") + @Schema(example = "255") private Long length; @NotNull @JsonProperty("type") - @Schema(example = "string") + @Schema(example = "varchar") private ColumnTypeDto columnType; @Schema(example = "255") @@ -114,9 +119,11 @@ public class ColumnDto { @Schema(example = "false") private Boolean isNullAllowed; + @Schema(example = "[\"val1\"]") @Parameter(description = "enum values, only considered when type = ENUM") private List<String> enums; + @Schema(example = "[\"val1\"]") @Parameter(description = "enum values, only considered when type = ENUM") private List<String> sets; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnTypeDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnTypeDto.java index d44b25b84ed4c51075ab4c075433750c4aafca42..a96337082937c085e28957b7768a354dc5ed8dd6 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnTypeDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnTypeDto.java @@ -1,10 +1,12 @@ package at.tuwien.api.database.table.columns; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; /* MYSQL 8 */ @Getter +@Schema public enum ColumnTypeDto { @JsonProperty("char") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/CreateTableColumnDto.java similarity index 97% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnCreateDto.java rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/CreateTableColumnDto.java index ca9bb10569e7bbeb30dd4b8080d0adbbcd2fab75..ca7f3b8d58a3ee08a342b6df0452719c786b863b 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnCreateDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/CreateTableColumnDto.java @@ -18,7 +18,7 @@ import java.util.List; @AllArgsConstructor @Jacksonized @ToString -public class ColumnCreateDto { +public class CreateTableColumnDto { @NotBlank @Schema(example = "Date") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptBriefDto.java index 1e2b36dc66a2f75a846e0ee66cef2037bb8cfd8b..3cc1231c7452aa809ef7ecf4d85244d0c9f400e0 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptBriefDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/ConceptBriefDto.java @@ -1,5 +1,6 @@ package at.tuwien.api.database.table.columns.concepts; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.*; @@ -16,13 +17,17 @@ import lombok.extern.jackson.Jacksonized; public class ConceptBriefDto { @NotNull + @Schema(example = "23") private Long id; @NotBlank + @Schema(example = "http://www.wikidata.org/entity/Q202444") private String uri; + @Schema(example = "given name") private String name; + @Schema(example = "name typically used to differentiate people from the same family, clan, or other social group who have a common last name") private String description; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitBriefDto.java index 407f3708eb7a7fbe2b9746122b1f712858b8cf5e..15d9ae90823e05491b692932af518a768cfc1305 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitBriefDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/concepts/UnitBriefDto.java @@ -1,5 +1,6 @@ package at.tuwien.api.database.table.columns.concepts; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.*; @@ -16,12 +17,16 @@ import lombok.extern.jackson.Jacksonized; public class UnitBriefDto { @NotNull + @Schema(example = "34") private Long id; @NotBlank + @Schema(example = "http://www.wikidata.org/entity/Q1422583") private String uri; + @Schema(example = "importance") private String name; + @Schema(example = "subjective magnitude of value, meaning, or purpose") private String description; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/ConstraintsDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/ConstraintsDto.java index 3cd36f6d687892224e668100e6171552c090b449..b9288b659bb7e2accb18c14e8258f631327d10f3 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/ConstraintsDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/ConstraintsDto.java @@ -4,6 +4,7 @@ import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto; import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto; import at.tuwien.api.database.table.constraints.unique.UniqueDto; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; import lombok.extern.jackson.Jacksonized; @@ -24,6 +25,7 @@ public class ConstraintsDto { @JsonProperty("foreign_keys") private List<ForeignKeyDto> foreignKeys; + @Schema(example = "[\"value > 1\"]") private Set<String> checks; @JsonProperty("primary_key") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/ConstraintsCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/CreateTableConstraintsDto.java similarity index 77% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/ConstraintsCreateDto.java rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/CreateTableConstraintsDto.java index 3d35a20b0c57ae76f2d5fb6c4843e4d46d43ffab..7b223372d2ae0057149e3b9ed95824c7a5baa05d 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/ConstraintsCreateDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/CreateTableConstraintsDto.java @@ -1,6 +1,6 @@ package at.tuwien.api.database.table.constraints; -import at.tuwien.api.database.table.constraints.foreign.ForeignKeyCreateDto; +import at.tuwien.api.database.table.constraints.foreign.CreateForeignKeyDto; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; import lombok.*; @@ -17,14 +17,14 @@ import java.util.Set; @AllArgsConstructor @Jacksonized @ToString -public class ConstraintsCreateDto { +public class CreateTableConstraintsDto { @NotNull private List<List<String>> uniques; @NotNull @JsonProperty("foreign_keys") - private List<ForeignKeyCreateDto> foreignKeys; + private List<CreateForeignKeyDto> foreignKeys; @NotNull private Set<String> checks; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/CreateForeignKeyDto.java similarity index 95% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyCreateDto.java rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/CreateForeignKeyDto.java index 8e2a110997bb257b9414a9780fb29751265cce76..31e43b0c6a4377b59d096f5acf5b6bf43067a295 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyCreateDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/CreateForeignKeyDto.java @@ -14,7 +14,7 @@ import java.util.List; @AllArgsConstructor @Jacksonized @ToString -public class ForeignKeyCreateDto { +public class CreateForeignKeyDto { @NotNull private List<String> columns; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyBriefDto.java index 58a4d5b2453f617297673891f4a879fb02409f10..56dd9863245a51219c1604c43636dd27adea2bd8 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyBriefDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyBriefDto.java @@ -1,5 +1,6 @@ package at.tuwien.api.database.table.constraints.foreign; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; import lombok.extern.jackson.Jacksonized; @@ -12,5 +13,6 @@ import lombok.extern.jackson.Jacksonized; @ToString public class ForeignKeyBriefDto { + @Schema(example = "8") private Long id; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyDto.java index 8016de91316bb0a5cbac30fc4148ecc39acdc33b..254666f9eb6b056501bc08ecebb745c5eac61345 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyDto.java @@ -4,6 +4,7 @@ import at.tuwien.api.database.table.TableBriefDto; import at.tuwien.api.database.table.TableDto; import at.tuwien.api.database.table.columns.ColumnDto; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; @@ -19,9 +20,11 @@ import java.util.List; @ToString public class ForeignKeyDto { + @Schema(example = "4") private Long id; @NotNull + @Schema(example = "fk_name") private String name; @NotNull @@ -35,8 +38,10 @@ public class ForeignKeyDto { private TableBriefDto referencedTable; @JsonProperty("on_update") + @Schema(example = "restrict") private ReferenceTypeDto onUpdate; @JsonProperty("on_delete") + @Schema(example = "restrict") private ReferenceTypeDto onDelete; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyReferenceDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyReferenceDto.java index 55fcc46ecf85fc097eeef7677b9d0c897c612aa3..f0d5b249cdbc41222a5c71c6d41855f1aa5cc5df 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyReferenceDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/foreign/ForeignKeyReferenceDto.java @@ -2,6 +2,7 @@ package at.tuwien.api.database.table.constraints.foreign; import at.tuwien.api.database.table.columns.ColumnBriefDto; import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; @@ -15,6 +16,7 @@ import lombok.extern.jackson.Jacksonized; @ToString public class ForeignKeyReferenceDto { + @Schema(example = "8") private Long id; @NotNull diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/primary/PrimaryKeyDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/primary/PrimaryKeyDto.java index 80df5d443b70146c2ce2cda6e96bbf75c1816e28..86d1d49960d2c9496ce5d23e26fa99edadec344e 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/primary/PrimaryKeyDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/primary/PrimaryKeyDto.java @@ -2,6 +2,7 @@ package at.tuwien.api.database.table.constraints.primary; import at.tuwien.api.database.table.TableBriefDto; import at.tuwien.api.database.table.columns.ColumnBriefDto; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; @@ -15,6 +16,7 @@ import lombok.extern.jackson.Jacksonized; @ToString public class PrimaryKeyDto { + @Schema(example = "8") private Long id; @NotNull diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/unique/UniqueDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/unique/UniqueDto.java index 2bcc9d6cf4fb4d130c398dc2ed0341af46f61df9..755f3a31b7a9634bff74c8992bb384719297c256 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/unique/UniqueDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/constraints/unique/UniqueDto.java @@ -1,13 +1,11 @@ - package at.tuwien.api.database.table.constraints.unique; import at.tuwien.api.database.table.TableBriefDto; -import at.tuwien.api.database.table.TableDto; -import at.tuwien.api.database.table.columns.ColumnDto; +import at.tuwien.api.database.table.columns.ColumnBriefDto; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; -import org.springframework.data.annotation.Id; import java.util.List; @@ -21,14 +19,16 @@ import java.util.List; public class UniqueDto { @NotNull + @Schema(example = "5") private Long id; @NotNull + @Schema(example = "uk_name") private String name; @NotNull private TableBriefDto table; @NotNull - private List<ColumnDto> columns; + private List<ColumnBriefDto> columns; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/internal/PrivilegedTableDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/internal/PrivilegedTableDto.java deleted file mode 100644 index 64b23f17c412c1042c0a1db9a040a67fcc612b39..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/internal/PrivilegedTableDto.java +++ /dev/null @@ -1,115 +0,0 @@ -package at.tuwien.api.database.table.internal; - -import at.tuwien.api.PrivilegedObjectDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.database.table.columns.ColumnDto; -import at.tuwien.api.database.table.constraints.ConstraintsDto; -import at.tuwien.api.identifier.IdentifierDto; -import at.tuwien.api.user.UserBriefDto; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import lombok.*; -import lombok.extern.jackson.Jacksonized; - -import java.time.Instant; -import java.util.List; - -@Getter -@Setter -@Builder -@NoArgsConstructor -@AllArgsConstructor -@Jacksonized -@ToString -@EqualsAndHashCode -public class PrivilegedTableDto extends PrivilegedObjectDto { - - @NotNull - private Long id; - - @NotNull - @JsonProperty("database_id") - private Long tdbid; - - @NotBlank - @Schema(example = "Air Quality") - private String name; - - @NotBlank - @JsonProperty("internal_name") - @Schema(example = "air_quality") - private String internalName; - - @Schema - private String alias; - - private List<IdentifierDto> identifiers; - - @NotNull - @JsonProperty("is_versioned") - @Schema(example = "true") - private Boolean isVersioned; - - @NotNull - @JsonProperty("is_schema_public") - @Schema(example = "true") - private Boolean isSchemaPublic; - - @NotNull - private UserBriefDto owner; - - @NotBlank - @JsonProperty("queue_name") - @Schema(example = "air_quality") - private String queueName; - - @JsonProperty("queue_type") - @Schema(example = "quorum") - private String queueType; - - @NotBlank - @JsonProperty("routing_key") - @Schema(example = "dbrepo.1.2") - private String routingKey; - - @Size(max = 2048) - @Schema(example = "Air Quality in Austria") - private String description; - - @NotNull - @JsonProperty("is_public") - @Schema(example = "true") - private Boolean isPublic; - - @JsonProperty("num_rows") - @Schema(example = "5") - private Long numRows; - - @JsonProperty("data_length") - @Schema(example = "16384", description = "in bytes") - private Long dataLength; - - @JsonProperty("max_data_length") - @Schema(example = "0", description = "in bytes") - private Long maxDataLength; - - @JsonProperty("avg_row_length") - @Schema(example = "3276", description = "in bytes") - private Long avgRowLength; - - @NotNull - private List<ColumnDto> columns; - - @NotNull - private ConstraintsDto constraints; - - @NotNull - private PrivilegedDatabaseDto database; - - @JsonProperty("last_retrieved") - private Instant lastRetrieved; - -} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/internal/TableCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/internal/TableCreateDto.java index 777a870bb9650f0e06b732f0a5776a6768902945..f8db928e8e9bb3d7491e67ea36756b95749a4482 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/internal/TableCreateDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/internal/TableCreateDto.java @@ -1,7 +1,7 @@ package at.tuwien.api.database.table.internal; -import at.tuwien.api.database.table.columns.ColumnCreateDto; -import at.tuwien.api.database.table.constraints.ConstraintsCreateDto; +import at.tuwien.api.database.table.columns.CreateTableColumnDto; +import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; @@ -41,8 +41,8 @@ public class TableCreateDto { private Boolean isSchemaPublic; @NotNull - private List<ColumnCreateDto> columns; + private List<CreateTableColumnDto> columns; @NotNull - private ConstraintsCreateDto constraints; + private CreateTableConstraintsDto constraints; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierCreateDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreateIdentifierDto.java similarity index 84% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierCreateDto.java rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreateIdentifierDto.java index 46eb1bbc7db597e788918745d526ba7dace1ed1b..db55272383828e1bfc0c870f086ecc2c27ecba03 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierCreateDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreateIdentifierDto.java @@ -19,7 +19,7 @@ import java.util.List; @AllArgsConstructor @Jacksonized @ToString -public class IdentifierCreateDto { +public class CreateIdentifierDto { @NotNull @JsonProperty("database_id") @@ -47,11 +47,11 @@ public class IdentifierCreateDto { @NotNull @NotEmpty - private List<IdentifierSaveTitleDto> titles; + private List<SaveIdentifierTitleDto> titles; - private List<IdentifierSaveDescriptionDto> descriptions; + private List<SaveIdentifierDescriptionDto> descriptions; - private List<IdentifierFunderSaveDto> funders; + private List<SaveIdentifierFunderDto> funders; private List<LicenseDto> licenses; @@ -76,9 +76,9 @@ public class IdentifierCreateDto { @NotNull @NotEmpty - private List<CreatorSaveDto> creators; + private List<SaveIdentifierCreatorDto> creators; @JsonProperty("related_identifiers") - private List<RelatedIdentifierSaveDto> relatedIdentifiers; + private List<SaveRelatedIdentifierDto> relatedIdentifiers; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorBriefDto.java new file mode 100644 index 0000000000000000000000000000000000000000..8265a1106bc8daef632f887e9c38c148d765fb01 --- /dev/null +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorBriefDto.java @@ -0,0 +1,53 @@ +package at.tuwien.api.identifier; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.*; +import lombok.extern.jackson.Jacksonized; + + +@Getter +@Setter +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +@Jacksonized +@ToString +public class CreatorBriefDto { + + @NotNull + @Schema(example = "11") + private Long id; + + @NotBlank + @JsonProperty("creator_name") + @Schema(example = "Carberry, Josiah") + private String creatorName; + + @JsonProperty("name_type") + @Schema(example = "Personal") + private NameTypeDto nameType; + + @JsonProperty("name_identifier") + @Schema(example = "0000-0002-1825-0097") + private String nameIdentifier; + + @JsonProperty("name_identifier_scheme") + @Schema(example = "ORCID") + private NameIdentifierSchemeTypeDto nameIdentifierScheme; + + @Schema(example = "Brown University") + private String affiliation; + + @JsonProperty("affiliation_identifier") + @Schema(example = "https://ror.org/05gq02987") + private String affiliationIdentifier; + + @JsonProperty("affiliation_identifier_scheme") + @Schema(example = "ROR") + private AffiliationIdentifierSchemeTypeDto affiliationIdentifierScheme; + +} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorDto.java index 9c166f869c5bcec81c1e67212616e03833fe64c7..a3a2976901aee60e60162788dd10df239206e826 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorDto.java @@ -21,6 +21,7 @@ import org.springframework.data.annotation.Id; public class CreatorDto { @NotNull + @Schema(example = "11") private Long id; @Schema(example = "Josiah") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java index 0a36c561a30a480f14251e1ddab396b8a3fcc9ae..f94edc2cf75421855a8bcd761252e6aba249bb27 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierBriefDto.java @@ -1,6 +1,5 @@ package at.tuwien.api.identifier; -import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; @@ -8,7 +7,6 @@ import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; -import java.time.Instant; import java.util.List; import java.util.UUID; @@ -22,6 +20,7 @@ import java.util.UUID; public class IdentifierBriefDto { @NotNull + @Schema(example = "2") private Long id; @NotNull @@ -42,11 +41,18 @@ public class IdentifierBriefDto { private Long viewId; @NotNull + @Schema(example = "database") private IdentifierTypeDto type; + @NotNull + private List<CreatorBriefDto> creators; + @NotNull private List<IdentifierTitleDto> titles; + @NotNull + private List<IdentifierDescriptionDto> descriptions; + @Schema(example = "10.1038/nphys1170") private String doi; @@ -59,10 +65,13 @@ public class IdentifierBriefDto { @Schema(example = "2022") private Integer publicationYear; + @NotNull + @Schema(example = "draft") private IdentifierStatusTypeDto status; @NotNull - @JsonProperty("created_by") - private UUID createdBy; + @JsonProperty("owned_by") + @Schema(example = "2f45ef7a-7f9b-4667-9156-152c87fe1ca5") + private UUID ownedBy; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDescriptionDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDescriptionDto.java index 55e6ff76214a8af82ec32991c62aa265909d75f6..fbcbb3afe7b6cb9ca27aee16b2875c5ed5d03c1b 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDescriptionDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDescriptionDto.java @@ -19,6 +19,7 @@ import org.springframework.data.annotation.Id; public class IdentifierDescriptionDto { @NotNull + @Schema(example = "3") private Long id; @Schema(example = "Air quality reports at Stephansplatz, Vienna") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDto.java index 87baf4870661e292dbb69d180cfb1be43ac15f16..53d40ecd781169f531a6cf215d370fd69be9d2b0 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierDto.java @@ -25,6 +25,7 @@ import java.util.List; public class IdentifierDto { @NotNull + @Schema(example = "2") private Long id; @NotNull @@ -45,13 +46,16 @@ public class IdentifierDto { private Long viewId; @NotNull + @Schema(example = "database") private IdentifierTypeDto type; @NotNull private List<IdentifierTitleDto> titles; + @NotNull private List<IdentifierDescriptionDto> descriptions; + @NotNull private List<IdentifierFunderDto> funders; @NotBlank @@ -106,13 +110,17 @@ public class IdentifierDto { @Schema(example = "2022") private Integer publicationYear; + @NotNull private LanguageTypeDto language; + @NotNull private List<LicenseDto> licenses; @NotNull private List<CreatorDto> creators; + @NotNull + @Schema(example = "draft") private IdentifierStatusTypeDto status; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierFunderDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierFunderDto.java index 921ba3eb983840dee342071bfde0a75f478946b4..93084d2d17679b94d825600761c1aa03c3b1bdde 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierFunderDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierFunderDto.java @@ -19,6 +19,7 @@ import org.springframework.data.annotation.Id; public class IdentifierFunderDto { @NotNull + @Schema(example = "2") private Long id; @NotBlank diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveDto.java index 8591cdc8c2b6b6c35672c8bf7451652b5a523e61..ed4d445de0ffd2686a84331981d3d5899a4a9b65 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveDto.java @@ -51,11 +51,11 @@ public class IdentifierSaveDto { @NotNull @NotEmpty - private List<IdentifierSaveTitleDto> titles; + private List<SaveIdentifierTitleDto> titles; - private List<IdentifierSaveDescriptionDto> descriptions; + private List<SaveIdentifierDescriptionDto> descriptions; - private List<IdentifierFunderSaveDto> funders; + private List<SaveIdentifierFunderDto> funders; private List<LicenseDto> licenses; @@ -80,9 +80,9 @@ public class IdentifierSaveDto { @NotNull @NotEmpty - private List<CreatorSaveDto> creators; + private List<SaveIdentifierCreatorDto> creators; @JsonProperty("related_identifiers") - private List<RelatedIdentifierSaveDto> relatedIdentifiers; + private List<SaveRelatedIdentifierDto> relatedIdentifiers; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierTitleDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierTitleDto.java index 9333a05ce961a403b84463a10abc86ddb2a2e86c..27e3b323eaca7d9ab481af61059a05fbe576c42d 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierTitleDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierTitleDto.java @@ -19,6 +19,7 @@ import org.springframework.data.annotation.Id; public class IdentifierTitleDto { @NotNull + @Schema(example = "4") private Long id; @Schema(example = "Airquality Demonstrator") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelatedIdentifierDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelatedIdentifierDto.java index 74525bf711988a0690aeba9c403a44156885b0f3..6ff5d9aed1297f5a12755d76d03cc668a273e0e5 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelatedIdentifierDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelatedIdentifierDto.java @@ -24,6 +24,7 @@ import java.time.Instant; public class RelatedIdentifierDto { @NotNull + @Schema(example = "8") private Long id; @NotNull diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorSaveDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierCreatorDto.java similarity index 97% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorSaveDto.java rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierCreatorDto.java index 86d51e7b4cc3d132959f60731acd1352765df20f..c87ff81d3c058edd475d89102c8e29468dae211e 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/CreatorSaveDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierCreatorDto.java @@ -15,7 +15,7 @@ import lombok.extern.jackson.Jacksonized; @AllArgsConstructor @Jacksonized @ToString -public class CreatorSaveDto { +public class SaveIdentifierCreatorDto { @NotNull @Schema(example = "1") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveDescriptionDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierDescriptionDto.java similarity index 94% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveDescriptionDto.java rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierDescriptionDto.java index 76f4f4b7bc1ff6e4763ec0e57f3de9ca1a1e125c..1d251db634d4f1a6cb0b369013c113aae69f1968 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveDescriptionDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierDescriptionDto.java @@ -15,7 +15,7 @@ import lombok.extern.jackson.Jacksonized; @AllArgsConstructor @Jacksonized @ToString -public class IdentifierSaveDescriptionDto { +public class SaveIdentifierDescriptionDto { @NotNull @Schema(example = "1") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierFunderSaveDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierFunderDto.java similarity index 96% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierFunderSaveDto.java rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierFunderDto.java index 81fd7c91ab44c0f1b89d18656c214fdc50958e38..89bea57a1cf5c69a4184fae5edc3d77f8062bb39 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierFunderSaveDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierFunderDto.java @@ -14,7 +14,7 @@ import lombok.extern.jackson.Jacksonized; @AllArgsConstructor @Jacksonized @ToString -public class IdentifierFunderSaveDto { +public class SaveIdentifierFunderDto { @NotNull @Schema(example = "1") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveTitleDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierTitleDto.java similarity index 95% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveTitleDto.java rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierTitleDto.java index 9da7e7ec8b7d61f35fe963b2e651c2662e7353e9..0832a77cee0323db7220cf88ff295982fee2c0a1 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/IdentifierSaveTitleDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveIdentifierTitleDto.java @@ -15,7 +15,7 @@ import lombok.extern.jackson.Jacksonized; @AllArgsConstructor @Jacksonized @ToString -public class IdentifierSaveTitleDto { +public class SaveIdentifierTitleDto { @NotNull @Schema(example = "1") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelatedIdentifierSaveDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveRelatedIdentifierDto.java similarity index 93% rename from dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelatedIdentifierSaveDto.java rename to dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveRelatedIdentifierDto.java index f72d5b02d29d038233031365b7172c93da567b5d..b3a95eee06fe4cc0cb91fb8df822e52c3f507221 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/RelatedIdentifierSaveDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/identifier/SaveRelatedIdentifierDto.java @@ -13,7 +13,7 @@ import jakarta.validation.constraints.NotNull; @AllArgsConstructor @Jacksonized @ToString -public class RelatedIdentifierSaveDto { +public class SaveRelatedIdentifierDto { @NotNull @Schema(example = "1") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/ModifyUserDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/ModifyUserDto.java new file mode 100644 index 0000000000000000000000000000000000000000..26d700e798e1517ae484dc60e9359bd8b5646965 --- /dev/null +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/ModifyUserDto.java @@ -0,0 +1,26 @@ +package at.tuwien.api.keycloak; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import lombok.*; +import lombok.extern.jackson.Jacksonized; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Jacksonized +@ToString +public class ModifyUserDto { + + @JsonProperty("firstName") + private String firstname; + + @JsonProperty("lastName") + private String lastname; + + @NotNull + private UserAttributesDto attributes; + +} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserAttributesDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserAttributesDto.java index 027955ba77b69fd708c1c18463c1a92d09c93c95..50718bc8034d500c2d707abacac58acf2bb95012 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserAttributesDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserAttributesDto.java @@ -16,12 +16,20 @@ import java.util.UUID; @ToString public class UserAttributesDto { - @Schema(example = "s3cr3t") - @JsonProperty("LDAP_ENTRY_DN") - private String[] ldapEntryDn; + @Schema(example = "dark") + @JsonProperty("THEME") + private String[] theme; - @Schema(example = "false") - @JsonProperty("LDAP_ID") - private UUID[] ldapId; + @Schema(example = "en") + @JsonProperty("LANGUAGE") + private String[] language; + + @Schema(example = "https://ror.org/04d836q62") + @JsonProperty("AFFILIATION") + private String[] affiliation; + + @Schema(example = "https://orcid.org/0000-0003-4216-302X") + @JsonProperty("ORCID") + private String[] orcid; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserDto.java deleted file mode 100644 index a2d7811ab0aa334a4f3a5d49916428b58166317b..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserDto.java +++ /dev/null @@ -1,52 +0,0 @@ -package at.tuwien.api.keycloak; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotNull; -import lombok.*; -import lombok.extern.jackson.Jacksonized; - -import java.util.UUID; - -@Getter -@Setter -@Builder -@NoArgsConstructor -@AllArgsConstructor -@Jacksonized -@ToString -public class UserDto { - - @NotNull - private UUID id; - - @NotNull - @Schema(example = "jcarberry", description = "Only contains lowercase characters") - private String username; - - @NotNull - @Schema(example = "true") - private Boolean enabled; - - @NotNull - @Schema(example = "false") - private Boolean totp; - - @NotNull - @JsonProperty("emailVerified") - @Schema(example = "false") - private Boolean emailVerified; - - @NotNull - @Schema(example = "jcarberry@brown.edu") - private String email; - - @NotNull - @JsonProperty("notBefore") - @Schema(example = "0") - private Long notBefore; - - @NotNull - private UserAttributesDto attributes; - -} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserIdAttributesDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserIdAttributesDto.java new file mode 100644 index 0000000000000000000000000000000000000000..3155d75f027d2864f2a06ecf19376c13c9be7d35 --- /dev/null +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/keycloak/UserIdAttributesDto.java @@ -0,0 +1,27 @@ +package at.tuwien.api.keycloak; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.extern.jackson.Jacksonized; + +import java.util.UUID; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Jacksonized +@ToString +public class UserIdAttributesDto { + + @Schema(example = "s3cr3t") + @JsonProperty("LDAP_ENTRY_DN") + private String[] ldapEntryDn; + + @Schema(example = "false") + @JsonProperty("LDAP_ID") + private UUID[] ldapId; + +} diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedSourceTypeDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedSourceTypeDto.java index 78b87e33212ab48ba2e37a583100eea780c459e7..f883a034f55bd5f04d3059f8eb50ef50a3867c79 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedSourceTypeDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/orcid/activities/employments/affiliation/group/summary/organization/disambiguated/OrcidDisambiguatedSourceTypeDto.java @@ -1,5 +1,6 @@ package at.tuwien.api.orcid.activities.employments.affiliation.group.summary.organization.disambiguated; public enum OrcidDisambiguatedSourceTypeDto { - RINGGOLD + RINGGOLD, + ROR } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDetailsDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDetailsDto.java index cd5e8fd3e0cefe2f016261470b1236e9a3442b16..2ab170d616c75c40d4be36af42854d518d3ec7c5 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDetailsDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDetailsDto.java @@ -1,6 +1,5 @@ package at.tuwien.api.user; -import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; @@ -30,10 +29,6 @@ public class UserDetailsDto implements UserDetails { @ToString.Exclude private String password; - @NotNull - @Email - private String email; - @Override public boolean isAccountNonExpired() { return true; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDto.java index 343d582b55da3af324aa23fd31ef61d8e1cd564d..e7367e2fb4e513a9681783dfdec89b55e57519e0 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/UserDto.java @@ -1,33 +1,40 @@ package at.tuwien.api.user; +import at.tuwien.api.CacheableDto; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.*; import lombok.extern.jackson.Jacksonized; +import java.time.Instant; import java.util.UUID; @Getter @Setter @Builder -@EqualsAndHashCode +@EqualsAndHashCode(callSuper = true) @NoArgsConstructor @AllArgsConstructor @Jacksonized @ToString -public class UserDto { +public class UserDto extends CacheableDto { @NotNull @Schema(example = "1ffc7b0e-9aeb-4e8b-b8f1-68f3936155b4") private UUID id; + @Schema(example = "Josiah Carberry") + private String name; + @NotNull - @Schema(example = "jcarberry", description = "Only contains lowercase characters") + @Schema(example = "username") private String username; - @Schema(example = "Josiah Carberry") - private String name; + @NotNull + @ToString.Exclude + @Schema(example = "p4ssw0rd") + private String password; @JsonProperty("qualified_name") @Schema(example = "Josiah Carberry — @jcarberry") @@ -44,4 +51,10 @@ public class UserDto { @NotNull private UserAttributesDto attributes; + /* lombok limitations prevent from convenient builder functions */ + + @JsonProperty("last_retrieved") + @Schema(example = "2025-01-23T12:09:01") + private Instant lastRetrieved; + } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/internal/PrivilegedUserDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/internal/PrivilegedUserDto.java deleted file mode 100644 index 56e24cd81590261137cfa3d4f0f3c45399d80e70..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/user/internal/PrivilegedUserDto.java +++ /dev/null @@ -1,58 +0,0 @@ -package at.tuwien.api.user.internal; - -import at.tuwien.api.PrivilegedObjectDto; -import at.tuwien.api.user.UserAttributesDto; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import lombok.*; -import lombok.extern.jackson.Jacksonized; - -import java.time.Instant; -import java.util.UUID; - -@Getter -@Setter -@Builder -@EqualsAndHashCode -@NoArgsConstructor -@AllArgsConstructor -@Jacksonized -@ToString -public class PrivilegedUserDto extends PrivilegedObjectDto { - - @NotNull - @Schema(example = "1ffc7b0e-9aeb-4e8b-b8f1-68f3936155b4") - private UUID id; - - @NotBlank - @Schema(example = "jcarberry", description = "Only contains lowercase characters") - private String username; - - @NotBlank - @Schema(example = "jcarberry") - private String password; - - @Schema(example = "Josiah Carberry") - private String name; - - @JsonProperty("qualified_name") - @Schema(example = "Josiah Carberry — @jcarberry") - private String qualifiedName; - - @JsonProperty("given_name") - @Schema(example = "Josiah") - private String firstname; - - @JsonProperty("family_name") - @Schema(example = "Carberry") - private String lastname; - - @NotNull - private UserAttributesDto attributes; - - @JsonProperty("last_retrieved") - private Instant lastRetrieved; - -} diff --git a/dbrepo-metadata-service/entities/pom.xml b/dbrepo-metadata-service/entities/pom.xml index 5b1c1d0cf133fcfea9de76e37cc0462d318481b6..1967b24868d61e29351b34c8608c6f428bc316f9 100644 --- a/dbrepo-metadata-service/entities/pom.xml +++ b/dbrepo-metadata-service/entities/pom.xml @@ -6,12 +6,12 @@ <parent> <groupId>at.tuwien</groupId> <artifactId>dbrepo-metadata-service</artifactId> - <version>1.6.1</version> + <version>1.6.3</version> </parent> <artifactId>dbrepo-metadata-service-entities</artifactId> <name>dbrepo-metadata-service-entity</name> - <version>1.6.1</version> + <version>1.6.3</version> <dependencies/> diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/user/User.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/user/User.java index fd87852c6ecce0e2e614a9c7dd05a5e41cfe2e16..ba86e3d29c6913d45d51ae0498fdac8d3092b657 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/user/User.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/user/User.java @@ -30,6 +30,10 @@ public class User { @Column(name = "ID", nullable = false, columnDefinition = "VARCHAR(36)") private UUID id; + @JdbcTypeCode(java.sql.Types.VARCHAR) + @Column(name = "keycloak_id", nullable = false, columnDefinition = "VARCHAR(36)") + private UUID keycloakId; + @Column(nullable = false) private String username; @@ -39,9 +43,6 @@ public class User { @Column private String lastname; - @Column(nullable = false) - private String email; - @Column private String orcid; diff --git a/dbrepo-metadata-service/metrics.md b/dbrepo-metadata-service/metrics.md index 56a69c68f6913ab2e3ea192cde66f329ea336e10..f3e0a3130f23e149a54f1eca8247c559443809da 100644 --- a/dbrepo-metadata-service/metrics.md +++ b/dbrepo-metadata-service/metrics.md @@ -59,8 +59,6 @@ | `dbrepo_user_find` | Get user | | `dbrepo_user_modify` | Update user | | `dbrepo_user_password_modify` | Update user password | -| `dbrepo_user_refresh_token` | Refresh token | -| `dbrepo_user_token` | Create token | | `dbrepo_users_list` | List users | | `dbrepo_view_create` | Create view | | `dbrepo_view_delete` | Delete view | diff --git a/dbrepo-metadata-service/oai/pom.xml b/dbrepo-metadata-service/oai/pom.xml index a3778f036317625e12a6b526a7f1fafadbe237f6..b6db9e69674d52ae557644b94b7eb5302563c86f 100644 --- a/dbrepo-metadata-service/oai/pom.xml +++ b/dbrepo-metadata-service/oai/pom.xml @@ -6,12 +6,12 @@ <parent> <groupId>at.tuwien</groupId> <artifactId>dbrepo-metadata-service</artifactId> - <version>1.6.1</version> + <version>1.6.3</version> </parent> <artifactId>dbrepo-metadata-service-oai</artifactId> <name>dbrepo-metadata-service-oai</name> - <version>1.6.1</version> + <version>1.6.3</version> <dependencies/> diff --git a/dbrepo-metadata-service/pom.xml b/dbrepo-metadata-service/pom.xml index 2803d9b5f39ddd69f34151251083c35e8a46b406..5dd6ce3318f7cb88a16c9c6ecc60c8d4c5ff5aa2 100644 --- a/dbrepo-metadata-service/pom.xml +++ b/dbrepo-metadata-service/pom.xml @@ -11,7 +11,7 @@ <groupId>at.tuwien</groupId> <artifactId>dbrepo-metadata-service</artifactId> <name>dbrepo-metadata-service</name> - <version>1.6.1</version> + <version>1.6.3</version> <description>Service that manages the metadata</description> @@ -27,7 +27,7 @@ <module>report</module> </modules> - <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.5/</url> + <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6/</url> <developers> <developer> <name>Martin Weise</name> @@ -52,7 +52,7 @@ <apache-jena.version>4.10.0</apache-jena.version> <opencsv.version>5.7.1</opencsv.version> <super-csv.version>2.4.0</super-csv.version> - <keycloak.version>21.0.2</keycloak.version> + <keycloak.version>26.0.4</keycloak.version> <springdoc-openapi.version>2.3.0</springdoc-openapi.version> <testcontainers.version>1.19.1</testcontainers.version> <jackson.version>2.15.2</jackson.version> @@ -187,6 +187,11 @@ <artifactId>keycloak-common</artifactId> <version>${keycloak.version}</version> </dependency> + <dependency> + <groupId>org.keycloak</groupId> + <artifactId>keycloak-admin-client</artifactId> + <version>${keycloak.version}</version> + </dependency> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> diff --git a/dbrepo-metadata-service/report/pom.xml b/dbrepo-metadata-service/report/pom.xml index 6234a844d2c89c01c7e3d200ce79397ac99eac37..8d4d32c15d3e50cb65ba2300c58d25dcbb87eebd 100644 --- a/dbrepo-metadata-service/report/pom.xml +++ b/dbrepo-metadata-service/report/pom.xml @@ -6,12 +6,12 @@ <parent> <artifactId>dbrepo-metadata-service</artifactId> <groupId>at.tuwien</groupId> - <version>1.6.1</version> + <version>1.6.3</version> </parent> <artifactId>dbrepo-metadata-service-report</artifactId> <name>dbrepo-metadata-service-report</name> - <version>1.6.1</version> + <version>1.6.3</version> <dependencies> <dependency> diff --git a/dbrepo-metadata-service/repositories/pom.xml b/dbrepo-metadata-service/repositories/pom.xml index 44fde031c181fa559abdbce4b81e59f76c5f4b48..57f89e7ed46587a564e57536d05b79fc1e5cb121 100644 --- a/dbrepo-metadata-service/repositories/pom.xml +++ b/dbrepo-metadata-service/repositories/pom.xml @@ -6,12 +6,12 @@ <parent> <artifactId>dbrepo-metadata-service</artifactId> <groupId>at.tuwien</groupId> - <version>1.6.1</version> + <version>1.6.3</version> </parent> <artifactId>dbrepo-metadata-service-repositories</artifactId> <name>dbrepo-metadata-service-repositories</name> - <version>1.6.1</version> + <version>1.6.3</version> <dependencies> <dependency> diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java index c5482f70411433f5df08bd0281a60c75d132bf26..cfbf858000ae4b2e58be5999c3c98123cc70582c 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java @@ -1,26 +1,25 @@ package at.tuwien.mapper; -import at.tuwien.api.auth.SignupRequestDto; import at.tuwien.api.container.ContainerBriefDto; -import at.tuwien.api.container.ContainerCreateDto; import at.tuwien.api.container.ContainerDto; +import at.tuwien.api.container.CreateContainerDto; import at.tuwien.api.container.image.DataTypeDto; import at.tuwien.api.container.image.ImageBriefDto; import at.tuwien.api.container.image.ImageCreateDto; import at.tuwien.api.container.image.ImageDto; import at.tuwien.api.crossref.CrossrefDto; import at.tuwien.api.database.*; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; import at.tuwien.api.database.table.TableBriefDto; import at.tuwien.api.database.table.TableDto; -import at.tuwien.api.database.table.columns.ColumnCreateDto; +import at.tuwien.api.database.table.columns.ColumnBriefDto; import at.tuwien.api.database.table.columns.ColumnDto; +import at.tuwien.api.database.table.columns.CreateTableColumnDto; import at.tuwien.api.database.table.columns.concepts.ConceptDto; import at.tuwien.api.database.table.columns.concepts.ConceptSaveDto; import at.tuwien.api.database.table.columns.concepts.UnitDto; import at.tuwien.api.database.table.columns.concepts.UnitSaveDto; -import at.tuwien.api.database.table.constraints.ConstraintsCreateDto; import at.tuwien.api.database.table.constraints.ConstraintsDto; +import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto; import at.tuwien.api.database.table.constraints.foreign.ForeignKeyBriefDto; import at.tuwien.api.database.table.constraints.foreign.ForeignKeyDto; import at.tuwien.api.database.table.constraints.foreign.ForeignKeyReferenceDto; @@ -31,9 +30,7 @@ import at.tuwien.api.datacite.doi.*; import at.tuwien.api.identifier.*; import at.tuwien.api.identifier.ld.LdCreatorDto; import at.tuwien.api.identifier.ld.LdDatasetDto; -import at.tuwien.api.keycloak.CredentialDto; -import at.tuwien.api.keycloak.CredentialTypeDto; -import at.tuwien.api.keycloak.UpdateCredentialsDto; +import at.tuwien.api.keycloak.TokenDto; import at.tuwien.api.keycloak.UserCreateDto; import at.tuwien.api.maintenance.BannerMessageBriefDto; import at.tuwien.api.maintenance.BannerMessageCreateDto; @@ -50,8 +47,8 @@ import at.tuwien.api.semantics.OntologyBriefDto; import at.tuwien.api.semantics.OntologyCreateDto; import at.tuwien.api.semantics.OntologyDto; import at.tuwien.api.user.UserBriefDto; -import at.tuwien.api.user.UserDetailsDto; import at.tuwien.api.user.UserDto; +import at.tuwien.api.user.UserUpdateDto; import at.tuwien.api.user.external.ExternalMetadataDto; import at.tuwien.api.user.external.ExternalResultType; import at.tuwien.api.user.external.affiliation.ExternalAffiliationDto; @@ -74,6 +71,8 @@ import at.tuwien.entities.maintenance.BannerMessage; import at.tuwien.entities.maintenance.BannerMessageType; import at.tuwien.entities.semantics.Ontology; import at.tuwien.entities.user.User; +import org.keycloak.representations.AccessTokenResponse; +import org.keycloak.representations.idm.UserRepresentation; import org.mapstruct.*; import java.text.Normalizer; @@ -97,6 +96,16 @@ public interface MetadataMapper { }) DataTypeDto dataTypeToDataTypeDto(DataType data); + @Mappings({ + @Mapping(target = "attributes", ignore = true) + }) + UserRepresentation userCreateDtoToUserRepresentation(UserCreateDto data); + + @Mappings({ + @Mapping(target = "accessToken", source = "token") + }) + TokenDto accessTokenResponseToTokenDto(AccessTokenResponse data); + BannerMessageDto bannerMessageToBannerMessageDto(BannerMessage data); BannerMessageBriefDto bannerMessageToBannerMessageBriefDto(BannerMessage data); @@ -110,7 +119,17 @@ public interface MetadataMapper { @Mappings({ @Mapping(target = "internalName", source = "name", qualifiedByName = "internalMapping") }) - Container containerCreateRequestDtoToContainer(ContainerCreateDto data); + Container containerCreateRequestDtoToContainer(CreateContainerDto data); + + UserUpdateDto userToUserUpdateDto(User data); + + default List<String> optionalValueToMap(String value) { + final List<String> attr = new LinkedList<>(); + if (value != null) { + attr.add(value); + } + return attr; + } ContainerDto containerToContainerDto(Container data); @@ -120,7 +139,10 @@ public interface MetadataMapper { }) ContainerBriefDto containerToContainerBriefDto(Container data); - PrivilegedDatabaseDto databaseToPrivilegedDatabaseDto(Database data); + @Mappings({ + @Mapping(target = "previewImage", expression = "java(database.getImage() != null ? \"/api/database/\" + database.getId() + \"/image\" : null)") + }) + DatabaseDto databaseToDatabaseDto(Database database); @Mappings({ @Mapping(target = "titles", source = "."), @@ -300,7 +322,8 @@ public interface MetadataMapper { IdentifierDto identifierToIdentifierDto(Identifier data); @Mappings({ - @Mapping(target = "databaseId", source = "database.id") + @Mapping(target = "databaseId", source = "database.id"), + @Mapping(target = "ownedBy", source = "owner.id") }) IdentifierBriefDto identifierToIdentifierBriefDto(Identifier data); @@ -359,19 +382,19 @@ public interface MetadataMapper { .build(); } - Identifier identifierCreateDtoToIdentifier(IdentifierCreateDto data); + Identifier identifierCreateDtoToIdentifier(CreateIdentifierDto data); Identifier identifierUpdateDtoToIdentifier(IdentifierSaveDto data); License licenseDtoToLicense(LicenseDto data); - IdentifierTitle identifierCreateTitleDtoToIdentifierTitle(IdentifierSaveTitleDto data); + IdentifierTitle identifierCreateTitleDtoToIdentifierTitle(SaveIdentifierTitleDto data); - IdentifierDescription identifierCreateDescriptionDtoToIdentifierDescription(IdentifierSaveDescriptionDto data); + IdentifierDescription identifierCreateDescriptionDtoToIdentifierDescription(SaveIdentifierDescriptionDto data); - IdentifierFunder identifierFunderSaveDtoToIdentifierFunder(IdentifierFunderSaveDto data); + IdentifierFunder identifierFunderSaveDtoToIdentifierFunder(SaveIdentifierFunderDto data); - IdentifierSaveDto identifierCreateDtoToIdentifierSaveDto(IdentifierCreateDto data); + IdentifierSaveDto identifierCreateDtoToIdentifierSaveDto(CreateIdentifierDto data); RelatedIdentifierDto relatedIdentifierToRelatedIdentifierDto(RelatedIdentifier data); @@ -385,12 +408,14 @@ public interface MetadataMapper { @Mapping(target = "nameIdentifierSchemeUri", source = "nameIdentifierScheme", qualifiedByName = "nameSchemaMapper"), @Mapping(target = "affiliationIdentifierSchemeUri", source = "affiliationIdentifierScheme", qualifiedByName = "affiliationSchemaMapper"), }) - Creator creatorCreateDtoToCreator(CreatorSaveDto data); + Creator creatorCreateDtoToCreator(SaveIdentifierCreatorDto data); - RelatedIdentifier relatedIdentifierCreateDtoToRelatedIdentifier(RelatedIdentifierSaveDto data); + RelatedIdentifier relatedIdentifierCreateDtoToRelatedIdentifier(SaveRelatedIdentifierDto data); IdentifierType identifierTypeDtoToIdentifierType(IdentifierTypeDto data); + IdentifierStatusType identifierStatusTypeDtoToIdentifierStatusType(IdentifierStatusTypeDto data); + default String identifierToLocationUrl(String baseUrl, Identifier data) { if (data.getType().equals(IdentifierType.SUBSET)) { return baseUrl + "/database/" + data.getDatabase().getId() + "/subset/" + data.getQueryId() + "/info?pid=" + data.getId(); @@ -490,7 +515,7 @@ public interface MetadataMapper { .name(data.getName()) .columns(data.getColumns() .stream() - .map(this::tableColumnToColumnDto) + .map(this::tableColumnToColumnBriefDto) .toList()) .table(tableToTableBriefDto(data.getTable())) .build(); @@ -531,7 +556,7 @@ public interface MetadataMapper { .build(); } - default TableDto customTableToTableDto(Table data) { + default TableDto tableToTableDto(Table data) { final TableDto table = TableDto.builder() .id(data.getId()) .name(data.getName()) @@ -544,6 +569,10 @@ public interface MetadataMapper { .description(data.getDescription()) .identifiers(new LinkedList<>()) .columns(new LinkedList<>()) + .database(databaseToDatabaseDto(data.getDatabase() + .toBuilder() + .tables(null) + .build())) .constraints(constraintsToConstraintsDto(data.getConstraints())) .build(); if (data.getIdentifiers() != null) { @@ -620,7 +649,8 @@ public interface MetadataMapper { Unique uniqueDtoToUnique(UniqueDto data); @Mappings({ - @Mapping(target = "ownedBy", source = "owner.id") + @Mapping(target = "ownedBy", source = "owner.id"), + @Mapping(target = "database", ignore = true) }) Table tableDtoToTable(TableDto data); @@ -629,7 +659,7 @@ public interface MetadataMapper { ReferenceType referenceTypeDtoToReferenceType(ReferenceTypeDto data); /* keep */ - default Constraints constraintsCreateDtoToConstraints(ConstraintsCreateDto data, Database database, Table table) { + default Constraints constraintsCreateDtoToConstraints(CreateTableConstraintsDto data, Database database, Table table) { final int[] idx = new int[]{0, 0}; final Constraints constrains = Constraints.builder() .checks(data.getChecks()) @@ -723,6 +753,12 @@ public interface MetadataMapper { }) ColumnDto tableColumnToColumnDto(TableColumn data); + @Mappings({ + @Mapping(target = "tableId", source = "table.id"), + @Mapping(target = "databaseId", source = "table.database.id") + }) + ColumnBriefDto tableColumnToColumnBriefDto(TableColumn data); + @Mappings({ @Mapping(target = "id", expression = "java(null)"), @Mapping(target = "columnType", source = "data.type"), @@ -730,41 +766,7 @@ public interface MetadataMapper { @Mapping(target = "name", source = "data.name"), @Mapping(target = "internalName", expression = "java(nameToInternalName(data.getName()))"), }) - TableColumn columnCreateDtoToTableColumn(ColumnCreateDto data, ContainerImage image); - - default UpdateCredentialsDto passwordToUpdateCredentialsDto(String password) { - return UpdateCredentialsDto.builder() - .credentials(List.of(CredentialDto.builder() - .temporary(false) - .type(CredentialTypeDto.PASSWORD) - .value(password) - .build())) - .build(); - } - - default UserCreateDto signupRequestDtoToUserCreateDto(SignupRequestDto data) { - return UserCreateDto.builder() - .username(data.getUsername()) - .email(data.getEmail()) - .credentials(List.of(CredentialDto.builder() - .type(CredentialTypeDto.PASSWORD) - .temporary(false) - .value(data.getPassword()) - .build())) - .enabled(true) - .build(); - } - - /* keep */ - UserBriefDto keycloakUserDtoToUserBriefDto(at.tuwien.api.keycloak.UserDto data); - - /* keep */ - @Mappings({ - @Mapping(target = "id", expression = "java(data.getId().toString())") - }) - UserDetailsDto userDtoToUserDetailsDto(UserDto data); - - User userDtoToUser(at.tuwien.api.keycloak.UserDto data); + TableColumn columnCreateDtoToTableColumn(CreateTableColumnDto data, ContainerImage image); /* keep */ @Mappings({ @@ -773,8 +775,6 @@ public interface MetadataMapper { }) UserBriefDto userToUserBriefDto(User data); - UserBriefDto userDtoToUserBriefDto(UserDto data); - /* keep */ @Mappings({ @Mapping(target = "attributes.language", source = "language"), @@ -787,9 +787,6 @@ public interface MetadataMapper { }) UserDto userToUserDto(User data); - /* keep */ - User userDtoToUserDto(UserDto data); - /* keep */ @Named("userToFullName") default String userToFullName(User data) { @@ -822,6 +819,10 @@ public interface MetadataMapper { .trim(); } + @Mappings({ + @Mapping(target = "database.views", ignore = true), + @Mapping(target = "database.tables", ignore = true) + }) ViewDto viewToViewDto(View data); @Mappings({ @@ -831,6 +832,9 @@ public interface MetadataMapper { ViewBriefDto viewToViewBriefDto(View data); + @Mappings({ + @Mapping(target = "database", ignore = true) + }) View viewDtoToView(ViewDto data); /* keep */ @@ -852,60 +856,7 @@ public interface MetadataMapper { LanguageType languageTypeDtoToLanguageType(LanguageTypeDto data); - default DatabaseDto customDatabaseToDatabaseDto(Database data) { - if (data == null) { - return null; - } - final DatabaseDto database = DatabaseDto.builder() - .id(data.getId()) - .name(data.getName()) - .internalName(data.getInternalName()) - .description(data.getDescription()) - .exchangeName(data.getExchangeName()) - .previewImage(data.getImage() != null ? "/api/database/" + data.getId() + "/image" : null) - .isPublic(data.getIsPublic()) - .isSchemaPublic(data.getIsSchemaPublic()) - .container(containerToContainerBriefDto(data.getContainer())) - .owner(userToUserBriefDto(data.getOwner())) - .contact(userToUserBriefDto(data.getContact())) - .subsets(new LinkedList<>()) - .accesses(new LinkedList<>()) - .tables(new LinkedList<>()) - .identifiers(new LinkedList<>()) - .build(); - if (data.getSubsets() != null) { - database.setSubsets(new LinkedList<>(data.getSubsets() - .stream() - .map(this::identifierToIdentifierBriefDto) - .toList())); - } - if (data.getTables() != null) { - database.setTables(new LinkedList<>(data.getTables() - .stream() - .map(this::tableToTableBriefDto) - .toList())); - } - if (data.getViews() != null) { - database.setViews(new LinkedList<>(data.getViews() - .stream() - .map(this::viewToViewBriefDto) - .toList())); - } - if (data.getAccesses() != null) { - database.setAccesses(new LinkedList<>(data.getAccesses() - .stream() - .filter(a -> !a.getUser().getIsInternal()) - .map(this::databaseAccessToDatabaseAccessDto) - .toList())); - } - if (data.getIdentifiers() != null) { - database.setIdentifiers(new LinkedList<>(data.getIdentifiers() - .stream() - .map(this::identifierToIdentifierBriefDto) - .toList())); - } - return database; - } + DatabaseBriefDto databaseDtoToDatabaseBriefDto(DatabaseDto data); @Mappings({ @Mapping(target = "ownerId", source = "owner.id") diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/UserRepository.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/UserRepository.java index 7415fb422c03882f7f71786b0edf756c7bd58159..30f2f20c1670f550f7463265f1d2d6afde967777 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/UserRepository.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/repository/UserRepository.java @@ -17,7 +17,5 @@ public interface UserRepository extends JpaRepository<User, UUID> { boolean existsByUsername(String username); - boolean existsByEmail(String email); - } diff --git a/dbrepo-metadata-service/rest-service/pom.xml b/dbrepo-metadata-service/rest-service/pom.xml index 233d2ac4658612ad06bccc5140bad70c08265ec5..ff5966688771f30a93b2ce4d95bc99ab6aa0a83f 100644 --- a/dbrepo-metadata-service/rest-service/pom.xml +++ b/dbrepo-metadata-service/rest-service/pom.xml @@ -6,12 +6,12 @@ <parent> <artifactId>dbrepo-metadata-service</artifactId> <groupId>at.tuwien</groupId> - <version>1.6.1</version> + <version>1.6.3</version> </parent> <artifactId>dbrepo-metadata-service-rest-service</artifactId> <name>dbrepo-metadata-service-rest</name> - <version>1.6.1</version> + <version>1.6.3</version> <dependencies> <dependency> diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/config/MvcConfig.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/config/MvcConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..6bdb80973176bc7ae5722b932e7f7b1a2a183d45 --- /dev/null +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/config/MvcConfig.java @@ -0,0 +1,16 @@ +package at.tuwien.config; + +import at.tuwien.converters.IdentifierStatusTypeDtoConverter; +import at.tuwien.converters.IdentifierTypeDtoConverter; +import org.springframework.context.annotation.Configuration; +import org.springframework.format.FormatterRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class MvcConfig implements WebMvcConfigurer { + @Override + public void addFormatters(FormatterRegistry registry) { + registry.addConverter(new IdentifierStatusTypeDtoConverter()); + registry.addConverter(new IdentifierTypeDtoConverter()); + } +} \ No newline at end of file diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierStatusTypeDtoConverter.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierStatusTypeDtoConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..96e67f63d2bb85bb0aaebd02237a2d8aaa6ecdfa --- /dev/null +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierStatusTypeDtoConverter.java @@ -0,0 +1,14 @@ +package at.tuwien.converters; + +import at.tuwien.api.identifier.IdentifierStatusTypeDto; +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Component; + +@Component +public class IdentifierStatusTypeDtoConverter implements Converter<String, IdentifierStatusTypeDto> { + + @Override + public IdentifierStatusTypeDto convert(String source) { + return IdentifierStatusTypeDto.valueOf(source.toUpperCase()); + } +} diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeConverter.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeDtoConverter.java similarity index 79% rename from dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeConverter.java rename to dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeDtoConverter.java index b3f52c4377989a1380c6be42b46ce96f1d902163..61e169604fa2cf1e10c464fdb1d1bc310ea7f125 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeConverter.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/converters/IdentifierTypeDtoConverter.java @@ -5,7 +5,7 @@ import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; @Component -public class IdentifierTypeConverter implements Converter<String, IdentifierTypeDto> { +public class IdentifierTypeDtoConverter implements Converter<String, IdentifierTypeDto> { @Override public IdentifierTypeDto convert(String source) { diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AbstractEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AbstractEndpoint.java index 4779a6428e33bde6be581921a9d15bd81a25c5b6..7ec1471f4d1f110e9d6eefff902b6190a4dbde5b 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AbstractEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AbstractEndpoint.java @@ -1,10 +1,8 @@ package at.tuwien.endpoints; +import at.tuwien.api.container.ContainerDto; import at.tuwien.api.user.UserDetailsDto; -import at.tuwien.exception.UserNotFoundException; -import at.tuwien.service.UserService; import org.springframework.security.core.Authentication; -import org.springframework.security.core.userdetails.User; import java.security.Principal; import java.util.UUID; @@ -45,4 +43,11 @@ public abstract class AbstractEndpoint { throw new IllegalArgumentException("Unknown principal instance: " + authentication.getPrincipal().getClass()); } + public void removeInternalData(ContainerDto container) { + container.setPassword(null); + container.setUsername(null); + container.setHost(null); + container.setPort(null); + } + } diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java index f184ffc3372ac10e35f2d6686b0c79e2ecaca818..9c109c87d68664793b3033d7be123d71a7b02d69 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/AccessEndpoint.java @@ -1,7 +1,7 @@ package at.tuwien.endpoints; import at.tuwien.api.database.DatabaseAccessDto; -import at.tuwien.api.database.UpdateDatabaseAccessDto; +import at.tuwien.api.database.CreateAccessDto; import at.tuwien.api.error.ApiErrorDto; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.DatabaseAccess; @@ -91,7 +91,7 @@ public class AccessEndpoint extends AbstractEndpoint { }) public ResponseEntity<DatabaseAccessDto> create(@NotNull @PathVariable("databaseId") Long databaseId, @PathVariable("userId") UUID userId, - @Valid @RequestBody UpdateDatabaseAccessDto data, + @Valid @RequestBody CreateAccessDto data, @NotNull Principal principal) throws NotAllowedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException, SearchServiceException, SearchServiceConnectionException { @@ -153,7 +153,7 @@ public class AccessEndpoint extends AbstractEndpoint { }) public ResponseEntity<Void> update(@NotNull @PathVariable("databaseId") Long databaseId, @PathVariable("userId") UUID userId, - @Valid @RequestBody UpdateDatabaseAccessDto data, + @Valid @RequestBody CreateAccessDto data, @NotNull Principal principal) throws NotAllowedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException, SearchServiceException, SearchServiceConnectionException { diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java index 3c506cfd0a910d10bba6401eebe5467d1c97e738..b5d153318cc9688d13784a80df41c6f28a862de3 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerEndpoint.java @@ -1,7 +1,7 @@ package at.tuwien.endpoints; import at.tuwien.api.container.ContainerBriefDto; -import at.tuwien.api.container.ContainerCreateDto; +import at.tuwien.api.container.CreateContainerDto; import at.tuwien.api.container.ContainerDto; import at.tuwien.api.error.ApiErrorDto; import at.tuwien.entities.container.Container; @@ -105,7 +105,7 @@ public class ContainerEndpoint extends AbstractEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<ContainerDto> create(@Valid @RequestBody ContainerCreateDto data) + public ResponseEntity<ContainerDto> create(@Valid @RequestBody CreateContainerDto data) throws ImageNotFoundException, ContainerAlreadyExistsException { log.debug("endpoint create container, data={}", data); return ResponseEntity.status(HttpStatus.CREATED) diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java index ad72fb0756f20fac58bc717c0da601f9b5bb1c74..50016103d83ccfffab65ddc153e6b88074e34e2c 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/DatabaseEndpoint.java @@ -5,8 +5,6 @@ import at.tuwien.api.error.ApiErrorDto; import at.tuwien.entities.container.Container; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.DatabaseAccess; -import at.tuwien.entities.database.View; -import at.tuwien.entities.database.table.Table; import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.mapper.MetadataMapper; @@ -73,7 +71,7 @@ public class DatabaseEndpoint extends AbstractEndpoint { @Header(name = "Access-Control-Expose-Headers", description = "Expose `X-Count` custom header", schema = @Schema(implementation = String.class), required = true)}, content = {@Content( mediaType = "application/json", - array = @ArraySchema(schema = @Schema(implementation = DatabaseDto.class)))}), + array = @ArraySchema(schema = @Schema(implementation = DatabaseBriefDto.class)))}), }) public ResponseEntity<List<DatabaseBriefDto>> list(@RequestParam(name = "internal_name", required = false) String internalName, Principal principal) { @@ -118,7 +116,7 @@ public class DatabaseEndpoint extends AbstractEndpoint { description = "Created a new database", content = {@Content( mediaType = "application/json", - schema = @Schema(implementation = DatabaseDto.class))}), + schema = @Schema(implementation = DatabaseBriefDto.class))}), @ApiResponse(responseCode = "400", description = "Database create query is malformed or image is not supported", content = {@Content( @@ -155,8 +153,8 @@ public class DatabaseEndpoint extends AbstractEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<DatabaseDto> create(@Valid @RequestBody DatabaseCreateDto data, - @NotNull Principal principal) throws DataServiceException, + public ResponseEntity<DatabaseBriefDto> create(@Valid @RequestBody CreateDatabaseDto data, + @NotNull Principal principal) throws DataServiceException, DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, ContainerNotFoundException, SearchServiceException, SearchServiceConnectionException, ContainerQuotaException { @@ -168,8 +166,8 @@ public class DatabaseEndpoint extends AbstractEndpoint { } final User caller = userService.findById(getId(principal)); return ResponseEntity.status(HttpStatus.CREATED) - .body(databaseMapper.customDatabaseToDatabaseDto( - databaseService.create(container, data, caller, userService.findAllInternalUsers()))); + .body(databaseMapper.databaseDtoToDatabaseBriefDto(databaseMapper.databaseToDatabaseDto( + databaseService.create(container, data, caller, userService.findAllInternalUsers())))); } @PutMapping("/{databaseId}/metadata/table") @@ -184,7 +182,7 @@ public class DatabaseEndpoint extends AbstractEndpoint { description = "Refreshed database tables metadata", content = {@Content( mediaType = "application/json", - schema = @Schema(implementation = DatabaseDto.class))}), + schema = @Schema(implementation = DatabaseBriefDto.class))}), @ApiResponse(responseCode = "400", description = "Failed to parse payload at search service", content = {@Content( @@ -196,7 +194,7 @@ public class DatabaseEndpoint extends AbstractEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), @ApiResponse(responseCode = "404", - description = "Failed to fin user/database in metadata database", + description = "Failed to find database in metadata database", content = {@Content( mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), @@ -211,9 +209,9 @@ public class DatabaseEndpoint extends AbstractEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<DatabaseDto> refreshTableMetadata(@NotNull @PathVariable("databaseId") Long databaseId, - @NotNull Principal principal) throws DataServiceException, - DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, UserNotFoundException, + public ResponseEntity<DatabaseBriefDto> refreshTableMetadata(@NotNull @PathVariable("databaseId") Long databaseId, + @NotNull Principal principal) throws DataServiceException, + DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException, NotAllowedException, QueryNotFoundException, MalformedException, TableNotFoundException { log.debug("endpoint refresh database metadata, databaseId={}", databaseId); @@ -222,8 +220,8 @@ public class DatabaseEndpoint extends AbstractEndpoint { log.error("Failed to refresh database tables metadata: not owner"); throw new NotAllowedException("Failed to refresh tables metadata: not owner"); } - return ResponseEntity.ok(databaseMapper.customDatabaseToDatabaseDto( - databaseService.updateTableMetadata(database))); + return ResponseEntity.ok(databaseMapper.databaseDtoToDatabaseBriefDto(databaseMapper.databaseToDatabaseDto( + databaseService.updateTableMetadata(database)))); } @PutMapping("/{databaseId}/metadata/view") @@ -238,7 +236,7 @@ public class DatabaseEndpoint extends AbstractEndpoint { description = "Refreshed database views metadata", content = {@Content( mediaType = "application/json", - schema = @Schema(implementation = DatabaseDto.class))}), + schema = @Schema(implementation = DatabaseBriefDto.class))}), @ApiResponse(responseCode = "403", description = "Refresh view metadata is not permitted", content = {@Content( @@ -260,9 +258,9 @@ public class DatabaseEndpoint extends AbstractEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<DatabaseDto> refreshViewMetadata(@NotNull @PathVariable("databaseId") Long databaseId, - @NotNull Principal principal) throws DataServiceException, - DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, UserNotFoundException, + public ResponseEntity<DatabaseBriefDto> refreshViewMetadata(@NotNull @PathVariable("databaseId") Long databaseId, + @NotNull Principal principal) throws DataServiceException, + DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException, NotAllowedException, QueryNotFoundException, ViewNotFoundException { log.debug("endpoint refresh database metadata, databaseId={}, principal.name={}", databaseId, principal.getName()); final Database database = databaseService.findById(databaseId); @@ -270,8 +268,8 @@ public class DatabaseEndpoint extends AbstractEndpoint { log.error("Failed to refresh database views metadata: not owner"); throw new NotAllowedException("Failed to refresh database views metadata: not owner"); } - return ResponseEntity.ok(databaseMapper.customDatabaseToDatabaseDto( - databaseService.updateViewMetadata(database))); + return ResponseEntity.ok(databaseMapper.databaseDtoToDatabaseBriefDto(databaseMapper.databaseToDatabaseDto( + databaseService.updateViewMetadata(database)))); } @PutMapping("/{databaseId}/visibility") @@ -286,7 +284,7 @@ public class DatabaseEndpoint extends AbstractEndpoint { description = "Visibility modified successfully", content = {@Content( mediaType = "application/json", - schema = @Schema(implementation = DatabaseDto.class))}), + schema = @Schema(implementation = DatabaseBriefDto.class))}), @ApiResponse(responseCode = "400", description = "The visibility payload is malformed", content = {@Content( @@ -313,9 +311,9 @@ public class DatabaseEndpoint extends AbstractEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<DatabaseDto> visibility(@NotNull @PathVariable("databaseId") Long databaseId, - @Valid @RequestBody DatabaseModifyVisibilityDto data, - @NotNull Principal principal) throws DatabaseNotFoundException, + public ResponseEntity<DatabaseBriefDto> visibility(@NotNull @PathVariable("databaseId") Long databaseId, + @Valid @RequestBody DatabaseModifyVisibilityDto data, + @NotNull Principal principal) throws DatabaseNotFoundException, NotAllowedException, SearchServiceException, SearchServiceConnectionException, UserNotFoundException { log.debug("endpoint modify database visibility, databaseId={}, data={}", databaseId, data); final Database database = databaseService.findById(databaseId); @@ -324,8 +322,8 @@ public class DatabaseEndpoint extends AbstractEndpoint { throw new NotAllowedException("Failed to modify database visibility: not owner"); } return ResponseEntity.accepted() - .body(databaseMapper.customDatabaseToDatabaseDto( - databaseService.modifyVisibility(database, data))); + .body(databaseMapper.databaseDtoToDatabaseBriefDto(databaseMapper.databaseToDatabaseDto( + databaseService.modifyVisibility(database, data)))); } @PutMapping("/{databaseId}/owner") @@ -340,7 +338,7 @@ public class DatabaseEndpoint extends AbstractEndpoint { description = "Transfer of ownership was successful", content = {@Content( mediaType = "application/json", - schema = @Schema(implementation = DatabaseDto.class))}), + schema = @Schema(implementation = DatabaseBriefDto.class))}), @ApiResponse(responseCode = "400", description = "Owner payload is malformed", content = {@Content( @@ -367,9 +365,9 @@ public class DatabaseEndpoint extends AbstractEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<DatabaseDto> transfer(@NotNull @PathVariable("databaseId") Long databaseId, - @Valid @RequestBody DatabaseTransferDto data, - @NotNull Principal principal) throws NotAllowedException, + public ResponseEntity<DatabaseBriefDto> transfer(@NotNull @PathVariable("databaseId") Long databaseId, + @Valid @RequestBody DatabaseTransferDto data, + @NotNull Principal principal) throws NotAllowedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, SearchServiceException, SearchServiceConnectionException { log.debug("endpoint transfer database, databaseId={}, transferDto.id={}", databaseId, data.getId()); @@ -380,8 +378,8 @@ public class DatabaseEndpoint extends AbstractEndpoint { throw new NotAllowedException("Failed to transfer database: not owner"); } return ResponseEntity.accepted() - .body(databaseMapper.customDatabaseToDatabaseDto( - databaseService.modifyOwner(database, newOwner))); + .body(databaseMapper.databaseDtoToDatabaseBriefDto(databaseMapper.databaseToDatabaseDto( + databaseService.modifyOwner(database, newOwner)))); } @PutMapping("/{databaseId}/image") @@ -396,7 +394,7 @@ public class DatabaseEndpoint extends AbstractEndpoint { description = "Modify of image was successful", content = {@Content( mediaType = "application/json", - schema = @Schema(implementation = DatabaseDto.class))}), + schema = @Schema(implementation = DatabaseBriefDto.class))}), @ApiResponse(responseCode = "403", description = "Modify of image is not permitted", content = {@Content( @@ -423,9 +421,9 @@ public class DatabaseEndpoint extends AbstractEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<DatabaseDto> modifyImage(@NotNull @PathVariable("databaseId") Long databaseId, - @Valid @RequestBody DatabaseModifyImageDto data, - @NotNull Principal principal) throws NotAllowedException, + public ResponseEntity<DatabaseBriefDto> modifyImage(@NotNull @PathVariable("databaseId") Long databaseId, + @Valid @RequestBody DatabaseModifyImageDto data, + @NotNull Principal principal) throws NotAllowedException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException, StorageUnavailableException, StorageNotFoundException { log.debug("endpoint modify database image, databaseId={}, data.key={}", databaseId, data.getKey()); @@ -439,8 +437,8 @@ public class DatabaseEndpoint extends AbstractEndpoint { image = storageService.getBytes(data.getKey()); } return ResponseEntity.accepted() - .body(databaseMapper.customDatabaseToDatabaseDto( - databaseService.modifyImage(database, image))); + .body(databaseMapper.databaseDtoToDatabaseBriefDto(databaseMapper.databaseToDatabaseDto( + databaseService.modifyImage(database, image)))); } @GetMapping("/{databaseId}/image") @@ -480,7 +478,7 @@ public class DatabaseEndpoint extends AbstractEndpoint { @Header(name = "Access-Control-Expose-Headers", description = "Expose custom headers", schema = @Schema(implementation = String.class))}, content = {@Content( mediaType = "application/json", - schema = @Schema(implementation = DatabaseDto.class))}), + schema = @Schema(implementation = DatabaseBriefDto.class))}), @ApiResponse(responseCode = "403", description = "Not allowed to view database", content = {@Content( @@ -515,7 +513,7 @@ public class DatabaseEndpoint extends AbstractEndpoint { .findFirst(); if (!database.getIsPublic() && !database.getIsSchemaPublic() && optional.isEmpty() && !isSystem(principal)) { log.error("Failed to find database: not public and no access found"); - throw new DatabaseNotFoundException("Failed to find database: not public and no access found"); + throw new NotAllowedException("Failed to find database: not public and no access found"); } /* reduce metadata */ database.setTables(database.getTables() @@ -536,24 +534,26 @@ public class DatabaseEndpoint extends AbstractEndpoint { throw new NotAllowedException("Failed to find database: not public and not authenticated"); } /* reduce metadata */ - database.setTables(database.getTables() - .stream() - .filter(t -> t.getIsPublic() || t.getIsSchemaPublic()) - .toList()); - database.setViews(database.getViews() - .stream() - .filter(v -> v.getIsPublic() || v.getIsSchemaPublic()) - .toList()); + database.getTables() + .removeAll(database.getTables() + .stream() + .filter(t -> !t.getIsPublic() && !t.getIsSchemaPublic()) + .toList()); + database.getViews() + .removeAll(database.getViews() + .stream() + .filter(v -> !v.getIsPublic() && !v.getIsSchemaPublic()) + .toList()); database.setAccesses(List.of()); } - final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(database); + final DatabaseDto dto = databaseMapper.databaseToDatabaseDto(database); final HttpHeaders headers = new HttpHeaders(); if (isSystem(principal)) { headers.set("X-Username", database.getContainer().getPrivilegedUsername()); headers.set("X-Password", database.getContainer().getPrivilegedPassword()); - headers.set("X-Host", database.getContainer().getHost()); - headers.set("X-Port", "" + database.getContainer().getPort()); - headers.set("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port"); + headers.set("Access-Control-Expose-Headers", "X-Username X-Password"); + } else { + removeInternalData(dto.getContainer()); } return ResponseEntity.status(HttpStatus.OK) .headers(headers) diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java index 2830f9714a62cb7fea0b0cf616b4bd54eff8d340..b3d699086ee93b943801a3139a2e2488dc9dcc8c 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/IdentifierEndpoint.java @@ -73,7 +73,7 @@ public class IdentifierEndpoint extends AbstractEndpoint { this.identifierService = identifierService; } - @GetMapping(produces = {MediaType.APPLICATION_JSON_VALUE, "application/ld+json"}) + @GetMapping @Transactional(readOnly = true) @Observed(name = "dbrepo_identifier_list") @Operation(summary = "List identifiers", @@ -87,48 +87,41 @@ public class IdentifierEndpoint extends AbstractEndpoint { @Content(mediaType = "application/ld+json", array = @ArraySchema(schema = @Schema(implementation = LdDatasetDto.class))) }), - @ApiResponse(responseCode = "406", - description = "Identifier could not be exported, the requested style is not known", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<?> findAll(@Valid @RequestParam(value = "dbid", required = false) Long dbid, + public ResponseEntity<?> findAll(@Valid @RequestParam(value = "type", required = false) IdentifierTypeDto type, + @Valid @RequestParam(value = "status", required = false) IdentifierStatusTypeDto status, + @Valid @RequestParam(value = "dbid", required = false) Long dbid, @Valid @RequestParam(value = "qid", required = false) Long qid, @Valid @RequestParam(value = "vid", required = false) Long vid, @Valid @RequestParam(value = "tid", required = false) Long tid, - @RequestHeader(HttpHeaders.ACCEPT) String accept) - throws FormatNotAvailableException { - log.debug("endpoint find identifiers, dbid={}, qid={}, vid={}, tid={}, accept={}", dbid, qid, vid, tid, accept); + @RequestHeader(HttpHeaders.ACCEPT) String accept, + Principal principal) { + log.debug("endpoint find identifiers, type={}, status={}, dbid={}, qid={}, vid={}, tid={}, accept={}", type, + status, dbid, qid, vid, tid, accept); final List<Identifier> identifiers = identifierService.findAll() .stream() + .filter(i -> !Objects.nonNull(type) || metadataMapper.identifierTypeDtoToIdentifierType(type).equals(i.getType())) + .filter(i -> !Objects.nonNull(status) || metadataMapper.identifierStatusTypeDtoToIdentifierStatusType(status).equals(i.getStatus())) .filter(i -> !Objects.nonNull(dbid) || dbid.equals(i.getDatabase().getId())) .filter(i -> !Objects.nonNull(qid) || qid.equals(i.getQueryId())) .filter(i -> !Objects.nonNull(vid) || vid.equals(i.getViewId())) .filter(i -> !Objects.nonNull(tid) || tid.equals(i.getTableId())) + .filter(i -> principal != null && i.getStatus().equals(IdentifierStatusType.DRAFT) ? i.getOwnedBy().equals(getId(principal)) : i.getStatus().equals(IdentifierStatusType.PUBLISHED)) .toList(); if (identifiers.isEmpty()) { return ResponseEntity.ok(List.of()); } log.trace("found persistent identifiers {}", identifiers); - return switch (accept) { - case "application/json" -> { - log.trace("accept header matches json"); - yield ResponseEntity.ok(identifiers.stream() - .map(metadataMapper::identifierToIdentifierBriefDto) - .toList()); - } - case "application/ld+json" -> { - log.trace("accept header matches json-ld"); - yield ResponseEntity.ok(identifiers.stream() - .map(i -> metadataMapper.identifierToLdDatasetDto(i, endpointConfig.getWebsiteUrl())) - .toList()); - } - default -> { - log.error("accept header {} is not supported", accept); - throw new FormatNotAvailableException("Must provide either application/json or application/ld+json headers"); - } - }; + if (accept.equals("application/ld+json")) { + log.trace("accept header matches json-ld"); + return ResponseEntity.ok(identifiers.stream() + .map(i -> metadataMapper.identifierToLdDatasetDto(i, endpointConfig.getWebsiteUrl())) + .toList()); + } + log.trace("default to json"); + return ResponseEntity.ok(identifiers.stream() + .map(metadataMapper::identifierToIdentifierBriefDto) + .toList()); } @GetMapping(value = "/{identifierId}", produces = {MediaType.APPLICATION_JSON_VALUE, "application/ld+json", @@ -156,6 +149,11 @@ public class IdentifierEndpoint extends AbstractEndpoint { content = {@Content( mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), + @ApiResponse(responseCode = "403", + description = "Not allowed to view identifier", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), @ApiResponse(responseCode = "404", description = "Identifier could not be found", content = {@Content( @@ -188,14 +186,23 @@ public class IdentifierEndpoint extends AbstractEndpoint { schema = @Schema(implementation = ApiErrorDto.class))}), }) public ResponseEntity<?> find(@Valid @PathVariable("identifierId") Long identifierId, - @RequestHeader(HttpHeaders.ACCEPT) String accept) throws IdentifierNotFoundException, + @RequestHeader(HttpHeaders.ACCEPT) String accept, + Principal principal) throws IdentifierNotFoundException, DataServiceException, DataServiceConnectionException, MalformedException, FormatNotAvailableException, - QueryNotFoundException { + QueryNotFoundException, NotAllowedException { log.debug("endpoint find identifier, identifierId={}, accept={}", identifierId, accept); if (accept == null) { accept = ""; } final Identifier identifier = identifierService.find(identifierId); + if (identifier.getStatus().equals(IdentifierStatusType.DRAFT)) { + if (principal == null) { + throw new NotAllowedException("Draft identifier: authentication required"); + } + if (!identifier.getOwnedBy().equals(getId(principal))) { + throw new NotAllowedException("Draft identifier: not authorized"); + } + } log.info("Found persistent identifier with id: {}", identifier.getId()); switch (accept) { case "application/json": @@ -475,7 +482,7 @@ public class IdentifierEndpoint extends AbstractEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<IdentifierDto> create(@NotNull @Valid @RequestBody IdentifierCreateDto data, + public ResponseEntity<IdentifierDto> create(@NotNull @Valid @RequestBody CreateIdentifierDto data, @NotNull Principal principal) throws DatabaseNotFoundException, UserNotFoundException, NotAllowedException, MalformedException, DataServiceConnectionException, SearchServiceException, DataServiceException, QueryNotFoundException, SearchServiceConnectionException, 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 9f4542fc023f8aaf336fc2de196d0c36ab93cea4..08535fde69a20f162ea3d4478110d9360db55f99 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 @@ -1,7 +1,7 @@ package at.tuwien.endpoints; import at.tuwien.api.database.table.TableBriefDto; -import at.tuwien.api.database.table.TableCreateDto; +import at.tuwien.api.database.table.CreateTableDto; import at.tuwien.api.database.table.TableDto; import at.tuwien.api.database.table.TableUpdateDto; import at.tuwien.api.database.table.columns.ColumnDto; @@ -358,9 +358,9 @@ public class TableEndpoint extends AbstractEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<TableDto> create(@NotNull @PathVariable("databaseId") Long databaseId, - @NotNull @Valid @RequestBody TableCreateDto data, - @NotNull Principal principal) throws NotAllowedException, MalformedException, + public ResponseEntity<TableBriefDto> create(@NotNull @PathVariable("databaseId") Long databaseId, + @NotNull @Valid @RequestBody CreateTableDto data, + @NotNull Principal principal) throws NotAllowedException, MalformedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException, TableNotFoundException, TableExistsException, SearchServiceException, SearchServiceConnectionException, OntologyNotFoundException, SemanticEntityNotFoundException { @@ -370,7 +370,7 @@ public class TableEndpoint extends AbstractEndpoint { endpointValidator.validateOnlyAccess(database, principal, true); endpointValidator.validateColumnCreateConstraints(data); return ResponseEntity.status(HttpStatus.CREATED) - .body(metadataMapper.customTableToTableDto( + .body(metadataMapper.tableToTableBriefDto( tableService.createTable(database, data, principal))); } @@ -413,10 +413,10 @@ public class TableEndpoint extends AbstractEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<TableDto> update(@NotNull @PathVariable("databaseId") Long databaseId, - @NotNull @PathVariable("tableId") Long tableId, - @NotNull @Valid @RequestBody TableUpdateDto data, - @NotNull Principal principal) throws NotAllowedException, + public ResponseEntity<TableBriefDto> update(@NotNull @PathVariable("databaseId") Long databaseId, + @NotNull @PathVariable("tableId") Long tableId, + @NotNull @Valid @RequestBody TableUpdateDto data, + @NotNull Principal principal) throws NotAllowedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, TableNotFoundException, SearchServiceException, SearchServiceConnectionException { log.debug("endpoint update table, databaseId={}, data.is_public={}, data.is_schema_public={}, principal.name={}", @@ -428,7 +428,7 @@ public class TableEndpoint extends AbstractEndpoint { throw new NotAllowedException("Failed to update table: not owner"); } return ResponseEntity.accepted() - .body(metadataMapper.customTableToTableDto( + .body(metadataMapper.tableToTableBriefDto( tableService.updateTable(table, data))); } @@ -443,11 +443,6 @@ public class TableEndpoint extends AbstractEndpoint { description = "Find table successfully", headers = {@Header(name = "X-Username", description = "The authentication username", schema = @Schema(implementation = String.class)), @Header(name = "X-Password", description = "The authentication password", schema = @Schema(implementation = String.class)), - @Header(name = "X-Host", description = "The database hostname", schema = @Schema(implementation = String.class)), - @Header(name = "X-Port", description = "The database port number", schema = @Schema(implementation = Integer.class)), - @Header(name = "X-Type", description = "The JDBC connection type", schema = @Schema(implementation = String.class)), - @Header(name = "X-Database", description = "The database internal name", schema = @Schema(implementation = String.class)), - @Header(name = "X-Table", description = "The table internal name", schema = @Schema(implementation = String.class)), @Header(name = "Access-Control-Expose-Headers", description = "Expose custom headers", schema = @Schema(implementation = String.class))}, content = {@Content( mediaType = "application/json", @@ -500,20 +495,18 @@ public class TableEndpoint extends AbstractEndpoint { table.setColumns(List.of()); table.setConstraints(null); } + final TableDto dto = metadataMapper.tableToTableDto(table); final HttpHeaders headers = new HttpHeaders(); if (isSystem(principal)) { headers.set("X-Username", table.getDatabase().getContainer().getPrivilegedUsername()); headers.set("X-Password", table.getDatabase().getContainer().getPrivilegedPassword()); - headers.set("X-Host", table.getDatabase().getContainer().getHost()); - headers.set("X-Port", "" + table.getDatabase().getContainer().getPort()); - headers.set("X-Type", table.getDatabase().getContainer().getImage().getJdbcMethod()); - headers.set("X-Database", table.getDatabase().getInternalName()); - headers.set("X-Table", table.getInternalName()); - headers.set("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port X-Type X-Database X-Table"); + headers.set("Access-Control-Expose-Headers", "X-Username X-Password"); + } else { + removeInternalData(dto.getDatabase().getContainer()); } return ResponseEntity.ok() .headers(headers) - .body(metadataMapper.customTableToTableDto(table)); + .body(dto); } @DeleteMapping("/{tableId}") diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java index 5a349ff3782f1c94a4aea6f4d609f3402437b9c0..51f323c30f1581314df88dab86ec2900775c215e 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/UserEndpoint.java @@ -1,10 +1,7 @@ package at.tuwien.endpoints; -import at.tuwien.api.auth.LoginRequestDto; -import at.tuwien.api.auth.RefreshTokenRequestDto; -import at.tuwien.api.auth.SignupRequestDto; +import at.tuwien.api.auth.CreateUserDto; import at.tuwien.api.error.ApiErrorDto; -import at.tuwien.api.keycloak.TokenDto; import at.tuwien.api.user.UserBriefDto; import at.tuwien.api.user.UserDto; import at.tuwien.api.user.UserPasswordDto; @@ -95,10 +92,11 @@ public class UserEndpoint extends AbstractEndpoint { @PostMapping @Transactional(rollbackFor = {Exception.class}) - @PreAuthorize("!isAuthenticated()") + @PreAuthorize("hasAuthority('system')") @Observed(name = "dbrepo_user_create") @Operation(summary = "Create user", - description = "Creates a user in the auth service and metadata database. Requires that no credentials are sent in the request.") + description = "This webhook is called from the auth service to add a user to the metadata database. Requires role `system`.", + hidden = true) @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Created user", @@ -139,117 +137,13 @@ public class UserEndpoint extends AbstractEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<UserDto> create(@NotNull @Valid @RequestBody SignupRequestDto data) + public ResponseEntity<UserBriefDto> create(@NotNull @Valid @RequestBody CreateUserDto data) throws UserExistsException, EmailExistsException, AuthServiceException, AuthServiceConnectionException, UserNotFoundException, CredentialsInvalidException { - log.debug("endpoint create user, data.username={}", data.getUsername()); - userService.validateUsernameNotExists(data.getUsername()); - userService.validateEmailNotExists(data.getEmail()); + log.debug("endpoint create user, data.id={}, data.username={}", data.getId(), data.getUsername()); return ResponseEntity.status(HttpStatus.CREATED) - .body(userMapper.userToUserDto( - userService.create(data, authenticationService.create(data).getAttributes().getLdapId()[0]))); - } - - @PostMapping("/token") - @Observed(name = "dbrepo_user_token") - @Operation(summary = "Create token", - description = "Creates a user token via the Auth Service.") - @ApiResponses(value = { - @ApiResponse(responseCode = "202", - description = "Obtained user token", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = TokenDto.class))}), - @ApiResponse(responseCode = "400", - description = "Invalid login request", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = ApiErrorDto.class))}), - @ApiResponse(responseCode = "403", - description = "Not allowed to get token", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = ApiErrorDto.class))}), - @ApiResponse(responseCode = "404", - description = "Failed to find user in auth database", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = ApiErrorDto.class))}), - @ApiResponse(responseCode = "428", - description = "Account is not fully setup in auth service (requires password change?)", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = ApiErrorDto.class))}), - @ApiResponse(responseCode = "502", - description = "Connection to auth service failed", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = ApiErrorDto.class))}), - @ApiResponse(responseCode = "503", - description = "Failed to get user in auth service", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = ApiErrorDto.class))}), - }) - public ResponseEntity<TokenDto> getToken(@NotNull @Valid @RequestBody LoginRequestDto data) - throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException, CredentialsInvalidException, - AccountNotSetupException { - log.debug("endpoint get token, data.username={}", data.getUsername()); - /* check */ - try { - userService.findByUsername(data.getUsername()); - } catch (UserNotFoundException e) { - /* need to sync */ - log.warn("User with username {} does not exist in metadata database yet", data.getUsername()); - final SignupRequestDto request = SignupRequestDto.builder() - .username(data.getUsername()) - .email("noreply@example.com") - .password(data.getPassword()) - .build(); - final at.tuwien.api.keycloak.UserDto user = authenticationService.findByUsername(data.getUsername()); - if (user.getAttributes().getLdapId() == null || user.getAttributes().getLdapId().length != 1) { - log.error("Failed to map ldap id for user with username: {}", data.getUsername()); - throw new UserNotFoundException("Failed to map ldap id"); - } - userService.create(request, user.getAttributes().getLdapId()[0]); - log.info("Patched missing user information for user with username: {}", data.getUsername()); - } - return ResponseEntity.accepted() - .body(authenticationService.obtainToken(data)); - } - - @PutMapping("/token") - @Observed(name = "dbrepo_user_refresh_token") - @Operation(summary = "Refresh token", - description = "Refreshes user token by refresh token.") - @ApiResponses(value = { - @ApiResponse(responseCode = "202", - description = "Refreshed user token", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = TokenDto.class))}), - @ApiResponse(responseCode = "400", - description = "Invalid refresh token", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = ApiErrorDto.class))}), - @ApiResponse(responseCode = "403", - description = "Not allowed", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = ApiErrorDto.class))}), - @ApiResponse(responseCode = "502", - description = "Connection to auth service failed", - content = {@Content( - mediaType = "application/json", - schema = @Schema(implementation = ApiErrorDto.class))}), - }) - public ResponseEntity<TokenDto> refreshToken(@NotNull @Valid @RequestBody RefreshTokenRequestDto data) - throws AuthServiceConnectionException, CredentialsInvalidException { - log.debug("endpoint refresh token"); - /* check */ - return ResponseEntity.accepted() - .body(authenticationService.refreshToken(data.getRefreshToken())); + .body(userMapper.userToUserBriefDto( + userService.create(data))); } @GetMapping("/{userId}") @@ -327,11 +221,16 @@ public class UserEndpoint extends AbstractEndpoint { content = {@Content( mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), + @ApiResponse(responseCode = "503", + description = "Failed to modify user at auth service", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<UserDto> modify(@NotNull @PathVariable("userId") UUID userId, - @NotNull @Valid @RequestBody UserUpdateDto data, - @NotNull Principal principal) throws NotAllowedException, - UserNotFoundException, DatabaseNotFoundException { + public ResponseEntity<UserBriefDto> modify(@NotNull @PathVariable("userId") UUID userId, + @NotNull @Valid @RequestBody UserUpdateDto data, + @NotNull Principal principal) throws NotAllowedException, + UserNotFoundException, AuthServiceException { log.debug("endpoint modify a user, userId={}, data={}", userId, data); final User user = userService.findById(userId); if (!user.getId().equals(getId(principal))) { @@ -339,7 +238,7 @@ public class UserEndpoint extends AbstractEndpoint { throw new NotAllowedException("Failed to modify user: not current user " + user.getId()); } return ResponseEntity.accepted() - .body(userMapper.userToUserDto( + .body(userMapper.userToUserBriefDto( userService.modify(user, data))); } @@ -381,9 +280,9 @@ public class UserEndpoint extends AbstractEndpoint { }) public ResponseEntity<Void> password(@NotNull @PathVariable("userId") UUID userId, @NotNull @Valid @RequestBody UserPasswordDto data, - @NotNull Principal principal) throws NotAllowedException, AuthServiceException, - AuthServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, DataServiceException, - DataServiceConnectionException, CredentialsInvalidException { + @NotNull Principal principal) throws NotAllowedException, + UserNotFoundException, DatabaseNotFoundException, DataServiceException, + DataServiceConnectionException { log.debug("endpoint modify a user password, userId={}, principal.name={}", userId, principal.getName()); final User user = userService.findById(userId); if (!user.getUsername().equals(principal.getName())) { diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java index 8a4a087da20e4578a40801ac670a7ed5a3826521..e8b40de8b2bfa05f9901a01ce0e269fbbffefe41 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java @@ -1,7 +1,7 @@ package at.tuwien.endpoints; import at.tuwien.api.database.ViewBriefDto; -import at.tuwien.api.database.ViewCreateDto; +import at.tuwien.api.database.CreateViewDto; import at.tuwien.api.database.ViewDto; import at.tuwien.api.database.ViewUpdateDto; import at.tuwien.api.error.ApiErrorDto; @@ -137,7 +137,7 @@ public class ViewEndpoint extends AbstractEndpoint { schema = @Schema(implementation = ApiErrorDto.class))}), }) public ResponseEntity<ViewBriefDto> create(@NotNull @PathVariable("databaseId") Long databaseId, - @NotNull @Valid @RequestBody ViewCreateDto data, + @NotNull @Valid @RequestBody CreateViewDto data, @NotNull Principal principal) throws NotAllowedException, MalformedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, UserNotFoundException, SearchServiceException, SearchServiceConnectionException { @@ -202,9 +202,13 @@ public class ViewEndpoint extends AbstractEndpoint { headers.set("X-View", view.getInternalName()); headers.set("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port X-Type X-Database X-View"); } + final ViewDto dto = metadataMapper.viewToViewDto(view); + if (!isSystem(principal)) { + removeInternalData(dto.getDatabase().getContainer()); + } return ResponseEntity.status(HttpStatus.OK) .headers(headers) - .body(metadataMapper.viewToViewDto(view)); + .body(dto); } @DeleteMapping("/{viewId}") @@ -248,9 +252,9 @@ public class ViewEndpoint extends AbstractEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<?> delete(@NotNull @PathVariable("databaseId") Long databaseId, - @NotNull @PathVariable("viewId") Long viewId, - @NotNull Principal principal) throws NotAllowedException, DataServiceException, + public ResponseEntity<Void> delete(@NotNull @PathVariable("databaseId") Long databaseId, + @NotNull @PathVariable("viewId") Long viewId, + @NotNull Principal principal) throws NotAllowedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, ViewNotFoundException, SearchServiceException, SearchServiceConnectionException, UserNotFoundException { log.debug("endpoint delete view, databaseId={}, viewId={}", databaseId, viewId); @@ -301,10 +305,10 @@ public class ViewEndpoint extends AbstractEndpoint { mediaType = "application/json", schema = @Schema(implementation = ApiErrorDto.class))}), }) - public ResponseEntity<ViewDto> update(@NotNull @PathVariable("databaseId") Long databaseId, - @NotNull @PathVariable("viewId") Long viewId, - @NotNull @Valid @RequestBody ViewUpdateDto data, - @NotNull Principal principal) throws NotAllowedException, + public ResponseEntity<ViewBriefDto> update(@NotNull @PathVariable("databaseId") Long databaseId, + @NotNull @PathVariable("viewId") Long viewId, + @NotNull @Valid @RequestBody ViewUpdateDto data, + @NotNull Principal principal) throws NotAllowedException, DataServiceConnectionException, DatabaseNotFoundException, ViewNotFoundException, SearchServiceException, SearchServiceConnectionException, UserNotFoundException { log.debug("endpoint update view, databaseId={}, viewId={}", databaseId, viewId); @@ -315,7 +319,7 @@ public class ViewEndpoint extends AbstractEndpoint { throw new NotAllowedException("Failed to update view: not the database- or view owner"); } return ResponseEntity.accepted() - .body(metadataMapper.viewToViewDto( + .body(metadataMapper.viewToViewBriefDto( viewService.update(database, view, data))); } diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java index 1f7c391bd2ef63d49ed1acd5255409a1564af0ca..a54f616b01e61edad50d85d4b5f0d494c9e429d6 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java @@ -1,9 +1,9 @@ package at.tuwien.validation; import at.tuwien.SortType; -import at.tuwien.api.database.table.TableCreateDto; -import at.tuwien.api.database.table.columns.ColumnCreateDto; +import at.tuwien.api.database.table.CreateTableDto; import at.tuwien.api.database.table.columns.ColumnTypeDto; +import at.tuwien.api.database.table.columns.CreateTableColumnDto; import at.tuwien.api.identifier.IdentifierSaveDto; import at.tuwien.endpoints.AbstractEndpoint; import at.tuwien.entities.database.AccessType; @@ -43,15 +43,6 @@ public class EndpointValidator extends AbstractEndpoint { this.accessService = accessService; } - public void validateOnlyPrivateDataAccess(Database database, Principal principal, boolean writeAccessOnly) - throws NotAllowedException, UserNotFoundException, AccessNotFoundException { - if (database.getIsPublic()) { - log.trace("database with id {} is public: no access needed", database.getId()); - return; - } - validateOnlyAccess(database, principal, writeAccessOnly); - } - public void validateOnlyPrivateSchemaAccess(Database database, Principal principal, boolean writeAccessOnly) throws NotAllowedException, UserNotFoundException, AccessNotFoundException { if (database.getIsSchemaPublic()) { @@ -61,11 +52,6 @@ public class EndpointValidator extends AbstractEndpoint { validateOnlyAccess(database, principal, writeAccessOnly); } - public void validateOnlyPrivateDataAccess(Database database, Principal principal) throws NotAllowedException, - UserNotFoundException, AccessNotFoundException { - validateOnlyPrivateDataAccess(database, principal, false); - } - public void validateOnlyPrivateSchemaAccess(Database database, Principal principal) throws NotAllowedException, UserNotFoundException, AccessNotFoundException { validateOnlyPrivateSchemaAccess(database, principal, false); @@ -87,12 +73,12 @@ public class EndpointValidator extends AbstractEndpoint { } } - public void validateColumnCreateConstraints(TableCreateDto data) throws MalformedException { + public void validateColumnCreateConstraints(CreateTableDto data) throws MalformedException { if (data == null) { throw new MalformedException("Validation failed: table data is null"); } /* check size */ - final Optional<ColumnCreateDto> optional0 = data.getColumns() + final Optional<CreateTableColumnDto> optional0 = data.getColumns() .stream() .filter(c -> Objects.isNull(c.getSize())) .filter(c -> NEED_SIZE.contains(c.getType())) @@ -101,7 +87,7 @@ public class EndpointValidator extends AbstractEndpoint { log.error("Validation failed: column {} need size parameter", optional0.get().getName()); throw new MalformedException("Validation failed: column " + optional0.get().getName() + " need size parameter"); } - final Optional<ColumnCreateDto> optional0a = data.getColumns() + final Optional<CreateTableColumnDto> optional0a = data.getColumns() .stream() .filter(c -> !Objects.isNull(c.getSize())) .filter(c -> CAN_HAVE_SIZE.contains(c.getType()) || CAN_HAVE_SIZE_AND_D.contains(c.getType())) @@ -111,7 +97,7 @@ public class EndpointValidator extends AbstractEndpoint { log.error("Validation failed: column {} needs positive size parameter", optional0a.get().getName()); throw new MalformedException("Validation failed: column " + optional0a.get().getName() + " needs positive size parameter"); } - final Optional<ColumnCreateDto> optional0b = data.getColumns() + final Optional<CreateTableColumnDto> optional0b = data.getColumns() .stream() .filter(c -> !Objects.isNull(c.getD())) .filter(c -> CAN_HAVE_SIZE_AND_D.contains(c.getType())) @@ -122,7 +108,7 @@ public class EndpointValidator extends AbstractEndpoint { throw new MalformedException("Validation failed: column " + optional0b.get().getName() + " needs positive d parameter"); } /* check size and d */ - final Optional<ColumnCreateDto> optional1 = data.getColumns() + final Optional<CreateTableColumnDto> optional1 = data.getColumns() .stream() .filter(c -> Objects.isNull(c.getSize()) ^ Objects.isNull(c.getD())) .filter(c -> CAN_HAVE_SIZE_AND_D.contains(c.getType())) @@ -132,7 +118,7 @@ public class EndpointValidator extends AbstractEndpoint { throw new MalformedException("Validation failed: column " + optional1.get().getName() + " either needs both size and d parameter or none (use default)"); } /* check enum */ - final Optional<ColumnCreateDto> optional2 = data.getColumns() + final Optional<CreateTableColumnDto> optional2 = data.getColumns() .stream() .filter(c -> c.getType().equals(ColumnTypeDto.ENUM)) .filter(c -> c.getEnums() == null || c.getEnums().isEmpty()) @@ -142,7 +128,7 @@ public class EndpointValidator extends AbstractEndpoint { throw new MalformedException("Validation failed: column " + optional2.get().getName() + " needs at least 1 allowed enum value"); } /* check set */ - final Optional<ColumnCreateDto> optional3 = data.getColumns() + final Optional<CreateTableColumnDto> optional3 = data.getColumns() .stream() .filter(c -> c.getType().equals(ColumnTypeDto.SET)) .filter(c -> c.getEnums() == null || c.getSets().isEmpty()) @@ -152,7 +138,7 @@ public class EndpointValidator extends AbstractEndpoint { throw new MalformedException("Validation failed: column " + optional3.get().getName() + " needs at least 1 allowed set value"); } /* check serial */ - final List<ColumnCreateDto> list4a = data.getColumns() + final List<CreateTableColumnDto> list4a = data.getColumns() .stream() .filter(c -> c.getType().equals(ColumnTypeDto.SERIAL)) .toList(); @@ -160,26 +146,15 @@ public class EndpointValidator extends AbstractEndpoint { log.error("Validation failed: only one column of type serial allowed"); throw new MalformedException("Validation failed: only one column of type serial allowed"); } - final Optional<ColumnCreateDto> optional4a = data.getColumns() + final Optional<CreateTableColumnDto> optional4a = data.getColumns() .stream() .filter(c -> c.getType().equals(ColumnTypeDto.SERIAL)) - .filter(ColumnCreateDto::getNullAllowed) + .filter(CreateTableColumnDto::getNullAllowed) .findFirst(); if (optional4a.isPresent()) { log.error("Validation failed: column {} type serial demands non-null", optional4a.get().getName()); throw new MalformedException("Validation failed: column " + optional4a.get().getName() + " type serial demands non-null"); } - final Optional<ColumnCreateDto> optional4b = data.getColumns() - .stream() - .filter(c -> c.getType().equals(ColumnTypeDto.SERIAL) && data.getConstraints() - .getUniques() - .stream() - .noneMatch(uk -> uk.size() == 1 && uk.contains(c.getName()))) - .findFirst(); - if (optional4b.isPresent()) { - log.error("Validation failed: column {} type serial demands a unique constraint", optional4b.get().getName()); - throw new MalformedException("Validation failed: column " + optional4b.get().getName() + " type serial demands a unique constraint"); - } } public boolean validateOnlyMineOrWriteAccessOrHasRole(User owner, Principal principal, DatabaseAccess access, String role) { @@ -204,18 +179,6 @@ public class EndpointValidator extends AbstractEndpoint { return false; } - public boolean validateOnlyMineOrReadAccessOrHasRole(User owner, Principal principal, DatabaseAccess access, String role) { - if (validateOnlyMineOrWriteAccessOrHasRole(owner, principal, access, role)) { - return true; - } - if (access.getType().equals(AccessType.READ)) { - log.debug("validation passed: user {} has read access", principal.getName()); - return true; - } - log.debug("validation failed: user {} has insufficient access {} or role", principal.getName(), access.getType()); - return false; - } - @Transactional(readOnly = true) public void validateOnlyOwnerOrWriteAll(Table table, User user) throws NotAllowedException, AccessNotFoundException { diff --git a/dbrepo-metadata-service/rest-service/src/main/resources/application.yml b/dbrepo-metadata-service/rest-service/src/main/resources/application.yml index 290864eea961100236eea2764297d01251c1ccbc..01d2de7d8a0f73dcc667b69ed499ae350a81d317 100644 --- a/dbrepo-metadata-service/rest-service/src/main/resources/application.yml +++ b/dbrepo-metadata-service/rest-service/src/main/resources/application.yml @@ -3,7 +3,7 @@ application: version: '@project.version@' spring: datasource: - url: "jdbc:mariadb://${METADATA_HOST:metadata-db}:${METADATA_PORT:3306}/${METADATA_DB:dbrepo}${METADATA_JDBC_EXTRA_ARGS}" + url: "jdbc:mariadb://${METADATA_HOST:localhost}:${METADATA_PORT:3306}/${METADATA_DB:dbrepo}${METADATA_JDBC_EXTRA_ARGS:}" driver-class-name: org.mariadb.jdbc.Driver username: "${METADATA_USERNAME:root}" password: "${METADATA_DB_PASSWORD:dbrepo}" @@ -18,7 +18,7 @@ spring: application: name: metadata-service rabbitmq: - host: "${BROKER_HOST:broker-service}" + host: "${BROKER_HOST:localhost}" virtual-host: "${BROKER_VIRTUALHOST:dbrepo}" username: "${BROKER_USERNAME:admin}" password: "${BROKER_PASSWORD:admin}" diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierStatusTypeDtoConverterUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierStatusTypeDtoConverterUnitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8c7316b3d15590979652ea4a04498271f068d2fc --- /dev/null +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierStatusTypeDtoConverterUnitTest.java @@ -0,0 +1,42 @@ +package at.tuwien.converters; + +import at.tuwien.api.identifier.IdentifierStatusTypeDto; +import at.tuwien.test.AbstractUnitTest; +import lombok.extern.log4j.Log4j2; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@Log4j2 +@SpringBootTest +public class IdentifierStatusTypeDtoConverterUnitTest extends AbstractUnitTest { + + @Autowired + private IdentifierStatusTypeDtoConverter identifierStatusTypeDtoConverter; + + @BeforeEach + public void beforeEach() { + genesis(); + } + + @Test + public void identifierStatusTypeDtoConverter_succeeds() { + + /* test */ + final IdentifierStatusTypeDto response = identifierStatusTypeDtoConverter.convert(IdentifierStatusTypeDto.DRAFT.getName()); + assertEquals(IdentifierStatusTypeDto.DRAFT, response); + } + + @Test + public void identifierStatusTypeDtoConverter_fails() { + + /* test */ + assertThrows(IllegalArgumentException.class, () -> { + identifierStatusTypeDtoConverter.convert("i_do_not_exist"); + }); + } +} diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeConverterUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeDtoConverterUnitTest.java similarity index 55% rename from dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeConverterUnitTest.java rename to dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeDtoConverterUnitTest.java index 7215e5db918f226e6a826fce66e4e129ca4f0c5f..98abd668d8ec0e30a0f420682a0c7b7fd3e5704d 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeConverterUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/converters/IdentifierTypeDtoConverterUnitTest.java @@ -8,14 +8,15 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; @Log4j2 @SpringBootTest -public class IdentifierTypeConverterUnitTest extends AbstractUnitTest { +public class IdentifierTypeDtoConverterUnitTest extends AbstractUnitTest { @Autowired - private IdentifierTypeConverter identifierTypeConverter; + private IdentifierTypeDtoConverter identifierTypeDtoConverter; @BeforeEach public void beforeEach() { @@ -23,19 +24,19 @@ public class IdentifierTypeConverterUnitTest extends AbstractUnitTest { } @Test - public void identifierTypeConverter_succeeds() { + public void IdentifierTypeDtoConverter_succeeds() { /* test */ - final IdentifierTypeDto response = identifierTypeConverter.convert(IdentifierTypeDto.DATABASE.getName()); + final IdentifierTypeDto response = identifierTypeDtoConverter.convert(IdentifierTypeDto.DATABASE.getName()); assertEquals(IdentifierTypeDto.DATABASE, response); } @Test - public void identifierTypeConverter_fails() { + public void IdentifierTypeDtoConverter_fails() { /* test */ assertThrows(IllegalArgumentException.class, () -> { - identifierTypeConverter.convert("i_do_not_exist"); + identifierTypeDtoConverter.convert("i_do_not_exist"); }); } } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AbstractEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AbstractEndpointUnitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..dfa4924957b9c300aeda92ad2ed305a4dd29b444 --- /dev/null +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AbstractEndpointUnitTest.java @@ -0,0 +1,94 @@ +package at.tuwien.endpoints; + +import at.tuwien.api.database.AccessTypeDto; +import at.tuwien.api.database.DatabaseAccessDto; +import at.tuwien.api.user.UserDetailsDto; +import at.tuwien.entities.database.Database; +import at.tuwien.entities.database.DatabaseAccess; +import at.tuwien.entities.user.User; +import at.tuwien.exception.*; +import at.tuwien.mapper.MetadataMapper; +import at.tuwien.service.AccessService; +import at.tuwien.service.DatabaseService; +import at.tuwien.service.UserService; +import at.tuwien.test.AbstractUnitTest; +import lombok.extern.log4j.Log4j2; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.test.context.support.WithAnonymousUser; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import java.security.Principal; +import java.util.List; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@Log4j2 +@SpringBootTest +@ExtendWith(SpringExtension.class) +public class AbstractEndpointUnitTest extends AbstractUnitTest { + + @Autowired + private AccessEndpoint accessEndpoint; + + @BeforeEach + public void beforeEach() { + genesis(); + } + + @Test + public void hasRole_noPrincipal_fails() { + + /* test */ + assertFalse(accessEndpoint.hasRole(null, "some-role")); + } + + @Test + public void hasRole_noRole_fails() { + + /* test */ + assertFalse(accessEndpoint.hasRole(USER_1_PRINCIPAL, null)); + } + + @Test + public void getId_fails() { + + /* test */ + assertNull(accessEndpoint.getId(null)); + } + + @Test + public void getId_noId_fails() { + final Principal principal = new UsernamePasswordAuthenticationToken(UserDetailsDto.builder() + .id(null) // <<< + .build(), null); + + /* test */ + assertThrows(IllegalArgumentException.class, () -> { + accessEndpoint.getId(principal); + }); + } + + @Test + public void getId_incompatible_fails() { + final Principal principal = new UsernamePasswordAuthenticationToken("", null); + + /* test */ + assertThrows(IllegalArgumentException.class, () -> { + accessEndpoint.getId(principal); + }); + } + +} diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java index f4a700e859e68f5705475a63dbc66f2afeaeb5c4..376769e3c318eaabc93e2a65def2673d85d3e7d2 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/AccessEndpointUnitTest.java @@ -219,6 +219,26 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { generic_update(USER_1_PRINCIPAL, USER_1, USER_2_ID, USER_2, DATABASE_1_USER_2_WRITE_OWN_ACCESS); } + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"update-database-access"}) + public void update_ownerNoAccess_fails() { + + /* test */ + assertThrows(NotAllowedException.class, () -> { + generic_update(USER_1_PRINCIPAL, USER_1, USER_1_ID, null, null); + }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"update-database-access"}) + public void update_ownerNoWriteAllAccess_fails() { + + /* test */ + assertThrows(NotAllowedException.class, () -> { + generic_update(USER_1_PRINCIPAL, USER_1, USER_LOCAL_ADMIN_ID, USER_LOCAL, null); + }); + } + @Test @WithAnonymousUser public void revoke_anonymous_fails() { @@ -249,6 +269,26 @@ public class AccessEndpointUnitTest extends AbstractUnitTest { }); } + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-database-access"}) + public void revoke_ownerNoAccess_fails() { + + /* test */ + assertThrows(NotAllowedException.class, () -> { + generic_revoke(USER_1_PRINCIPAL, USER_1, USER_1_ID, null); + }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-database-access"}) + public void revoke_ownerNoWriteAllAccess_fails() { + + /* test */ + assertThrows(NotAllowedException.class, () -> { + generic_revoke(USER_1_PRINCIPAL, USER_1, USER_LOCAL_ADMIN_ID, USER_LOCAL); + }); + } + @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"delete-database-access"}) public void revoke_succeeds() throws NotAllowedException, DataServiceException, DataServiceConnectionException, diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java index ab3f4485b2cf35134c2d0ee126ee30af04636165..00185d9ea134c33eba73ba7c24a02ff2d606ab1d 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ContainerEndpointUnitTest.java @@ -1,12 +1,14 @@ package at.tuwien.endpoints; -import at.tuwien.test.AbstractUnitTest; import at.tuwien.api.container.ContainerBriefDto; -import at.tuwien.api.container.ContainerCreateDto; import at.tuwien.api.container.ContainerDto; +import at.tuwien.api.container.CreateContainerDto; import at.tuwien.entities.container.Container; -import at.tuwien.exception.*; +import at.tuwien.exception.ContainerAlreadyExistsException; +import at.tuwien.exception.ContainerNotFoundException; +import at.tuwien.exception.ImageNotFoundException; import at.tuwien.service.impl.ContainerServiceImpl; +import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -14,6 +16,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.test.context.support.WithAnonymousUser; @@ -52,19 +55,23 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest { } @Test - @WithMockUser(username = USER_1_USERNAME, authorities = {"find-container"}) - public void findById_hasRole_succeeds() throws ContainerNotFoundException { + @WithMockUser(username = USER_1_USERNAME) + public void findById_succeeds() throws ContainerNotFoundException { /* test */ findById_generic(CONTAINER_1_ID, CONTAINER_1, USER_1_PRINCIPAL); } @Test - @WithMockUser(username = USER_4_USERNAME) - public void findById_noRole_succeeds() throws ContainerNotFoundException { + @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME) + public void findById_system_succeeds() throws ContainerNotFoundException { /* test */ - findById_generic(CONTAINER_1_ID, CONTAINER_1, USER_4_PRINCIPAL); + final ResponseEntity<ContainerDto> response = findById_generic(CONTAINER_1_ID, CONTAINER_1, USER_LOCAL_ADMIN_PRINCIPAL); + final HttpHeaders headers = response.getHeaders() ; + assertEquals(List.of(CONTAINER_1_PRIVILEGED_USERNAME), headers.get("X-Username")); + assertEquals(List.of(CONTAINER_1_PRIVILEGED_PASSWORD), headers.get("X-Password")); + assertEquals(List.of("X-Username X-Password"), headers.get("Access-Control-Expose-Headers")); } @Test @@ -122,7 +129,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser public void create_anonymous_fails() { - final ContainerCreateDto request = ContainerCreateDto.builder() + final CreateContainerDto request = CreateContainerDto.builder() .name(CONTAINER_1_NAME) .imageId(IMAGE_1_ID) .build(); @@ -136,7 +143,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"create-container"}) public void create_hasRole_succeeds() throws ContainerAlreadyExistsException, ImageNotFoundException { - final ContainerCreateDto request = ContainerCreateDto.builder() + final CreateContainerDto request = CreateContainerDto.builder() .name(CONTAINER_1_NAME) .imageId(IMAGE_1_ID) .build(); @@ -148,7 +155,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_4_USERNAME) public void create_noRole_fails() { - final ContainerCreateDto request = ContainerCreateDto.builder() + final CreateContainerDto request = CreateContainerDto.builder() .name(CONTAINER_1_NAME) .imageId(IMAGE_1_ID) .build(); @@ -171,7 +178,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest { /* ## GENERIC TEST CASES ## */ /* ################################################################################################### */ - public void findById_generic(Long containerId, Container container, Principal principal) + public ResponseEntity<ContainerDto> findById_generic(Long containerId, Container container, Principal principal) throws ContainerNotFoundException { /* mock */ @@ -182,6 +189,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest { final ResponseEntity<ContainerDto> response = containerEndpoint.findById(containerId, principal); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); + return response; } public void delete_generic(Long containerId, Container container) throws ContainerNotFoundException { @@ -221,7 +229,7 @@ public class ContainerEndpointUnitTest extends AbstractUnitTest { assertEquals(CONTAINER_2_INTERNALNAME, container2.getInternalName()); } - public void create_generic(ContainerCreateDto data) throws ContainerAlreadyExistsException, ImageNotFoundException { + public void create_generic(CreateContainerDto data) throws ContainerAlreadyExistsException, ImageNotFoundException { /* mock */ when(containerService.create(data)) diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java index 11d64faf8b9562ff42ab2120d5f6fa151710d462..fd91fb5655ad563ee0b4f8503dbdb5b60db6fea9 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/DatabaseEndpointUnitTest.java @@ -4,7 +4,6 @@ import at.tuwien.api.database.*; import at.tuwien.entities.database.Database; import at.tuwien.entities.user.User; import at.tuwien.exception.*; -import at.tuwien.gateway.KeycloakGateway; import at.tuwien.service.*; import at.tuwien.service.impl.DatabaseServiceImpl; import at.tuwien.test.AbstractUnitTest; @@ -42,9 +41,6 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @MockBean private AccessService accessService; - @MockBean - private KeycloakGateway keycloakGateway; - @MockBean private ContainerService containerService; @@ -68,7 +64,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser public void create_anonymous_fails() { - final DatabaseCreateDto request = DatabaseCreateDto.builder() + final CreateDatabaseDto request = CreateDatabaseDto.builder() .cid(CONTAINER_1_ID) .name(DATABASE_1_NAME) .isPublic(DATABASE_1_PUBLIC) @@ -83,7 +79,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_4_USERNAME) public void create_noRole_fails() { - final DatabaseCreateDto request = DatabaseCreateDto.builder() + final CreateDatabaseDto request = CreateDatabaseDto.builder() .cid(CONTAINER_3_ID) .name(DATABASE_3_NAME) .isPublic(DATABASE_3_PUBLIC) @@ -101,7 +97,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { DatabaseNotFoundException, ContainerNotFoundException, SearchServiceException, SearchServiceConnectionException, AuthServiceException, AuthServiceConnectionException, BrokerServiceException, BrokerServiceConnectionException, ContainerQuotaException { - final DatabaseCreateDto request = DatabaseCreateDto.builder() + final CreateDatabaseDto request = CreateDatabaseDto.builder() .cid(CONTAINER_1_ID) .name(DATABASE_1_NAME) .isPublic(DATABASE_1_PUBLIC) @@ -124,7 +120,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"create-database"}) public void create_quotaExceeded_fails() throws UserNotFoundException, ContainerNotFoundException { - final DatabaseCreateDto request = DatabaseCreateDto.builder() + final CreateDatabaseDto request = CreateDatabaseDto.builder() .cid(CONTAINER_4_ID) .name(DATABASE_1_NAME) .isPublic(DATABASE_1_PUBLIC) @@ -144,7 +140,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser - public void refreshTableMetadata_anonymous_succeeds() { + public void refreshTableMetadata_anonymous_fails() { /* test */ assertThrows(AccessDeniedException.class, () -> { @@ -154,7 +150,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_1_USERNAME) - public void refreshTableMetadata_noRole_succeeds() { + public void refreshTableMetadata_noRole_fails() { /* test */ assertThrows(AccessDeniedException.class, () -> { @@ -198,7 +194,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_1); /* test */ - final ResponseEntity<DatabaseDto> response = databaseEndpoint.refreshTableMetadata(DATABASE_1_ID, USER_1_PRINCIPAL); + final ResponseEntity<DatabaseBriefDto> response = databaseEndpoint.refreshTableMetadata(DATABASE_1_ID, USER_1_PRINCIPAL); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); } @@ -218,7 +214,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_1); /* test */ - final ResponseEntity<DatabaseDto> response = databaseEndpoint.refreshViewMetadata(DATABASE_1_ID, USER_1_PRINCIPAL); + final ResponseEntity<DatabaseBriefDto> response = databaseEndpoint.refreshViewMetadata(DATABASE_1_ID, USER_1_PRINCIPAL); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); } @@ -353,15 +349,12 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-database-visibility"}) public void visibility_hasRole_succeeds() throws NotAllowedException, UserNotFoundException, - DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException, AuthServiceException, - AuthServiceConnectionException { + DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException { final DatabaseModifyVisibilityDto request = DatabaseModifyVisibilityDto.builder() .isPublic(true) .build(); /* mock */ - when(keycloakGateway.findByUsername(USER_1_USERNAME)) - .thenReturn(USER_1_KEYCLOAK_DTO); when(userService.findById(USER_1_ID)) .thenReturn(USER_1); @@ -509,7 +502,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-database-owner"}) public void transfer_hasRole_succeeds() throws DataServiceConnectionException, DataServiceException, NotAllowedException, UserNotFoundException, DatabaseNotFoundException, SearchServiceException, - SearchServiceConnectionException, AuthServiceException, AuthServiceConnectionException { + SearchServiceConnectionException { final DatabaseTransferDto request = DatabaseTransferDto.builder() .id(USER_4_ID) .build(); @@ -517,8 +510,6 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { /* mock */ when(databaseService.findById(DATABASE_1_ID)) .thenReturn(DATABASE_1); - when(keycloakGateway.findByUsername(USER_1_USERNAME)) - .thenReturn(USER_1_KEYCLOAK_DTO); when(userService.findById(USER_1_ID)) .thenReturn(USER_1); when(userService.findById(USER_4_ID)) @@ -550,7 +541,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser - public void findById_anonymous_fails() { + public void findById_anonymousPrivateSchemaNoAccess_fails() { /* test */ assertThrows(NotAllowedException.class, () -> { @@ -560,40 +551,51 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser - public void findById_anonymousNotFound_fails() { + public void findById_anonymousPublicSchemaNoAccess_succeeds() throws UserNotFoundException, NotAllowedException, + DataServiceException, DatabaseNotFoundException, ExchangeNotFoundException, DataServiceConnectionException { /* test */ - assertThrows(DatabaseNotFoundException.class, () -> { - findById_generic(DATABASE_1_ID, null, null); - }); + final DatabaseDto database = findById_generic(DATABASE_2_ID, DATABASE_2, null); + assertEquals(3, database.getTables().size()); + assertEquals(1, database.getViews().size()); + assertEquals(0, database.getAccesses().size()); } @Test - @WithMockUser(username = USER_1_USERNAME, authorities = {"find-database"}) - public void findById_hasRole_succeeds() throws DataServiceException, DataServiceConnectionException, - DatabaseNotFoundException, ExchangeNotFoundException, UserNotFoundException, NotAllowedException { - - /* pre-condition */ - assertTrue(DATABASE_3_PUBLIC); + @WithAnonymousUser + public void findById_anonymousPrivateSchemaNoAccessSystem_succeeds() throws UserNotFoundException, + NotAllowedException, DataServiceException, DatabaseNotFoundException, ExchangeNotFoundException, + DataServiceConnectionException { /* test */ - findById_generic(DATABASE_3_ID, DATABASE_3, USER_1_PRINCIPAL); + final DatabaseDto database = findById_generic(DATABASE_1_ID, DATABASE_1, USER_LOCAL_ADMIN_PRINCIPAL); + assertEquals(4, database.getTables().size()); + assertEquals(2, database.getViews().size()); + assertNotEquals(0, database.getAccesses().size()); } @Test - @WithMockUser(username = USER_1_USERNAME, authorities = {"find-database"}) - public void findById_hasRoleForeign_succeeds() throws DataServiceException, DataServiceConnectionException, - DatabaseNotFoundException, ExchangeNotFoundException, UserNotFoundException, NotAllowedException { + @WithAnonymousUser + public void findById_privateSchema_fails() { - /* pre-condition */ - assertTrue(DATABASE_3_PUBLIC); + /* test */ + assertThrows(NotAllowedException.class, () -> { + findById_generic(DATABASE_1_ID, DATABASE_1, null); + }); + } + + @Test + @WithAnonymousUser + public void findById_anonymousNotFound_fails() { /* test */ - findById_generic(DATABASE_3_ID, DATABASE_3, USER_1_PRINCIPAL); + assertThrows(DatabaseNotFoundException.class, () -> { + findById_generic(DATABASE_1_ID, null, null); + }); } @Test - @WithMockUser(username = USER_1_USERNAME, authorities = {"find-database"}) + @WithMockUser(username = USER_1_USERNAME) public void findById_ownerSeesAccessRights_succeeds() throws DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, ExchangeNotFoundException, UserNotFoundException, NotAllowedException { @@ -602,10 +604,10 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { .thenReturn(List.of(DATABASE_1_USER_1_WRITE_ALL_ACCESS, DATABASE_1_USER_2_READ_ACCESS)); /* test */ - final DatabaseDto response = findById_generic(DATABASE_1_ID, DATABASE_1, USER_1_PRINCIPAL); - final List<DatabaseAccessDto> accessList = response.getAccesses(); - assertNotNull(accessList); - assertEquals(3, accessList.size()); + final DatabaseDto database = findById_generic(DATABASE_1_ID, DATABASE_1, USER_1_PRINCIPAL); + assertEquals(4, database.getTables().size()); + assertEquals(3, database.getViews().size()); + assertEquals(3, database.getAccesses().size()); } @Test @@ -669,7 +671,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { assertEquals(expectedSize, body.size()); } - public void create_generic(DatabaseCreateDto data, Principal principal, User user) throws DataServiceException, + public void create_generic(CreateDatabaseDto data, Principal principal, User user) throws DataServiceException, DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, ContainerNotFoundException, SearchServiceException, SearchServiceConnectionException, BrokerServiceException, BrokerServiceConnectionException, ContainerQuotaException { @@ -682,7 +684,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { .thenReturn(DATABASE_1); /* test */ - final ResponseEntity<DatabaseDto> response = databaseEndpoint.create(data, principal); + final ResponseEntity<DatabaseBriefDto> response = databaseEndpoint.create(data, principal); assertEquals(HttpStatus.CREATED, response.getStatusCode()); assertNotNull(response.getBody()); } @@ -704,7 +706,7 @@ public class DatabaseEndpointUnitTest extends AbstractUnitTest { } /* test */ - final ResponseEntity<DatabaseDto> response = databaseEndpoint.visibility(databaseId, data, principal); + final ResponseEntity<DatabaseBriefDto> response = databaseEndpoint.visibility(databaseId, data, principal); assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); assertNotNull(response.getBody()); } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java index 74a252c5a63572e569a1e7b8379637e2d34dc03d..419393b485096b84f6495bfcd6ce2910e0c9ae46 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/IdentifierEndpointUnitTest.java @@ -122,12 +122,58 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { ); } + public static Stream<Arguments> findAll_anonymousFilterDatabase_parameters() { + return Stream.of( + Arguments.arguments("dbid", DATABASE_1_ID, null, null, null, null, 1), + Arguments.arguments("qid", DATABASE_1_ID, QUERY_1_ID, null, null, null, 0), + Arguments.arguments("vid", DATABASE_1_ID, null, VIEW_1_ID, null, null, 0), + Arguments.arguments("tid", DATABASE_1_ID, null, null, TABLE_1_ID, null, 0), + Arguments.arguments("status_published", DATABASE_1_ID, null, null, null, "PUBLISHED", 1), + Arguments.arguments("status_draft", DATABASE_1_ID, null, null, null, "DRAFT", 0) + ); + } + + public static Stream<Arguments> findAll_filterSubset_parameters() { + return Stream.of( + Arguments.arguments("status_published", DATABASE_2_ID, null, null, null, "PUBLISHED", 0), + Arguments.arguments("status_draft", DATABASE_2_ID, null, null, null, "DRAFT", 1) + ); + } + public static Stream<Arguments> findAll_filterDatabase_parameters() { return Stream.of( - Arguments.arguments("dbid", DATABASE_1_ID, null, null, null, 4), - Arguments.arguments("qid", DATABASE_1_ID, QUERY_1_ID, null, null, 1), - Arguments.arguments("vid", DATABASE_1_ID, null, VIEW_1_ID, null, 1), - Arguments.arguments("tid", DATABASE_1_ID, null, null, TABLE_1_ID, 1) + Arguments.arguments("database_dbid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, null, null, 1, USER_1_PRINCIPAL), + Arguments.arguments("database_qid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, QUERY_1_ID, null, null, 0, USER_1_PRINCIPAL), + Arguments.arguments("database_vid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, USER_1_PRINCIPAL), + Arguments.arguments("database_tid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, USER_1_PRINCIPAL), + Arguments.arguments("subset_dbid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, null, null, 1, USER_1_PRINCIPAL), + Arguments.arguments("subset_qid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, QUERY_1_ID, null, null, 1, USER_1_PRINCIPAL), + Arguments.arguments("subset_vid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, USER_1_PRINCIPAL), + Arguments.arguments("subset_tid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, USER_1_PRINCIPAL), + Arguments.arguments("view_dbid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, null, null, 1, USER_1_PRINCIPAL), + Arguments.arguments("view_qid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, QUERY_1_ID, null, null, 0, USER_1_PRINCIPAL), + Arguments.arguments("view_vid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, VIEW_1_ID, null, 1, USER_1_PRINCIPAL), + Arguments.arguments("view_tid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, USER_1_PRINCIPAL), + Arguments.arguments("table_dbid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, null, null, 1, USER_1_PRINCIPAL), + Arguments.arguments("table_qid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, QUERY_1_ID, null, null, 0, USER_1_PRINCIPAL), + Arguments.arguments("table_vid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, USER_1_PRINCIPAL), + Arguments.arguments("table_tid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, null, TABLE_1_ID, 1, USER_1_PRINCIPAL), + Arguments.arguments("anon_database_dbid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, null, null, 1, null), + Arguments.arguments("anon_database_qid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, QUERY_1_ID, null, null, 0, null), + Arguments.arguments("anon_database_vid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, null), + Arguments.arguments("anon_database_tid", IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, null), + Arguments.arguments("anon_subset_dbid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, null, null, 1, null), + Arguments.arguments("anon_subset_qid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, QUERY_1_ID, null, null, 1, null), + Arguments.arguments("anon_subset_vid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, null), + Arguments.arguments("anon_subset_tid", IdentifierTypeDto.SUBSET, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, null), + Arguments.arguments("anon_view_dbid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, null, null, 1, null), + Arguments.arguments("anon_view_qid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, QUERY_1_ID, null, null, 0, null), + Arguments.arguments("anon_view_vid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, VIEW_1_ID, null, 1, null), + Arguments.arguments("anon_view_tid", IdentifierTypeDto.VIEW, null, DATABASE_1_ID, null, null, TABLE_1_ID, 0, null), + Arguments.arguments("anon_table_dbid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, null, null, 1, null), + Arguments.arguments("anon_table_qid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, QUERY_1_ID, null, null, 0, null), + Arguments.arguments("anon_table_vid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, VIEW_1_ID, null, 0, null), + Arguments.arguments("anon_table_tid", IdentifierTypeDto.TABLE, null, DATABASE_1_ID, null, null, TABLE_1_ID, 1, null) ); } @@ -146,14 +192,14 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser - public void findAll_empty_succeeds() throws FormatNotAvailableException { + public void findAll_empty_succeeds() { /* mock */ when(identifierService.findAll()) .thenReturn(List.of()); /* test */ - final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, "application/json"); + final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, null, null, "application/json", null); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody(); @@ -161,12 +207,90 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { assertEquals(0, identifiers.size()); } + @ParameterizedTest + @MethodSource("findAll_anonymousFilterDatabase_parameters") + @WithAnonymousUser + public void findAll_anonymousFilterDatabase_succeeds(String name, Long databaseId, Long queryId, Long viewId, + Long tableId, IdentifierStatusTypeDto status, + Integer expectedSize) throws ViewNotFoundException, + TableNotFoundException, DatabaseNotFoundException { + + /* mock */ + when(identifierService.findAll()) + .thenReturn(List.of(IDENTIFIER_1, IDENTIFIER_2, IDENTIFIER_3, IDENTIFIER_4, IDENTIFIER_5, IDENTIFIER_6, IDENTIFIER_7)); + if (viewId != null) { + when(viewService.findById(DATABASE_1, VIEW_1_ID)) + .thenReturn(VIEW_1); + } + if (tableId != null) { + when(tableService.findById(DATABASE_1, TABLE_1_ID)) + .thenReturn(TABLE_1); + } + + /* test */ + final ResponseEntity<?> response = identifierEndpoint.findAll(IdentifierTypeDto.DATABASE, status, databaseId, queryId, viewId, tableId, "application/json", null); + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertNotNull(response.getBody()); + final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody(); + assertNotNull(identifiers); + assertEquals(expectedSize, identifiers.size()); + } + + @ParameterizedTest + @MethodSource("findAll_filterSubset_parameters") + @WithMockUser(username = USER_2_USERNAME) + public void findAll_filterSubset_succeeds(String name, Long databaseId, Long queryId, Long viewId, Long tableId, + IdentifierStatusTypeDto status, Integer expectedSize) { + + /* mock */ + when(identifierService.findAll()) + .thenReturn(List.of(IDENTIFIER_1, IDENTIFIER_2, IDENTIFIER_3, IDENTIFIER_4, IDENTIFIER_5, IDENTIFIER_6, IDENTIFIER_7)); + + /* test */ + final ResponseEntity<?> response = identifierEndpoint.findAll(IdentifierTypeDto.SUBSET, status, databaseId, queryId, viewId, tableId, "application/json", USER_2_PRINCIPAL); + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertNotNull(response.getBody()); + final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody(); + assertNotNull(identifiers); + assertEquals(expectedSize, identifiers.size()); + } + + @ParameterizedTest + @MethodSource("findAll_anonymousFilterDatabase_parameters") + @WithAnonymousUser + public void findAll_wrongPrincipalFilterDatabase_succeeds(String name, Long databaseId, Long queryId, Long viewId, + Long tableId, IdentifierStatusTypeDto status, + Integer expectedSize) + throws ViewNotFoundException, TableNotFoundException, DatabaseNotFoundException { + + /* mock */ + when(identifierService.findAll()) + .thenReturn(List.of(IDENTIFIER_1, IDENTIFIER_2, IDENTIFIER_3, IDENTIFIER_4, IDENTIFIER_5, IDENTIFIER_6, IDENTIFIER_7)); + if (viewId != null) { + when(viewService.findById(DATABASE_1, VIEW_1_ID)) + .thenReturn(VIEW_1); + } + if (tableId != null) { + when(tableService.findById(DATABASE_1, TABLE_1_ID)) + .thenReturn(TABLE_1); + } + + /* test */ + final ResponseEntity<?> response = identifierEndpoint.findAll(IdentifierTypeDto.DATABASE, status, databaseId, queryId, viewId, tableId, "application/json", USER_2_PRINCIPAL); + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertNotNull(response.getBody()); + final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody(); + assertNotNull(identifiers); + assertEquals(expectedSize, identifiers.size()); + } + @ParameterizedTest @MethodSource("findAll_filterDatabase_parameters") @WithAnonymousUser - public void findAll_filterDatabase_succeeds(String name, Long databaseId, Long queryId, Long viewId, Long tableId, - Integer expectedSize) throws FormatNotAvailableException, - ViewNotFoundException, TableNotFoundException, DatabaseNotFoundException { + public void findAll_filterDatabase_succeeds(String name, IdentifierTypeDto type, IdentifierStatusTypeDto status, + Long databaseId, Long queryId, Long viewId, Long tableId, + Integer expectedSize, Principal principal) throws ViewNotFoundException, + TableNotFoundException, DatabaseNotFoundException { /* mock */ when(identifierService.findAll()) @@ -181,7 +305,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { } /* test */ - final ResponseEntity<?> response = identifierEndpoint.findAll(databaseId, queryId, viewId, tableId, "application/json"); + final ResponseEntity<?> response = identifierEndpoint.findAll(type, status, databaseId, queryId, viewId, tableId, "application/json", principal); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody(); @@ -191,14 +315,14 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser - public void findAll_json_succeeds() throws FormatNotAvailableException { + public void findAll_json_succeeds() { /* mock */ when(identifierService.findAll()) .thenReturn(List.of(IDENTIFIER_1)); /* test */ - final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, "application/json"); + final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, null, null, "application/json", null); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody(); @@ -208,14 +332,14 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser - public void findAll_jsonLd_succeeds() throws FormatNotAvailableException { + public void findAll_jsonLd_succeeds() { /* mock */ when(identifierService.findAll()) .thenReturn(List.of(IDENTIFIER_1)); /* test */ - final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, "application/ld+json"); + final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, null, null, "application/ld+json", null); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); final List<LdDatasetDto> identifiers = (List<LdDatasetDto>) response.getBody(); @@ -225,23 +349,95 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser - public void findAll_format_fails() { + public void findAll_format_succeeds() { /* mock */ when(identifierService.findAll()) .thenReturn(List.of(IDENTIFIER_1)); + /* test */ + final ResponseEntity<?> response = identifierEndpoint.findAll(null, null, null, null, null, null, "text/html", null); + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertNotNull(response.getBody()); + final List<IdentifierBriefDto> identifiers = (List<IdentifierBriefDto>) response.getBody(); + assertNotNull(identifiers); + assertEquals(1, identifiers.size()); + } + + @Test + @WithAnonymousUser + public void find_textCsvDatabase_fails() throws IdentifierNotFoundException { + + /* mock */ + when(identifierService.find(IDENTIFIER_1_ID)) + .thenReturn(IDENTIFIER_1); + /* test */ assertThrows(FormatNotAvailableException.class, () -> { - identifierEndpoint.findAll(null, null, null, null, "text/csv"); + identifierEndpoint.find(IDENTIFIER_1_ID, "text/csv", null); + }); + } + + @Test + @WithAnonymousUser + public void find_draft_fails() throws IdentifierNotFoundException { + + /* mock */ + when(identifierService.find(IDENTIFIER_5_ID)) + .thenReturn(IDENTIFIER_5); + + /* test */ + assertThrows(NotAllowedException.class, () -> { + identifierEndpoint.find(IDENTIFIER_5_ID, "application/json", null); + }); + } + + @Test + @WithMockUser(username = USER_1_USERNAME) + public void find_draftNotOwner_fails() throws IdentifierNotFoundException { + + /* mock */ + when(identifierService.find(IDENTIFIER_5_ID)) + .thenReturn(IDENTIFIER_5); + + /* test */ + assertThrows(NotAllowedException.class, () -> { + identifierEndpoint.find(IDENTIFIER_5_ID, "application/json", USER_1_PRINCIPAL); }); } + @Test + @WithMockUser(username = USER_2_USERNAME) + public void find_draft_succeeds() throws IdentifierNotFoundException, MalformedException, NotAllowedException, + DataServiceException, QueryNotFoundException, DataServiceConnectionException, FormatNotAvailableException { + + /* mock */ + when(identifierService.find(IDENTIFIER_5_ID)) + .thenReturn(IDENTIFIER_5); + + /* test */ + identifierEndpoint.find(IDENTIFIER_5_ID, "application/json", USER_2_PRINCIPAL); + } + @Test @WithAnonymousUser + public void find_defaultHtmlRespondsJson_succeeds() throws IdentifierNotFoundException, MalformedException, + NotAllowedException, DataServiceException, QueryNotFoundException, DataServiceConnectionException, + FormatNotAvailableException { + + /* mock */ + when(identifierService.find(IDENTIFIER_1_ID)) + .thenReturn(IDENTIFIER_1); + + /* test */ + identifierEndpoint.find(IDENTIFIER_1_ID, "text/html", null); + } + + @Test + @WithMockUser(username = USER_4_USERNAME) public void find_json0_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException { + FormatNotAvailableException, NotAllowedException { final String accept = "application/json"; final IdentifierDto compare = objectMapper.readValue(FileUtils.readFileToString(new File("src/test/resources/json/metadata0.json"), StandardCharsets.UTF_8), IdentifierDto.class); @@ -250,7 +446,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(IDENTIFIER_7); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept, USER_4_PRINCIPAL); assertEquals(HttpStatus.OK, response.getStatusCode()); final IdentifierDto body = (IdentifierDto) response.getBody(); assertNotNull(body); @@ -271,7 +467,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_json1_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException { + FormatNotAvailableException, NotAllowedException { final String accept = "application/json"; final IdentifierDto compare = objectMapper.readValue(FileUtils.readFileToString(new File("src/test/resources/json/metadata1.json"), StandardCharsets.UTF_8), IdentifierDto.class); @@ -280,7 +476,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(IDENTIFIER_1); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null); assertEquals(HttpStatus.OK, response.getStatusCode()); final IdentifierDto body = (IdentifierDto) response.getBody(); assertNotNull(body); @@ -321,7 +517,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_csv_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException { + FormatNotAvailableException, NotAllowedException { final String accept = "text/csv"; final InputStreamResource compare = new InputStreamResource(FileUtils.openInputStream(new File("src/test/resources/csv/keyboard.csv"))); final InputStreamResource mock = new InputStreamResource(FileUtils.openInputStream(new File("src/test/resources/csv/keyboard.csv"))); @@ -333,7 +529,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(mock); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_2_ID, accept); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_2_ID, accept, null); assertEquals(HttpStatus.OK, response.getStatusCode()); final InputStreamResource body = (InputStreamResource) response.getBody(); assertNotNull(body); @@ -344,7 +540,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_bibliography_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException { + FormatNotAvailableException, NotAllowedException { final String accept = "text/bibliography"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa1.txt"), StandardCharsets.UTF_8); @@ -356,7 +552,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(IDENTIFIER_1); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null); assertEquals(HttpStatus.OK, response.getStatusCode()); final String body = (String) response.getBody(); assertNotNull(body); @@ -365,9 +561,29 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser + public void find_anonymousBibliographyApa0_fails() throws IOException, MalformedException, + IdentifierNotFoundException { + final String accept = "text/bibliography; style=apa"; + final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa0.txt"), + StandardCharsets.UTF_8); + + /* mock */ + when(identifierService.exportBibliography(IDENTIFIER_7, BibliographyTypeDto.APA)) + .thenReturn(compare); + when(identifierService.find(IDENTIFIER_7_ID)) + .thenReturn(IDENTIFIER_7); + + /* test */ + assertThrows(NotAllowedException.class, () -> { + identifierEndpoint.find(IDENTIFIER_7_ID, accept, null); + }); + } + + @Test + @WithMockUser(username = USER_4_USERNAME) public void find_bibliographyApa0_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException { + FormatNotAvailableException, NotAllowedException { final String accept = "text/bibliography; style=apa"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa0.txt"), StandardCharsets.UTF_8); @@ -379,7 +595,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(IDENTIFIER_7); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept, USER_4_PRINCIPAL); assertEquals(HttpStatus.OK, response.getStatusCode()); final String body = (String) response.getBody(); assertNotNull(body); @@ -390,7 +606,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_bibliographyApa1_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException { + FormatNotAvailableException, NotAllowedException { final String accept = "text/bibliography; style=apa"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa1.txt"), StandardCharsets.UTF_8); @@ -402,7 +618,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(IDENTIFIER_1); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null); assertEquals(HttpStatus.OK, response.getStatusCode()); final String body = (String) response.getBody(); assertNotNull(body); @@ -410,10 +626,10 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { } @Test - @WithAnonymousUser - public void find_bibliographyApa2_succeeds() throws IOException, MalformedException, DataServiceException, + @WithMockUser(username = USER_2_USERNAME) + public void find_draftBibliographyApa2_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException { + FormatNotAvailableException, NotAllowedException { final String accept = "text/bibliography; style=apa"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa2.txt"), StandardCharsets.UTF_8); @@ -425,7 +641,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(IDENTIFIER_5); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_5_ID, accept); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_5_ID, accept, USER_2_PRINCIPAL); assertEquals(HttpStatus.OK, response.getStatusCode()); final String body = (String) response.getBody(); assertNotNull(body); @@ -436,7 +652,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_bibliographyApa3_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException { + FormatNotAvailableException, NotAllowedException { final String accept = "text/bibliography; style=apa"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa3.txt"), StandardCharsets.UTF_8); @@ -448,7 +664,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(IDENTIFIER_6); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_6_ID, accept); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_6_ID, accept, null); assertEquals(HttpStatus.OK, response.getStatusCode()); final String body = (String) response.getBody(); assertNotNull(body); @@ -459,7 +675,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_bibliographyApa4_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException { + FormatNotAvailableException, NotAllowedException { final String accept = "text/bibliography; style=apa"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_apa4.txt"), StandardCharsets.UTF_8); @@ -471,7 +687,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(IDENTIFIER_1_WITH_DOI); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null); assertEquals(HttpStatus.OK, response.getStatusCode()); final String body = (String) response.getBody(); assertNotNull(body); @@ -479,10 +695,10 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { } @Test - @WithAnonymousUser + @WithMockUser(username = USER_4_USERNAME) public void find_bibliographyIeee0_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException { + FormatNotAvailableException, NotAllowedException { final String accept = "text/bibliography; style=ieee"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_ieee0.txt"), StandardCharsets.UTF_8); @@ -494,7 +710,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(IDENTIFIER_7); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept, USER_4_PRINCIPAL); assertEquals(HttpStatus.OK, response.getStatusCode()); final String body = (String) response.getBody(); assertNotNull(body); @@ -505,7 +721,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_bibliographyIeee1_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException { + FormatNotAvailableException, NotAllowedException { final String accept = "text/bibliography; style=ieee"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_ieee1.txt"), StandardCharsets.UTF_8); @@ -517,7 +733,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(IDENTIFIER_1); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null); assertEquals(HttpStatus.OK, response.getStatusCode()); final String body = (String) response.getBody(); assertNotNull(body); @@ -525,10 +741,10 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { } @Test - @WithAnonymousUser + @WithMockUser(username = USER_2_USERNAME) public void find_bibliographyIeee2_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException { + FormatNotAvailableException, NotAllowedException { final String accept = "text/bibliography; style=ieee"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_ieee2.txt"), StandardCharsets.UTF_8); @@ -540,7 +756,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(IDENTIFIER_5); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_5_ID, accept); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_5_ID, accept, USER_2_PRINCIPAL); assertEquals(HttpStatus.OK, response.getStatusCode()); final String body = (String) response.getBody(); assertNotNull(body); @@ -551,7 +767,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_bibliographyIeee3_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException { + FormatNotAvailableException, NotAllowedException { final String accept = "text/bibliography; style=ieee"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_ieee3.txt"), StandardCharsets.UTF_8); @@ -563,7 +779,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(IDENTIFIER_1_WITH_DOI); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null); assertEquals(HttpStatus.OK, response.getStatusCode()); final String body = (String) response.getBody(); assertNotNull(body); @@ -571,10 +787,10 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { } @Test - @WithAnonymousUser + @WithMockUser(username = USER_4_USERNAME) public void find_bibliographyBibtex0_succeeds() throws IOException, MalformedException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException { + FormatNotAvailableException, NotAllowedException { final String accept = "text/bibliography; style=bibtex"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_bibtex0.txt"), StandardCharsets.UTF_8); @@ -586,7 +802,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(IDENTIFIER_7); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_7_ID, accept, USER_4_PRINCIPAL); assertEquals(HttpStatus.OK, response.getStatusCode()); final String body = (String) response.getBody(); assertNotNull(body); @@ -597,7 +813,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_bibliographyBibtex1_succeeds() throws MalformedException, IOException, DataServiceException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException { + FormatNotAvailableException, NotAllowedException { final String accept = "text/bibliography; style=bibtex"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_bibtex1.txt"), StandardCharsets.UTF_8); @@ -609,7 +825,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(IDENTIFIER_1); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null); assertEquals(HttpStatus.OK, response.getStatusCode()); final String body = (String) response.getBody(); assertNotNull(body); @@ -617,10 +833,10 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { } @Test - @WithAnonymousUser + @WithMockUser(username = USER_2_USERNAME) public void find_bibliographyBibtex2_succeeds() throws MalformedException, DataServiceException, IOException, DataServiceConnectionException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException { + FormatNotAvailableException, NotAllowedException { final String accept = "text/bibliography; style=bibtex"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_bibtex2.txt"), StandardCharsets.UTF_8); @@ -632,7 +848,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(IDENTIFIER_5); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_5_ID, accept); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_5_ID, accept, USER_2_PRINCIPAL); assertEquals(HttpStatus.OK, response.getStatusCode()); final String body = (String) response.getBody(); assertNotNull(body); @@ -643,7 +859,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_bibliographyBibtex3_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException, IOException, QueryNotFoundException, IdentifierNotFoundException, - FormatNotAvailableException { + FormatNotAvailableException, NotAllowedException { final String accept = "text/bibliography; style=bibtex"; final String compare = FileUtils.readFileToString(new File("src/test/resources/bibliography/style_bibtex3.txt"), StandardCharsets.UTF_8); @@ -655,7 +871,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(IDENTIFIER_1_WITH_DOI); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null); assertEquals(HttpStatus.OK, response.getStatusCode()); final String body = (String) response.getBody(); assertNotNull(body); @@ -665,7 +881,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser public void find_jsonLd_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException, - QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException { + QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException, NotAllowedException { final String accept = "application/ld+json"; /* mock */ @@ -673,7 +889,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(IDENTIFIER_1); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null); assertEquals(HttpStatus.OK, response.getStatusCode()); final LdDatasetDto body = (LdDatasetDto) response.getBody(); assertNotNull(body); @@ -689,22 +905,22 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(IDENTIFIER_7); /* test */ - assertThrows(FormatNotAvailableException.class, () -> { - identifierEndpoint.find(IDENTIFIER_7_ID, accept); + assertThrows(NotAllowedException.class, () -> { + identifierEndpoint.find(IDENTIFIER_7_ID, accept, null); }); } @Test @WithAnonymousUser public void find_move_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException, - QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException { + QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException, NotAllowedException { /* mock */ when(identifierService.find(IDENTIFIER_1_ID)) .thenReturn(IDENTIFIER_1); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, null); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, null, null); assertEquals(HttpStatus.MOVED_PERMANENTLY, response.getStatusCode()); } @@ -848,7 +1064,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser public void find_json_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException, - FormatNotAvailableException, QueryNotFoundException, IdentifierNotFoundException { + FormatNotAvailableException, QueryNotFoundException, IdentifierNotFoundException, NotAllowedException { final String accept = "application/json"; /* mock */ @@ -856,7 +1072,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { .thenReturn(IDENTIFIER_1); /* test */ - final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept); + final ResponseEntity<?> response = identifierEndpoint.find(IDENTIFIER_1_ID, accept, null); assertEquals(HttpStatus.OK, response.getStatusCode()); final IdentifierDto body = (IdentifierDto) response.getBody(); assertNotNull(body); @@ -875,7 +1091,8 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @Test @WithAnonymousUser public void find_xml_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException, - IOException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException { + IOException, QueryNotFoundException, IdentifierNotFoundException, FormatNotAvailableException, + NotAllowedException { final InputStreamResource resource = new InputStreamResource(FileUtils.openInputStream( new File("src/test/resources/xml/datacite-example-dataset-v4.xml"))); @@ -892,7 +1109,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { @WithAnonymousUser public void find_httpRedirect_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException, FormatNotAvailableException, QueryNotFoundException, - IdentifierNotFoundException { + IdentifierNotFoundException, NotAllowedException { /* test */ final ResponseEntity<?> response = generic_find(null, null); @@ -1291,7 +1508,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { protected ResponseEntity<?> generic_find(String accept, InputStreamResource resource) throws MalformedException, DataServiceException, DataServiceConnectionException, FormatNotAvailableException, - QueryNotFoundException, IdentifierNotFoundException { + QueryNotFoundException, IdentifierNotFoundException, NotAllowedException { /* mock */ when(identifierService.find(IDENTIFIER_1_ID)) @@ -1304,7 +1521,7 @@ public class IdentifierEndpointUnitTest extends AbstractUnitTest { } /* test */ - return identifierEndpoint.find(IDENTIFIER_1_ID, accept); + return identifierEndpoint.find(IDENTIFIER_1_ID, accept, null); } protected static String inputStreamToString(InputStream inputStream) throws IOException { 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 ef06d7f37fd01373df24be3c27f95919850b9fae..a17d31649e6824442613261b91bca4ee923a4817 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 @@ -1,14 +1,14 @@ package at.tuwien.endpoints; import at.tuwien.api.database.table.TableBriefDto; -import at.tuwien.api.database.table.TableCreateDto; +import at.tuwien.api.database.table.CreateTableDto; import at.tuwien.api.database.table.TableDto; import at.tuwien.api.database.table.TableUpdateDto; -import at.tuwien.api.database.table.columns.ColumnCreateDto; +import at.tuwien.api.database.table.columns.CreateTableColumnDto; import at.tuwien.api.database.table.columns.ColumnDto; import at.tuwien.api.database.table.columns.ColumnTypeDto; import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; -import at.tuwien.api.database.table.constraints.ConstraintsCreateDto; +import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto; import at.tuwien.api.semantics.EntityDto; import at.tuwien.api.semantics.TableColumnEntityDto; import at.tuwien.entities.database.Database; @@ -203,10 +203,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) public void create_publicDecimalColumnSizeTooSmall_fails() { - final TableCreateDto request = TableCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() .name("Some Table") .description("Some Description") - .columns(List.of(ColumnCreateDto.builder() + .columns(List.of(CreateTableColumnDto.builder() .name("ID") .type(ColumnTypeDto.DECIMAL) .size(-1L) // <<< @@ -224,10 +224,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) public void create_publicDecimalColumnDTooSmall_fails() { - final TableCreateDto request = TableCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() .name("Some Table") .description("Some Description") - .columns(List.of(ColumnCreateDto.builder() + .columns(List.of(CreateTableColumnDto.builder() .name("ID") .type(ColumnTypeDto.DECIMAL) .size(0L) @@ -247,10 +247,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) public void create_publicOptionalSizeNone_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, SearchServiceException, NotAllowedException, SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException, SearchServiceConnectionException { - final TableCreateDto request = TableCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() .name("Some Table") .description("Some Description") - .columns(List.of(ColumnCreateDto.builder() + .columns(List.of(CreateTableColumnDto.builder() .name("ID") .type(columnType) .size(null) // <<< @@ -278,10 +278,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) public void create_publicOptionalSize_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, SearchServiceException, NotAllowedException, SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException, SearchServiceConnectionException { - final TableCreateDto request = TableCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() .name("Some Table") .description("Some Description") - .columns(List.of(ColumnCreateDto.builder() + .columns(List.of(CreateTableColumnDto.builder() .name("ID") .type(columnType) .size(40L) @@ -303,15 +303,15 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) public void create_publicNeedNothing_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, SearchServiceException, NotAllowedException, SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException, SearchServiceConnectionException { - final TableCreateDto request = TableCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() .name("Some Table") .description("Some Description") - .columns(List.of(ColumnCreateDto.builder() + .columns(List.of(CreateTableColumnDto.builder() .name("ID") .type(columnType) .nullAllowed(false) .build())) - .constraints(ConstraintsCreateDto.builder() + .constraints(CreateTableConstraintsDto.builder() .uniques(List.of(List.of("ID"))) .build()) .build(); @@ -329,10 +329,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) public void create_publicNeedSize_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, SearchServiceException, NotAllowedException, SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException, SearchServiceConnectionException { - final TableCreateDto request = TableCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() .name("Some Table") .description("Some Description") - .columns(List.of(ColumnCreateDto.builder() + .columns(List.of(CreateTableColumnDto.builder() .name("ID") .type(columnType) .size(40L) @@ -353,10 +353,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @MethodSource("needSize_parameters") @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) public void create_publicNeedSizeNone_fails(ColumnTypeDto columnType) { - final TableCreateDto request = TableCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() .name("Some Table") .description("Some Description") - .columns(List.of(ColumnCreateDto.builder() + .columns(List.of(CreateTableColumnDto.builder() .name("ID") .type(columnType) .size(null) // <<< @@ -375,10 +375,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @MethodSource("canHaveSizeAndD_parameters") @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) public void create_publicCanHaveSizeAndDSizeNone_fails(ColumnTypeDto columnType) { - final TableCreateDto request = TableCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() .name("Some Table") .description("Some Description") - .columns(List.of(ColumnCreateDto.builder() + .columns(List.of(CreateTableColumnDto.builder() .name("ID") .type(columnType) .size(null) // <<< @@ -397,10 +397,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @MethodSource("canHaveSizeAndD_parameters") @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) public void create_publicCanHaveSizeAndDDNone_fails(ColumnTypeDto columnType) { - final TableCreateDto request = TableCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() .name("Some Table") .description("Some Description") - .columns(List.of(ColumnCreateDto.builder() + .columns(List.of(CreateTableColumnDto.builder() .name("ID") .type(columnType) .size(0L) @@ -423,10 +423,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest { DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException, SearchServiceConnectionException { - final TableCreateDto request = TableCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() .name("Some Table") .description("Some Description") - .columns(List.of(ColumnCreateDto.builder() + .columns(List.of(CreateTableColumnDto.builder() .name("ID") .type(columnType) .size(null) // <<< @@ -446,20 +446,20 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) public void create_publicHasMultipleSerial_fails() { - final TableCreateDto request = TableCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() .name("Some Table") .description("Some Description") - .columns(List.of(ColumnCreateDto.builder() + .columns(List.of(CreateTableColumnDto.builder() .name("ID") .type(ColumnTypeDto.SERIAL) .nullAllowed(false) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Counter") .type(ColumnTypeDto.SERIAL) .nullAllowed(false) .build())) - .constraints(ConstraintsCreateDto.builder() + .constraints(CreateTableConstraintsDto.builder() .uniques(List.of(List.of("ID"), List.of("Counter"))) .build()) @@ -474,15 +474,15 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) public void create_publicSerialNullAllowed_fails() { - final TableCreateDto request = TableCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() .name("Some Table") .description("Some Description") - .columns(List.of(ColumnCreateDto.builder() + .columns(List.of(CreateTableColumnDto.builder() .name("ID") .type(ColumnTypeDto.SERIAL) .nullAllowed(true) // <<< .build())) - .constraints(ConstraintsCreateDto.builder() + .constraints(CreateTableConstraintsDto.builder() .uniques(List.of(List.of("ID"))) .build()) .build(); @@ -501,10 +501,10 @@ public class TableEndpointUnitTest extends AbstractUnitTest { DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException, SearchServiceConnectionException { - final TableCreateDto request = TableCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() .name("Some Table") .description("Some Description") - .columns(List.of(ColumnCreateDto.builder() + .columns(List.of(CreateTableColumnDto.builder() .name("ID") .type(columnType) .size(0L) // <<< @@ -1040,7 +1040,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { .build(); /* test */ - final ResponseEntity<TableDto> response = generic_update(request, USER_1_PRINCIPAL); + final ResponseEntity<TableBriefDto> response = generic_update(request, USER_1_PRINCIPAL); assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); assertNotNull(response.getBody()); } @@ -1147,7 +1147,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { return tableEndpoint.list(databaseId, principal); } - protected ResponseEntity<TableDto> generic_create(Long databaseId, Database database, TableCreateDto data, + protected ResponseEntity<TableBriefDto> generic_create(Long databaseId, Database database, CreateTableDto data, Principal principal, User user, DatabaseAccess access) throws MalformedException, NotAllowedException, DataServiceException, DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, AccessNotFoundException, TableNotFoundException, @@ -1273,7 +1273,7 @@ public class TableEndpointUnitTest extends AbstractUnitTest { return tableEndpoint.updateColumn(databaseId, tableId, columnId, data, principal); } - protected ResponseEntity<TableDto> generic_update(TableUpdateDto data, Principal caller) + protected ResponseEntity<TableBriefDto> generic_update(TableUpdateDto data, Principal caller) throws TableNotFoundException, SearchServiceException, NotAllowedException, DataServiceException, DatabaseNotFoundException, SearchServiceConnectionException, DataServiceConnectionException { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UserEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UserEndpointUnitTest.java index be0ea28c496d9c3bd65df14f8a312af5c9003069..b1a65fc0cdce05ee9d1bcdfa0ad63e03f47933ba 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UserEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/UserEndpointUnitTest.java @@ -1,8 +1,6 @@ package at.tuwien.endpoints; -import at.tuwien.api.auth.LoginRequestDto; -import at.tuwien.api.auth.SignupRequestDto; -import at.tuwien.api.keycloak.UserAttributesDto; +import at.tuwien.api.auth.CreateUserDto; import at.tuwien.api.user.UserBriefDto; import at.tuwien.api.user.UserDto; import at.tuwien.api.user.UserPasswordDto; @@ -17,9 +15,6 @@ import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -34,7 +29,6 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import java.security.Principal; import java.util.List; import java.util.UUID; -import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; @@ -56,13 +50,6 @@ public class UserEndpointUnitTest extends AbstractUnitTest { @Autowired private UserEndpoint userEndpoint; - public static Stream<Arguments> getToken_parameters() { - return Stream.of( - Arguments.arguments("null", null), - Arguments.arguments("empty", new UUID[]{}) - ); - } - @BeforeEach public void beforeEach() { genesis(); @@ -104,31 +91,21 @@ public class UserEndpointUnitTest extends AbstractUnitTest { } @Test - @WithAnonymousUser - public void create_anonymous_succeeds() throws UserExistsException, EmailExistsException, UserNotFoundException, + @WithMockUser(username = USER_LOCAL_ADMIN_USERNAME, authorities = {"system"}) + public void create_succeeds() throws UserExistsException, EmailExistsException, UserNotFoundException, AuthServiceException, AuthServiceConnectionException, CredentialsInvalidException { - final SignupRequestDto request = SignupRequestDto.builder() - .email(USER_1_EMAIL) - .username(USER_1_USERNAME) - .password(USER_1_PASSWORD) - .build(); /* test */ - create_generic(request, USER_1, USER_1_KEYCLOAK_DTO, USER_1_ID); + create_generic(USER_1_SIGNUP_REQUEST_DTO, USER_1); } @Test @WithMockUser(username = USER_1_USERNAME) - public void create_isAuthenticated_fails() { - final SignupRequestDto request = SignupRequestDto.builder() - .email(USER_2_EMAIL) - .username(USER_2_USERNAME) - .password(USER_2_PASSWORD) - .build(); + public void create_noRole_fails() { /* test */ assertThrows(org.springframework.security.access.AccessDeniedException.class, () -> { - create_generic(request, null, null, null); + create_generic(USER_1_SIGNUP_REQUEST_DTO, null); }); } @@ -235,7 +212,8 @@ public class UserEndpointUnitTest extends AbstractUnitTest { @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"modify-user-information"}) - public void modify_succeeds() throws NotAllowedException, UserNotFoundException, DatabaseNotFoundException { + public void modify_succeeds() throws NotAllowedException, UserNotFoundException, DatabaseNotFoundException, + AuthServiceException, AuthServiceConnectionException { final UserUpdateDto request = UserUpdateDto.builder() .firstname(USER_1_FIRSTNAME) .lastname(USER_1_LASTNAME) @@ -286,136 +264,6 @@ public class UserEndpointUnitTest extends AbstractUnitTest { password_generic(USER_1_PRINCIPAL, request); } - @Test - @WithAnonymousUser - public void getToken_anonymous_succeeds() throws UserNotFoundException, AuthServiceException, - AuthServiceConnectionException, AccountNotSetupException, CredentialsInvalidException { - - /* test */ - getToken_generic(USER_1_LOGIN_REQUEST_DTO, USER_1_PRINCIPAL, USER_1); - } - - @Test - @WithMockUser(username = USER_1_USERNAME) - public void getToken_loggedIn_succeeds() throws UserNotFoundException, AuthServiceException, - AuthServiceConnectionException, AccountNotSetupException, CredentialsInvalidException { - - /* test */ - getToken_generic(USER_1_LOGIN_REQUEST_DTO, USER_1_PRINCIPAL, USER_1); - } - - @Test - @WithAnonymousUser - public void getToken_notExists_succeeds() throws UserNotFoundException, AuthServiceException, - AuthServiceConnectionException, AccountNotSetupException, CredentialsInvalidException { - - /* mock */ - when(authenticationService.findByUsername(USER_1_USERNAME)) - .thenReturn(USER_1_KEYCLOAK_DTO); - when(userService.create(any(SignupRequestDto.class), any(UUID.class))) - .thenReturn(USER_1); - - /* test */ - getToken_generic(USER_1_LOGIN_REQUEST_DTO, USER_1_PRINCIPAL, null); - } - - @Test - @WithAnonymousUser - public void getToken_notExists_fails() throws UserNotFoundException, AuthServiceException, - AuthServiceConnectionException, CredentialsInvalidException { - - /* mock */ - doThrow(UserNotFoundException.class) - .when(authenticationService) - .findByUsername(USER_1_USERNAME); - - /* test */ - assertThrows(UserNotFoundException.class, () -> { - getToken_generic(USER_1_LOGIN_REQUEST_DTO, USER_1_PRINCIPAL, null); - }); - } - - @ParameterizedTest - @MethodSource("getToken_parameters") - @WithAnonymousUser - public void getToken_missingLdapId_fails(String name, UUID[] ldapId) throws UserNotFoundException, AuthServiceException, - AuthServiceConnectionException, CredentialsInvalidException { - final at.tuwien.api.keycloak.UserDto mock = at.tuwien.api.keycloak.UserDto.builder() - .attributes(UserAttributesDto.builder() - .ldapId(ldapId) - .build()) - .build(); - - /* mock */ - when(authenticationService.findByUsername(USER_1_USERNAME)) - .thenReturn(mock); - - /* test */ - assertThrows(UserNotFoundException.class, () -> { - getToken_generic(USER_1_LOGIN_REQUEST_DTO, USER_1_PRINCIPAL, null); - }); - } - - @Test - @WithAnonymousUser - public void refreshToken_anonymous_succeeds() throws AuthServiceConnectionException, CredentialsInvalidException { - - /* mock */ - when(authenticationService.refreshToken(anyString())) - .thenReturn(TOKEN_DTO); - - /* test */ - final ResponseEntity<?> response = userEndpoint.refreshToken(REFRESH_TOKEN_REQUEST_DTO); - assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); - assertNotNull(response.getBody()); - } - - @Test - @WithMockUser(username = USER_1_USERNAME) - public void refreshToken_loggedIn_succeeds() throws AuthServiceConnectionException, CredentialsInvalidException { - - /* mock */ - when(authenticationService.refreshToken(anyString())) - .thenReturn(TOKEN_DTO); - - /* test */ - final ResponseEntity<?> response = userEndpoint.refreshToken(REFRESH_TOKEN_REQUEST_DTO); - assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); - assertNotNull(response.getBody()); - } - - @Test - @WithMockUser(username = USER_1_USERNAME) - public void refreshToken_authServiceConnection_fails() throws AuthServiceConnectionException, - CredentialsInvalidException { - - /* mock */ - doThrow(AuthServiceConnectionException.class) - .when(authenticationService) - .refreshToken(anyString()); - - /* test */ - assertThrows(AuthServiceConnectionException.class, () -> { - userEndpoint.refreshToken(REFRESH_TOKEN_REQUEST_DTO); - }); - } - - @Test - @WithMockUser(username = USER_1_USERNAME) - public void refreshToken_invalidCredentials_fails() throws AuthServiceConnectionException, - CredentialsInvalidException { - - /* mock */ - doThrow(CredentialsInvalidException.class) - .when(authenticationService) - .refreshToken(anyString()); - - /* test */ - assertThrows(CredentialsInvalidException.class, () -> { - userEndpoint.refreshToken(REFRESH_TOKEN_REQUEST_DTO); - }); - } - /* ################################################################################################### */ /* ## GENERIC TEST CASES ## */ /* ################################################################################################### */ @@ -445,22 +293,17 @@ public class UserEndpointUnitTest extends AbstractUnitTest { return response.getBody(); } - protected void create_generic(SignupRequestDto data, User user, at.tuwien.api.keycloak.UserDto userDto, UUID id) - throws UserExistsException, EmailExistsException, UserNotFoundException, AuthServiceException, - AuthServiceConnectionException, CredentialsInvalidException { + protected void create_generic(CreateUserDto data, User user) throws UserExistsException, EmailExistsException, + UserNotFoundException, AuthServiceException, AuthServiceConnectionException, CredentialsInvalidException { /* mock */ - when(userService.create(eq(data), any(UUID.class))) + when(userService.create(any(CreateUserDto.class))) .thenReturn(user); - when(authenticationService.findByUsername(data.getUsername())) - .thenReturn(userDto); - when(authenticationService.create(data)) - .thenReturn(userDto); /* test */ - final ResponseEntity<UserDto> response = userEndpoint.create(data); + final ResponseEntity<UserBriefDto> response = userEndpoint.create(data); assertEquals(HttpStatus.CREATED, response.getStatusCode()); - final UserDto body = response.getBody(); + final UserBriefDto body = response.getBody(); assertNotNull(body); } @@ -486,7 +329,8 @@ public class UserEndpointUnitTest extends AbstractUnitTest { } protected void modify_generic(UUID userId, User user, Principal principal, UserUpdateDto data) - throws NotAllowedException, UserNotFoundException, DatabaseNotFoundException { + throws NotAllowedException, UserNotFoundException, DatabaseNotFoundException, AuthServiceException, + AuthServiceConnectionException { /* mock */ if (user != null) { when(userService.findById(userId)) @@ -496,9 +340,9 @@ public class UserEndpointUnitTest extends AbstractUnitTest { .thenReturn(user); /* test */ - final ResponseEntity<UserDto> response = userEndpoint.modify(userId, data, principal); + final ResponseEntity<UserBriefDto> response = userEndpoint.modify(userId, data, principal); assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); - final UserDto body = response.getBody(); + final UserBriefDto body = response.getBody(); assertNotNull(body); } @@ -522,26 +366,4 @@ public class UserEndpointUnitTest extends AbstractUnitTest { final ResponseEntity<?> response = userEndpoint.password(USER_1_ID, data, principal); assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); } - - protected void getToken_generic(LoginRequestDto request, Principal principal, User user) - throws UserNotFoundException, AuthServiceConnectionException, AccountNotSetupException, - CredentialsInvalidException, AuthServiceException { - - /* mock */ - when(authenticationService.obtainToken(any(LoginRequestDto.class))) - .thenReturn(TOKEN_DTO); - if (user != null) { - when(userService.findByUsername(principal.getName())) - .thenReturn(user); - } else { - doThrow(UserNotFoundException.class) - .when(userService) - .findByUsername(principal.getName()); - } - - /* test */ - final ResponseEntity<?> response = userEndpoint.getToken(request); - assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); - assertNotNull(response.getBody()); - } } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java index 2815dd6c0557a31490dff959bcff7f60e559b805..d1434ef9e4035cd13d81a4f12ec68bad71683bf1 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/ViewEndpointUnitTest.java @@ -1,7 +1,7 @@ package at.tuwien.endpoints; +import at.tuwien.api.database.CreateViewDto; import at.tuwien.api.database.ViewBriefDto; -import at.tuwien.api.database.ViewCreateDto; import at.tuwien.api.database.ViewDto; import at.tuwien.api.database.ViewUpdateDto; import at.tuwien.entities.database.Database; @@ -21,6 +21,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.AccessDeniedException; @@ -173,6 +174,25 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { find_generic(DATABASE_3_ID, DATABASE_3, USER_2_PRINCIPAL, USER_2_ID, USER_2, DATABASE_2_USER_1_READ_ACCESS); } + @Test + @WithMockUser(username = USER_2_USERNAME) + public void find_publicSystem_succeeds() throws UserNotFoundException, DatabaseNotFoundException, + AccessNotFoundException, ViewNotFoundException { + + /* test */ + final ResponseEntity<ViewDto> response = find_generic(DATABASE_3_ID, DATABASE_3, USER_LOCAL_ADMIN_PRINCIPAL, + USER_LOCAL_ADMIN_ID, null, null); + final HttpHeaders headers = response.getHeaders(); + assertEquals(List.of(CONTAINER_1_PRIVILEGED_USERNAME), headers.get("X-Username")); + assertEquals(List.of(CONTAINER_1_PRIVILEGED_PASSWORD), headers.get("X-Password")); + assertEquals(List.of(CONTAINER_1_HOST), headers.get("X-Host")); + assertEquals(List.of("" + CONTAINER_1_PORT), headers.get("X-Port")); + assertEquals(List.of(IMAGE_1_JDBC), headers.get("X-Type")); + assertEquals(List.of(DATABASE_3_INTERNALNAME), headers.get("X-Database")); + assertEquals(List.of(VIEW_5_INTERNAL_NAME), headers.get("X-View")); + assertEquals(List.of("X-Username X-Password X-Host X-Port X-Type X-Database X-View"), headers.get("Access-Control-Expose-Headers")); + } + @Test @WithMockUser(username = USER_2_USERNAME) public void find_publicHasRoleHasAccess_succeeds() throws UserNotFoundException, DatabaseNotFoundException, @@ -461,7 +481,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { DatabaseAccess access) throws MalformedException, DataServiceException, DataServiceConnectionException, NotAllowedException, UserNotFoundException, DatabaseNotFoundException, AccessNotFoundException, SearchServiceException, SearchServiceConnectionException { - final ViewCreateDto request = ViewCreateDto.builder() + final CreateViewDto request = CreateViewDto.builder() .name(VIEW_1_NAME) .query(VIEW_1_QUERY) .isPublic(VIEW_1_PUBLIC) @@ -494,9 +514,9 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { assertEquals(VIEW_1_NAME, response.getBody().getName()); } - protected void find_generic(Long databaseId, Database database, Principal principal, UUID userId, User user, - DatabaseAccess access) throws DatabaseNotFoundException, UserNotFoundException, - AccessNotFoundException, ViewNotFoundException { + protected ResponseEntity<ViewDto> find_generic(Long databaseId, Database database, Principal principal, + UUID userId, User user, DatabaseAccess access) + throws DatabaseNotFoundException, UserNotFoundException, AccessNotFoundException, ViewNotFoundException { /* mock */ when(databaseService.findById(databaseId)) @@ -514,18 +534,18 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { when(userService.findById(userId)) .thenReturn(user); when(viewService.findById(any(Database.class), anyLong())) - .thenReturn(VIEW_1); + .thenReturn(VIEW_5); } else { when(viewService.findById(any(Database.class), anyLong())) - .thenReturn(VIEW_1); + .thenReturn(VIEW_5); } /* test */ - final ResponseEntity<ViewDto> response = viewEndpoint.find(databaseId, VIEW_1_ID, USER_1_PRINCIPAL); + final ResponseEntity<ViewDto> response = viewEndpoint.find(databaseId, VIEW_5_ID, principal); assertEquals(HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); - assertEquals(VIEW_1_ID, response.getBody().getId()); - assertEquals(VIEW_1_NAME, response.getBody().getName()); + assertEquals(VIEW_5_ID, response.getBody().getId()); + return response; } protected void delete_generic(Long databaseId, Database database, Long viewId, View view, Principal principal, @@ -571,7 +591,7 @@ public class ViewEndpointUnitTest extends AbstractUnitTest { .thenReturn(VIEW_1); /* test */ - final ResponseEntity<ViewDto> response = viewEndpoint.update(DATABASE_1_ID, VIEW_1_ID, request, principal); + final ResponseEntity<ViewBriefDto> response = viewEndpoint.update(DATABASE_1_ID, VIEW_1_ID, request, principal); assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); assertNotNull(response.getBody()); } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayIntegrationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e72cd7fa7591a7e641c74df6eab07845b0a193ea --- /dev/null +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayIntegrationTest.java @@ -0,0 +1,114 @@ +package at.tuwien.gateway; + +import at.tuwien.exception.UserNotFoundException; +import at.tuwien.gateway.impl.KeycloakGatewayImpl; +import at.tuwien.test.AbstractUnitTest; +import at.tuwien.utils.KeycloakUtils; +import dasniko.testcontainers.keycloak.KeycloakContainer; +import lombok.extern.log4j.Log4j2; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.testcontainers.images.PullPolicy; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +@Log4j2 +@SpringBootTest +@Testcontainers +@ExtendWith(SpringExtension.class) +public class KeycloakGatewayIntegrationTest extends AbstractUnitTest { + + @Autowired + private KeycloakGatewayImpl keycloakGateway; + + @Autowired + private KeycloakUtils keycloakUtils; + + @BeforeEach + public void beforeEach() { + genesis(); + /* auth service */ + keycloakUtils.deleteUser(USER_1_USERNAME); + } + + @Container + private static KeycloakContainer keycloakContainer = new KeycloakContainer(KEYCLOAK_IMAGE) + .withImagePullPolicy(PullPolicy.alwaysPull()) + .withAdminUsername("admin") + .withAdminPassword("admin") + .withRealmImportFile("./init/dbrepo-realm.json") + .withEnv("KC_HOSTNAME_STRICT_HTTPS", "false"); + + @DynamicPropertySource + static void keycloakProperties(DynamicPropertyRegistry registry) { + final String authServiceEndpoint = "http://localhost:" + keycloakContainer.getMappedPort(8080); + log.trace("set auth endpoint: {}", authServiceEndpoint); + registry.add("dbrepo.endpoints.authService", () -> authServiceEndpoint); + } + + @Test + public void deleteUser_succeeds() throws UserNotFoundException { + + /* mock */ + keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST); + + /* test */ + keycloakGateway.deleteUser(keycloakUtils.getUserId(USER_1_USERNAME)); + } + + @Test + public void deleteUser_notFound_fails() { + + /* test */ + assertThrows(UserNotFoundException.class, () -> { + keycloakGateway.deleteUser(USER_1_ID); + }); + } + + @Test + public void findByUsername_succeeds() throws UserNotFoundException { + + /* mock */ + keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST); + + /* test */ + keycloakGateway.findByUsername(USER_1_USERNAME); + } + + @Test + public void findByUsername_notFound_fails() { + + /* test */ + assertThrows(UserNotFoundException.class, () -> { + keycloakGateway.findByUsername(USER_1_USERNAME); + }); + } + + @Test + public void updateUserCredentials_succeeds() throws UserNotFoundException { + + /* mock */ + keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST); + + /* test */ + keycloakGateway.updateUserCredentials(keycloakUtils.getUserId(USER_1_USERNAME), USER_1_PASSWORD_DTO); + } + + @Test + public void updateUserCredentials_notFound_fails() { + + /* test */ + assertThrows(UserNotFoundException.class, () -> { + keycloakGateway.updateUserCredentials(keycloakUtils.getUserId(USER_1_USERNAME), USER_1_PASSWORD_DTO); + }); + } + +} diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayUnitTest.java deleted file mode 100644 index bb3bcbb094ad1e9a2510abe20b9649ee73e6e975..0000000000000000000000000000000000000000 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/KeycloakGatewayUnitTest.java +++ /dev/null @@ -1,489 +0,0 @@ -package at.tuwien.gateway; - -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.keycloak.TokenDto; -import at.tuwien.api.keycloak.UserDto; -import at.tuwien.exception.*; -import at.tuwien.gateway.impl.KeycloakGatewayImpl; -import lombok.extern.log4j.Log4j2; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.*; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.HttpServerErrorException; -import org.springframework.web.client.RestTemplate; - -import java.nio.charset.Charset; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; - -@Log4j2 -@SpringBootTest -@ExtendWith(SpringExtension.class) -public class KeycloakGatewayUnitTest extends AbstractUnitTest { - - @MockBean - @Qualifier("keycloakRestTemplate") - private RestTemplate keycloakRestTemplate; - - @MockBean - @Qualifier("restTemplate") - private RestTemplate restTemplate; - - @Autowired - private KeycloakGatewayImpl keycloakGateway; - - @Test - public void createUser_succeeds() throws UserExistsException, EmailExistsException, AuthServiceException, - AuthServiceConnectionException { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class))) - .thenReturn(ResponseEntity.status(HttpStatus.CREATED) - .build()); - - /* test */ - keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST); - } - - @Test - public void createUser_fails() { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class))) - .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT) - .build()); - - /* test */ - assertThrows(AuthServiceException.class, () -> { - keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST); - }); - } - - @Test - public void createUser_sameUsername_fails() { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - doThrow(HttpClientErrorException.Conflict.class) - .when(keycloakRestTemplate) - .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class)); - - /* test */ - assertThrows(UserExistsException.class, () -> { - keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST); - }); - } - - @Test - public void createUser_connection_fails() { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - doThrow(HttpServerErrorException.class) - .when(keycloakRestTemplate) - .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class)); - - /* test */ - assertThrows(AuthServiceConnectionException.class, () -> { - keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST); - }); - } - - @Test - public void deleteUser_fails() { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .build()); - - /* test */ - assertThrows(AuthServiceException.class, () -> { - keycloakGateway.deleteUser(USER_1_ID); - }); - } - - @Test - public void deleteUser_succeeds() throws UserNotFoundException, AuthServiceException, - AuthServiceConnectionException { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class))) - .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT) - .build()); - - /* test */ - keycloakGateway.deleteUser(USER_1_ID); - } - - @Test - public void deleteUser_notFound_fails() { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - doThrow(HttpClientErrorException.NotFound.class) - .when(keycloakRestTemplate) - .exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class)); - - /* test */ - assertThrows(UserNotFoundException.class, () -> { - keycloakGateway.deleteUser(USER_1_ID); - }); - } - - @Test - public void deleteUser_unexpected_fails() { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - doThrow(HttpClientErrorException.Conflict.class) - .when(keycloakRestTemplate) - .exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class)); - - /* test */ - assertThrows(AuthServiceException.class, () -> { - keycloakGateway.deleteUser(USER_1_ID); - }); - } - - @Test - public void deleteUser_connection_fails() { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - doThrow(HttpServerErrorException.class) - .when(keycloakRestTemplate) - .exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class)); - - /* test */ - assertThrows(AuthServiceConnectionException.class, () -> { - keycloakGateway.deleteUser(USER_1_ID); - }); - } - - @Test - public void updateUserCredentials_succeeds() throws AuthServiceException, AuthServiceConnectionException, - UserNotFoundException { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class))) - .thenReturn(ResponseEntity.status(HttpStatus.NO_CONTENT) - .build()); - - /* test */ - keycloakGateway.updateUserCredentials(USER_1_ID, USER_1_PASSWORD_DTO); - } - - @Test - public void updateUserCredentials_fails() { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .build()); - - /* test */ - assertThrows(AuthServiceException.class, () -> { - keycloakGateway.updateUserCredentials(USER_1_ID, USER_1_PASSWORD_DTO); - }); - } - - @Test - public void updateUserCredentials_connection_fails() { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - doThrow(HttpServerErrorException.class) - .when(keycloakRestTemplate) - .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)); - - /* test */ - assertThrows(AuthServiceConnectionException.class, () -> { - keycloakGateway.updateUserCredentials(USER_1_ID, USER_1_PASSWORD_DTO); - }); - } - - @Test - public void updateUserCredentials_unexpected_fails() { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - doThrow(HttpClientErrorException.Conflict.class) - .when(keycloakRestTemplate) - .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class)); - - /* test */ - assertThrows(AuthServiceException.class, () -> { - keycloakGateway.updateUserCredentials(USER_1_ID, USER_1_PASSWORD_DTO); - }); - } - - @Test - public void findByUsername_notFound_fails() { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto[].class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(new UserDto[]{})); - - /* test */ - assertThrows(UserNotFoundException.class, () -> { - keycloakGateway.findByUsername(USER_1_USERNAME); - }); - } - - @Test - public void findByUsername_connection_fails() { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - doThrow(HttpServerErrorException.class) - .when(keycloakRestTemplate) - .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto[].class)); - - /* test */ - assertThrows(AuthServiceConnectionException.class, () -> { - keycloakGateway.findByUsername(USER_1_USERNAME); - }); - } - - @Test - public void findByUsername_unexpected_fails() { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - doThrow(HttpClientErrorException.Conflict.class) - .when(keycloakRestTemplate) - .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto[].class)); - - /* test */ - assertThrows(AuthServiceException.class, () -> { - keycloakGateway.findByUsername(USER_1_USERNAME); - }); - } - - @Test - public void findById_succeeds() throws UserNotFoundException, AuthServiceException, AuthServiceConnectionException { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - when(keycloakRestTemplate.exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(USER_1_KEYCLOAK_DTO)); - - /* test */ - final UserDto response = keycloakGateway.findById(USER_1_ID); - assertEquals(USER_1_ID, response.getId()); - } - - @Test - public void findById_notFound_fails() { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - doThrow(HttpClientErrorException.NotFound.class) - .when(keycloakRestTemplate) - .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto.class)); - - /* test */ - assertThrows(UserNotFoundException.class, () -> { - keycloakGateway.findById(USER_1_ID); - }); - } - - @Test - public void findById_connection_fails() { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - doThrow(HttpServerErrorException.class) - .when(keycloakRestTemplate) - .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto.class)); - - /* test */ - assertThrows(AuthServiceConnectionException.class, () -> { - keycloakGateway.findById(USER_1_ID); - }); - } - - @Test - public void findById_unexpected_fails() { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - doThrow(HttpClientErrorException.Conflict.class) - .when(keycloakRestTemplate) - .exchange(anyString(), eq(HttpMethod.GET), any(HttpEntity.class), eq(UserDto.class)); - - /* test */ - assertThrows(AuthServiceException.class, () -> { - keycloakGateway.findById(USER_1_ID); - }); - } - - @Test - public void refreshUserToken_succeeds() throws AuthServiceConnectionException, CredentialsInvalidException { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - - /* test */ - final TokenDto response = keycloakGateway.refreshUserToken(TOKEN_DTO.getRefreshToken()); - assertNotNull(response.getAccessToken()); - } - - @Test - public void refreshUserToken_connection_fails() { - - /* mock */ - doThrow(HttpServerErrorException.class) - .when(restTemplate) - .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)); - - /* test */ - assertThrows(AuthServiceConnectionException.class, () -> { - keycloakGateway.refreshUserToken(TOKEN_DTO.getRefreshToken()); - }); - } - - @Test - public void refreshUserToken_unauthorized_fails() { - - /* mock */ - doThrow(HttpClientErrorException.Unauthorized.class) - .when(restTemplate) - .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)); - - /* test */ - assertThrows(CredentialsInvalidException.class, () -> { - keycloakGateway.refreshUserToken(TOKEN_DTO.getRefreshToken()); - }); - } - - @Test - public void refreshUserToken_badRequest_fails() { - - /* mock */ - doThrow(HttpClientErrorException.BadRequest.class) - .when(restTemplate) - .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)); - - /* test */ - assertThrows(CredentialsInvalidException.class, () -> { - keycloakGateway.refreshUserToken(TOKEN_DTO.getRefreshToken()); - }); - } - - @Test - public void refreshUserToken_badRequestInactiveSession_fails() { - - /* mock */ - doThrow(HttpClientErrorException.BadRequest.create(HttpStatus.BAD_REQUEST, "Session not active", new HttpHeaders(), new byte[]{}, Charset.defaultCharset())) - .when(restTemplate) - .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)); - - /* test */ - assertThrows(CredentialsInvalidException.class, () -> { - keycloakGateway.refreshUserToken(TOKEN_DTO.getRefreshToken()); - }); - } - - @Test - public void obtainUserToken_succeeds() throws AuthServiceConnectionException, - AccountNotSetupException, CredentialsInvalidException { - - /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class))) - .thenReturn(ResponseEntity.status(HttpStatus.OK) - .body(TOKEN_DTO)); - - /* test */ - final TokenDto response = keycloakGateway.obtainUserToken(USER_1_USERNAME, USER_1_PASSWORD); - assertNotNull(response.getAccessToken()); - } - - @Test - public void obtainUserToken_connection_fails() { - - /* mock */ - doThrow(HttpServerErrorException.class) - .when(restTemplate) - .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)); - - /* test */ - assertThrows(AuthServiceConnectionException.class, () -> { - keycloakGateway.obtainUserToken(USER_1_USERNAME, USER_1_PASSWORD); - }); - } - - @Test - public void obtainUserToken_unauthorized_fails() { - - /* mock */ - doThrow(HttpClientErrorException.Unauthorized.class) - .when(restTemplate) - .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(TokenDto.class)); - - /* test */ - assertThrows(CredentialsInvalidException.class, () -> { - keycloakGateway.obtainUserToken(USER_1_USERNAME, USER_1_PASSWORD); - }); - } - -} diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/SearchServiceGatewayUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/SearchServiceGatewayUnitTest.java index b1ce21d4e5e8315b08087dc0d85712509a07973e..b39dd06bac8cd722ccc6e464b1b97438f48b4850 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/SearchServiceGatewayUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/gateway/SearchServiceGatewayUnitTest.java @@ -1,7 +1,7 @@ package at.tuwien.gateway; import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.database.DatabaseDto; +import at.tuwien.api.database.DatabaseBriefDto; import at.tuwien.exception.*; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.Test; @@ -37,11 +37,11 @@ public class SearchServiceGatewayUnitTest extends AbstractUnitTest { @Test public void update_succeeds() throws DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException { - final ResponseEntity<DatabaseDto> mock = ResponseEntity.accepted() + final ResponseEntity<DatabaseBriefDto> mock = ResponseEntity.accepted() .build(); /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class))) + when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class))) .thenReturn(mock); /* test */ @@ -50,11 +50,11 @@ public class SearchServiceGatewayUnitTest extends AbstractUnitTest { @Test public void update_badRequest_fails() { - final ResponseEntity<DatabaseDto> mock = ResponseEntity.status(HttpStatus.BAD_REQUEST) + final ResponseEntity<DatabaseBriefDto> mock = ResponseEntity.status(HttpStatus.BAD_REQUEST) .build(); /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class))) + when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class))) .thenReturn(mock); /* test */ @@ -65,11 +65,11 @@ public class SearchServiceGatewayUnitTest extends AbstractUnitTest { @Test public void update_unexpectedResponse_fails() { - final ResponseEntity<DatabaseDto> mock = ResponseEntity.status(HttpStatus.OK) + final ResponseEntity<DatabaseBriefDto> mock = ResponseEntity.status(HttpStatus.OK) .build(); /* mock */ - when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class))) + when(restTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class))) .thenReturn(mock); /* test */ @@ -84,7 +84,7 @@ public class SearchServiceGatewayUnitTest extends AbstractUnitTest { /* mock */ doThrow(HttpServerErrorException.ServiceUnavailable.class) .when(restTemplate) - .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class)); + .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class)); /* test */ assertThrows(SearchServiceConnectionException.class, () -> { @@ -98,7 +98,7 @@ public class SearchServiceGatewayUnitTest extends AbstractUnitTest { /* mock */ doThrow(HttpClientErrorException.NotFound.class) .when(restTemplate) - .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class)); + .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class)); /* test */ assertThrows(DatabaseNotFoundException.class, () -> { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java index 9b778e67fb3243e238053972add0f3522c07b9d6..6505506eeaca607cd96e3324e869c2db0907cc4f 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java @@ -1,13 +1,7 @@ package at.tuwien.mapper; -import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.ViewBriefDto; -import at.tuwien.api.database.ViewDto; -import at.tuwien.api.database.table.TableBriefDto; -import at.tuwien.api.identifier.IdentifierDto; import at.tuwien.api.identifier.IdentifierTypeDto; import at.tuwien.api.user.UserBriefDto; -import at.tuwien.api.user.UserDto; import at.tuwien.entities.identifier.Identifier; import at.tuwien.entities.identifier.IdentifierType; import at.tuwien.test.AbstractUnitTest; diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/AuthenticationPrivilegedIntegrationMvcTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/AuthenticationPrivilegedIntegrationMvcTest.java index eec5aebf4bea668164c51bae655c074cb306e4c2..0365db6c4a09dfaedb742528b3bb08d4784d53f1 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/AuthenticationPrivilegedIntegrationMvcTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/AuthenticationPrivilegedIntegrationMvcTest.java @@ -9,8 +9,6 @@ import at.tuwien.repository.ContainerRepository; import at.tuwien.repository.DatabaseRepository; import at.tuwien.repository.LicenseRepository; import at.tuwien.repository.UserRepository; -import at.tuwien.service.AuthenticationService; -import at.tuwien.service.UserService; import at.tuwien.test.AbstractUnitTest; import at.tuwien.utils.KeycloakUtils; import dasniko.testcontainers.keycloak.KeycloakContainer; @@ -31,7 +29,7 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.util.List; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; @@ -50,9 +48,6 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest @Autowired private KeycloakUtils keycloakUtils; - @Autowired - private KeycloakGateway keycloakGateway; - @Autowired private UserRepository userRepository; @@ -66,7 +61,7 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest private DatabaseRepository databaseRepository; @Autowired - private AuthenticationService authenticationService; + private KeycloakGateway keycloakGateway; @Container private static KeycloakContainer keycloakContainer = new KeycloakContainer(KEYCLOAK_IMAGE) @@ -98,7 +93,7 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest public void findById_database_basicUser_succeeds() throws Exception { /* mock */ - keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST); + keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST); /* test */ this.mockMvc.perform(get("/api/database/1").with(httpBasic(USER_1_USERNAME, USER_1_PASSWORD))) @@ -113,16 +108,14 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest public void findById_database_basicAdmin_succeeds() throws Exception { /* pre condition */ - keycloakGateway.createUser(USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST); + keycloakUtils.createUser(USER_LOCAL_ADMIN_ID, USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST); /* test */ this.mockMvc.perform(get("/api/database/1").with(httpBasic(USER_LOCAL_ADMIN_USERNAME, USER_LOCAL_ADMIN_PASSWORD))) .andDo(print()) .andExpect(header().string("X-Username", CONTAINER_1_PRIVILEGED_USERNAME)) .andExpect(header().string("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD)) - .andExpect(header().string("X-Host", CONTAINER_1_HOST)) - .andExpect(header().string("X-Port", "" + CONTAINER_1_PORT)) - .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port")) + .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password")) .andExpect(status().isOk()); } @@ -130,17 +123,15 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest public void findById_database_bearerAdmin_succeeds() throws Exception { /* pre condition */ - keycloakGateway.createUser(USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST); - final TokenDto jwt = authenticationService.obtainToken(USER_LOCAL_ADMIN_LOGIN_REQUEST_DTO); + keycloakUtils.createUser(USER_LOCAL_ADMIN_ID, USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST); + final TokenDto jwt = keycloakGateway.obtainUserToken(USER_LOCAL_ADMIN_USERNAME, USER_LOCAL_ADMIN_PASSWORD); /* test */ this.mockMvc.perform(get("/api/database/1").header("Authorization", "Bearer " + jwt.getAccessToken())) .andDo(print()) .andExpect(header().string("X-Username", CONTAINER_1_PRIVILEGED_USERNAME)) .andExpect(header().string("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD)) - .andExpect(header().string("X-Host", CONTAINER_1_HOST)) - .andExpect(header().string("X-Port", "" + CONTAINER_1_PORT)) - .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port")) + .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password")) .andExpect(status().isOk()); } @@ -148,8 +139,8 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest public void findById_table_bearerAdmin_succeeds() throws Exception { /* pre condition */ - keycloakGateway.createUser(USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST); - final TokenDto jwt = authenticationService.obtainToken(USER_LOCAL_ADMIN_LOGIN_REQUEST_DTO); + keycloakUtils.createUser(USER_LOCAL_ADMIN_ID, USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST); + final TokenDto jwt = keycloakGateway.obtainUserToken(USER_LOCAL_ADMIN_USERNAME, USER_LOCAL_ADMIN_PASSWORD); /* test */ @@ -157,12 +148,7 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest .andDo(print()) .andExpect(header().string("X-Username", CONTAINER_1_PRIVILEGED_USERNAME)) .andExpect(header().string("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD)) - .andExpect(header().string("X-Host", CONTAINER_1_HOST)) - .andExpect(header().string("X-Port", "" + CONTAINER_1_PORT)) - .andExpect(header().string("X-Type", IMAGE_1_JDBC)) - .andExpect(header().string("X-Database", DATABASE_1_INTERNALNAME)) - .andExpect(header().string("X-Table", TABLE_1_INTERNAL_NAME)) - .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port X-Type X-Database X-Table")) + .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password")) .andExpect(status().isOk()); } @@ -170,18 +156,13 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest public void findById_table_basicUser_succeeds() throws Exception { /* mock */ - keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST); + keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST); /* test */ this.mockMvc.perform(get("/api/database/1/table/1").with(httpBasic(USER_1_USERNAME, USER_1_PASSWORD))) .andDo(print()) .andExpect(header().doesNotExist("X-Username")) .andExpect(header().doesNotExist("X-Password")) - .andExpect(header().doesNotExist("X-Host")) - .andExpect(header().doesNotExist("X-Port")) - .andExpect(header().doesNotExist("X-Type")) - .andExpect(header().doesNotExist("X-Database")) - .andExpect(header().doesNotExist("X-Table")) .andExpect(header().doesNotExist("Access-Control-Expose-Headers")) .andExpect(status().isOk()); } @@ -190,19 +171,14 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest public void findById_table_basicAdmin_succeeds() throws Exception { /* mock */ - keycloakGateway.createUser(USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST); + keycloakUtils.createUser(USER_LOCAL_ADMIN_ID, USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST); /* test */ this.mockMvc.perform(get("/api/database/1/table/1").with(httpBasic(USER_LOCAL_ADMIN_USERNAME, USER_LOCAL_ADMIN_PASSWORD))) .andDo(print()) .andExpect(header().string("X-Username", CONTAINER_1_PRIVILEGED_USERNAME)) .andExpect(header().string("X-Password", CONTAINER_1_PRIVILEGED_PASSWORD)) - .andExpect(header().string("X-Host", CONTAINER_1_HOST)) - .andExpect(header().string("X-Port", "" + CONTAINER_1_PORT)) - .andExpect(header().string("X-Type", IMAGE_1_JDBC)) - .andExpect(header().string("X-Database", DATABASE_1_INTERNALNAME)) - .andExpect(header().string("X-Table", TABLE_1_INTERNAL_NAME)) - .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port X-Type X-Database X-Table")) + .andExpect(header().string("Access-Control-Expose-Headers", "X-Username X-Password")) .andExpect(status().isOk()); } @@ -210,18 +186,13 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest public void findById_view_basicUser_succeeds() throws Exception { /* mock */ - keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST); + keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST); /* test */ this.mockMvc.perform(get("/api/database/1/view/1").with(httpBasic(USER_1_USERNAME, USER_1_PASSWORD))) .andDo(print()) .andExpect(header().doesNotExist("X-Username")) .andExpect(header().doesNotExist("X-Password")) - .andExpect(header().doesNotExist("X-Host")) - .andExpect(header().doesNotExist("X-Port")) - .andExpect(header().doesNotExist("X-Type")) - .andExpect(header().doesNotExist("X-Database")) - .andExpect(header().doesNotExist("X-View")) .andExpect(header().doesNotExist("Access-Control-Expose-Headers")) .andExpect(status().isOk()); } @@ -230,7 +201,7 @@ public class AuthenticationPrivilegedIntegrationMvcTest extends AbstractUnitTest public void findById_container_basicUser_succeeds() throws Exception { /* mock */ - keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST); + keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST); /* test */ this.mockMvc.perform(get("/api/container/1").with(httpBasic(USER_1_USERNAME, USER_1_PASSWORD))) diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java index 5ae4aad0187cc52749416bdb3208d3ff678d5285..790262c7399d36fb0d9a3cf6103f7899300daffb 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mvc/PrometheusEndpointMvcTest.java @@ -1,15 +1,14 @@ package at.tuwien.mvc; -import at.tuwien.api.auth.RefreshTokenRequestDto; -import at.tuwien.api.database.table.TableStatisticDto; -import at.tuwien.api.database.table.columns.ColumnStatisticDto; -import at.tuwien.api.semantics.TableColumnEntityDto; -import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.container.ContainerCreateDto; -import at.tuwien.api.database.*; +import at.tuwien.api.container.CreateContainerDto; +import at.tuwien.api.database.DatabaseModifyImageDto; +import at.tuwien.api.database.DatabaseModifyVisibilityDto; +import at.tuwien.api.database.DatabaseTransferDto; import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; +import at.tuwien.api.identifier.IdentifierTypeDto; import at.tuwien.config.MetricsConfig; import at.tuwien.endpoints.*; +import at.tuwien.test.AbstractUnitTest; import io.micrometer.observation.annotation.Observed; import io.micrometer.observation.tck.TestObservationRegistry; import io.swagger.v3.oas.annotations.Operation; @@ -27,7 +26,6 @@ import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; -import org.springframework.security.test.context.support.WithAnonymousUser; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; @@ -35,7 +33,10 @@ import org.springframework.test.web.servlet.MockMvc; import java.io.File; import java.io.IOException; import java.lang.reflect.Method; -import java.util.*; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; import static io.micrometer.observation.tck.TestObservationRegistryAssert.assertThat; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -173,7 +174,7 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest { /* ignore */ } try { - containerEndpoint.create(ContainerCreateDto.builder().name(CONTAINER_1_NAME).imageId(IMAGE_1_ID).build()); + containerEndpoint.create(CreateContainerDto.builder().name(CONTAINER_1_NAME).imageId(IMAGE_1_ID).build()); } catch (Exception e) { /* ignore */ } @@ -276,7 +277,7 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest { /* ignore */ } try { - identifierEndpoint.findAll(DATABASE_1_ID, null, null, null, MediaType.APPLICATION_JSON_VALUE); + identifierEndpoint.findAll(IdentifierTypeDto.DATABASE, null, DATABASE_1_ID, null, null, null, MediaType.APPLICATION_JSON_VALUE, null); } catch (Exception e) { /* ignore */ } @@ -590,45 +591,16 @@ public class PrometheusEndpointMvcTest extends AbstractUnitTest { } catch (Exception e) { /* ignore */ } - try { - userEndpoint.refreshToken(RefreshTokenRequestDto.builder().build()); - } catch (Exception e) { - /* ignore */ - } /* test */ - for (String metric : List.of("dbrepo_user_refresh_token", "dbrepo_users_list", - "dbrepo_user_find", "dbrepo_user_modify", "dbrepo_user_password_modify")) { + for (String metric : List.of("dbrepo_users_list", "dbrepo_user_find", "dbrepo_user_modify", + "dbrepo_user_password_modify")) { assertThat(registry) .hasObservationWithNameEqualTo(metric); } generic_openApiDocs(UserEndpoint.class); } - @Test - @WithAnonymousUser - public void prometheusUserEndpoint2_succeeds() { - - /* mock */ - try { - userEndpoint.create(USER_1_SIGNUP_REQUEST_DTO); - } catch (Exception e) { - /* ignore */ - } - try { - userEndpoint.getToken(USER_1_LOGIN_REQUEST_DTO); - } catch (Exception e) { - /* ignore */ - } - - /* test */ - for (String metric : List.of("dbrepo_user_create", "dbrepo_user_token")) { - assertThat(registry) - .hasObservationWithNameEqualTo(metric); - } - // already done above - } - @Test @WithMockUser(username = USER_1_USERNAME, authorities = {"create-database-view", "delete-database-view"}) public void prometheusViewEndpoint_succeeds() { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AccessServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AccessServiceUnitTest.java index c647cdbd7403b5f5c742953fd9978e0c8d98ab06..1c96e6283d3d62bc5c31652f82a73312454e2035 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AccessServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AccessServiceUnitTest.java @@ -3,7 +3,7 @@ package at.tuwien.service; import at.tuwien.exception.*; import at.tuwien.test.AbstractUnitTest; import at.tuwien.api.database.AccessTypeDto; -import at.tuwien.api.database.DatabaseDto; +import at.tuwien.api.database.DatabaseBriefDto; import at.tuwien.entities.database.AccessType; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.DatabaseAccess; @@ -80,7 +80,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest { when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(Void.class))) .thenReturn(ResponseEntity.status(HttpStatus.CREATED) .build()); - when(searchServiceRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class))) + when(searchServiceRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class))) .thenReturn(ResponseEntity.accepted() .build()); @@ -155,7 +155,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest { .build()); doThrow(HttpClientErrorException.BadRequest.class) .when(searchServiceRestTemplate) - .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class)); + .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class)); /* test */ assertThrows(SearchServiceException.class, () -> { @@ -174,7 +174,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest { .build()); doThrow(HttpClientErrorException.Unauthorized.class) .when(searchServiceRestTemplate) - .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class)); + .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class)); /* test */ assertThrows(SearchServiceException.class, () -> { @@ -193,7 +193,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest { .build()); doThrow(HttpClientErrorException.NotFound.class) .when(searchServiceRestTemplate) - .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class)); + .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class)); /* test */ assertThrows(DatabaseNotFoundException.class, () -> { @@ -212,7 +212,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest { .build()); doThrow(HttpServerErrorException.InternalServerError.class) .when(searchServiceRestTemplate) - .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class)); + .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class)); /* test */ assertThrows(SearchServiceConnectionException.class, () -> { @@ -230,7 +230,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest { when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Void.class))) .thenReturn(ResponseEntity.accepted() .build()); - when(searchServiceRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class))) + when(searchServiceRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class))) .thenReturn(ResponseEntity.accepted() .build()); @@ -305,7 +305,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest { .build()); doThrow(HttpClientErrorException.BadRequest.class) .when(searchServiceRestTemplate) - .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class)); + .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class)); /* test */ assertThrows(SearchServiceException.class, () -> { @@ -324,7 +324,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest { .build()); doThrow(HttpClientErrorException.Unauthorized.class) .when(searchServiceRestTemplate) - .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class)); + .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class)); /* test */ assertThrows(SearchServiceException.class, () -> { @@ -343,7 +343,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest { .build()); doThrow(HttpClientErrorException.NotFound.class) .when(searchServiceRestTemplate) - .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class)); + .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class)); /* test */ assertThrows(DatabaseNotFoundException.class, () -> { @@ -362,7 +362,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest { .build()); doThrow(HttpServerErrorException.InternalServerError.class) .when(searchServiceRestTemplate) - .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class)); + .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class)); /* test */ assertThrows(SearchServiceConnectionException.class, () -> { @@ -382,7 +382,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest { when(dataServiceRestTemplate.exchange(anyString(), eq(HttpMethod.DELETE), any(HttpEntity.class), eq(Void.class))) .thenReturn(ResponseEntity.accepted() .build()); - when(searchServiceRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class))) + when(searchServiceRestTemplate.exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class))) .thenReturn(ResponseEntity.accepted() .build()); @@ -445,7 +445,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest { .build()); doThrow(HttpClientErrorException.BadRequest.class) .when(searchServiceRestTemplate) - .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class)); + .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class)); /* test */ assertThrows(SearchServiceException.class, () -> { @@ -466,7 +466,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest { .build()); doThrow(HttpClientErrorException.Unauthorized.class) .when(searchServiceRestTemplate) - .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class)); + .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class)); /* test */ assertThrows(SearchServiceException.class, () -> { @@ -487,7 +487,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest { .build()); doThrow(HttpClientErrorException.NotFound.class) .when(searchServiceRestTemplate) - .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class)); + .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class)); /* test */ assertThrows(DatabaseNotFoundException.class, () -> { @@ -508,7 +508,7 @@ public class AccessServiceUnitTest extends AbstractUnitTest { .build()); doThrow(HttpServerErrorException.InternalServerError.class) .when(searchServiceRestTemplate) - .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseDto.class)); + .exchange(anyString(), eq(HttpMethod.PUT), any(HttpEntity.class), eq(DatabaseBriefDto.class)); /* test */ assertThrows(SearchServiceConnectionException.class, () -> { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java index fa1cd5d4beeb1fe8fb40d8f59fa974b5d2501dba..d655a25cf1f599b2e92a9fd426cfa343747a3fe1 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/AuthenticationServiceIntegrationTest.java @@ -1,9 +1,10 @@ package at.tuwien.service; -import at.tuwien.test.AbstractUnitTest; import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.gateway.KeycloakGateway; +import at.tuwien.test.AbstractUnitTest; +import at.tuwien.utils.KeycloakUtils; import dasniko.testcontainers.keycloak.KeycloakContainer; import lombok.extern.log4j.Log4j2; import org.junit.jupiter.api.BeforeEach; @@ -19,6 +20,8 @@ import org.testcontainers.images.PullPolicy; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; +import java.util.UUID; + @Log4j2 @Testcontainers @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) @@ -32,13 +35,16 @@ public class AuthenticationServiceIntegrationTest extends AbstractUnitTest { @Autowired private KeycloakGateway keycloakGateway; + @Autowired + private KeycloakUtils keycloakUtils; + @BeforeEach public void beforeEach() { genesis(); } @Container - private static KeycloakContainer keycloakContainer = new KeycloakContainer("quay.io/keycloak/keycloak:24.0") + private static KeycloakContainer keycloakContainer = new KeycloakContainer(KEYCLOAK_IMAGE) .withImagePullPolicy(PullPolicy.alwaysPull()) .withAdminUsername("admin") .withAdminPassword("admin") @@ -47,7 +53,9 @@ public class AuthenticationServiceIntegrationTest extends AbstractUnitTest { @DynamicPropertySource static void keycloakProperties(DynamicPropertyRegistry registry) { - registry.add("dbrepo.endpoints.authService", () -> "http://localhost:" + keycloakContainer.getMappedPort(8080)); + final String authServiceEndpoint = "http://localhost:" + keycloakContainer.getMappedPort(8080); + log.trace("set auth endpoint: {}", authServiceEndpoint); + registry.add("dbrepo.endpoints.authService", () -> authServiceEndpoint); } @Test @@ -55,14 +63,10 @@ public class AuthenticationServiceIntegrationTest extends AbstractUnitTest { AuthServiceException, AuthServiceConnectionException, CredentialsInvalidException { /* mock */ - try { - keycloakGateway.deleteUser(keycloakGateway.findByUsername(USER_1_USERNAME).getId()); - } catch (Exception e) { - /* ignore */ - } - keycloakGateway.createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST); + keycloakUtils.deleteUser(USER_1_USERNAME); + keycloakUtils.createUser(USER_1_ID, USER_1_KEYCLOAK_SIGNUP_REQUEST); final User request = User.builder() - .id(keycloakGateway.findByUsername(USER_1_USERNAME).getId()) + .keycloakId(UUID.fromString(keycloakGateway.findByUsername(USER_1_USERNAME).getId())) .username(USER_1_USERNAME) .build(); @@ -70,20 +74,4 @@ public class AuthenticationServiceIntegrationTest extends AbstractUnitTest { authenticationService.delete(request); } - @Test - public void create_succeeds() throws EmailExistsException, UserExistsException, - DataServiceConnectionException, AuthServiceException, AuthServiceConnectionException, - CredentialsInvalidException { - - /* mock */ - try { - keycloakGateway.deleteUser(keycloakGateway.findByUsername(USER_1_USERNAME).getId()); - } catch (Exception e) { - /* ignore */ - } - - /* test */ - authenticationService.create(USER_1_SIGNUP_REQUEST_DTO); - } - } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceUnitTest.java index a4f067689355776977c648bfedb0a218941a1cbb..bb19a404ddf23f29e257808974c0ebd787e3c416 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ContainerServiceUnitTest.java @@ -1,7 +1,7 @@ package at.tuwien.service; +import at.tuwien.api.container.CreateContainerDto; import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.container.ContainerCreateDto; import at.tuwien.entities.container.Container; import at.tuwien.exception.*; import at.tuwien.repository.ContainerRepository; @@ -48,7 +48,7 @@ public class ContainerServiceUnitTest extends AbstractUnitTest { @Test public void create_succeeds() throws ContainerAlreadyExistsException, ImageNotFoundException { - final ContainerCreateDto request = ContainerCreateDto.builder() + final CreateContainerDto request = CreateContainerDto.builder() .imageId(IMAGE_1_ID) .name(CONTAINER_1_NAME) .build(); @@ -68,7 +68,7 @@ public class ContainerServiceUnitTest extends AbstractUnitTest { @Test public void create_containerExists_fails() { - final ContainerCreateDto request = ContainerCreateDto.builder() + final CreateContainerDto request = CreateContainerDto.builder() .imageId(IMAGE_1_ID) .name(CONTAINER_1_NAME) .build(); @@ -85,7 +85,7 @@ public class ContainerServiceUnitTest extends AbstractUnitTest { @Test public void create_imageNotFound_fails() { - final ContainerCreateDto request = ContainerCreateDto.builder() + final CreateContainerDto request = CreateContainerDto.builder() .name(CONTAINER_3_NAME) .imageId(9999L) .build(); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java index 182fe8e14ac5cd63ad1752fec07ee9b511ba8726..b77bc30d3811ed30c7994129ae2110e12903d0f9 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DataCiteIdentifierServicePersistenceTest.java @@ -1,20 +1,20 @@ package at.tuwien.service; +import at.tuwien.api.datacite.DataCiteBody; +import at.tuwien.api.datacite.doi.DataCiteDoi; import at.tuwien.api.identifier.BibliographyTypeDto; +import at.tuwien.entities.database.Database; import at.tuwien.entities.identifier.Creator; import at.tuwien.entities.identifier.Identifier; import at.tuwien.entities.identifier.IdentifierStatusType; import at.tuwien.entities.identifier.NameIdentifierSchemeType; +import at.tuwien.exception.*; +import at.tuwien.gateway.SearchServiceGateway; import at.tuwien.repository.ContainerRepository; import at.tuwien.repository.DatabaseRepository; import at.tuwien.repository.LicenseRepository; import at.tuwien.repository.UserRepository; import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.datacite.DataCiteBody; -import at.tuwien.api.datacite.doi.DataCiteDoi; -import at.tuwien.entities.database.Database; -import at.tuwien.exception.*; -import at.tuwien.gateway.SearchServiceGateway; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -141,7 +141,7 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest { when(restTemplate.exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(dataCiteBodyParameterizedTypeReference))) .thenReturn(mock); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ dataCiteIdentifierService.save(DATABASE_1, USER_1, IDENTIFIER_1_SAVE_DTO); @@ -156,7 +156,7 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest { .when(restTemplate) .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(dataCiteBodyParameterizedTypeReference)); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ assertThrows(MalformedException.class, () -> { @@ -173,7 +173,7 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest { .when(restTemplate) .exchange(anyString(), eq(HttpMethod.POST), any(HttpEntity.class), eq(dataCiteBodyParameterizedTypeReference)); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ assertThrows(DataServiceConnectionException.class, () -> { @@ -332,7 +332,7 @@ public class DataCiteIdentifierServicePersistenceTest extends AbstractUnitTest { /* mock */ when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ dataCiteIdentifierService.delete(IDENTIFIER_1); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java index 1b6570abd821337fe032bead021cf9d5a4b9fc8c..18d037fe452cb6cdab5b4d0f0fe68b5ed6142cf0 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/DatabaseServiceUnitTest.java @@ -110,7 +110,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ final Database response = databaseService.modifyImage(DATABASE_1, image); @@ -164,7 +164,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ final Database response = databaseService.updateViewMetadata(DATABASE_1); @@ -222,7 +222,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ final Database response = databaseService.updateViewMetadata(DATABASE_1); @@ -240,7 +240,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ final Database response = databaseService.updateViewMetadata(DATABASE_1); @@ -258,7 +258,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ final Database response = databaseService.updateTableMetadata(DATABASE_1); @@ -276,7 +276,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ final Database response = databaseService.updateTableMetadata(DATABASE_1); @@ -294,7 +294,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ final Database response = databaseService.updateTableMetadata(DATABASE_1); @@ -517,7 +517,7 @@ public class DatabaseServiceUnitTest extends AbstractUnitTest { /* mock */ when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java index 0c87dcdd692533cd751401f9be37fee69b5186cc..40fc28fe4d89524a928d474e0d3328853bee5df7 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/IdentifierServicePersistenceTest.java @@ -176,7 +176,7 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest { when(dataServiceGateway.findQuery(IDENTIFIER_5_DATABASE_ID, IDENTIFIER_5_QUERY_ID)) .thenReturn(QUERY_2_DTO); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_2_DTO); + .thenReturn(DATABASE_2_BRIEF_DTO); /* test */ identifierService.save(DATABASE_2, USER_2, IDENTIFIER_5_SAVE_DTO); @@ -286,7 +286,7 @@ public class IdentifierServicePersistenceTest extends AbstractUnitTest { /* mock */ when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ identifierService.delete(IDENTIFIER_1); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceUnitTest.java index 725d956f570e7ed6678047b4bb9d7baf85cbe33b..dc77ff263b37406845afb93e80a5afc27f59f380 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ImageServiceUnitTest.java @@ -132,7 +132,7 @@ public class ImageServiceUnitTest extends AbstractUnitTest { when(imageRepository.save(any())) .thenReturn(IMAGE_1); when(mockImageService.update(IMAGE_1, request)) - .thenReturn(CONTAINER_1_IMAGE); + .thenReturn(IMAGE_1); /* test */ final ContainerImage response = mockImageService.update(IMAGE_1, request); @@ -153,7 +153,7 @@ public class ImageServiceUnitTest extends AbstractUnitTest { when(imageRepository.save(any())) .thenReturn(IMAGE_1); when(mockImageService.update(IMAGE_1, request)) - .thenReturn(CONTAINER_1_IMAGE); + .thenReturn(IMAGE_1); /* test */ final ContainerImage response = mockImageService.update(IMAGE_1, request); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java index 3126f9e9f42b36fb8dc09dfa3f8e60c88d851722..b0efccab9ac856f727ee3377554e7cf8a01bb2c7 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServicePersistenceTest.java @@ -1,9 +1,9 @@ package at.tuwien.service; -import at.tuwien.api.database.table.TableCreateDto; -import at.tuwien.api.database.table.columns.ColumnCreateDto; +import at.tuwien.api.database.table.CreateTableDto; +import at.tuwien.api.database.table.columns.CreateTableColumnDto; import at.tuwien.api.database.table.columns.ColumnTypeDto; -import at.tuwien.api.database.table.constraints.ConstraintsCreateDto; +import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.table.Table; import at.tuwien.entities.database.table.columns.TableColumn; @@ -82,22 +82,22 @@ public class TableServicePersistenceTest extends AbstractUnitTest { @Transactional public void create_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException, UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, TableExistsException, SearchServiceException, SearchServiceConnectionException, OntologyNotFoundException, SemanticEntityNotFoundException { - final TableCreateDto request = TableCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() .name("New Table") .description("A wonderful table") .isPublic(true) .isSchemaPublic(true) - .columns(List.of(ColumnCreateDto.builder() + .columns(List.of(CreateTableColumnDto.builder() .name("id") .nullAllowed(false) .type(ColumnTypeDto.BIGINT) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("date") .nullAllowed(true) .type(ColumnTypeDto.DATE) .build())) - .constraints(ConstraintsCreateDto.builder() + .constraints(CreateTableConstraintsDto.builder() .checks(Set.of()) .uniques(List.of(List.of("date"))) .foreignKeys(List.of()) @@ -112,7 +112,7 @@ public class TableServicePersistenceTest extends AbstractUnitTest { .when(dataServiceGateway) .createTable(DATABASE_1_ID, request); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ final Table response = tableService.createTable(DATABASE_1, request, USER_1_PRINCIPAL); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java index d975e808e3dd03e3b4fd0f27d3af4b60f4fec7a1..8cb5081f6d98b68971f71f2da5538ab72bd772a8 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java @@ -1,13 +1,13 @@ package at.tuwien.service; -import at.tuwien.api.database.table.TableCreateDto; +import at.tuwien.api.database.table.CreateTableDto; import at.tuwien.api.database.table.TableStatisticDto; -import at.tuwien.api.database.table.columns.ColumnCreateDto; +import at.tuwien.api.database.table.columns.CreateTableColumnDto; import at.tuwien.api.database.table.columns.ColumnStatisticDto; import at.tuwien.api.database.table.columns.ColumnTypeDto; import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; -import at.tuwien.api.database.table.constraints.ConstraintsCreateDto; -import at.tuwien.api.database.table.constraints.foreign.ForeignKeyCreateDto; +import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto; +import at.tuwien.api.database.table.constraints.foreign.CreateForeignKeyDto; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.table.Table; import at.tuwien.entities.database.table.columns.TableColumn; @@ -135,7 +135,7 @@ public class TableServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ tableService.updateStatistics(TABLE_8); @@ -224,7 +224,7 @@ public class TableServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ final TableColumn response = tableService.update(TABLE_1_COLUMNS.get(0), request); @@ -256,7 +256,7 @@ public class TableServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ final TableColumn response = tableService.update(TABLE_1_COLUMNS.get(0), request); @@ -275,11 +275,11 @@ public class TableServiceUnitTest extends AbstractUnitTest { .thenReturn(USER_1); doNothing() .when(dataServiceGateway) - .createTable(eq(DATABASE_1_ID), any(TableCreateDto.class)); + .createTable(eq(DATABASE_1_ID), any(CreateTableDto.class)); when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ final Table response = tableService.createTable(DATABASE_1, TABLE_3_CREATE_DTO, USER_1_PRINCIPAL); @@ -291,15 +291,15 @@ public class TableServiceUnitTest extends AbstractUnitTest { DataServiceConnectionException, UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, TableExistsException, SearchServiceException, SearchServiceConnectionException, MalformedException, OntologyNotFoundException, SemanticEntityNotFoundException { - final TableCreateDto request = TableCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() .name("New Table") .description("A wonderful table") - .columns(List.of(ColumnCreateDto.builder() + .columns(List.of(CreateTableColumnDto.builder() .name("I Am Späshül") .nullAllowed(true) .type(ColumnTypeDto.TEXT) .build())) - .constraints(ConstraintsCreateDto.builder() + .constraints(CreateTableConstraintsDto.builder() .checks(Set.of()) .uniques(List.of(List.of("I Am Späshül"))) .foreignKeys(List.of()) @@ -312,11 +312,11 @@ public class TableServiceUnitTest extends AbstractUnitTest { .thenReturn(USER_1); doNothing() .when(dataServiceGateway) - .createTable(eq(DATABASE_1_ID), any(TableCreateDto.class)); + .createTable(eq(DATABASE_1_ID), any(CreateTableDto.class)); when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ final Table response = tableService.createTable(DATABASE_1, request, USER_1_PRINCIPAL); @@ -344,15 +344,15 @@ public class TableServiceUnitTest extends AbstractUnitTest { public void createTable_dateFormatNotFound_fails() throws DataServiceException, DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, TableExistsException, SearchServiceException, SearchServiceConnectionException { - final TableCreateDto request = TableCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() .name("New Table") .description("A wonderful table") - .columns(List.of(ColumnCreateDto.builder() + .columns(List.of(CreateTableColumnDto.builder() .name("date") .nullAllowed(true) .type(ColumnTypeDto.DATE) .build())) - .constraints(ConstraintsCreateDto.builder() + .constraints(CreateTableConstraintsDto.builder() .checks(Set.of()) .uniques(List.of(List.of("date"))) .foreignKeys(List.of()) @@ -365,11 +365,11 @@ public class TableServiceUnitTest extends AbstractUnitTest { .thenReturn(USER_1); doNothing() .when(dataServiceGateway) - .createTable(eq(DATABASE_1_ID), any(TableCreateDto.class)); + .createTable(eq(DATABASE_1_ID), any(CreateTableDto.class)); when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ assertThrows(MalformedException.class, () -> { @@ -392,7 +392,7 @@ public class TableServiceUnitTest extends AbstractUnitTest { .when(dataServiceGateway) .createTable(DATABASE_1_ID, TABLE_3_CREATE_DTO); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ final Table response = tableService.createTable(DATABASE_1, TABLE_3_CREATE_DTO, USER_1_PRINCIPAL); @@ -413,7 +413,7 @@ public class TableServiceUnitTest extends AbstractUnitTest { .when(dataServiceGateway) .createTable(DATABASE_1_ID, TABLE_5_CREATE_DTO); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ assertThrows(DataServiceException.class, () -> { @@ -423,11 +423,11 @@ public class TableServiceUnitTest extends AbstractUnitTest { @Test public void createTable_primaryKeyMalformed_fails() throws UserNotFoundException { - final TableCreateDto request = TableCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() .name(TABLE_5_NAME) .description(TABLE_5_DESCRIPTION) .columns(TABLE_5_COLUMNS_CREATE) - .constraints(ConstraintsCreateDto.builder() + .constraints(CreateTableConstraintsDto.builder() .foreignKeys(new LinkedList<>()) .checks(new LinkedHashSet<>()) .primaryKey(Set.of("i_do_not_exist")) @@ -447,11 +447,11 @@ public class TableServiceUnitTest extends AbstractUnitTest { @Test public void createTable_uniquesMalformed_fails() throws UserNotFoundException { - final TableCreateDto request = TableCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() .name(TABLE_5_NAME) .description(TABLE_5_DESCRIPTION) .columns(TABLE_5_COLUMNS_CREATE) - .constraints(ConstraintsCreateDto.builder() + .constraints(CreateTableConstraintsDto.builder() .foreignKeys(new LinkedList<>()) .checks(new LinkedHashSet<>()) .primaryKey(new LinkedHashSet<>()) @@ -473,12 +473,12 @@ public class TableServiceUnitTest extends AbstractUnitTest { @Test public void createTable_foreignKeyMalformed_fails() throws UserNotFoundException { - final TableCreateDto request = TableCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() .name(TABLE_5_NAME) .description(TABLE_5_DESCRIPTION) .columns(TABLE_5_COLUMNS_CREATE) - .constraints(ConstraintsCreateDto.builder() - .foreignKeys(List.of(ForeignKeyCreateDto.builder() + .constraints(CreateTableConstraintsDto.builder() + .foreignKeys(List.of(CreateForeignKeyDto.builder() .columns(List.of("some_column")) .referencedColumns(List.of("some_foreign_column")) .referencedTable("some_referenced_table") @@ -511,7 +511,7 @@ public class TableServiceUnitTest extends AbstractUnitTest { .when(dataServiceGateway) .deleteTable(DATABASE_1_ID, TABLE_1_ID); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ tableService.deleteTable(TABLE_1); @@ -527,7 +527,7 @@ public class TableServiceUnitTest extends AbstractUnitTest { .when(dataServiceGateway) .deleteTable(DATABASE_1_ID, TABLE_4_ID); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ tableService.deleteTable(TABLE_4); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServicePersistenceTest.java index 09a372a6eb3ca23bb0539b8a1be4a648a1bff9a1..e9d6b158ce097fc469694ee1d09e068357120d39 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServicePersistenceTest.java @@ -1,12 +1,10 @@ package at.tuwien.service; -import at.tuwien.api.auth.SignupRequestDto; import at.tuwien.api.user.UserPasswordDto; import at.tuwien.api.user.UserUpdateDto; import at.tuwien.entities.user.User; -import at.tuwien.exception.EmailExistsException; -import at.tuwien.exception.UserExistsException; -import at.tuwien.exception.UserNotFoundException; +import at.tuwien.exception.*; +import at.tuwien.gateway.KeycloakGateway; import at.tuwien.repository.UserRepository; import at.tuwien.test.AbstractUnitTest; import lombok.extern.log4j.Log4j2; @@ -15,12 +13,14 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit.jupiter.SpringExtension; import java.util.List; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.doNothing; @Log4j2 @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) @@ -34,6 +34,9 @@ public class UserServicePersistenceTest extends AbstractUnitTest { @Autowired private UserService userService; + @MockBean + private KeycloakGateway keycloakGateway; + @BeforeEach public void beforeEach() { genesis(); @@ -68,20 +71,16 @@ public class UserServicePersistenceTest extends AbstractUnitTest { } @Test - public void create_succeeds() throws UserExistsException, UserNotFoundException, EmailExistsException { - final SignupRequestDto request = SignupRequestDto.builder() - .username(USER_2_USERNAME) - .password(USER_2_PASSWORD) - .email(USER_2_EMAIL) - .build(); + public void create_succeeds() throws UserExistsException, UserNotFoundException, EmailExistsException, + AuthServiceException, AuthServiceConnectionException { /* test */ - final User response = userService.create(request, USER_2_ID); + final User response = userService.create(USER_2_SIGNUP_REQUEST_DTO); assertEquals(USER_2_USERNAME, response.getUsername()); } @Test - public void modify_succeeds() { + public void modify_succeeds() throws UserNotFoundException, AuthServiceException { final UserUpdateDto request = UserUpdateDto.builder() .firstname(USER_1_FIRSTNAME) .lastname(USER_1_LASTNAME) @@ -91,6 +90,11 @@ public class UserServicePersistenceTest extends AbstractUnitTest { .language("de") .build(); + /* mock */ + doNothing() + .when(keycloakGateway) + .updateUser(USER_1_ID, request); + /* test */ final User response = userService.modify(USER_1, request); assertEquals(USER_1_ID, response.getId()); @@ -103,17 +107,14 @@ public class UserServicePersistenceTest extends AbstractUnitTest { } @Test - public void updatePassword_succeeds() { + public void updatePassword_succeeds() throws UserNotFoundException, AuthServiceException, + AuthServiceConnectionException { final UserPasswordDto request = UserPasswordDto.builder() .password(USER_3_PASSWORD) .build(); /* mock */ - final User user = userService.create(SignupRequestDto.builder() - .username(USER_3_USERNAME) - .password(USER_3_PASSWORD) - .email(USER_3_EMAIL) - .build(), USER_3_ID); + final User user = userService.create(USER_3_SIGNUP_REQUEST_DTO); /* test */ userService.updatePassword(user, request); @@ -151,20 +152,4 @@ public class UserServicePersistenceTest extends AbstractUnitTest { userService.validateUsernameNotExists(USER_1_USERNAME); }); } - - @Test - public void validateEmailNotExists_succeeds() throws EmailExistsException { - - /* test */ - userService.validateEmailNotExists(USER_2_EMAIL); - } - - @Test - public void validateEmailNotExists_fails() { - - /* test */ - assertThrows(EmailExistsException.class, () -> { - userService.validateEmailNotExists(USER_1_EMAIL); - }); - } } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java index a9fe4694cc69d8eb347e9fefd12498704b8797fd..4c423aa25b6fd36f82485d836c190c1b2779e12d 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/UserServiceUnitTest.java @@ -1,10 +1,10 @@ package at.tuwien.service; -import at.tuwien.test.AbstractUnitTest; import at.tuwien.entities.user.User; import at.tuwien.exception.*; import at.tuwien.gateway.KeycloakGateway; import at.tuwien.repository.UserRepository; +import at.tuwien.test.AbstractUnitTest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -86,20 +86,15 @@ public class UserServiceUnitTest extends AbstractUnitTest { .thenReturn(Optional.of(USER_1)); when(userRepository.save(any(User.class))) .thenReturn(USER_1); - doNothing() - .when(keycloakGateway) - .createUser(USER_1_KEYCLOAK_SIGNUP_REQUEST); - when(keycloakGateway.findByUsername(USER_1_USERNAME)) - .thenReturn(USER_1_KEYCLOAK_DTO); /* test */ - final User response = userService.create(USER_1_SIGNUP_REQUEST_DTO, USER_1_ID); + final User response = userService.create(USER_1_SIGNUP_REQUEST_DTO); assertEquals(USER_1_ID, response.getId()); assertEquals(USER_1_USERNAME, response.getUsername()); } @Test - public void modify_succeeds() { + public void modify_succeeds() throws UserNotFoundException, AuthServiceException { /* mock */ when(userRepository.findById(USER_1_ID)) @@ -114,8 +109,7 @@ public class UserServiceUnitTest extends AbstractUnitTest { } @Test - public void updatePassword_succeeds() throws AuthServiceException, AuthServiceConnectionException, - UserNotFoundException { + public void updatePassword_succeeds() throws UserNotFoundException { /* mock */ doNothing() diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java index 8ca002472a085a58ea5ee58fff8a2a0614c94fd9..57a84965dc81615613f201e6aee4e771582ac090 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java @@ -89,7 +89,7 @@ public class ViewServicePersistenceTest extends AbstractUnitTest { .when(dataServiceGateway) .deleteView(DATABASE_1_ID, VIEW_1_ID); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ viewService.delete(VIEW_1); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceUnitTest.java index cd9fe03c655d33b014239af4f05f0f0ae9b6d1e9..4ba217a60c0b5a520e7fcd1c59a610769530760e 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServiceUnitTest.java @@ -2,7 +2,7 @@ package at.tuwien.service; import at.tuwien.repository.DatabaseRepository; import at.tuwien.test.AbstractUnitTest; -import at.tuwien.api.database.ViewCreateDto; +import at.tuwien.api.database.CreateViewDto; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.View; import at.tuwien.exception.*; @@ -50,7 +50,7 @@ public class ViewServiceUnitTest extends AbstractUnitTest { @Test public void create_succeeds() throws MalformedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException { - final ViewCreateDto request = ViewCreateDto.builder() + final CreateViewDto request = CreateViewDto.builder() .name(VIEW_1_NAME) .query(VIEW_1_QUERY) .isPublic(VIEW_1_PUBLIC) @@ -62,7 +62,7 @@ public class ViewServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ final View response = viewService.create(DATABASE_1, USER_1, request); @@ -117,7 +117,7 @@ public class ViewServiceUnitTest extends AbstractUnitTest { when(databaseRepository.save(any(Database.class))) .thenReturn(DATABASE_1); when(searchServiceGateway.update(any(Database.class))) - .thenReturn(DATABASE_1_DTO); + .thenReturn(DATABASE_1_BRIEF_DTO); /* test */ viewService.delete(VIEW_1); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/KeycloakUtils.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/KeycloakUtils.java index f5ad18b694081ed50b879d6690e2a85748b3bece..b3612fcc0fc306892db006bd12aa6ef483cf45a9 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/KeycloakUtils.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/utils/KeycloakUtils.java @@ -1,34 +1,71 @@ package at.tuwien.utils; -import at.tuwien.exception.AuthServiceConnectionException; -import at.tuwien.exception.AuthServiceException; +import at.tuwien.api.keycloak.UserCreateDto; +import at.tuwien.config.KeycloakConfig; import at.tuwien.exception.UserNotFoundException; -import at.tuwien.gateway.KeycloakGateway; +import at.tuwien.mapper.MetadataMapper; +import jakarta.ws.rs.core.Response; import lombok.extern.log4j.Log4j2; +import org.keycloak.admin.client.Keycloak; +import org.keycloak.representations.idm.UserRepresentation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.util.List; import java.util.UUID; @Log4j2 @Component public class KeycloakUtils { - final static UUID realmId = UUID.fromString("82c39861-d877-4667-a0f3-4daa2ee230e0"); - - private final KeycloakGateway keycloakGateway; + private final Keycloak keycloak; + private final KeycloakConfig keycloakConfig; + private final MetadataMapper metadataMapper; @Autowired - public KeycloakUtils(KeycloakGateway keycloakGateway) { - this.keycloakGateway = keycloakGateway; + public KeycloakUtils(Keycloak keycloak, KeycloakConfig keycloakConfig, MetadataMapper metadataMapper) { + this.keycloak = keycloak; + this.keycloakConfig = keycloakConfig; + this.metadataMapper = metadataMapper; + } + + public void createUser(UUID ldapId, UserCreateDto data) { + final UserRepresentation user = metadataMapper.userCreateDtoToUserRepresentation(data); + user.singleAttribute("CUSTOM_ID", ldapId.toString()); + try (Response response = keycloak.realm(keycloakConfig.getRealm()) + .users() + .create(user)) { + if (response.getStatus() != 201) { + log.warn("Failed to create user: {}", response.getStatus()); + } + } + log.debug("Created user {} at auth service", data.getUsername()); } - public void deleteUser(String username) throws AuthServiceException, AuthServiceConnectionException { - try { - final UUID userId = keycloakGateway.findByUsername(username).getId(); - keycloakGateway.deleteUser(userId); - } catch (UserNotFoundException e) { - /* ignore */ + public UUID getUserId(String username) throws UserNotFoundException { + final List<UserRepresentation> users = keycloak.realm(keycloakConfig.getRealm()) + .users() + .search(username); + if (users.isEmpty()) { + throw new UserNotFoundException("Failed to find user: " + username); + } + return UUID.fromString(users.get(0).getId()); + } + + public void deleteUser(String username) { + final List<UserRepresentation> users = keycloak.realm(keycloakConfig.getRealm()) + .users() + .search(username); + if (users.isEmpty()) { + log.warn("Failed to find user"); + return; + } + try (Response response = keycloak.realm(keycloakConfig.getRealm()) + .users() + .delete(users.get(0).getId())) { + if (response.getStatus() != 200) { + log.error("Failed to delete user: {}", response.getStatus()); + } } } } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java index 342a9e328ecc8e69abe7bfedf1827bdc7777fff3..486db28e5945737e776da4b8f0aaf6d6d977715e 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/validator/EndpointValidatorUnitTest.java @@ -1,9 +1,9 @@ package at.tuwien.validator; import at.tuwien.SortType; -import at.tuwien.api.database.table.TableCreateDto; -import at.tuwien.api.database.table.columns.ColumnCreateDto; +import at.tuwien.api.database.table.CreateTableDto; import at.tuwien.api.database.table.columns.ColumnTypeDto; +import at.tuwien.api.database.table.columns.CreateTableColumnDto; import at.tuwien.api.identifier.IdentifierSaveDto; import at.tuwien.entities.database.Database; import at.tuwien.entities.user.User; @@ -70,6 +70,14 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest { endpointValidator.validateDataParams(0L, 1L); } + @Test + public void validateOnlyAccess_system_succeeds() throws UserNotFoundException, NotAllowedException, + AccessNotFoundException { + + /* test */ + endpointValidator.validateOnlyAccess(DATABASE_1, USER_LOCAL_ADMIN_PRINCIPAL, false); + } + @Test public void validateDataParams_bothNull_succeeds() throws PaginationException { @@ -222,6 +230,20 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest { endpointValidator.validateOnlyAccessOrPublic(DATABASE_1, USER_1_PRINCIPAL); } + @Test + public void validateOnlyWriteOwnOrWriteAllAccess_succeeds() throws DatabaseNotFoundException, + TableNotFoundException, AccessNotFoundException, NotAllowedException { + + /* mock */ + when(tableService.findById(DATABASE_1, TABLE_1_ID)) + .thenReturn(TABLE_1); + when(accessService.find(eq(DATABASE_1), any(User.class))) + .thenReturn(DATABASE_1_USER_1_WRITE_ALL_ACCESS); + + /* test */ + endpointValidator.validateOnlyWriteOwnOrWriteAllAccess(TABLE_1, USER_1); + } + @Test public void validateOnlyWriteOwnOrWriteAllAccess_privateHasReadAccess_fails() throws DatabaseNotFoundException, TableNotFoundException, AccessNotFoundException { @@ -264,8 +286,8 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest { @ParameterizedTest @MethodSource("needSize_parameters") public void validateColumnCreateConstraints_needSize_fails(ColumnTypeDto type) { - final TableCreateDto request = TableCreateDto.builder() - .columns(List.of(ColumnCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() + .columns(List.of(CreateTableColumnDto.builder() .type(type) .size(null) // <<<<<< .build())) @@ -279,8 +301,8 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest { @Test public void validateColumnCreateConstraints_needEnum_fails() { - final TableCreateDto request = TableCreateDto.builder() - .columns(List.of(ColumnCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() + .columns(List.of(CreateTableColumnDto.builder() .type(ColumnTypeDto.ENUM) .enums(null) // <<<<<<< .build())) @@ -294,8 +316,8 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest { @Test public void validateColumnCreateConstraints_needSet_fails() { - final TableCreateDto request = TableCreateDto.builder() - .columns(List.of(ColumnCreateDto.builder() + final CreateTableDto request = CreateTableDto.builder() + .columns(List.of(CreateTableColumnDto.builder() .type(ColumnTypeDto.SET) .sets(null) // <<<<<<< .build())) @@ -323,6 +345,20 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest { }); } + @Test + public void validateOnlyPrivateDataHasRole_publicDatabase_succeeds() throws NotAllowedException { + + /* test */ + endpointValidator.validateOnlyPrivateDataHasRole(DATABASE_4, null, "nobody-role"); + } + + @Test + public void validateOnlyPrivateDataHasRole_privateDatabaseHasRole_succeeds() throws NotAllowedException { + + /* test */ + endpointValidator.validateOnlyPrivateDataHasRole(DATABASE_1, USER_1_PRINCIPAL, "find-database"); + } + @Test public void validateOnlyPrivateDataHasRole_privatePrincipalMissing_fails() { @@ -491,6 +527,13 @@ public class EndpointValidatorUnitTest extends AbstractUnitTest { assertTrue(endpointValidator.validatePublicationDate(request)); } + @Test + public void validateOnlyMineOrWriteAccessOrHasRole_succeeds() { + + /* test */ + assertTrue(endpointValidator.validateOnlyMineOrWriteAccessOrHasRole(USER_1, USER_1_PRINCIPAL, null, "find-database")); + } + @Test public void validateOnlyMineOrWriteAccessOrHasRole_noAccess_fails() { diff --git a/dbrepo-metadata-service/rest-service/src/test/resources/init/dbrepo-realm.json b/dbrepo-metadata-service/rest-service/src/test/resources/init/dbrepo-realm.json index 7ee28b34a4f2d662bb43979930732dec74da8a63..fb6df2007f2c5d50ab9ad744b622e248ea158cde 100644 --- a/dbrepo-metadata-service/rest-service/src/test/resources/init/dbrepo-realm.json +++ b/dbrepo-metadata-service/rest-service/src/test/resources/init/dbrepo-realm.json @@ -27,7 +27,7 @@ "oauth2DevicePollingInterval" : 5, "enabled" : true, "sslRequired" : "none", - "registrationAllowed" : false, + "registrationAllowed" : true, "registrationEmailAsUsername" : false, "rememberMe" : false, "verifyEmail" : true, @@ -38,6 +38,7 @@ "bruteForceProtected" : false, "permanentLockout" : false, "maxTemporaryLockouts" : 0, + "bruteForceStrategy" : "MULTIPLE", "maxFailureWaitSeconds" : 900, "minimumQuickLoginWaitSeconds" : 60, "waitIncrementSeconds" : 60, @@ -73,7 +74,7 @@ "description" : "${default-system-roles}", "composite" : true, "composites" : { - "realm" : [ "delete-database-view", "update-semantic-unit", "export-query-data", "default-data-steward-roles", "execute-query", "default-user-handling", "delete-table-data", "find-query", "list-database-views", "persist-query", "update-search-index", "delete-database-access", "view-table-history", "create-ontology", "update-ontology", "modify-user-theme", "default-system-roles", "create-semantic-concept", "default-container-handling", "create-container", "create-table", "default-broker-handling", "default-maintenance-handling", "execute-semantic-query", "uma_authorization", "table-semantic-analyse", "list-containers", "check-database-access", "escalated-query-handling", "delete-identifier", "modify-database-owner", "list-tables", "export-table-data", "create-database-access", "delete-container", "re-execute-query", "create-semantic-unit", "escalated-identifier-handling", "system", "update-table-statistic", "escalated-semantics-handling", "default-database-handling", "delete-ontology", "find-database", "find-database-view", "update-semantic-concept", "find-user", "import-database-data", "publish-identifier", "default-roles-dbrepo", "find-foreign-user", "create-database", "create-maintenance-message", "find-maintenance-message", "escalated-container-handling", "default-researcher-roles", "default-identifier-handling", "escalated-user-handling", "modify-user-information", "create-database-view", "update-maintenance-message", "delete-foreign-table", "offline_access", "modify-foreign-table-column-semantics", "delete-maintenance-message", "find-container", "insert-table-data", "modify-identifier-metadata", "modify-database-image", "escalated-broker-handling", "modify-table-column-semantics", "escalated-database-handling", "default-semantics-handling", "update-database-access", "default-query-handling", "find-table", "list-queries", "default-developer-roles", "create-identifier", "escalated-table-handling", "find-identifier", "view-database-view-data", "view-table-data", "list-licenses", "default-table-handling", "list-identifiers", "create-foreign-identifier", "list-databases", "list-ontologies", "modify-database-visibility", "list-maintenance-messages", "delete-table" ] + "realm" : [ "delete-database-view", "update-semantic-unit", "export-query-data", "check-foreign-database-access", "default-data-steward-roles", "execute-query", "default-user-handling", "delete-table-data", "find-query", "list-database-views", "persist-query", "update-search-index", "delete-database-access", "view-table-history", "create-ontology", "update-ontology", "modify-user-theme", "default-system-roles", "create-semantic-concept", "default-container-handling", "create-container", "create-table", "default-broker-handling", "default-maintenance-handling", "execute-semantic-query", "uma_authorization", "table-semantic-analyse", "list-containers", "check-database-access", "escalated-query-handling", "delete-identifier", "modify-database-owner", "list-tables", "export-table-data", "create-database-access", "delete-container", "re-execute-query", "create-semantic-unit", "escalated-identifier-handling", "system", "update-table-statistic", "escalated-semantics-handling", "default-database-handling", "delete-ontology", "find-database", "find-database-view", "update-semantic-concept", "find-user", "import-database-data", "publish-identifier", "default-roles-dbrepo", "find-foreign-user", "create-database", "create-maintenance-message", "find-maintenance-message", "escalated-container-handling", "default-researcher-roles", "default-identifier-handling", "escalated-user-handling", "modify-user-information", "create-database-view", "update-maintenance-message", "delete-foreign-table", "offline_access", "modify-foreign-table-column-semantics", "delete-maintenance-message", "find-container", "insert-table-data", "modify-identifier-metadata", "modify-database-image", "escalated-broker-handling", "modify-table-column-semantics", "escalated-database-handling", "default-semantics-handling", "update-database-access", "default-query-handling", "find-table", "list-queries", "default-developer-roles", "create-identifier", "escalated-table-handling", "find-identifier", "view-table-data", "list-licenses", "default-table-handling", "list-identifiers", "create-foreign-identifier", "list-databases", "list-ontologies", "modify-database-visibility", "list-maintenance-messages", "delete-table" ] }, "clientRole" : false, "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", @@ -146,19 +147,11 @@ "description" : "${default-table-handling}", "composite" : true, "composites" : { - "realm" : [ "modify-table-column-semantics", "list-tables", "update-table-statistic", "find-table", "create-table", "delete-table" ] + "realm" : [ "modify-table-column-semantics", "list-tables", "update-table-statistic", "find-table", "create-table", "delete-table", "update-table" ] }, "clientRole" : false, "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", "attributes" : { } - }, { - "id" : "b0d66d3d-59b4-4aae-aa66-e3d5a49f28e3", - "name" : "view-database-view-data", - "description" : "${view-database-view-data}", - "composite" : false, - "clientRole" : false, - "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", - "attributes" : { } }, { "id" : "f5ea431a-9b2c-4195-bcb4-9511f38e4b44", "name" : "create-database-view", @@ -219,7 +212,7 @@ "description" : "${default-researcher-roles}", "composite" : true, "composites" : { - "realm" : [ "default-table-handling", "default-semantics-handling", "default-container-handling", "default-query-handling", "default-user-handling", "default-database-handling", "default-broker-handling", "default-identifier-handling" ] + "realm" : [ "default-table-handling", "default-semantics-handling", "default-container-handling", "default-query-handling", "default-user-handling", "default-database-handling", "default-broker-handling", "default-identifier-handling", "default-view-handling" ] }, "clientRole" : false, "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", @@ -264,6 +257,14 @@ "clientRole" : false, "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", "attributes" : { } + }, { + "id" : "22449528-00c9-4e86-9400-4b8ae6fd8f4d", + "name" : "modify-view-visibility", + "description" : "${modify-view-visibility}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } }, { "id" : "c12c1f4e-186f-4153-a795-26e79fb623d6", "name" : "create-ontology", @@ -296,6 +297,17 @@ "clientRole" : false, "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", "attributes" : { } + }, { + "id" : "d75e7938-9d5e-4cb3-8c57-18a446867d3a", + "name" : "default-view-handling", + "description" : "${default-view-handling}", + "composite" : true, + "composites" : { + "realm" : [ "delete-database-view", "update-database-view", "create-database-view", "modify-view-visibility", "find-database-view", "list-database-views" ] + }, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } }, { "id" : "535f1484-4514-4d24-8d97-e3f6c11a426b", "name" : "create-container", @@ -390,17 +402,33 @@ "clientRole" : false, "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", "attributes" : { } + }, { + "id" : "6ae766b0-b8b4-4067-a95d-c8576bc4ac77", + "name" : "update-table", + "description" : "${update-table}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } }, { "id" : "64c16bfb-2015-48ad-a23f-637ff24419cb", "name" : "default-query-handling", "description" : "${default-query-handling}", "composite" : true, "composites" : { - "realm" : [ "delete-database-view", "export-query-data", "execute-query", "delete-table-data", "export-table-data", "list-queries", "find-query", "list-database-views", "persist-query", "view-database-view-data", "view-table-data", "re-execute-query", "view-table-history", "create-database-view", "find-database-view", "insert-table-data" ] + "realm" : [ "delete-database-view", "export-query-data", "execute-query", "delete-table-data", "export-table-data", "list-queries", "find-query", "list-database-views", "persist-query", "view-table-data", "re-execute-query", "view-table-history", "create-database-view", "find-database-view", "insert-table-data" ] }, "clientRole" : false, "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", "attributes" : { } + }, { + "id" : "b05e9b2b-748d-490b-949b-e78655bf7805", + "name" : "check-foreign-database-access", + "description" : "${check-foreign-database-access}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } }, { "id" : "c047d521-cec3-4444-86c4-aef098489b7b", "name" : "delete-maintenance-message", @@ -409,6 +437,14 @@ "clientRole" : false, "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", "attributes" : { } + }, { + "id" : "df20b7d1-8d30-4a99-80eb-e8195fab0e76", + "name" : "update-database-view", + "description" : "${update-database-view}", + "composite" : false, + "clientRole" : false, + "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", + "attributes" : { } }, { "id" : "88f82262-be80-4d18-9fb4-5529da031f33", "name" : "system", @@ -522,7 +558,7 @@ "description" : "${default-container-handling}", "composite" : true, "composites" : { - "realm" : [ "find-container", "list-containers" ] + "realm" : [ "find-container" ] }, "clientRole" : false, "containerId" : "82c39861-d877-4667-a0f3-4daa2ee230e0", @@ -902,7 +938,7 @@ "composite" : true, "composites" : { "client" : { - "realm-management" : [ "query-realms", "view-identity-providers", "manage-identity-providers", "manage-authorization", "query-clients", "view-authorization", "view-users", "manage-users", "view-realm", "query-users", "view-clients", "query-groups", "create-client", "manage-clients", "manage-events", "impersonation", "view-events", "manage-realm" ] + "realm-management" : [ "query-realms", "manage-authorization", "manage-identity-providers", "view-identity-providers", "query-clients", "view-authorization", "view-users", "manage-users", "view-realm", "query-users", "view-clients", "create-client", "query-groups", "impersonation", "manage-clients", "manage-events", "view-events", "manage-realm" ] } }, "clientRole" : true, @@ -1203,12 +1239,13 @@ "frontchannelLogout" : false, "protocol" : "openid-connect", "attributes" : { + "realm_client" : "false", "post.logout.redirect.uris" : "+" }, "authenticationFlowBindingOverrides" : { }, "fullScopeAllowed" : false, "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] }, { "id" : "d3c4a04e-39ce-4549-a34a-11e25774cd96", @@ -1233,6 +1270,7 @@ "frontchannelLogout" : false, "protocol" : "openid-connect", "attributes" : { + "realm_client" : "false", "post.logout.redirect.uris" : "+", "pkce.code.challenge.method" : "S256" }, @@ -1247,7 +1285,7 @@ "consentRequired" : false, "config" : { } } ], - "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] }, { "id" : "81ef0f59-a5ca-4be4-a1d1-0c32edf1cfd6", @@ -1270,12 +1308,14 @@ "frontchannelLogout" : false, "protocol" : "openid-connect", "attributes" : { + "realm_client" : "false", + "client.use.lightweight.access.token.enabled" : "true", "post.logout.redirect.uris" : "+" }, "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, + "fullScopeAllowed" : true, "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] }, { "id" : "88694c91-753d-4c44-9740-ec9ac06bba45", @@ -1298,6 +1338,7 @@ "frontchannelLogout" : false, "protocol" : "openid-connect", "attributes" : { + "realm_client" : "true", "post.logout.redirect.uris" : "+" }, "authenticationFlowBindingOverrides" : { }, @@ -1331,6 +1372,7 @@ "frontchannelLogout" : true, "protocol" : "openid-connect", "attributes" : { + "realm_client" : "false", "oidc.ciba.grant.enabled" : "false", "client.secret.creation.time" : "1680085365", "backchannel.logout.session.required" : "true", @@ -1342,6 +1384,38 @@ "fullScopeAllowed" : true, "nodeReRegistrationTimeout" : -1, "protocolMappers" : [ { + "id" : "266edf62-a19a-483b-b594-81428e4af792", + "name" : "orcid", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "ORCID", + "id.token.claim" : "true", + "lightweight.claim" : "false", + "access.token.claim" : "true", + "claim.name" : "orcid", + "jsonType.label" : "String" + } + }, { + "id" : "1a21798a-38b6-4df5-89f0-86942415246f", + "name" : "theme", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "THEME", + "id.token.claim" : "true", + "lightweight.claim" : "false", + "access.token.claim" : "true", + "claim.name" : "theme", + "jsonType.label" : "String" + } + }, { "id" : "da0b27c1-ae2e-4baa-bf78-db233e15c78d", "name" : "preferred_username", "protocol" : "openid-connect", @@ -1355,27 +1429,77 @@ "userinfo.token.claim" : "true" } }, { - "id" : "7c94de93-f60f-487b-b4b7-1891c67f74cc", - "name" : "aud", + "id" : "1bc6a1f4-4be2-439c-8c7f-b3fb0bb9956a", + "name" : "affiliation", "protocol" : "openid-connect", - "protocolMapper" : "oidc-hardcoded-claim-mapper", + "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "claim.value" : "dbrepo", + "introspection.token.claim" : "true", "userinfo.token.claim" : "true", + "user.attribute" : "AFFILIATION", "id.token.claim" : "true", + "lightweight.claim" : "false", "access.token.claim" : "true", - "claim.name" : "aud", - "access.tokenResponse.claim" : "false" + "claim.name" : "affiliation", + "jsonType.label" : "String" } }, { - "id" : "0b4c644f-0cf0-4794-8395-d5d83009dabe", + "id" : "7cbf6dc6-653e-40a9-9974-0e5bf7a363c3", + "name" : "given name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "firstName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "given_name", + "jsonType.label" : "String" + } + }, { + "id" : "70bbd779-d085-4204-ac4b-3a40abab9d88", + "name" : "language", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "LANGUAGE", + "id.token.claim" : "true", + "lightweight.claim" : "false", + "access.token.claim" : "true", + "claim.name" : "language", + "jsonType.label" : "String" + } + }, { + "id" : "b817424d-7f91-43d8-b7d0-6a32582377fb", + "name" : "family name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "lastName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "family_name", + "jsonType.label" : "String" + } + }, { + "id" : "030a1cd9-53d1-4a62-a375-94d50a2dc6fc", "name" : "uid", "protocol" : "openid-connect", "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { + "aggregate.attrs" : "false", "introspection.token.claim" : "true", + "multivalued" : "false", "userinfo.token.claim" : "true", "user.attribute" : "CUSTOM_ID", "id.token.claim" : "true", @@ -1384,9 +1508,26 @@ "claim.name" : "uid", "jsonType.label" : "String" } + }, { + "id" : "c304ed2f-5952-4772-838d-91998a45f154", + "name" : "aud", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-hardcoded-claim-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "claim.value" : "account", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "lightweight.claim" : "false", + "access.token.claim" : "true", + "claim.name" : "aud", + "jsonType.label" : "String", + "access.tokenResponse.claim" : "false" + } } ], - "defaultClientScopes" : [ "roles", "attributes" ], - "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ] + "defaultClientScopes" : [ "roles", "basic" ], + "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "attributes", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ] }, { "id" : "25741f6b-4867-4138-8238-6345c6ba8702", "clientId" : "rabbitmq-client", @@ -1413,6 +1554,7 @@ "frontchannelLogout" : true, "protocol" : "openid-connect", "attributes" : { + "realm_client" : "false", "oidc.ciba.grant.enabled" : "false", "client.secret.creation.time" : "1680000860", "backchannel.logout.session.required" : "true", @@ -1430,12 +1572,12 @@ "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "false", "user.attribute" : "username", "id.token.claim" : "false", "access.token.claim" : "true", "claim.name" : "client_id", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "false" } }, { "id" : "f1afc22d-f595-403b-ba2e-6ab19d98205e", @@ -1444,15 +1586,15 @@ "protocolMapper" : "oidc-hardcoded-claim-mapper", "consentRequired" : false, "config" : { - "claim.value" : "rabbitmq", - "userinfo.token.claim" : "false", "id.token.claim" : "false", "access.token.claim" : "true", "claim.name" : "aud", + "claim.value" : "rabbitmq", + "userinfo.token.claim" : "false", "access.tokenResponse.claim" : "false" } } ], - "defaultClientScopes" : [ "web-origins", "acr", "rabbitmq.tag:management" ], + "defaultClientScopes" : [ "web-origins", "acr", "rabbitmq.tag:management", "basic" ], "optionalClientScopes" : [ "rabbitmq.read:*/*", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "roles", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ] }, { "id" : "cfffd5d0-aa19-4057-8ca0-f2c51ca0e930", @@ -1475,6 +1617,7 @@ "frontchannelLogout" : false, "protocol" : "openid-connect", "attributes" : { + "realm_client" : "true", "post.logout.redirect.uris" : "+" }, "authenticationFlowBindingOverrides" : { }, @@ -1505,11 +1648,13 @@ "frontchannelLogout" : false, "protocol" : "openid-connect", "attributes" : { + "realm_client" : "false", + "client.use.lightweight.access.token.enabled" : "true", "post.logout.redirect.uris" : "+", "pkce.code.challenge.method" : "S256" }, "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, + "fullScopeAllowed" : true, "nodeReRegistrationTimeout" : 0, "protocolMappers" : [ { "id" : "c4d54410-3f22-4259-9571-94da2c43b752", @@ -1518,15 +1663,15 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "locale", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "locale", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } } ], - "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] } ], "clientScopes" : [ { @@ -1547,8 +1692,8 @@ "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${emailScopeConsentText}" + "consent.screen.text" : "${emailScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "782819fe-ba5d-4ddb-9f95-cabb69d79c8d", @@ -1557,12 +1702,12 @@ "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "emailVerified", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "email_verified", - "jsonType.label" : "boolean" + "jsonType.label" : "boolean", + "userinfo.token.claim" : "true" } }, { "id" : "ca613fc8-bbf2-4240-8b33-a1874f1559f3", @@ -1571,12 +1716,12 @@ "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "email", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "email", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } } ] }, { @@ -1586,8 +1731,8 @@ "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${profileScopeConsentText}" + "consent.screen.text" : "${profileScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "84f0487a-1d7d-470c-9b8e-5835294ae235", @@ -1596,12 +1741,12 @@ "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "username", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "preferred_username", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "bbdcdb36-3ec0-443d-b1af-9993d40f0567", @@ -1610,12 +1755,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "gender", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "gender", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "9faa870b-5491-4ce9-b27d-c9ce07d6a95e", @@ -1624,12 +1769,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "birthdate", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "birthdate", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "f0e3c012-9523-4076-83ae-e466e2d08220", @@ -1649,12 +1794,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "profile", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "profile", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "18cfbf4b-0a8e-45c7-a832-c0f72c92f3f3", @@ -1663,12 +1808,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "updatedAt", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "updated_at", - "jsonType.label" : "long" + "jsonType.label" : "long", + "userinfo.token.claim" : "true" } }, { "id" : "841ea785-26ab-429a-a420-09ce3948924d", @@ -1677,12 +1822,12 @@ "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "lastName", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "family_name", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "bfba13ff-f952-4e89-bbb1-a693fdebfae8", @@ -1691,12 +1836,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "website", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "website", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "475f071d-5149-4379-b928-76482f5f519c", @@ -1705,12 +1850,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "zoneinfo", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "zoneinfo", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "b8bebfed-b5e9-4604-a0ee-9817f7d439ac", @@ -1719,12 +1864,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "middleName", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "middle_name", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "445232c8-6830-476c-a6f1-8bbef167595a", @@ -1733,12 +1878,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "picture", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "picture", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "65f2e474-6ede-4872-86e4-e49504dd0f2a", @@ -1747,12 +1892,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "locale", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "locale", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "16cd5a27-ccf3-453c-ae1e-8621813ab73c", @@ -1761,12 +1906,12 @@ "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "firstName", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "given_name", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "f9efedfc-3388-457c-b10a-1dff4525ff9b", @@ -1775,12 +1920,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "nickname", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "nickname", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } } ] }, { @@ -1814,12 +1959,12 @@ "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "username", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "upn", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } } ] }, { @@ -1861,8 +2006,8 @@ "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${phoneScopeConsentText}" + "consent.screen.text" : "${phoneScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "dae802fb-9138-408a-b80e-a40eb0f56814", @@ -1871,12 +2016,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "phoneNumber", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "phone_number", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "feb06a8d-b0eb-4911-8464-368d93f566fa", @@ -1885,12 +2030,12 @@ "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "phoneNumberVerified", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "phone_number_verified", - "jsonType.label" : "boolean" + "jsonType.label" : "boolean", + "userinfo.token.claim" : "true" } } ] }, { @@ -1900,8 +2045,8 @@ "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "false", - "display.on.consent.screen" : "false", - "consent.screen.text" : "" + "consent.screen.text" : "", + "display.on.consent.screen" : "false" }, "protocolMappers" : [ { "id" : "c6411e3b-6478-453d-b530-5fe175a4d786", @@ -1981,6 +2126,61 @@ "gui.order" : "", "consent.screen.text" : "" } + }, { + "id" : "aa5c6ca7-812d-4fff-80b9-f5095ca82ce6", + "name" : "service_account", + "description" : "Specific scope for a client enabled for service accounts", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "bb359b0f-97dc-4d6a-9a2f-89458b53c512", + "name" : "Client IP Address", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "clientAddress", + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "clientAddress", + "jsonType.label" : "String" + } + }, { + "id" : "7aa3a4d2-3dd1-48dd-8886-562906eadb2a", + "name" : "Client Host", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "clientHost", + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "clientHost", + "jsonType.label" : "String" + } + }, { + "id" : "c4882d39-e815-49f5-8a73-eb8b83572eae", + "name" : "Client ID", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "client_id", + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "client_id", + "jsonType.label" : "String" + } + } ] }, { "id" : "210cc792-6c07-45a6-a77e-827cdf3b41ba", "name" : "offline_access", @@ -1997,8 +2197,8 @@ "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${addressScopeConsentText}" + "consent.screen.text" : "${addressScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "8d4ffe4d-1d01-4ca1-8ff4-44eacca61b30", @@ -2029,6 +2229,41 @@ "gui.order" : "", "consent.screen.text" : "" } + }, { + "id" : "ba11267a-478b-4b32-872f-4eb2d125d116", + "name" : "basic", + "description" : "OpenID Connect scope for add all basic claims to the token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "1445e14f-49b0-4666-8ddc-691493c24ad9", + "name" : "sub", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-sub-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "access.token.claim" : "true" + } + }, { + "id" : "846f1ef0-2b86-4e07-9d25-691d25af5fce", + "name" : "auth_time", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "AUTH_TIME", + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "auth_time", + "jsonType.label" : "long" + } + } ] }, { "id" : "37f61543-dad7-4a82-8e10-77acdd1eefdc", "name" : "roles", @@ -2036,8 +2271,8 @@ "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "false", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${rolesScopeConsentText}" + "consent.screen.text" : "${rolesScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "3b6b6914-8ad1-4a71-88ec-444f754aaacb", @@ -2053,11 +2288,15 @@ "protocolMapper" : "oidc-usermodel-realm-role-mapper", "consentRequired" : false, "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "false", + "multivalued" : "true", "user.attribute" : "foo", + "id.token.claim" : "true", + "lightweight.claim" : "false", "access.token.claim" : "true", "claim.name" : "realm_access.roles", - "jsonType.label" : "String", - "multivalued" : "true" + "jsonType.label" : "String" } }, { "id" : "a7bd6723-e58e-47f7-95c0-2925ce99283d", @@ -2074,7 +2313,7 @@ } } ] } ], - "defaultDefaultClientScopes" : [ "rabbitmq.tag:administrator", "rabbitmq.tag:management" ], + "defaultDefaultClientScopes" : [ "rabbitmq.tag:administrator", "rabbitmq.tag:management", "basic" ], "defaultOptionalClientScopes" : [ "rabbitmq.write:*/*", "offline_access", "rabbitmq.configure:*/*", "roles", "role_list", "address", "phone", "acr", "microprofile-jwt", "email", "attributes", "profile", "rabbitmq.read:*/*", "web-origins" ], "browserSecurityHeaders" : { "contentSecurityPolicyReportOnly" : "", @@ -2087,6 +2326,10 @@ "strictTransportSecurity" : "max-age=31536000; includeSubDomains" }, "smtpServer" : { }, + "loginTheme" : "keycloak", + "accountTheme" : "", + "adminTheme" : "", + "emailTheme" : "", "eventsEnabled" : false, "eventsListeners" : [ "jboss-logging" ], "enabledEventTypes" : [ "SEND_RESET_PASSWORD", "UPDATE_CONSENT_ERROR", "GRANT_CONSENT", "VERIFY_PROFILE_ERROR", "REMOVE_TOTP", "REVOKE_GRANT", "UPDATE_TOTP", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "IMPERSONATE_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "OAUTH2_DEVICE_CODE_TO_TOKEN_ERROR", "RESTART_AUTHENTICATION", "IMPERSONATE", "UPDATE_PROFILE_ERROR", "LOGIN", "OAUTH2_DEVICE_VERIFY_USER_CODE", "UPDATE_PASSWORD_ERROR", "CLIENT_INITIATED_ACCOUNT_LINKING", "TOKEN_EXCHANGE", "AUTHREQID_TO_TOKEN", "LOGOUT", "REGISTER", "DELETE_ACCOUNT_ERROR", "CLIENT_REGISTER", "IDENTITY_PROVIDER_LINK_ACCOUNT", "DELETE_ACCOUNT", "UPDATE_PASSWORD", "CLIENT_DELETE", "FEDERATED_IDENTITY_LINK_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN", "CLIENT_DELETE_ERROR", "VERIFY_EMAIL", "CLIENT_LOGIN_ERROR", "RESTART_AUTHENTICATION_ERROR", "EXECUTE_ACTIONS", "REMOVE_FEDERATED_IDENTITY_ERROR", "TOKEN_EXCHANGE_ERROR", "PERMISSION_TOKEN", "SEND_IDENTITY_PROVIDER_LINK_ERROR", "EXECUTE_ACTION_TOKEN_ERROR", "SEND_VERIFY_EMAIL", "OAUTH2_DEVICE_AUTH", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "OAUTH2_DEVICE_CODE_TO_TOKEN", "IDENTITY_PROVIDER_POST_LOGIN", "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR", "OAUTH2_DEVICE_VERIFY_USER_CODE_ERROR", "UPDATE_EMAIL", "REGISTER_ERROR", "REVOKE_GRANT_ERROR", "EXECUTE_ACTION_TOKEN", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "CLIENT_UPDATE_ERROR", "AUTHREQID_TO_TOKEN_ERROR", "UPDATE_PROFILE", "CLIENT_REGISTER_ERROR", "FEDERATED_IDENTITY_LINK", "SEND_IDENTITY_PROVIDER_LINK", "SEND_VERIFY_EMAIL_ERROR", "RESET_PASSWORD", "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR", "OAUTH2_DEVICE_AUTH_ERROR", "UPDATE_CONSENT", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "SEND_RESET_PASSWORD_ERROR", "CLIENT_UPDATE", "CUSTOM_REQUIRED_ACTION_ERROR", "IDENTITY_PROVIDER_POST_LOGIN_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN", "VERIFY_PROFILE", "GRANT_CONSENT_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR" ], @@ -2136,7 +2379,7 @@ "subType" : "anonymous", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "oidc-usermodel-property-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper", "saml-role-list-mapper" ] + "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-role-list-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper" ] } }, { "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1", @@ -2162,11 +2405,11 @@ "subType" : "authenticated", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-full-name-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper" ] + "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "saml-role-list-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-attribute-mapper" ] } } ], "org.keycloak.userprofile.UserProfileProvider" : [ { - "id" : "fb763636-e1ea-49c7-adca-ea105cdec4ad", + "id" : "a407a1d6-a7f6-4a72-ba3a-149de03d5a43", "providerId" : "declarative-user-profile", "subComponents" : { }, "config" : { @@ -2185,17 +2428,6 @@ "priority" : [ "100" ], "algorithm" : [ "RSA-OAEP" ] } - }, { - "id" : "230cb681-9ceb-4b1b-8a4c-929a11b08de0", - "name" : "hmac-generated-hs512", - "providerId" : "hmac-generated", - "subComponents" : { }, - "config" : { - "kid" : [ "8a489935-9a95-459b-9059-59b438ef0fa8" ], - "secret" : [ "xSCVgBlrLPWoF54gKQdR7BqXlfNaCD43xtS_ZgQRC0tGNAbqhy2Q9y8LdD2IR7K__8VGaDGYtyZayopgTebhDBb4gHDjDOBX7flhFYRrm0G3aTIuCIyFG-bPULwmyP_oHeC6tjwdQhqx5G0tE2mQQqPC9dDZuUA5I7QREIGK8cI" ], - "priority" : [ "100" ], - "algorithm" : [ "HS512" ] - } }, { "id" : "28ca0b6d-b2e2-4785-b04b-2391e6344e30", "name" : "aes-generated", @@ -2212,8 +2444,8 @@ "providerId" : "hmac-generated", "subComponents" : { }, "config" : { - "kid" : [ "5034d264-cb50-4006-a59e-2ce636eb5f38" ], - "secret" : [ "ToVIw-a4IE-Yp9JpP8ztb8NAICYO8CT3tUiDPT6DdiBcgzKJ9Ym9vspxGVdmPceX3mAgbnGLAcTx1PkInSVrbZs-tX9QXFwdlyGbewhKiNpH8wEg32Wk4GuUDpTv8JCsymgWyQBY681jvIMv05eCoK2QWpqCzcgP828KM5peCzo" ], + "kid" : [ "7f9f9054-5697-4f60-bdc8-67e3bd0f4db6" ], + "secret" : [ "1SCIY20z3AbAHCL28LuJfBU-7zfsZv5dacgliUeGdRW_WK3vH9fJUpPu1f7iDrdlhF7YQmHxLXsWjxhQId4ShI7QBdgKCArHWqi0GeH37oNXfZFg_uv-K_3JSfxfGBRu5jpRQhhSBxESZWsFVkskhxWUvNe6b5l9dFbMIif72rI" ], "priority" : [ "100" ], "algorithm" : [ "HS256" ] } @@ -2228,12 +2460,23 @@ "certificate" : [ "MIICmzCCAYMCBgGG3GWyBTANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZkYnJlcG8wHhcNMjMwMzEzMTkxMzE3WhcNMzMwMzEzMTkxNDU3WjARMQ8wDQYDVQQDDAZkYnJlcG8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqqcdDYFZZb28M0tEJzEP77FmD/Xqioyj9zWX6VwUSOMAgmMmn8eqs9hT9T0a+q4YTo9tUW1PNbUpwprA5b4Uk04DcIajxDVMUR/PjcHytmkqwVskq9AZW/Vngdoo+8tSbuIybwe/3Vwt266hbHpDcM97a+DXcYooRl7tQWCEX7RP27wQrMD9epDQ6IgKayZg9vC9/03dsIqwH9jXQRiZlFvwiEKhX2aY7lPGBaCK414JO00K/Z49iov9TRa/IYVbSt5qwgrx6DcqsBSPwOnI6A85UGfeUEZ/7coVJiL7RvBlsllapsL9eWTbQajVh94k9Ei3sibEPbtH+U2OAM78zAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAASnN1Cuif1sdfEK2kWAURSXGJCohCROLWdKFjaeHPRaEfpbFJsgxW0Yj3nwX5O3bUlOWoTyENwnXSsXMQsqnNi+At32CKaKO8+AkhAbgQL9F0B+KeJwmYv3cUj5N/LYkJjBvZBzUZ4Ugu5dcxH0k7AktLAIwimkyEnxTNolOA3UyrGGpREr8MCKWVr10RFuOpF/0CsJNNwbHXzalO9D756EUcRWZ9VSg6QVNso0YYRKTnILWDn9hcTRnqGy3SHo3anFTqQZ+BB57YbgFWy6udC0LYRB3zdp6zNti87eu/VEymiDY/mmo1AB8Tm0b6vxFz4AKcL3ax5qS6YnZ9efSzk=" ], "priority" : [ "100" ] } + }, { + "id" : "addbae10-c6ae-4735-851f-7a5ea035ce25", + "name" : "hmac-generated-hs512", + "providerId" : "hmac-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "352d0ea1-8218-42b5-ab78-e2ca56cf6a95" ], + "secret" : [ "_kr6EZOZ8IKqPWgJltHAAsQ34wCIGPs8oOQLYWwJrSIH7Qie3CEVKZnICyBP1goR-QgUtg25tR8Qu5MkvYkb8assJ8Iok5x_8iYCR4Txkf_mS-emrlAtQajlIjmOfNBtx704dTnZlP9rWzqpW6mrpeiOaiCw1K0XCpY5C_ZjXKw" ], + "priority" : [ "100" ], + "algorithm" : [ "HS512" ] + } } ] }, "internationalizationEnabled" : false, "supportedLocales" : [ ], "authenticationFlows" : [ { - "id" : "88e5d526-2298-413c-a904-133ad839d47f", + "id" : "259dd7b6-01b7-433a-bda4-028857151ecd", "alias" : "Account verification options", "description" : "Method with which to verity the existing account", "providerId" : "basic-flow", @@ -2255,7 +2498,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "a690c715-fbae-4c20-b680-bd4010718761", + "id" : "542ca1d7-9627-4102-b843-98837ce433fb", "alias" : "Browser - Conditional OTP", "description" : "Flow to determine if the OTP is required for the authentication", "providerId" : "basic-flow", @@ -2277,7 +2520,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "ad6d407e-c73e-4439-baf3-d7c99c6cb6ad", + "id" : "4f153b98-6851-440b-a022-0a14e67a9b2f", "alias" : "Direct Grant - Conditional OTP", "description" : "Flow to determine if the OTP is required for the authentication", "providerId" : "basic-flow", @@ -2299,7 +2542,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "e5d03405-e10a-408a-adb2-41dbb4f24515", + "id" : "3d791b35-d35c-40b2-bb3e-e806d72b27ee", "alias" : "First broker login - Conditional OTP", "description" : "Flow to determine if the OTP is required for the authentication", "providerId" : "basic-flow", @@ -2321,7 +2564,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "96b93843-62d0-44f1-84dd-21cc5f95f523", + "id" : "9b746104-9371-4c3f-b69f-9322cead1b08", "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", @@ -2343,7 +2586,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "088f4051-36ab-4952-a4f2-4ba53c408083", + "id" : "7a164efe-c97b-4fbb-950d-7745359ba9a4", "alias" : "Reset - Conditional OTP", "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", "providerId" : "basic-flow", @@ -2365,7 +2608,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "05f37bb2-779d-4e3f-ad1b-f6eb33bb3de4", + "id" : "4fdc5e1b-1b55-4662-8360-67d75fa22677", "alias" : "User creation or linking", "description" : "Flow for the existing/non-existing user alternatives", "providerId" : "basic-flow", @@ -2388,7 +2631,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "300a5647-7d2c-4348-9f1f-51504bfda1c4", + "id" : "75893341-c338-44d8-ae27-a3fc7bfe8f2d", "alias" : "Verify Existing Account by Re-authentication", "description" : "Reauthentication of existing account", "providerId" : "basic-flow", @@ -2410,7 +2653,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "26afc672-314b-4ad9-9711-7aaeafd7c00c", + "id" : "89626b76-f4cf-4c46-934c-4408c225a44b", "alias" : "browser", "description" : "browser based authentication", "providerId" : "basic-flow", @@ -2446,7 +2689,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "9b301f6c-eda7-4da0-ba09-1a6454ff910d", + "id" : "4112115a-e7a7-44c2-9af5-65d538e4ba0d", "alias" : "clients", "description" : "Base authentication for clients", "providerId" : "client-flow", @@ -2482,7 +2725,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "6e54f1be-dbad-4b6d-8eee-8e048d413c63", + "id" : "f82a9b0a-2c0a-4cb1-96b2-6c78b0b1f14f", "alias" : "direct grant", "description" : "OpenID Connect Resource Owner Grant", "providerId" : "basic-flow", @@ -2511,7 +2754,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "31da4b94-03c4-4d79-9ac3-5df1445c0781", + "id" : "3614e155-e8ce-4958-98fb-a27e4706cc70", "alias" : "docker auth", "description" : "Used by Docker clients to authenticate against the IDP", "providerId" : "basic-flow", @@ -2526,7 +2769,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "2e16651d-681f-4d9b-9dd4-9acdb465cd43", + "id" : "506f9b96-5002-47c0-96e3-3830a0fcfa26", "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", @@ -2549,7 +2792,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "da109a26-fefa-48a4-ae8e-1d49627c2db8", + "id" : "4b7a7e91-36db-4b27-8e2d-01a04a822980", "alias" : "forms", "description" : "Username, password, otp and other auth forms.", "providerId" : "basic-flow", @@ -2571,7 +2814,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "4c983c77-241f-41c5-8b8a-e2cd6fc08914", + "id" : "04c2fe01-5076-4aa4-9596-4efb4004195f", "alias" : "registration", "description" : "registration flow", "providerId" : "basic-flow", @@ -2587,7 +2830,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "d62c8dd6-633c-408a-aa99-43071510efb4", + "id" : "d12f77e1-7733-44a2-98ff-fd75c784d721", "alias" : "registration form", "description" : "registration form", "providerId" : "form-flow", @@ -2616,7 +2859,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "c8ca5be7-e76d-4e16-b5ca-3ced99d92dbb", + "id" : "91f6048c-a376-4809-8f37-c8d7a517830c", "alias" : "reset credentials", "description" : "Reset credentials for a user if they forgot their password or something", "providerId" : "basic-flow", @@ -2652,7 +2895,7 @@ "userSetupAllowed" : false } ] }, { - "id" : "389c1c37-e8af-4610-a507-e1257f55b954", + "id" : "7b8fb487-53b8-4533-a696-76bc05256cb1", "alias" : "saml ecp", "description" : "SAML ECP Profile Authentication Flow", "providerId" : "basic-flow", @@ -2668,13 +2911,13 @@ } ] } ], "authenticatorConfig" : [ { - "id" : "d66ca9d0-1645-4c84-abfe-c0a696f17de4", + "id" : "48372696-0579-45e5-b074-5e8dbdbbe7d6", "alias" : "create unique user config", "config" : { "require.password.update.after.registration" : "false" } }, { - "id" : "061cc6b8-90be-4423-9bf9-974ead709b5d", + "id" : "08df3b83-e522-42a7-9e24-9028b960bf39", "alias" : "review profile config", "config" : { "update.profile.on.first.login" : "missing" @@ -2785,10 +3028,12 @@ "actionTokenGeneratedByUserLifespan-idp-verify-account-via-email" : "", "parRequestUriLifespan" : "60", "clientSessionMaxLifespan" : "0", + "organizationsEnabled" : "false", "shortVerificationUri" : "" }, - "keycloakVersion" : "24.0.5", + "keycloakVersion" : "26.0.4", "userManagedAccessAllowed" : false, + "organizationsEnabled" : false, "clientProfiles" : { "profiles" : [ ] }, diff --git a/dbrepo-metadata-service/services/pom.xml b/dbrepo-metadata-service/services/pom.xml index 2961f680d12220dbfbf6c91a7cf64797ff213bf3..d1b8f9a7026e77f2235c580f0149f4dac17df779 100644 --- a/dbrepo-metadata-service/services/pom.xml +++ b/dbrepo-metadata-service/services/pom.xml @@ -6,12 +6,12 @@ <parent> <artifactId>dbrepo-metadata-service</artifactId> <groupId>at.tuwien</groupId> - <version>1.6.1</version> + <version>1.6.3</version> </parent> <artifactId>dbrepo-metadata-service-services</artifactId> <name>dbrepo-metadata-service-services</name> - <version>1.6.1</version> + <version>1.6.3</version> <dependencies> <dependency> diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java index b9fea2b54b1c242f58dbc0cd578e9dff328ba49c..d6535bad491b18744afecbe4fdc4792dfd3e7f33 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/BasicAuthenticationProvider.java @@ -1,7 +1,6 @@ package at.tuwien.auth; import at.tuwien.api.keycloak.TokenDto; -import at.tuwien.exception.*; import at.tuwien.gateway.KeycloakGateway; import jakarta.servlet.ServletException; import lombok.extern.log4j.Log4j2; @@ -34,8 +33,7 @@ public class BasicAuthenticationProvider implements AuthenticationManager { final UserDetails userDetails = authTokenFilter.verifyJwt(tokenDto.getAccessToken()); log.debug("set basic auth principal: {}", userDetails); return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); - } catch (ServletException | CredentialsInvalidException | AccountNotSetupException | - AuthServiceConnectionException e) { + } catch (ServletException e) { throw new BadCredentialsException("Failed to authenticate with authentication service", e); } } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java index 835b7245d1ef2ca017375990dd77c20693f3ef6f..b0edc929ed0097ce94e65153707dc47406f0f3c9 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/auth/InternalRequestInterceptor.java @@ -2,9 +2,6 @@ package at.tuwien.auth; import at.tuwien.api.keycloak.TokenDto; import at.tuwien.config.GatewayConfig; -import at.tuwien.exception.AccountNotSetupException; -import at.tuwien.exception.AuthServiceConnectionException; -import at.tuwien.exception.CredentialsInvalidException; import at.tuwien.gateway.KeycloakGateway; import lombok.extern.log4j.Log4j2; import org.springframework.http.HttpHeaders; @@ -33,15 +30,10 @@ public class InternalRequestInterceptor implements ClientHttpRequestInterceptor throws IOException { final HttpHeaders headers = request.getHeaders(); headers.setAccept(List.of(MediaType.APPLICATION_JSON)); - try { - final TokenDto token = keycloakGateway.obtainUserToken(gatewayConfig.getSystemUsername(), - gatewayConfig.getSystemPassword()); - headers.setBearerAuth(token.getAccessToken()); - log.trace("set bearer token for internal user: {}", gatewayConfig.getSystemUsername()); - return execution.execute(request, body); - } catch (AuthServiceConnectionException | CredentialsInvalidException | AccountNotSetupException e) { - log.error("Failed to obtain token for internal user: {}", gatewayConfig.getSystemUsername()); - throw new IOException("Failed to obtain token for internal user", e); - } + final TokenDto token = keycloakGateway.obtainUserToken(gatewayConfig.getSystemUsername(), + gatewayConfig.getSystemPassword()); + headers.setBearerAuth(token.getAccessToken()); + log.trace("set bearer token for internal user: {}", gatewayConfig.getSystemUsername()); + return execution.execute(request, body); } } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java index a24bbf41b8168b6e5c9ffef70c1b7bbbd6f5c674..4b62b61dcba2e06f9847d9eb20042b1f535bbc8d 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/config/KeycloakConfig.java @@ -1,12 +1,11 @@ package at.tuwien.config; -import at.tuwien.interceptor.KeycloakInterceptor; import lombok.Getter; +import org.keycloak.admin.client.Keycloak; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; -import org.springframework.web.util.DefaultUriBuilderFactory; @Getter @Configuration @@ -27,17 +26,15 @@ public class KeycloakConfig { @Value("${dbrepo.keycloak.clientSecret}") private String keycloakClientSecret; + private final String realm = "dbrepo"; + @Bean public RestTemplate restTemplate() { return new RestTemplate(); } - @Bean("keycloakRestTemplate") - public RestTemplate brokerRestTemplate() { - final RestTemplate restTemplate = new RestTemplate(); - restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(keycloakEndpoint)); - restTemplate.getInterceptors() - .add(new KeycloakInterceptor(restTemplate(), keycloakUsername, keycloakPassword, keycloakEndpoint)); - return restTemplate; + @Bean + public Keycloak keycloak() { + return Keycloak.getInstance(keycloakEndpoint, "master", keycloakUsername, keycloakPassword, "admin-cli"); } } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java index 976830cebbb17d0378ee6e4afedba30170507250..4ee76c36bf7adf98fe38a32fcab869759ec3af0a 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/DataServiceGateway.java @@ -3,11 +3,11 @@ package at.tuwien.gateway; import at.tuwien.ExportResourceDto; import at.tuwien.api.database.AccessTypeDto; import at.tuwien.api.database.DatabaseDto; -import at.tuwien.api.database.ViewCreateDto; +import at.tuwien.api.database.CreateViewDto; import at.tuwien.api.database.ViewDto; import at.tuwien.api.database.internal.CreateDatabaseDto; import at.tuwien.api.database.query.QueryDto; -import at.tuwien.api.database.table.TableCreateDto; +import at.tuwien.api.database.table.CreateTableDto; import at.tuwien.api.database.table.TableDto; import at.tuwien.api.database.table.TableStatisticDto; import at.tuwien.api.database.table.TableUpdateDto; @@ -94,7 +94,7 @@ public interface DataServiceGateway { * @throws DatabaseNotFoundException Some of the privileged parameters of the given database were not provided by the metadata service. * @throws TableExistsException A table with this internal name exists already in the database. */ - void createTable(Long databaseId, TableCreateDto data) throws DataServiceConnectionException, DataServiceException, + void createTable(Long databaseId, CreateTableDto data) throws DataServiceConnectionException, DataServiceException, DatabaseNotFoundException, TableExistsException; /** @@ -118,7 +118,7 @@ public interface DataServiceGateway { * @throws DataServiceConnectionException The connection to the data service could not be established. * @throws DataServiceException The data service responded unexpectedly. */ - ViewDto createView(Long databaseId, ViewCreateDto data) throws DataServiceConnectionException, DataServiceException; + ViewDto createView(Long databaseId, CreateViewDto data) throws DataServiceConnectionException, DataServiceException; /** * Deletes a given view in the given database. diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java index 94ea986f78727a6fdc927b4e7ebb25ca6f0616bd..cd5fd08a7ef64e88134a1fc19aa0840ad1e98020 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/KeycloakGateway.java @@ -1,37 +1,26 @@ package at.tuwien.gateway; import at.tuwien.api.keycloak.TokenDto; -import at.tuwien.api.keycloak.UserCreateDto; -import at.tuwien.api.keycloak.UserDto; import at.tuwien.api.user.UserPasswordDto; -import at.tuwien.exception.*; +import at.tuwien.api.user.UserUpdateDto; +import at.tuwien.exception.AuthServiceException; +import at.tuwien.exception.UserNotFoundException; +import org.keycloak.representations.idm.UserRepresentation; import java.util.UUID; public interface KeycloakGateway { - TokenDto obtainUserToken(String username, String password) throws AuthServiceConnectionException, - CredentialsInvalidException, AccountNotSetupException; + TokenDto obtainUserToken(String username, String password); - TokenDto refreshUserToken(String refreshToken) throws AuthServiceConnectionException, - CredentialsInvalidException; - - /** - * Creates a user at the Authentication Service with given credentials. - * - * @param data The user credentials. - * @throws UserExistsException The user already exists at the Authentication Service. - * @throws EmailExistsException The user email already exists in the metadata database. - */ - void createUser(UserCreateDto data) throws AuthServiceException, AuthServiceConnectionException, - EmailExistsException, UserExistsException; + UserRepresentation findByUsername(String username) throws UserNotFoundException; /** * Deletes a user at the Authentication Service with given user id. * * @param id The user id. */ - void deleteUser(UUID id) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException; + void deleteUser(UUID id) throws UserNotFoundException; /** * Update the credentials for a given user. @@ -39,17 +28,7 @@ public interface KeycloakGateway { * @param id The user id. * @param password The user credential. */ - void updateUserCredentials(UUID id, UserPasswordDto password) throws AuthServiceException, - AuthServiceConnectionException, UserNotFoundException; - - /** - * Finds a user in the metadata database by given username. - * - * @param username The user username. - * @return The updated user. - */ - UserDto findByUsername(String username) throws AuthServiceException, AuthServiceConnectionException, - UserNotFoundException; + void updateUserCredentials(UUID id, UserPasswordDto password) throws UserNotFoundException; - UserDto findById(UUID id) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException; + void updateUser(UUID id, UserUpdateDto data) throws AuthServiceException, UserNotFoundException; } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/SearchServiceGateway.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/SearchServiceGateway.java index f5e2f49c02023fe9145f137089e4550c9ae5b769..6632a08194411f74d5b4d22d4f1e0de6eda91a47 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/SearchServiceGateway.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/SearchServiceGateway.java @@ -1,12 +1,12 @@ package at.tuwien.gateway; -import at.tuwien.api.database.DatabaseDto; +import at.tuwien.api.database.DatabaseBriefDto; import at.tuwien.entities.database.Database; import at.tuwien.exception.*; public interface SearchServiceGateway { - DatabaseDto update(Database database) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException; + DatabaseBriefDto update(Database database) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException; void delete(Long databaseId) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException; } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java index 2b0cd72dda4c3896ae104e477d3f825dab0cb995..6ee2ef084b962e30bd614dd1073aecf65a0ced09 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/DataServiceGatewayImpl.java @@ -4,7 +4,7 @@ import at.tuwien.ExportResourceDto; import at.tuwien.api.database.*; import at.tuwien.api.database.internal.CreateDatabaseDto; import at.tuwien.api.database.query.QueryDto; -import at.tuwien.api.database.table.TableCreateDto; +import at.tuwien.api.database.table.CreateTableDto; import at.tuwien.api.database.table.TableDto; import at.tuwien.api.database.table.TableStatisticDto; import at.tuwien.api.database.table.TableUpdateDto; @@ -48,7 +48,7 @@ public class DataServiceGatewayImpl implements DataServiceGateway { log.trace("create access at endpoint {} with path {}", gatewayConfig.getDataEndpoint(), path); try { response = restTemplate.exchange(path, HttpMethod.POST, - new HttpEntity<>(UpdateDatabaseAccessDto.builder().type(access).build()), Void.class); + new HttpEntity<>(CreateAccessDto.builder().type(access).build()), Void.class); } catch (HttpServerErrorException e) { log.error("Failed to create access: {}", e.getMessage()); throw new DataServiceConnectionException("Failed to create access: " + e.getMessage(), e); @@ -73,7 +73,7 @@ public class DataServiceGatewayImpl implements DataServiceGateway { log.trace("update access at endpoint {} with path {}", gatewayConfig.getDataEndpoint(), path); try { response = restTemplate.exchange(path, HttpMethod.PUT, - new HttpEntity<>(UpdateDatabaseAccessDto.builder().type(access).build()), Void.class); + new HttpEntity<>(CreateAccessDto.builder().type(access).build()), Void.class); } catch (HttpServerErrorException e) { log.error("Failed to update access: {}", e.getMessage()); throw new DataServiceConnectionException("Failed to update access: " + e.getMessage(), e); @@ -188,7 +188,7 @@ public class DataServiceGatewayImpl implements DataServiceGateway { } @Override - public void createTable(Long databaseId, TableCreateDto data) throws DataServiceConnectionException, DataServiceException, + public void createTable(Long databaseId, CreateTableDto data) throws DataServiceConnectionException, DataServiceException, DatabaseNotFoundException, TableExistsException { final ResponseEntity<Void> response; final String path = "/api/database/" + databaseId + "/table"; @@ -239,7 +239,7 @@ public class DataServiceGatewayImpl implements DataServiceGateway { } @Override - public ViewDto createView(Long databaseId, ViewCreateDto data) throws DataServiceConnectionException, DataServiceException { + public ViewDto createView(Long databaseId, CreateViewDto data) throws DataServiceConnectionException, DataServiceException { final ResponseEntity<ViewDto> response; final String path = "/api/database/" + databaseId + "/view"; log.trace("create view at endpoint {} with path {}", gatewayConfig.getDataEndpoint(), path); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java index bce9d6e264b5283864c4e0ce4d2a157bd3d7dab4..af54651d6c36197e136134003291ea88f5df2a49 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/KeycloakGatewayImpl.java @@ -1,232 +1,128 @@ package at.tuwien.gateway.impl; -import at.tuwien.api.auth.KeycloakErrorDto; -import at.tuwien.api.keycloak.*; +import at.tuwien.api.keycloak.TokenDto; import at.tuwien.api.user.UserPasswordDto; +import at.tuwien.api.user.UserUpdateDto; import at.tuwien.config.KeycloakConfig; -import at.tuwien.exception.*; +import at.tuwien.exception.AuthServiceException; +import at.tuwien.exception.UserNotFoundException; import at.tuwien.gateway.KeycloakGateway; import at.tuwien.mapper.MetadataMapper; +import jakarta.ws.rs.BadRequestException; +import jakarta.ws.rs.ForbiddenException; +import jakarta.ws.rs.NotFoundException; +import jakarta.ws.rs.core.Response; import lombok.extern.log4j.Log4j2; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.http.*; +import org.keycloak.OAuth2Constants; +import org.keycloak.admin.client.Keycloak; +import org.keycloak.admin.client.KeycloakBuilder; +import org.keycloak.admin.client.resource.UserResource; +import org.keycloak.representations.idm.CredentialRepresentation; +import org.keycloak.representations.idm.UserRepresentation; import org.springframework.stereotype.Service; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.HttpServerErrorException; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.util.DefaultUriBuilderFactory; +import java.util.List; import java.util.UUID; @Log4j2 @Service public class KeycloakGatewayImpl implements KeycloakGateway { - private final RestTemplate restTemplate; - private final RestTemplate keycloakRestTemplate; + private final Keycloak keycloak; private final KeycloakConfig keycloakConfig; private final MetadataMapper metadataMapper; - public KeycloakGatewayImpl(@Qualifier("restTemplate") RestTemplate restTemplate, - @Qualifier("keycloakRestTemplate") RestTemplate keycloakRestTemplate, - KeycloakConfig keycloakConfig, MetadataMapper metadataMapper) { - restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(keycloakConfig.getKeycloakEndpoint())); - this.restTemplate = restTemplate; - this.keycloakRestTemplate = keycloakRestTemplate; + public KeycloakGatewayImpl(Keycloak keycloak, KeycloakConfig keycloakConfig, MetadataMapper metadataMapper) { + this.keycloak = keycloak; this.keycloakConfig = keycloakConfig; this.metadataMapper = metadataMapper; } @Override - public TokenDto obtainUserToken(String username, String password) throws AuthServiceConnectionException, - CredentialsInvalidException, AccountNotSetupException { - final HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); - final MultiValueMap<String, String> payload = new LinkedMultiValueMap<>(); - payload.add("username", username); - payload.add("password", password); - payload.add("grant_type", "password"); - payload.add("scope", "openid roles"); - payload.add("client_id", keycloakConfig.getKeycloakClient()); - payload.add("client_secret", keycloakConfig.getKeycloakClientSecret()); - final String path = "/realms/dbrepo/protocol/openid-connect/token"; - log.trace("obtain user token at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path); - final ResponseEntity<TokenDto> response; - try { - response = restTemplate.exchange(path, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class); - } catch (HttpServerErrorException e) { - log.error("Failed to obtain user token: {}", e.getMessage()); - throw new AuthServiceConnectionException("Service unavailable", e); - } catch (HttpClientErrorException.BadRequest e) { - final KeycloakErrorDto error = e.getResponseBodyAs(KeycloakErrorDto.class); - if (error != null && error.getError().equals("invalid_grant")) { - log.error("Failed to obtain user token: {}", error.getErrorDescription()); - throw new AccountNotSetupException(error.getErrorDescription()); - } - log.error("Failed to obtain user token: bad request"); - throw new CredentialsInvalidException("Bad request", e); - } catch (HttpClientErrorException.Unauthorized e) { - log.error("Failed to obtain user token: invalid credentials"); - throw new CredentialsInvalidException("Invalid credentials", e); + public TokenDto obtainUserToken(String username, String password) { + try (Keycloak userKeycloak = KeycloakBuilder.builder() + .serverUrl(keycloakConfig.getKeycloakEndpoint()) + .realm(keycloakConfig.getRealm()) + .grantType(OAuth2Constants.PASSWORD) + .clientId(keycloakConfig.getKeycloakClient()) + .clientSecret(keycloakConfig.getKeycloakClientSecret()) + .username(username) + .password(password) + .build()) { + return metadataMapper.accessTokenResponseToTokenDto(userKeycloak.tokenManager() + .getAccessToken()); } - return response.getBody(); } @Override - public TokenDto refreshUserToken(String refreshToken) throws AuthServiceConnectionException, - CredentialsInvalidException { - final HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); - final MultiValueMap<String, String> payload = new LinkedMultiValueMap<>(); - payload.add("refresh_token", refreshToken); - payload.add("grant_type", "refresh_token"); - payload.add("client_id", keycloakConfig.getKeycloakClient()); - payload.add("client_secret", keycloakConfig.getKeycloakClientSecret()); - final String path = "/realms/dbrepo/protocol/openid-connect/token"; - log.trace("refresh user token at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path); - final ResponseEntity<TokenDto> response; - try { - response = restTemplate.exchange(path, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class); - } catch (HttpServerErrorException e) { - log.error("Failed to refresh user token: {}", e.getMessage()); - throw new AuthServiceConnectionException("Service unavailable", e); - } catch (HttpClientErrorException.Unauthorized e) { - log.error("Failed to refresh user token: invalid credentials"); - throw new CredentialsInvalidException("Invalid credentials", e); - } catch (HttpClientErrorException.BadRequest e) { - if (e.getMessage() != null && e.getMessage().contains("Session not active")) { - log.error("Failed to refresh user token: inactive session", e); - throw new CredentialsInvalidException("Inactive session", e); - } - log.error("Failed to refresh user token: unexpected response: {}", e.getMessage(), e); - throw new CredentialsInvalidException("Unexpected response: " + e.getMessage(), e); + public UserRepresentation findByUsername(String username) throws UserNotFoundException { + final List<UserRepresentation> users = keycloak.realm(keycloakConfig.getRealm()) + .users() + .search(username); + if (users.isEmpty()) { + log.error("Failed to find user with username {}", username); + throw new UserNotFoundException("Failed to find user"); } - return response.getBody(); + return users.get(0); } @Override - public void createUser(UserCreateDto data) throws AuthServiceException, AuthServiceConnectionException, - EmailExistsException, UserExistsException { - final String path = "/admin/realms/dbrepo/users"; - log.trace("create user at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path); - final ResponseEntity<Void> response; - try { - response = keycloakRestTemplate.exchange(path, HttpMethod.POST, new HttpEntity<>(data), Void.class); - } catch (HttpServerErrorException e) { - log.error("Failed to create user: {}", e.getMessage()); - throw new AuthServiceConnectionException("Service unavailable", e); - } catch (HttpClientErrorException.Conflict e) { - if (e.getResponseBodyAsByteArray() != null && e.getResponseBodyAsByteArray().length > 0) { - final KeycloakErrorDto error = e.getResponseBodyAs(KeycloakErrorDto.class); - if (error != null && error.getErrorMessage().contains("same email")) { - log.error("Failed to create user: email exists: {}", e.getMessage()); - throw new EmailExistsException("E-Mail exists", e); - } + public void deleteUser(UUID id) throws UserNotFoundException { + try (Response response = keycloak.realm(keycloakConfig.getRealm()) + .users() + .delete(String.valueOf(id))) { + if (response.getStatus() == 404) { + log.error("Failed to delete user: not found"); + throw new UserNotFoundException("Failed to delete user: not found"); } - log.error("Failed to create user: user exists: {}", e.getMessage()); - throw new UserExistsException("User exists", e); - } - if (!response.getStatusCode().equals(HttpStatus.CREATED)) { - log.error("Failed to create user: unexpected status: {}", response.getStatusCode().value()); - throw new AuthServiceException("Unexpected status: " + response.getStatusCode().value()); - } - log.debug("Created user {} at auth service", data.getUsername()); - } - - @Override - public void deleteUser(UUID id) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException { - final String path = "/admin/realms/dbrepo/users/" + id; - log.trace("delete user at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path); - final ResponseEntity<Void> response; - try { - response = keycloakRestTemplate.exchange(path, HttpMethod.DELETE, HttpEntity.EMPTY, Void.class); - } catch (HttpServerErrorException e) { - log.error("Failed to delete user: {}", e.getMessage()); - throw new AuthServiceConnectionException("Service unavailable", e); - } catch (HttpClientErrorException.NotFound e) { - log.error("Failed to delete user: user not found: {}", e.getMessage()); - throw new UserNotFoundException("User not found", e); - } catch (Exception e) { - log.error("Failed to delete user: unexpected response: {}", e.getMessage()); - throw new AuthServiceException("Unexpected result", e); - } - if (!response.getStatusCode().equals(HttpStatus.NO_CONTENT)) { - log.error("Failed to delete user: unexpected response"); - throw new AuthServiceException("Unexpected result"); } log.info("Deleted user {} at auth service", id); } @Override - public void updateUserCredentials(UUID id, UserPasswordDto data) throws AuthServiceException, - AuthServiceConnectionException, UserNotFoundException { - final UpdateCredentialsDto payload = metadataMapper.passwordToUpdateCredentialsDto(data.getPassword()); - final String path = "/admin/realms/dbrepo/users/" + id; - log.trace("update user credentials at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path); - final ResponseEntity<Void> response; + public void updateUserCredentials(UUID id, UserPasswordDto data) throws UserNotFoundException { + final CredentialRepresentation credential = new CredentialRepresentation(); + credential.setTemporary(false); + credential.setValue(data.getPassword()); + credential.setType(CredentialRepresentation.PASSWORD); try { - response = keycloakRestTemplate.exchange(path, HttpMethod.PUT, new HttpEntity<>(payload), Void.class); - } catch (HttpServerErrorException e) { - log.error("Failed to update user credentials: {}", e.getMessage()); - throw new AuthServiceConnectionException("Service unavailable", e); - } catch (HttpClientErrorException.NotFound e) { - log.error("Failed to update user credentials: user not found: {}", e.getMessage()); - throw new UserNotFoundException("User not found", e); - } catch (Exception e) { - log.error("Failed to update user: unexpected response: {}", e.getMessage()); - throw new AuthServiceException("Unexpected result", e); - } - if (!response.getStatusCode().equals(HttpStatus.NO_CONTENT)) { - log.error("Failed to update user: unexpected status: {}", response.getStatusCode().value()); - throw new AuthServiceException("Unexpected status: " + response.getStatusCode().value()); + keycloak.realm(keycloakConfig.getRealm()) + .users() + .get(String.valueOf(id)) + .resetPassword(credential); + } catch (NotFoundException e) { + log.error("Failed to update user password: not found"); + throw new UserNotFoundException("Failed to update user password: not found", e); } log.info("Updated user {} password at auth service", id); } @Override - public UserDto findByUsername(String username) throws AuthServiceException, AuthServiceConnectionException, - UserNotFoundException { - final String path = "/admin/realms/dbrepo/users/?username=" + username; - log.trace("find user by username at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path); - final ResponseEntity<UserDto[]> response; + public void updateUser(UUID id, UserUpdateDto data) throws AuthServiceException, UserNotFoundException { + final UserResource resource = keycloak.realm(keycloakConfig.getRealm()) + .users() + .get(String.valueOf(id)); + UserRepresentation user; try { - response = keycloakRestTemplate.exchange(path, HttpMethod.GET, HttpEntity.EMPTY, UserDto[].class); - } catch (HttpServerErrorException e) { - log.error("Failed to find user: {}", e.getMessage()); - throw new AuthServiceConnectionException("Service unavailable", e); - } catch (Exception e) { - log.error("Failed to find user: unexpected response: {}", e.getMessage()); - throw new AuthServiceException("Unexpected result", e); + user = resource.toRepresentation(); + } catch (NotFoundException e) { + log.error("Failed to update user: not found: {}", e.getMessage()); + throw new UserNotFoundException("Failed to update user: not found", e); } - final UserDto[] body = response.getBody(); - if (body == null || body.length != 1) { - log.error("Failed to find user with username {}", username); - throw new UserNotFoundException("Failed to find user with username " + username); - } - return body[0]; - } - - @Override - public UserDto findById(UUID id) throws AuthServiceException, AuthServiceConnectionException, - UserNotFoundException { - final String path = "/admin/realms/dbrepo/users/" + id; - log.trace("find user by id at endpoint {} with path {}", keycloakConfig.getKeycloakEndpoint(), path); - final ResponseEntity<UserDto> response; + user.setFirstName(data.getFirstname()); + user.setLastName(data.getLastname()); + user.singleAttribute("THEME", data.getTheme()); + user.singleAttribute("ORCID", data.getOrcid()); + user.singleAttribute("LANGUAGE", data.getLanguage()); + user.singleAttribute("AFFILIATION", data.getAffiliation()); + log.trace("update user: {}", data); try { - response = keycloakRestTemplate.exchange(path, HttpMethod.GET, HttpEntity.EMPTY, UserDto.class); - } catch (HttpServerErrorException e) { - log.error("Failed to find user: {}", e.getMessage()); - throw new AuthServiceConnectionException("Service unavailable", e); - } catch (HttpClientErrorException.NotFound e) { - log.error("Failed to find user: not found: {}", e.getMessage()); - throw new UserNotFoundException("User not found"); - } catch (Exception e) { - log.error("Failed to find user: unexpected response: {}", e.getMessage()); - throw new AuthServiceException("Unexpected result", e); + resource.update(user); + } catch (ForbiddenException e) { + log.error("Failed to update user: forbidden: {}", e.getMessage()); + throw new AuthServiceException("Failed to update user: forbidden", e); } - return response.getBody(); + log.info("Updated user {} attributes at auth service", id); } } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java index 0f14b8d34826fe94829146f53a0cc22fb9e97333..503cad47ec5d2a8abd7ec4e76757b2f8ddb48ecd 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/gateway/impl/SearchServiceGatewayImpl.java @@ -1,6 +1,6 @@ package at.tuwien.gateway.impl; -import at.tuwien.api.database.DatabaseDto; +import at.tuwien.api.database.DatabaseBriefDto; import at.tuwien.config.GatewayConfig; import at.tuwien.entities.database.Database; import at.tuwien.exception.DatabaseNotFoundException; @@ -35,8 +35,8 @@ public class SearchServiceGatewayImpl implements SearchServiceGateway { } @Override - public DatabaseDto update(Database database) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException { - final ResponseEntity<DatabaseDto> response; + public DatabaseBriefDto update(Database database) throws SearchServiceConnectionException, SearchServiceException, DatabaseNotFoundException { + final ResponseEntity<DatabaseBriefDto> response; final HttpHeaders headers = new HttpHeaders(); headers.set("Accept", "application/json"); headers.set("Content-Type", "application/json"); @@ -44,7 +44,7 @@ public class SearchServiceGatewayImpl implements SearchServiceGateway { log.trace("update database at endpoint {} with path {}", gatewayConfig.getSearchEndpoint(), path); try { response = restTemplate.exchange(path, HttpMethod.PUT, new HttpEntity<>( - metadataMapper.databaseToPrivilegedDatabaseDto(database), headers), DatabaseDto.class); + metadataMapper.databaseToDatabaseDto(database), headers), DatabaseBriefDto.class); } catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable | HttpServerErrorException.InternalServerError e) { log.error("Failed to update database: {}", e.getMessage()); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/AuthenticationService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/AuthenticationService.java index eb378290aaf0cec147292a4528efae7e3928811b..75b647bf954fd638dfde8ffa8b7f650d03ce7c49 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/AuthenticationService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/AuthenticationService.java @@ -1,30 +1,14 @@ package at.tuwien.service; -import at.tuwien.api.auth.LoginRequestDto; -import at.tuwien.api.auth.SignupRequestDto; -import at.tuwien.api.keycloak.TokenDto; -import at.tuwien.api.keycloak.UserDto; import at.tuwien.api.user.UserPasswordDto; import at.tuwien.entities.user.User; -import at.tuwien.exception.*; - -import java.util.UUID; +import at.tuwien.exception.AuthServiceConnectionException; +import at.tuwien.exception.AuthServiceException; +import at.tuwien.exception.CredentialsInvalidException; +import at.tuwien.exception.UserNotFoundException; public interface AuthenticationService { - /** - * Create a user at the Authentication Service with given credentials. - * - * @param data The credentials. - * @return The user, if successful. - * @throws UserExistsException The user already exists at the auth database. - * @throws AuthServiceException The auth service responded with unexpected behavior. - * @throws AuthServiceConnectionException The connection with the auth service could not be established. - * @throws EmailExistsException The user email already exists in the metadata database. - */ - UserDto create(SignupRequestDto data) throws UserExistsException, AuthServiceException, AuthServiceConnectionException, - EmailExistsException, CredentialsInvalidException; - /** * Deletes a user at the Authentication Service with given user id. * @@ -35,31 +19,12 @@ public interface AuthenticationService { */ void delete(User user) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException, CredentialsInvalidException; - /** - * Finds a user with given username. - * - * @param username The username. - * @return The user, if successful. - * @throws AuthServiceException The auth service responded with unexpected behavior. - * @throws AuthServiceConnectionException The connection with the auth service could not be established. - * @throws UserNotFoundException The user was not found in the auth database. - */ - UserDto findByUsername(String username) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException, CredentialsInvalidException; - - UserDto findById(UUID id) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException, CredentialsInvalidException; - - TokenDto obtainToken(LoginRequestDto data) throws AuthServiceConnectionException, CredentialsInvalidException, AccountNotSetupException; - - TokenDto refreshToken(String refreshToken) throws AuthServiceConnectionException, CredentialsInvalidException; - /** * Updates the password of a user with given id. * * @param user The user. * @param data The new password. - * @throws AuthServiceException The auth service responded with unexpected behavior. - * @throws AuthServiceConnectionException The connection with the auth service could not be established. + * @throws UserNotFoundException The user was not found after creation in the auth database. */ - void updatePassword(User user, UserPasswordDto data) throws AuthServiceException, AuthServiceConnectionException, - CredentialsInvalidException, UserNotFoundException; + void updatePassword(User user, UserPasswordDto data) throws UserNotFoundException; } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ContainerService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ContainerService.java index aa5a3295c49688f91d47960f2e254f5a5721604f..9aa2dc6c89839999c255595d65deb7399e702feb 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ContainerService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ContainerService.java @@ -1,11 +1,9 @@ package at.tuwien.service; -import at.tuwien.api.container.ContainerCreateDto; +import at.tuwien.api.container.CreateContainerDto; import at.tuwien.entities.container.Container; -import at.tuwien.entities.user.User; import at.tuwien.exception.*; -import java.security.Principal; import java.util.List; public interface ContainerService { @@ -18,7 +16,7 @@ public interface ContainerService { * @throws ImageNotFoundException The image of the container was not found in the metadata database. * @throws ContainerAlreadyExistsException A container with this name already exists. */ - Container create(ContainerCreateDto createDto) throws ImageNotFoundException, + Container create(CreateContainerDto createDto) throws ImageNotFoundException, ContainerAlreadyExistsException; /** diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/DatabaseService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/DatabaseService.java index 3000ece11e91cc2b58f2edcfac85f6a0f8a60528..4e3765fd6ec8231d8bcfdcdaae83c0c96bcb8788 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/DatabaseService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/DatabaseService.java @@ -1,6 +1,6 @@ package at.tuwien.service; -import at.tuwien.api.database.DatabaseCreateDto; +import at.tuwien.api.database.CreateDatabaseDto; import at.tuwien.api.database.DatabaseModifyVisibilityDto; import at.tuwien.entities.container.Container; import at.tuwien.entities.database.Database; @@ -68,7 +68,7 @@ public interface DatabaseService { * @throws DataServiceException If the data service returned non-successfully. * @throws DataServiceConnectionException If failing to connect to the data service/search service. */ - Database create(Container container, DatabaseCreateDto createDto, User user, List<User> internalUsers) throws UserNotFoundException, + Database create(Container container, CreateDatabaseDto createDto, User user, List<User> internalUsers) throws UserNotFoundException, ContainerNotFoundException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/IdentifierService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/IdentifierService.java index ded8204f32b8b6f99af5553952dfa6f0c535c652..47183700f91df1b24194fef24d931992b6b8b932 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/IdentifierService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/IdentifierService.java @@ -1,7 +1,7 @@ package at.tuwien.service; import at.tuwien.api.identifier.BibliographyTypeDto; -import at.tuwien.api.identifier.IdentifierCreateDto; +import at.tuwien.api.identifier.CreateIdentifierDto; import at.tuwien.api.identifier.IdentifierSaveDto; import at.tuwien.api.identifier.IdentifierTypeDto; import at.tuwien.entities.database.Database; @@ -139,7 +139,7 @@ public interface IdentifierService { * @throws SearchServiceException * @throws SearchServiceConnectionException */ - Identifier create(Database database, User user, IdentifierCreateDto data) throws DataServiceException, + Identifier create(Database database, User user, CreateIdentifierDto data) throws DataServiceException, DataServiceConnectionException, IdentifierNotFoundException, MalformedException, ViewNotFoundException, DatabaseNotFoundException, QueryNotFoundException, SearchServiceException, SearchServiceConnectionException, ExternalServiceException; 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 299283e68bbf6bd07ddb6b042248ead6681a6970..c0880c07dc8230d803ad455093cbea17c3145f61 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 @@ -1,6 +1,6 @@ package at.tuwien.service; -import at.tuwien.api.database.table.TableCreateDto; +import at.tuwien.api.database.table.CreateTableDto; import at.tuwien.api.database.table.TableUpdateDto; import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; import at.tuwien.entities.database.Database; @@ -39,7 +39,7 @@ public interface TableService { * @param principal The principal. * @return The created table. */ - Table createTable(Database database, TableCreateDto createDto, Principal principal) + Table createTable(Database database, CreateTableDto createDto, Principal principal) throws TableNotFoundException, DataServiceException, DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, TableExistsException, SearchServiceException, SearchServiceConnectionException, MalformedException, OntologyNotFoundException, SemanticEntityNotFoundException; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UserService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UserService.java index 6416da9b803d93f633f13223127a978954dd6e5d..581641a93ab95927d63c5b4a5f6b069eb6f270b7 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UserService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/UserService.java @@ -1,10 +1,11 @@ package at.tuwien.service; -import at.tuwien.api.auth.SignupRequestDto; +import at.tuwien.api.auth.CreateUserDto; import at.tuwien.api.user.UserPasswordDto; import at.tuwien.api.user.UserUpdateDto; import at.tuwien.entities.user.User; -import at.tuwien.exception.EmailExistsException; +import at.tuwien.exception.AuthServiceConnectionException; +import at.tuwien.exception.AuthServiceException; import at.tuwien.exception.UserExistsException; import at.tuwien.exception.UserNotFoundException; @@ -44,10 +45,9 @@ public interface UserService { * Creates a user in the metadata database managed by Keycloak in the given realm. * * @param data The user data. - * @param id The user id. * @return The user, if successful. */ - User create(SignupRequestDto data, UUID id); + User create(CreateUserDto data) throws UserNotFoundException, AuthServiceException; /** * Updates the user information for a user with given id in the metadata database. @@ -56,7 +56,7 @@ public interface UserService { * @param data The user information. * @return The user if successful. False otherwise. */ - User modify(User user, UserUpdateDto data); + User modify(User user, UserUpdateDto data) throws UserNotFoundException, AuthServiceException; /** * Updates the user password for a user with given id in the metadata database. @@ -74,13 +74,5 @@ public interface UserService { */ void validateUsernameNotExists(String username) throws UserExistsException; - /** - * Validates if a user with the given email already exists in the metadata database. - * - * @param email The email. - * @throws EmailExistsException The user with this email already exists. - */ - void validateEmailNotExists(String email) throws EmailExistsException; - String getMariaDbPassword(String password); } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ViewService.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ViewService.java index 9ec30b74f2efd58886269f8e8994f4852ead827e..4d183f1cc467d070a51a89edca99850c81a9b2ed 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ViewService.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/ViewService.java @@ -1,12 +1,11 @@ package at.tuwien.service; -import at.tuwien.api.database.ViewCreateDto; +import at.tuwien.api.database.CreateViewDto; import at.tuwien.api.database.ViewUpdateDto; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.View; import at.tuwien.entities.user.User; import at.tuwien.exception.*; -import org.springframework.transaction.annotation.Transactional; import java.util.List; @@ -53,7 +52,7 @@ public interface ViewService { * @throws SearchServiceConnectionException * @throws ViewNotFoundException */ - View create(Database database, User user, ViewCreateDto data) throws MalformedException, DataServiceException, + View create(Database database, User user, CreateViewDto data) throws MalformedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException; diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java index 52aa5048891102ae10494790992076f9375388f5..1159913039ef59227758006f28d678db99329386 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/AuthenticationServiceImpl.java @@ -1,81 +1,36 @@ package at.tuwien.service.impl; -import at.tuwien.api.auth.LoginRequestDto; -import at.tuwien.api.auth.SignupRequestDto; -import at.tuwien.api.keycloak.TokenDto; -import at.tuwien.api.keycloak.UserDto; import at.tuwien.api.user.UserPasswordDto; import at.tuwien.entities.user.User; -import at.tuwien.exception.*; +import at.tuwien.exception.AuthServiceConnectionException; +import at.tuwien.exception.AuthServiceException; +import at.tuwien.exception.CredentialsInvalidException; +import at.tuwien.exception.UserNotFoundException; import at.tuwien.gateway.KeycloakGateway; -import at.tuwien.mapper.MetadataMapper; import at.tuwien.service.AuthenticationService; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.UUID; - @Log4j2 @Service public class AuthenticationServiceImpl implements AuthenticationService { - private final MetadataMapper metadataMapper; private final KeycloakGateway keycloakGateway; @Autowired - public AuthenticationServiceImpl(MetadataMapper metadataMapper, KeycloakGateway keycloakGateway) { - this.metadataMapper = metadataMapper; + public AuthenticationServiceImpl(KeycloakGateway keycloakGateway) { this.keycloakGateway = keycloakGateway; } @Override - public UserDto create(SignupRequestDto data) throws UserExistsException, AuthServiceException, - AuthServiceConnectionException, EmailExistsException, CredentialsInvalidException { - keycloakGateway.createUser(metadataMapper.signupRequestDtoToUserCreateDto(data)); - try { - return findByUsername(data.getUsername()); - } catch (UserNotFoundException e) { - throw new AuthServiceException("Failed to find user in auth service", e); - } - } - - @Override - public void delete(User user) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException, - CredentialsInvalidException { - final UserDto keycloakUser = findByUsername(user.getUsername()); - keycloakGateway.deleteUser(keycloakUser.getId()); - } - - @Override - public UserDto findByUsername(String username) throws AuthServiceException, AuthServiceConnectionException, - UserNotFoundException, CredentialsInvalidException { - return keycloakGateway.findByUsername(username); - } - - @Override - public UserDto findById(UUID id) throws AuthServiceException, AuthServiceConnectionException, UserNotFoundException, - CredentialsInvalidException { - return keycloakGateway.findById(id); - } - - @Override - public TokenDto obtainToken(LoginRequestDto data) throws AuthServiceConnectionException, - CredentialsInvalidException, AccountNotSetupException { - return keycloakGateway.obtainUserToken(data.getUsername(), data.getPassword()); - } - - @Override - public TokenDto refreshToken(String refreshToken) throws AuthServiceConnectionException, - CredentialsInvalidException { - return keycloakGateway.refreshUserToken(refreshToken); + public void delete(User user) throws AuthServiceException, UserNotFoundException { + keycloakGateway.deleteUser(user.getKeycloakId()); } @Override - public void updatePassword(User user, UserPasswordDto data) throws AuthServiceException, - AuthServiceConnectionException, CredentialsInvalidException, UserNotFoundException { - final UserDto keycloakUser = findByUsername(user.getUsername()); - keycloakGateway.updateUserCredentials(keycloakUser.getId(), data); + public void updatePassword(User user, UserPasswordDto data) throws UserNotFoundException { + keycloakGateway.updateUserCredentials(user.getKeycloakId(), data); } } diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java index 91db7736db7d9a4a4e931c744a938e78d72308c9..2a3c3215367605b943a3a2701c47b139c20c1b5d 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ContainerServiceImpl.java @@ -1,6 +1,6 @@ package at.tuwien.service.impl; -import at.tuwien.api.container.ContainerCreateDto; +import at.tuwien.api.container.CreateContainerDto; import at.tuwien.entities.container.Container; import at.tuwien.entities.container.image.ContainerImage; import at.tuwien.exception.ContainerAlreadyExistsException; @@ -38,7 +38,7 @@ public class ContainerServiceImpl implements ContainerService { @Override @Transactional - public Container create(ContainerCreateDto data) throws ImageNotFoundException, + public Container create(CreateContainerDto data) throws ImageNotFoundException, ContainerAlreadyExistsException { final String containerName = "dbrepo-userdb-" + metadataMapper.nameToInternalName(data.getName()); /* check */ diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java index 0151ea92f7c4e8110bda544b70b7d341381902c2..b4e42a67e15939c2b779fc0dbe9d392371588c76 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DataCiteIdentifierServiceImpl.java @@ -6,7 +6,7 @@ import at.tuwien.api.datacite.doi.DataCiteCreateDoi; import at.tuwien.api.datacite.doi.DataCiteDoi; import at.tuwien.api.datacite.doi.DataCiteDoiEvent; import at.tuwien.api.identifier.BibliographyTypeDto; -import at.tuwien.api.identifier.IdentifierCreateDto; +import at.tuwien.api.identifier.CreateIdentifierDto; import at.tuwien.api.identifier.IdentifierSaveDto; import at.tuwien.api.identifier.IdentifierTypeDto; import at.tuwien.config.DataCiteConfig; @@ -105,7 +105,7 @@ public class DataCiteIdentifierServiceImpl implements IdentifierService { @Override @Transactional(rollbackFor = {Exception.class}) - public Identifier create(Database database, User user, IdentifierCreateDto data) throws DataServiceException, + public Identifier create(Database database, User user, CreateIdentifierDto data) throws DataServiceException, DataServiceConnectionException, IdentifierNotFoundException, MalformedException, ViewNotFoundException, DatabaseNotFoundException, QueryNotFoundException, SearchServiceException, SearchServiceConnectionException, ExternalServiceException { diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java index 7415ded56a8a2a926742ef3b44b025f7fb535baa..8b4c73fb2f063cfc779fa001b7982675d74cf447 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/DatabaseServiceImpl.java @@ -1,10 +1,9 @@ package at.tuwien.service.impl; -import at.tuwien.api.database.DatabaseCreateDto; +import at.tuwien.api.database.CreateDatabaseDto; import at.tuwien.api.database.DatabaseDto; import at.tuwien.api.database.DatabaseModifyVisibilityDto; import at.tuwien.api.database.ViewDto; -import at.tuwien.api.database.internal.CreateDatabaseDto; import at.tuwien.api.database.table.TableDto; import at.tuwien.api.user.internal.UpdateUserPasswordDto; import at.tuwien.entities.container.Container; @@ -96,7 +95,7 @@ public class DatabaseServiceImpl implements DatabaseService { @Override @Transactional - public Database create(Container container, DatabaseCreateDto data, User user, List<User> internalUsers) + public Database create(Container container, CreateDatabaseDto data, User user, List<User> internalUsers) throws UserNotFoundException, ContainerNotFoundException, DataServiceException, SearchServiceException, DataServiceConnectionException, DatabaseNotFoundException, SearchServiceConnectionException { final Database entity = Database.builder() @@ -116,7 +115,7 @@ public class DatabaseServiceImpl implements DatabaseService { .identifiers(new LinkedList<>()) .build(); /* create in data database */ - final CreateDatabaseDto payload = CreateDatabaseDto.builder() + final at.tuwien.api.database.internal.CreateDatabaseDto payload = at.tuwien.api.database.internal.CreateDatabaseDto.builder() .containerId(data.getCid()) .userId(user.getId()) .username(user.getUsername()) @@ -217,6 +216,8 @@ public class DatabaseServiceImpl implements DatabaseService { } log.debug("fetched unknown table from data service: {}.{}", database.getInternalName(), table.getInternalName()); final Table tableEntity = metadataMapper.tableDtoToTable(table); + tableEntity.setIsPublic(database.getIsPublic()); + tableEntity.setIsSchemaPublic(database.getIsSchemaPublic()); tableEntity.setDatabase(database); tableEntity.getColumns() .forEach(column -> { diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java index 39e4824706a6d89a3588c6748c46ee2c3935b63e..96b8bd83963cca91e4731812ee0812a54a4630dc 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/IdentifierServiceImpl.java @@ -3,7 +3,7 @@ package at.tuwien.service.impl; import at.tuwien.ExportResourceDto; import at.tuwien.api.database.query.QueryDto; import at.tuwien.api.identifier.BibliographyTypeDto; -import at.tuwien.api.identifier.IdentifierCreateDto; +import at.tuwien.api.identifier.CreateIdentifierDto; import at.tuwien.api.identifier.IdentifierSaveDto; import at.tuwien.api.identifier.IdentifierTypeDto; import at.tuwien.config.MetadataConfig; @@ -228,7 +228,7 @@ public class IdentifierServiceImpl implements IdentifierService { @Override @Transactional - public Identifier create(Database database, User user, IdentifierCreateDto data) throws SearchServiceException, + public Identifier create(Database database, User user, CreateIdentifierDto data) throws SearchServiceException, DataServiceException, QueryNotFoundException, DataServiceConnectionException, DatabaseNotFoundException, SearchServiceConnectionException, IdentifierNotFoundException, ViewNotFoundException { final Identifier identifier = metadataMapper.identifierCreateDtoToIdentifier(data); @@ -287,7 +287,7 @@ public class IdentifierServiceImpl implements IdentifierService { /* save identifier */ switch (identifier.getType()) { case SUBSET -> { - log.debug("identifier type: subset with id {} and database with id {}", identifier.getQueryId(), identifier.getDatabase().getId()); + log.debug("identifier type: subset with id {}", identifier.getQueryId()); final QueryDto query = dataServiceGateway.findQuery(identifier.getDatabase().getId(), identifier.getQueryId()); identifier.setQuery(query.getQuery()); identifier.setQueryId(query.getId()); @@ -298,14 +298,14 @@ public class IdentifierServiceImpl implements IdentifierService { identifier.setResultHash(query.getResultHash()); } case VIEW -> { - log.debug("identifier type: view with id {} and database with id {}", identifier.getViewId(), identifier.getDatabase().getId()); + log.debug("identifier type: view with id {}", identifier.getViewId()); final View view = viewService.findById(identifier.getDatabase(), identifier.getViewId()); identifier.setViewId(view.getId()); identifier.setQuery(view.getQuery()); identifier.setQueryNormalized(view.getQuery()); identifier.setQueryHash(view.getQueryHash()); } - case DATABASE -> log.debug("identifier type: database with id {}", identifier.getDatabase()); + case DATABASE -> log.debug("identifier type: database with id {}", identifier.getDatabase().getId()); case TABLE -> log.debug("identifier type: table with id {}", identifier.getTableId()); } /* save identifier in 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 52a9a63667c8faa22bdd142d5161f04e85d70513..da92fb7ef59eac9af0df3cf1f779da150c2d437f 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 @@ -1,9 +1,9 @@ package at.tuwien.service.impl; -import at.tuwien.api.database.table.TableCreateDto; +import at.tuwien.api.database.table.CreateTableDto; import at.tuwien.api.database.table.TableStatisticDto; import at.tuwien.api.database.table.TableUpdateDto; -import at.tuwien.api.database.table.columns.ColumnCreateDto; +import at.tuwien.api.database.table.columns.CreateTableColumnDto; import at.tuwien.api.database.table.columns.ColumnStatisticDto; import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; import at.tuwien.config.RabbitConfig; @@ -90,7 +90,7 @@ public class TableServiceImpl implements TableService { @Override @Transactional - public Table createTable(Database database, TableCreateDto data, Principal principal) throws DataServiceException, + public Table createTable(Database database, CreateTableDto data, Principal principal) throws DataServiceException, DataServiceConnectionException, UserNotFoundException, TableNotFoundException, DatabaseNotFoundException, TableExistsException, SearchServiceException, SearchServiceConnectionException, MalformedException, OntologyNotFoundException, SemanticEntityNotFoundException { @@ -117,7 +117,7 @@ public class TableServiceImpl implements TableService { /* set the ordinal position for the columns */ final int[] idx = new int[]{0}; for (int i = 0; i < data.getColumns().size(); i++) { - final ColumnCreateDto c = data.getColumns().get(i); + final CreateTableColumnDto c = data.getColumns().get(i); final TableColumn column = metadataMapper.columnCreateDtoToTableColumn(c, database.getContainer().getImage()); column.setOrdinalPosition(idx[0]++); column.setTable(table); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java index 6f9f43aeda934ecd7065ead11077ad529597e118..cb550be1a5d408139b656f0d0619467f8f59fa26 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/UserServiceImpl.java @@ -1,17 +1,20 @@ package at.tuwien.service.impl; -import at.tuwien.api.auth.SignupRequestDto; +import at.tuwien.api.auth.CreateUserDto; import at.tuwien.api.user.UserPasswordDto; import at.tuwien.api.user.UserUpdateDto; -import at.tuwien.config.KeycloakConfig; import at.tuwien.entities.user.User; -import at.tuwien.exception.EmailExistsException; +import at.tuwien.exception.AuthServiceConnectionException; +import at.tuwien.exception.AuthServiceException; import at.tuwien.exception.UserExistsException; import at.tuwien.exception.UserNotFoundException; +import at.tuwien.gateway.KeycloakGateway; +import at.tuwien.mapper.MetadataMapper; import at.tuwien.repository.UserRepository; import at.tuwien.service.UserService; import lombok.extern.log4j.Log4j2; import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.RandomStringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -24,13 +27,16 @@ import java.util.UUID; @Service public class UserServiceImpl implements UserService { - private final KeycloakConfig keycloakConfig; + private final MetadataMapper metadataMapper; private final UserRepository userRepository; + private final KeycloakGateway keycloakGateway; @Autowired - public UserServiceImpl(KeycloakConfig keycloakConfig, UserRepository userRepository) { - this.keycloakConfig = keycloakConfig; + public UserServiceImpl(MetadataMapper metadataMapper, UserRepository userRepository, + KeycloakGateway keycloakGateway) { + this.metadataMapper = metadataMapper; this.userRepository = userRepository; + this.keycloakGateway = keycloakGateway; } @Override @@ -64,32 +70,36 @@ public class UserServiceImpl implements UserService { } @Override - public User create(SignupRequestDto data, UUID id) { + public User create(CreateUserDto data) throws UserNotFoundException, AuthServiceException { /* create at authentication service */ final User entity = User.builder() - .id(id) + .id(data.getLdapId()) + .keycloakId(data.getId()) .username(data.getUsername()) - .email(data.getEmail()) .theme("light") - .mariadbPassword(getMariaDbPassword(data.getPassword())) + .mariadbPassword(getMariaDbPassword(RandomStringUtils.randomAlphabetic(10))) /* user needs to set it later to access */ .language("en") + .firstname(data.getGivenName()) + .lastname(data.getFamilyName()) .isInternal(false) .build(); - /* create at metadata database */ + /* save in metadata database */ final User user = userRepository.save(entity); log.info("Created user with id: {}", user.getId()); return user; } @Override - public User modify(User user, UserUpdateDto data) { + public User modify(User user, UserUpdateDto data) throws UserNotFoundException, AuthServiceException { user.setFirstname(data.getFirstname()); user.setLastname(data.getLastname()); user.setAffiliation(data.getAffiliation()); user.setOrcid(data.getOrcid()); user.setTheme(data.getTheme()); user.setLanguage(data.getLanguage()); - /* create at metadata database */ + /* save in auth service */ + keycloakGateway.updateUser(user.getKeycloakId(), data); + /* save in metadata database */ user = userRepository.save(user); log.info("Modified user with id: {}", user.getId()); return user; @@ -110,13 +120,6 @@ public class UserServiceImpl implements UserService { } } - @Override - public void validateEmailNotExists(String email) throws EmailExistsException { - if (userRepository.existsByEmail(email)) { - throw new EmailExistsException("User with email " + email + " already exists"); - } - } - @Override public String getMariaDbPassword(String password) { final byte[] utf8 = password.getBytes(StandardCharsets.UTF_8); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java index b0a8f017962ccc808d8f3d1a37ae584fb1106316..8ca688b1edcc869be309561b4c9fef434e081285 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java @@ -1,6 +1,6 @@ package at.tuwien.service.impl; -import at.tuwien.api.database.ViewCreateDto; +import at.tuwien.api.database.CreateViewDto; import at.tuwien.api.database.ViewDto; import at.tuwien.api.database.ViewUpdateDto; import at.tuwien.entities.database.Database; @@ -87,7 +87,7 @@ public class ViewServiceImpl implements ViewService { @Override @Transactional - public View create(Database database, User creator, ViewCreateDto data) throws MalformedException, + public View create(Database database, User creator, CreateViewDto data) throws MalformedException, DataServiceException, DataServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException { /* create in metadata database */ diff --git a/dbrepo-metadata-service/test/pom.xml b/dbrepo-metadata-service/test/pom.xml index c58104714adaebc14cfb1c3b5e268e807d8c8e29..d51ed22d4d84941f982296b18b4fcb9005db7dce 100644 --- a/dbrepo-metadata-service/test/pom.xml +++ b/dbrepo-metadata-service/test/pom.xml @@ -6,12 +6,12 @@ <parent> <groupId>at.tuwien</groupId> <artifactId>dbrepo-metadata-service</artifactId> - <version>1.6.1</version> + <version>1.6.3</version> </parent> <artifactId>dbrepo-metadata-service-test</artifactId> <name>dbrepo-metadata-service-test</name> - <version>1.6.1</version> + <version>1.6.3</version> <dependencies> <dependency> diff --git a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java index 91936adaf8f27c87dbd4019b4ee6ce8a67e118a5..f78366fe89f6c631ae29da8020af629f71c528e6 100644 --- a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java +++ b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java @@ -12,7 +12,7 @@ public abstract class AbstractUnitTest extends BaseTest { public void genesis() { IMAGE_1_DTO.setOperators(IMAGE_1_OPERATORS_DTO); - CONTAINER_1_PRIVILEGED_DTO.setImage(IMAGE_1_DTO); + CONTAINER_1_DTO.setImage(IMAGE_1_DTO); IMAGE_1.setOperators(new LinkedList<>(IMAGE_1_OPERATORS)); CONTAINER_1.setDatabases(new LinkedList<>(List.of(DATABASE_1, DATABASE_2, DATABASE_3))); CONTAINER_4.setDatabases(new LinkedList<>(List.of(DATABASE_4))); @@ -36,13 +36,12 @@ public abstract class AbstractUnitTest extends BaseTest { DATABASE_1.setIsSchemaPublic(DATABASE_1_SCHEMA_PUBLIC); DATABASE_1_USER_1_READ_ACCESS.setType(AccessType.READ); DATABASE_1.setAccesses(new LinkedList<>(List.of(DATABASE_1_USER_1_READ_ACCESS, DATABASE_1_USER_2_WRITE_OWN_ACCESS, DATABASE_1_USER_3_WRITE_ALL_ACCESS))); + DATABASE_1_DTO.setAccesses(new LinkedList<>(List.of(DATABASE_1_USER_1_READ_ACCESS_DTO, DATABASE_1_USER_2_WRITE_OWN_ACCESS_DTO, DATABASE_1_USER_3_WRITE_ALL_ACCESS_DTO))); DATABASE_1_PRIVILEGED_DTO.setAccesses(new LinkedList<>(List.of(DATABASE_1_USER_1_READ_ACCESS_DTO, DATABASE_1_USER_2_WRITE_OWN_ACCESS_DTO, DATABASE_1_USER_3_WRITE_ALL_ACCESS_DTO))); - TABLE_1.setDatabase(DATABASE_1); UNIT_1.setId(UNIT_1_ID); + TABLE_1.setDatabase(DATABASE_1); TABLE_1.setColumns(new LinkedList<>(TABLE_1_COLUMNS)); TABLE_1.setConstraints(TABLE_1_CONSTRAINTS); - TABLE_1_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_1_COLUMNS_DTO)); - TABLE_1_PRIVILEGED_DTO.setDatabase(DATABASE_1_PRIVILEGED_DTO); VIEW_1_DTO.setIdentifiers(VIEW_1_DTO_IDENTIFIERS); DATABASE_1.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_1, IDENTIFIER_2, IDENTIFIER_3, IDENTIFIER_4))); IDENTIFIER_1.setDatabase(DATABASE_1); @@ -51,20 +50,24 @@ public abstract class AbstractUnitTest extends BaseTest { IDENTIFIER_4.setDatabase(DATABASE_1); DATABASE_1.setTables(new LinkedList<>(List.of(TABLE_1, TABLE_2, TABLE_3, TABLE_4))); DATABASE_1.setViews(new LinkedList<>(List.of(VIEW_1, VIEW_2, VIEW_3))); - DATABASE_1_PRIVILEGED_DTO.setContainer(CONTAINER_1_PRIVILEGED_DTO); - DATABASE_1_PRIVILEGED_DTO.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_1_DTO, IDENTIFIER_2_DTO, IDENTIFIER_3_DTO, IDENTIFIER_4_DTO))); - DATABASE_1_PRIVILEGED_DTO.setTables(new LinkedList<>(List.of(TABLE_1_DTO, TABLE_2_DTO, TABLE_3_DTO, TABLE_4_DTO))); - DATABASE_1_PRIVILEGED_DTO.setViews(new LinkedList<>(List.of(VIEW_1_DTO, VIEW_2_DTO, VIEW_3_DTO))); + DATABASE_1_DTO.setContainer(CONTAINER_1_DTO); + DATABASE_1_DTO.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_1_DTO, IDENTIFIER_2_DTO, IDENTIFIER_3_DTO, IDENTIFIER_4_DTO))); + DATABASE_1_DTO.setTables(new LinkedList<>(List.of(TABLE_1_DTO, TABLE_2_DTO, TABLE_3_DTO, TABLE_4_DTO))); + DATABASE_1_DTO.setViews(new LinkedList<>(List.of(VIEW_1_DTO, VIEW_2_DTO, VIEW_3_DTO))); TABLE_1_DTO.setColumns(new LinkedList<>(TABLE_1_COLUMNS_DTO)); TABLE_1_DTO.setConstraints(TABLE_1_CONSTRAINTS_DTO); + TABLE_1_PRIVILEGED_DTO.setDatabase(DATABASE_1_PRIVILEGED_DTO); + TABLE_1_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_1_COLUMNS_DTO)); + TABLE_1_PRIVILEGED_DTO.setConstraints(TABLE_1_CONSTRAINTS_DTO); TABLE_2.setDatabase(DATABASE_1); TABLE_2.setColumns(new LinkedList<>(TABLE_2_COLUMNS)); TABLE_2_CONSTRAINTS.getForeignKeys().get(0).getReferences().get(0).setForeignKey(TABLE_2_CONSTRAINTS.getForeignKeys().get(0)); TABLE_2.setConstraints(TABLE_2_CONSTRAINTS); - TABLE_2_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_2_COLUMNS_DTO)); - TABLE_2_PRIVILEGED_DTO.setDatabase(DATABASE_1_PRIVILEGED_DTO); TABLE_2_DTO.setColumns(new LinkedList<>(TABLE_2_COLUMNS_DTO)); TABLE_2_DTO.setConstraints(TABLE_2_CONSTRAINTS_DTO); + TABLE_2_PRIVILEGED_DTO.setDatabase(DATABASE_1_PRIVILEGED_DTO); + TABLE_2_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_2_COLUMNS_DTO)); + TABLE_2_PRIVILEGED_DTO.setConstraints(TABLE_2_CONSTRAINTS_DTO); TABLE_3.setDatabase(DATABASE_1); TABLE_3.setColumns(new LinkedList<>(TABLE_3_COLUMNS)); TABLE_3.setConstraints(TABLE_3_CONSTRAINTS); @@ -75,6 +78,9 @@ public abstract class AbstractUnitTest extends BaseTest { TABLE_4.setConstraints(TABLE_4_CONSTRAINTS); TABLE_4_DTO.setColumns(TABLE_4_COLUMNS_DTO); TABLE_4_DTO.setConstraints(TABLE_4_CONSTRAINTS_DTO); + TABLE_4_PRIVILEGED_DTO.setDatabase(DATABASE_1_PRIVILEGED_DTO); + TABLE_4_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_4_COLUMNS_DTO)); + TABLE_4_PRIVILEGED_DTO.setConstraints(TABLE_4_CONSTRAINTS_DTO); VIEW_1.setDatabase(DATABASE_1); VIEW_1.setColumns(new LinkedList<>(VIEW_1_COLUMNS)); VIEW_1.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_3))); @@ -92,22 +98,21 @@ public abstract class AbstractUnitTest extends BaseTest { /* DATABASE 2 */ DATABASE_2.setSubsets(new LinkedList<>()); DATABASE_2.setAccesses(new LinkedList<>(List.of(DATABASE_2_USER_2_WRITE_ALL_ACCESS, DATABASE_2_USER_3_READ_ACCESS))); + DATABASE_2_DTO.setAccesses(new LinkedList<>(List.of(DATABASE_2_USER_2_WRITE_ALL_ACCESS_DTO, DATABASE_2_USER_3_READ_ACCESS_DTO))); DATABASE_2_PRIVILEGED_DTO.setAccesses(new LinkedList<>(List.of(DATABASE_2_USER_2_WRITE_ALL_ACCESS_DTO, DATABASE_2_USER_3_READ_ACCESS_DTO))); DATABASE_2.setTables(new LinkedList<>(List.of(TABLE_5, TABLE_6, TABLE_7))); VIEW_4.setColumns(new LinkedList<>(VIEW_4_COLUMNS)); DATABASE_2.setViews(new LinkedList<>(List.of(VIEW_4))); DATABASE_2.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_5))); - DATABASE_2_PRIVILEGED_DTO.setTables(new LinkedList<>(List.of(TABLE_5_DTO, TABLE_6_DTO, TABLE_7_DTO))); - DATABASE_2_PRIVILEGED_DTO.setViews(new LinkedList<>(List.of(VIEW_4_DTO))); - DATABASE_2_PRIVILEGED_DTO.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_5_DTO))); + DATABASE_2_DTO.setTables(new LinkedList<>(List.of(TABLE_5_DTO, TABLE_6_DTO, TABLE_7_DTO))); + DATABASE_2_DTO.setViews(new LinkedList<>(List.of(VIEW_4_DTO))); + DATABASE_2_DTO.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_5_DTO))); TABLE_5.setDatabase(DATABASE_2); TABLE_5.setColumns(new LinkedList<>(TABLE_5_COLUMNS)); TABLE_5.setConstraints(TABLE_5_CONSTRAINTS); - TABLE_5_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_5_COLUMNS_DTO)); - TABLE_5_PRIVILEGED_DTO.setConstraints(TABLE_5_CONSTRAINTS_DTO); - TABLE_5_PRIVILEGED_DTO.setDatabase(DATABASE_2_PRIVILEGED_DTO); - TABLE_5_DTO.setColumns(TABLE_5_COLUMNS_DTO); + TABLE_5_DTO.setColumns(new LinkedList<>(TABLE_5_COLUMNS_DTO)); TABLE_5_DTO.setConstraints(TABLE_5_CONSTRAINTS_DTO); + TABLE_5_PRIVILEGED_DTO.setDatabase(DATABASE_2_PRIVILEGED_DTO); TABLE_6.setDatabase(DATABASE_2); TABLE_6.setColumns(new LinkedList<>(TABLE_6_COLUMNS)); TABLE_6.setConstraints(TABLE_6_CONSTRAINTS); @@ -124,31 +129,37 @@ public abstract class AbstractUnitTest extends BaseTest { IDENTIFIER_5.setDatabase(DATABASE_2); /* DATABASE 3 */ DATABASE_3.setSubsets(new LinkedList<>()); - DATABASE_3.setAccesses(new LinkedList<>(List.of(DATABASE_3_USER_1_WRITE_ALL_ACCESS))); DATABASE_3.setTables(new LinkedList<>(List.of(TABLE_8))); DATABASE_3.setViews(new LinkedList<>(List.of(VIEW_5))); DATABASE_3.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_6))); + DATABASE_3.setAccesses(new LinkedList<>(List.of(DATABASE_3_USER_1_WRITE_ALL_ACCESS))); + DATABASE_3_DTO.setTables(new LinkedList<>(List.of(TABLE_8_DTO))); + DATABASE_3_DTO.setViews(new LinkedList<>(List.of(VIEW_5_DTO))); + DATABASE_3_DTO.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_6_DTO))); + DATABASE_3_DTO.setAccesses(new LinkedList<>(List.of(DATABASE_3_USER_1_WRITE_ALL_ACCESS_DTO))); + DATABASE_3_PRIVILEGED_DTO.setAccesses(new LinkedList<>(List.of(DATABASE_3_USER_1_WRITE_ALL_ACCESS_DTO))); TABLE_8.setDatabase(DATABASE_3); TABLE_8.setColumns(new LinkedList<>(TABLE_8_COLUMNS)); TABLE_8.setConstraints(TABLE_8_CONSTRAINTS); TABLE_8_DTO.setColumns(new LinkedList<>(TABLE_8_COLUMNS_DTO)); TABLE_8_DTO.setConstraints(TABLE_8_CONSTRAINTS_DTO); TABLE_8_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_8_COLUMNS_DTO)); - TABLE_8_PRIVILEGED_DTO.setConstraints(TABLE_8_CONSTRAINTS_DTO); TABLE_8_PRIVILEGED_DTO.setDatabase(DATABASE_3_PRIVILEGED_DTO); VIEW_5.setDatabase(DATABASE_3); VIEW_5.setColumns(VIEW_5_COLUMNS); VIEW_5_DTO.setColumns(VIEW_5_COLUMNS_DTO); IDENTIFIER_6.setDatabase(DATABASE_3); /* DATABASE 4 */ + DATABASE_4.setSubsets(new LinkedList<>()); + DATABASE_4.setAccesses(new LinkedList<>(List.of(DATABASE_4_USER_1_READ_ACCESS, DATABASE_4_USER_2_WRITE_OWN_ACCESS, DATABASE_4_USER_3_WRITE_ALL_ACCESS))); + DATABASE_4.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_7))); + DATABASE_4_DTO.setTables(new LinkedList<>(List.of(TABLE_9_DTO))); + DATABASE_4_DTO.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_7_DTO))); TABLE_9.setDatabase(DATABASE_4); TABLE_9.setColumns(TABLE_9_COLUMNS); TABLE_9.setConstraints(TABLE_9_CONSTRAINTS); TABLE_9_DTO.setColumns(TABLE_9_COLUMNS_DTO); TABLE_9_DTO.setConstraints(TABLE_9_CONSTRAINTS_DTO); - DATABASE_4.setSubsets(new LinkedList<>()); - DATABASE_4.setAccesses(new LinkedList<>(List.of(DATABASE_4_USER_1_READ_ACCESS, DATABASE_4_USER_2_WRITE_OWN_ACCESS, DATABASE_4_USER_3_WRITE_ALL_ACCESS))); - DATABASE_4.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_7))); IDENTIFIER_7.setStatus(IdentifierStatusType.DRAFT); IDENTIFIER_7.setDatabase(DATABASE_4); } diff --git a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java index 368b1d182c3b4d4289426673804bab23ccd8c0e1..0f07af9af968eae4e16f1f54a099312a20cabbb0 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 @@ -5,31 +5,26 @@ import at.tuwien.api.amqp.CreateVirtualHostDto; import at.tuwien.api.amqp.ExchangeDto; import at.tuwien.api.amqp.GrantVirtualHostPermissionsDto; import at.tuwien.api.amqp.QueueDto; +import at.tuwien.api.auth.CreateUserDto; import at.tuwien.api.auth.LoginRequestDto; import at.tuwien.api.auth.RefreshTokenRequestDto; -import at.tuwien.api.auth.SignupRequestDto; import at.tuwien.api.container.ContainerBriefDto; import at.tuwien.api.container.ContainerDto; import at.tuwien.api.container.image.*; -import at.tuwien.api.container.internal.PrivilegedContainerDto; import at.tuwien.api.database.*; -import at.tuwien.api.database.internal.CreateDatabaseDto; -import at.tuwien.api.database.internal.PrivilegedDatabaseDto; -import at.tuwien.api.database.internal.PrivilegedViewDto; import at.tuwien.api.database.query.QueryBriefDto; import at.tuwien.api.database.query.QueryDto; +import at.tuwien.api.database.table.CreateTableDto; import at.tuwien.api.database.table.TableBriefDto; -import at.tuwien.api.database.table.TableCreateDto; import at.tuwien.api.database.table.TableDto; import at.tuwien.api.database.table.TableStatisticDto; import at.tuwien.api.database.table.columns.*; import at.tuwien.api.database.table.columns.concepts.*; -import at.tuwien.api.database.table.constraints.ConstraintsCreateDto; import at.tuwien.api.database.table.constraints.ConstraintsDto; +import at.tuwien.api.database.table.constraints.CreateTableConstraintsDto; import at.tuwien.api.database.table.constraints.foreign.*; import at.tuwien.api.database.table.constraints.primary.PrimaryKeyDto; import at.tuwien.api.database.table.constraints.unique.UniqueDto; -import at.tuwien.api.database.table.internal.PrivilegedTableDto; import at.tuwien.api.datacite.DataCiteBody; import at.tuwien.api.datacite.DataCiteData; import at.tuwien.api.datacite.doi.DataCiteDoi; @@ -51,9 +46,7 @@ import at.tuwien.api.orcid.person.name.OrcidNameDto; import at.tuwien.api.orcid.person.name.OrcidValueDto; import at.tuwien.api.semantics.*; import at.tuwien.api.user.UserAttributesDto; -import at.tuwien.api.user.UserDto; import at.tuwien.api.user.*; -import at.tuwien.api.user.internal.PrivilegedUserDto; import at.tuwien.api.user.internal.UpdateUserPasswordDto; import at.tuwien.entities.container.Container; import at.tuwien.entities.container.image.ContainerImage; @@ -105,12 +98,12 @@ import static java.time.temporal.ChronoUnit.MINUTES; * <ul> * <li>Table 1 (Private Data, Private Schema)</li> * <li>Table 2 (Private Data, Public Schema)</li> - * <li>Table 3</li> - * <li>Table 4</li> + * <li>Table 3 (Private Data, Private Schema)</li> + * <li>Table 4 (Public Data, Private Schema)</li> * <li>Query 1</li> - * <li>View 1</li> - * <li>View 2</li> - * <li>View 3</li> + * <li>View 1 (Private Data, Private Schema)</li> + * <li>View 2 (Public Data, Public Schema)</li> + * <li>View 3 (Public Data, Private Schema)</li> * <li>Identifier 1 (Title=en, Description=en, type=database)</li> * <li>Identifier 2 (Title=en, Description=en, type=subset, queryId=1)</li> * <li>Identifier 3 (Title=en, Description=en, type=view, viewId=1)</li> @@ -119,26 +112,26 @@ import static java.time.temporal.ChronoUnit.MINUTES; * <p> * Database 2 (Private Data, Public Schema, User 2) -> Container 1 * <ul> - * <li>Table 5</li> - * <li>Table 6</li> - * <li>Table 7</li> + * <li>Table 5 (Public Data, Public Schema)</li> + * <li>Table 6 (Public Data, Private Schema)</li> + * <li>Table 7 (Public Data, Public Schema)</li> * <li>Query 2</li> * <li>Query 6</li> - * <li>View 4</li> + * <li>View 4 (Public Data, Private Schema)</li> * <li>Identifier 5 (Title=de, Description=de)</li> * </ul> * <p> * Database 3 (Public Data, Private Schema, User 3) -> Container 1 * <ul> - * <li>Table 8</li> + * <li>Table 8 (Private Data, Private Schema)</li> * <li>Query 3</li> * <li>Query 4</li> * <li>Query 5</li> - * <li>View 5</li> + * <li>View 5 (Public Data, Public Schema)</li> * <li>Identifier 6 (Title=en, Description=en, Query=3)</li> * </ul> * <p> - * Database 4 (Public Data, Public Schema, User 4) -> Container 4 + * Database 4 (Public Data, Public Schema, User 4) -> Container 2 * <li>Table 9</li> * <li>Identifier 7</li> * <li>Query 7</li> @@ -157,7 +150,9 @@ public abstract class BaseTest { public final static String MARIADB_IMAGE = "mariadb:11.3.2"; - public final static String KEYCLOAK_IMAGE = "quay.io/keycloak/keycloak:24.0"; + public final static String RABBITMQ_IMAGE = "rabbitmq:3.13.7"; + + public final static String KEYCLOAK_IMAGE = "quay.io/keycloak/keycloak:26.0"; public final static String[] DEFAULT_SEMANTICS_HANDLING = new String[]{"default-semantics-handling", "create-semantic-unit", "execute-semantic-query", "table-semantic-analyse", "create-semantic-concept"}; @@ -170,7 +165,7 @@ public abstract class BaseTest { "update-semantic-unit", "create-ontology", "update-ontology"}; public final static String[] DEFAULT_CONTAINER_HANDLING = new String[]{"default-container-handling", - "create-container", "list-containers", "modify-container-state", "find-container"}; + "create-container", "list-containers", "modify-container-state"}; public final static String[] ESCALATED_CONTAINER_HANDLING = new String[]{"escalated-container-handling", "modify-foreign-container-state", "delete-container"}; @@ -190,9 +185,9 @@ public abstract class BaseTest { "modify-identifier-metadata", "update-foreign-identifier", "create-foreign-identifier"}; public final static String[] DEFAULT_QUERY_HANDLING = new String[]{"default-query-handling", "view-table-data", - "execute-query", "view-table-history", "list-database-views", "view-database-view-data", - "export-query-data", "create-database-view", "delete-database-view", "delete-table-data", - "export-table-data", "persist-query", "re-execute-query", "insert-table-data", "find-database-view"}; + "execute-query", "view-table-history", "list-database-views", "export-query-data", "create-database-view", + "delete-database-view", "delete-table-data", "export-table-data", "persist-query", "re-execute-query", + "insert-table-data", "find-database-view"}; public final static String[] ESCALATED_QUERY_HANDLING = new String[]{"escalated-query-handling"}; @@ -221,7 +216,7 @@ public abstract class BaseTest { public final static String[] DEFAULT_DATA_STEWARD_ROLES = ArrayUtils.merge(List.of(new String[]{"default-data-steward-roles"}, ESCALATED_IDENTIFIER_HANDLING, DEFAULT_SEMANTICS_HANDLING, ESCALATED_SEMANTICS_HANDLING, DEFAULT_VIEW_HANDLING)); - public final static String[] DEFAULT_LOCAL_ADMIN_ROLES = new String[]{"admin"}; + public final static String[] DEFAULT_LOCAL_ADMIN_ROLES = new String[]{"system"}; public final static List<GrantedAuthorityDto> AUTHORITY_LOCAL_ADMIN_ROLES = Arrays.stream(DEFAULT_LOCAL_ADMIN_ROLES) .map(GrantedAuthorityDto::new) @@ -267,15 +262,15 @@ public abstract class BaseTest { public final static String ROLE_DEFAULT_RESEARCHER_ROLES_NAME = "default-researcher-roles"; public final static UUID ROLE_DEFAULT_RESEARCHER_ROLES_REALM_ID = REALM_DBREPO_ID; - public final static UpdateDatabaseAccessDto UPDATE_DATABASE_ACCESS_READ_DTO = UpdateDatabaseAccessDto.builder() + public final static CreateAccessDto UPDATE_DATABASE_ACCESS_READ_DTO = CreateAccessDto.builder() .type(AccessTypeDto.READ) .build(); - public final static UpdateDatabaseAccessDto UPDATE_DATABASE_ACCESS_WRITE_OWN_DTO = UpdateDatabaseAccessDto.builder() + public final static CreateAccessDto UPDATE_DATABASE_ACCESS_WRITE_OWN_DTO = CreateAccessDto.builder() .type(AccessTypeDto.WRITE_OWN) .build(); - public final static UpdateDatabaseAccessDto UPDATE_DATABASE_ACCESS_WRITE_ALL_DTO = UpdateDatabaseAccessDto.builder() + public final static CreateAccessDto UPDATE_DATABASE_ACCESS_WRITE_ALL_DTO = CreateAccessDto.builder() .type(AccessTypeDto.WRITE_ALL) .build(); @@ -444,13 +439,13 @@ public abstract class BaseTest { public final static String USER_BROKER_PASSWORD = "guest"; public final static UUID USER_LOCAL_ADMIN_ID = UUID.fromString("a54dcb2e-a644-4e82-87e7-05a96413983d"); + public final static UUID USER_LOCAL_ADMIN_KEYCLOAK_ID = UUID.fromString("703c2ca0-8fc3-4c03-9bc5-4dae6b211e78"); public final static String USER_LOCAL_ADMIN_USERNAME = "admin"; @SuppressWarnings("java:S2068") public final static String USER_LOCAL_ADMIN_PASSWORD = "admin"; public final static String USER_LOCAL_ADMIN_THEME = "dark"; public final static Boolean USER_LOCAL_ADMIN_IS_INTERNAL = true; public final static Boolean USER_LOCAL_ADMIN_ENABLED = true; - public final static String USER_LOCAL_ADMIN_EMAIL = "admin@local"; @SuppressWarnings("java:S2068") public final static String USER_LOCAL_ADMIN_MARIADB_PASSWORD = "*440BA4FD1A87A0999647DB67C0EE258198B247BA"; @@ -460,7 +455,7 @@ public abstract class BaseTest { .build(); public final static UserDetails USER_LOCAL_ADMIN_DETAILS = UserDetailsDto.builder() - .id(String.valueOf(USER_LOCAL_ADMIN_ID)) + .id(USER_LOCAL_ADMIN_ID.toString()) .username(USER_LOCAL_ADMIN_USERNAME) .password(USER_LOCAL_ADMIN_PASSWORD) .authorities(AUTHORITY_DEFAULT_LOCAL_ADMIN_AUTHORITIES) @@ -468,8 +463,8 @@ public abstract class BaseTest { public final static User USER_LOCAL = User.builder() .id(USER_LOCAL_ADMIN_ID) + .keycloakId(USER_LOCAL_ADMIN_KEYCLOAK_ID) .username(USER_LOCAL_ADMIN_USERNAME) - .email(USER_LOCAL_ADMIN_EMAIL) .mariadbPassword(USER_LOCAL_ADMIN_MARIADB_PASSWORD) .theme(USER_LOCAL_ADMIN_THEME) .isInternal(USER_LOCAL_ADMIN_IS_INTERNAL) @@ -479,8 +474,7 @@ public abstract class BaseTest { USER_LOCAL_ADMIN_PASSWORD, USER_LOCAL_ADMIN_DETAILS.getAuthorities()); public final static UUID USER_1_ID = UUID.fromString("cd5bab0d-7799-4069-85fb-c5d738572a0b"); - public final static UUID USER_1_LDAP_ID = UUID.fromString("cd5bab0d-7799-4069-85fb-c5d738572a0b"); - public final static String USER_1_EMAIL = "john.doe@example.com"; + public final static UUID USER_1_KEYCLOAK_ID = UUID.fromString("cd5bab0d-7799-4069-85fb-c5d738572a0b"); public final static String USER_1_USERNAME = "junit1"; @SuppressWarnings("java:S2068") public final static String USER_1_PASSWORD = "junit1"; @@ -534,7 +528,6 @@ public abstract class BaseTest { public final static UserCreateDto USER_1_KEYCLOAK_SIGNUP_REQUEST = UserCreateDto.builder() .username(USER_1_USERNAME) - .email(USER_1_EMAIL) .enabled(USER_1_ENABLED) .credentials(new LinkedList<>(List.of(USER_1_KEYCLOAK_CREDENTIAL_1))) .attributes(UserCreateAttributesDto.builder() @@ -544,7 +537,6 @@ public abstract class BaseTest { public final static UserCreateDto USER_LOCAL_KEYCLOAK_SIGNUP_REQUEST = UserCreateDto.builder() .username(USER_LOCAL_ADMIN_USERNAME) - .email(USER_LOCAL_ADMIN_EMAIL) .enabled(USER_LOCAL_ADMIN_ENABLED) .credentials(new LinkedList<>(List.of(USER_LOCAL_KEYCLOAK_CREDENTIAL_1))) .groups(new LinkedList<>(List.of("system"))) @@ -553,21 +545,10 @@ public abstract class BaseTest { .build()) .build(); - public final static PrivilegedUserDto USER_1_PRIVILEGED_DTO = PrivilegedUserDto.builder() - .id(USER_1_ID) - .username(USER_1_USERNAME) - .password(USER_1_PASSWORD) - .attributes(USER_1_ATTRIBUTES_DTO) - .firstname(USER_1_FIRSTNAME) - .lastname(USER_1_LASTNAME) - .qualifiedName(USER_1_QUALIFIED_NAME) - .lastRetrieved(Instant.now()) - .build(); - public final static User USER_1 = User.builder() .id(USER_1_ID) + .keycloakId(USER_1_KEYCLOAK_ID) .username(USER_1_USERNAME) - .email(USER_1_EMAIL) .firstname(USER_1_FIRSTNAME) .lastname(USER_1_LASTNAME) .affiliation(USER_1_AFFILIATION) @@ -601,19 +582,6 @@ public abstract class BaseTest { .password(USER_1_PASSWORD) .build(); - public final static at.tuwien.api.keycloak.UserDto USER_1_KEYCLOAK_DTO = at.tuwien.api.keycloak.UserDto.builder() - .id(USER_1_ID) - .username(USER_1_USERNAME) - .email(USER_1_EMAIL) - .emailVerified(USER_1_VERIFIED) - .notBefore(USER_1_NOT_BEFORE) - .totp(USER_1_TOTP) - .attributes(at.tuwien.api.keycloak.UserAttributesDto.builder() - .ldapEntryDn(new String[]{"cn=" + USER_1_USERNAME + ",dn=dbrepo,dn=at"}) - .ldapId(new UUID[]{USER_1_LDAP_ID}) - .build()) - .build(); - public final static UserBriefDto USER_1_BRIEF_DTO = UserBriefDto.builder() .id(USER_1_ID) .username(USER_1_USERNAME) @@ -627,7 +595,6 @@ public abstract class BaseTest { public final static UserDetails USER_1_DETAILS = UserDetailsDto.builder() .id(USER_1_ID.toString()) .username(USER_1_USERNAME) - .email(USER_1_EMAIL) .password(USER_1_PASSWORD) .authorities(AUTHORITY_DEFAULT_RESEARCHER_AUTHORITIES) .build(); @@ -635,10 +602,10 @@ public abstract class BaseTest { public final static Principal USER_1_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_1_DETAILS, USER_1_PASSWORD, USER_1_DETAILS.getAuthorities()); - public final static SignupRequestDto USER_1_SIGNUP_REQUEST_DTO = SignupRequestDto.builder() + public final static CreateUserDto USER_1_SIGNUP_REQUEST_DTO = CreateUserDto.builder() + .id(USER_1_KEYCLOAK_ID) + .ldapId(USER_1_ID) .username(USER_1_USERNAME) - .password(USER_1_PASSWORD) - .email(USER_1_EMAIL) .build(); public final static LoginRequestDto USER_1_LOGIN_REQUEST_DTO = LoginRequestDto.builder() @@ -647,7 +614,7 @@ public abstract class BaseTest { .build(); public final static UUID USER_2_ID = UUID.fromString("eeb9a51b-4cd8-4039-90bf-e24f17372f7c"); - public final static UUID USER_2_LDAP_ID = UUID.fromString("eeb9a51b-4cd8-4039-90bf-e24f17372f7c"); + public final static UUID USER_2_KEYCLOAK_ID = UUID.fromString("eeb9a51b-4cd8-4039-90bf-e24f17372f7c"); public final static String USER_2_EMAIL = "jane.doe@example.com"; public final static String USER_2_USERNAME = "junit2"; public final static String USER_2_FIRSTNAME = "Jane"; @@ -681,8 +648,8 @@ public abstract class BaseTest { public final static User USER_2 = User.builder() .id(USER_2_ID) + .keycloakId(USER_2_KEYCLOAK_ID) .username(USER_2_USERNAME) - .email(USER_2_EMAIL) .firstname(USER_2_FIRSTNAME) .lastname(USER_2_LASTNAME) .affiliation(USER_2_AFFILIATION) @@ -713,50 +680,32 @@ public abstract class BaseTest { .qualifiedName(USER_2_QUALIFIED_NAME) .build(); - public final static SignupRequestDto USER_2_SIGNUP_REQUEST_DTO = SignupRequestDto.builder() + public final static CreateUserDto USER_2_SIGNUP_REQUEST_DTO = CreateUserDto.builder() + .id(USER_2_KEYCLOAK_ID) + .ldapId(USER_2_ID) .username(USER_2_USERNAME) - .password(USER_2_PASSWORD) .email(USER_2_EMAIL) + .givenName(USER_2_FIRSTNAME) + .familyName(USER_2_LASTNAME) .build(); public final static UserDetails USER_2_DETAILS = UserDetailsDto.builder() .id(USER_2_ID.toString()) .username(USER_2_USERNAME) - .email(USER_2_EMAIL) .password(USER_2_PASSWORD) .authorities(AUTHORITY_DEFAULT_RESEARCHER_AUTHORITIES) .build(); - public final static at.tuwien.api.keycloak.UserDto USER_2_KEYCLOAK_DTO = at.tuwien.api.keycloak.UserDto.builder() - .id(USER_2_ID) - .username(USER_2_USERNAME) - .email(USER_2_EMAIL) - .emailVerified(USER_2_VERIFIED) - .notBefore(USER_2_NOT_BEFORE) - .totp(USER_2_TOTP) - .build(); - public final static at.tuwien.api.amqp.UserDetailsDto USER_2_DETAILS_DTO = at.tuwien.api.amqp.UserDetailsDto.builder() .name(USER_2_USERNAME) .tags(new String[]{}) .build(); - public final static PrivilegedUserDto USER_2_PRIVILEGED_DTO = PrivilegedUserDto.builder() - .id(USER_2_ID) - .username(USER_2_USERNAME) - .password(USER_2_PASSWORD) - .attributes(USER_2_ATTRIBUTES_DTO) - .firstname(USER_2_FIRSTNAME) - .lastname(USER_2_LASTNAME) - .qualifiedName(USER_2_QUALIFIED_NAME) - .lastRetrieved(Instant.now()) - .build(); - public final static Principal USER_2_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_2_DETAILS, USER_2_PASSWORD, USER_2_DETAILS.getAuthorities()); public final static UUID USER_3_ID = UUID.fromString("7b080e33-d8db-4276-9d53-47208e657006"); - public final static UUID USER_3_LDAP_ID = UUID.fromString("7b080e33-d8db-4276-9d53-47208e657006"); + public final static UUID USER_3_KEYCLOAK_ID = UUID.fromString("b0108bc3-95aa-4a3f-8868-dc301286aeca"); public final static String USER_3_USERNAME = "junit3"; public final static String USER_3_FIRSTNAME = "System"; public final static String USER_3_LASTNAME = "System"; @@ -788,8 +737,8 @@ public abstract class BaseTest { public final static User USER_3 = User.builder() .id(USER_3_ID) + .keycloakId(USER_3_KEYCLOAK_ID) .username(USER_3_USERNAME) - .email(USER_3_EMAIL) .firstname(USER_3_FIRSTNAME) .lastname(USER_3_LASTNAME) .affiliation(USER_3_AFFILIATION) @@ -821,18 +770,14 @@ public abstract class BaseTest { public final static UserDetails USER_3_DETAILS = UserDetailsDto.builder() .id(USER_3_ID.toString()) .username(USER_3_USERNAME) - .email(USER_3_EMAIL) .password(USER_3_PASSWORD) .authorities(AUTHORITY_DEFAULT_RESEARCHER_AUTHORITIES) .build(); - public final static at.tuwien.api.keycloak.UserDto USER_3_KEYCLOAK_DTO = at.tuwien.api.keycloak.UserDto.builder() - .id(USER_3_ID) + public final static CreateUserDto USER_3_SIGNUP_REQUEST_DTO = CreateUserDto.builder() + .id(USER_3_KEYCLOAK_ID) + .ldapId(USER_3_ID) .username(USER_3_USERNAME) - .email(USER_3_EMAIL) - .emailVerified(USER_3_VERIFIED) - .notBefore(USER_3_NOT_BEFORE) - .totp(USER_3_TOTP) .build(); public final static Principal USER_3_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_3_DETAILS, @@ -843,19 +788,8 @@ public abstract class BaseTest { .tags(new String[]{}) .build(); - public final static PrivilegedUserDto USER_3_PRIVILEGED_DTO = PrivilegedUserDto.builder() - .id(USER_3_ID) - .username(USER_3_USERNAME) - .password(USER_3_PASSWORD) - .attributes(USER_3_ATTRIBUTES_DTO) - .firstname(USER_3_FIRSTNAME) - .lastname(USER_3_LASTNAME) - .qualifiedName(USER_3_QUALIFIED_NAME) - .lastRetrieved(Instant.now()) - .build(); - public final static UUID USER_4_ID = UUID.fromString("791d58c5-bfab-4520-b4fc-b44d4ab9feb0"); - public final static UUID USER_4_LDAP_ID = UUID.fromString("791d58c5-bfab-4520-b4fc-b44d4ab9feb0"); + public final static UUID USER_4_KEYCLOAK_ID = UUID.fromString("25040ad3-6d57-4052-b357-6b4c8a6e7f4d"); public final static String USER_4_USERNAME = "junit4"; public final static String USER_4_FIRSTNAME = "JUnit"; public final static String USER_4_LASTNAME = "4"; @@ -867,7 +801,6 @@ public abstract class BaseTest { @SuppressWarnings("java:S2068") public final static String USER_4_DATABASE_PASSWORD = "*C20EF5C6875857DEFA9BE6E9B62DD76AAAE51882" /* junit4 */; public final static String USER_4_QUALIFIED_NAME = USER_4_FIRSTNAME + " " + USER_4_LASTNAME + " — @" + USER_4_USERNAME; - public final static String USER_4_EMAIL = "junit4@ossdip.at"; public final static Boolean USER_4_VERIFIED = true; public final static Boolean USER_4_ENABLED = true; public final static Boolean USER_4_IS_INTERNAL = false; @@ -884,8 +817,8 @@ public abstract class BaseTest { public final static User USER_4 = User.builder() .id(USER_4_ID) + .keycloakId(USER_4_KEYCLOAK_ID) .username(USER_4_USERNAME) - .email(USER_4_EMAIL) .firstname(USER_4_FIRSTNAME) .lastname(USER_4_LASTNAME) .affiliation(USER_4_AFFILIATION) @@ -917,7 +850,6 @@ public abstract class BaseTest { public final static UserDetails USER_4_DETAILS = UserDetailsDto.builder() .id(USER_4_ID.toString()) .username(USER_4_USERNAME) - .email(USER_4_EMAIL) .password(USER_4_PASSWORD) .authorities(new LinkedList<>()) .build(); @@ -925,19 +857,8 @@ public abstract class BaseTest { public final static Principal USER_4_PRINCIPAL = new UsernamePasswordAuthenticationToken(USER_4_DETAILS, USER_4_PASSWORD, USER_4_DETAILS.getAuthorities()); - public final static PrivilegedUserDto USER_4_PRIVILEGED_DTO = PrivilegedUserDto.builder() - .id(USER_4_ID) - .username(USER_4_USERNAME) - .password(USER_4_PASSWORD) - .attributes(USER_4_ATTRIBUTES_DTO) - .firstname(USER_4_FIRSTNAME) - .lastname(USER_4_LASTNAME) - .qualifiedName(USER_4_QUALIFIED_NAME) - .lastRetrieved(Instant.now()) - .build(); - public final static UUID USER_5_ID = UUID.fromString("28ff851d-d7bc-4422-959c-edd7a5b15630"); - public final static UUID USER_5_LDAP_ID = UUID.fromString("28ff851d-d7bc-4422-959c-edd7a5b15630"); + public final static UUID USER_5_KEYCLOAK_ID = UUID.fromString("28ff851d-d7bc-4422-959c-edd7a5b15630"); public final static String USER_5_USERNAME = "nobody"; public final static String USER_5_FIRSTNAME = "No"; public final static String USER_5_LASTNAME = "Body"; @@ -949,7 +870,6 @@ public abstract class BaseTest { @SuppressWarnings("java:S2068") public final static String USER_5_DATABASE_PASSWORD = "*C20EF5C6875857DEFA9BE6E9B62DD76AAAE51882" /* junit5 */; public final static String USER_5_QUALIFIED_NAME = USER_5_FIRSTNAME + " " + USER_5_LASTNAME + " — @" + USER_5_USERNAME; - public final static String USER_5_EMAIL = "system@ossdip.at"; public final static Boolean USER_5_VERIFIED = true; public final static Boolean USER_5_ENABLED = true; public final static Boolean USER_5_IS_INTERNAL = false; @@ -973,17 +893,6 @@ public abstract class BaseTest { .attributes(USER_5_ATTRIBUTES_DTO) .build(); - public final static PrivilegedUserDto USER_5_PRIVILEGED_DTO = PrivilegedUserDto.builder() - .id(USER_5_ID) - .username(USER_5_USERNAME) - .firstname(USER_5_FIRSTNAME) - .lastname(USER_5_LASTNAME) - .qualifiedName(USER_5_QUALIFIED_NAME) - .password(USER_5_PASSWORD) - .attributes(USER_5_ATTRIBUTES_DTO) - .lastRetrieved(Instant.now()) - .build(); - public final static UserBriefDto USER_5_BRIEF_DTO = UserBriefDto.builder() .id(USER_5_ID) .username(USER_5_USERNAME) @@ -995,7 +904,6 @@ public abstract class BaseTest { public final static UserDetails USER_5_DETAILS = UserDetailsDto.builder() .id(USER_5_ID.toString()) .username(USER_5_USERNAME) - .email(USER_5_EMAIL) .password(USER_5_PASSWORD) .authorities(AUTHORITY_DEFAULT_DEVELOPER_AUTHORITIES) .build(); @@ -1005,8 +913,8 @@ public abstract class BaseTest { public final static User USER_5 = User.builder() .id(USER_5_ID) + .keycloakId(USER_5_KEYCLOAK_ID) .username(USER_5_USERNAME) - .email(USER_5_EMAIL) .firstname(USER_5_FIRSTNAME) .lastname(USER_5_LASTNAME) .affiliation(USER_5_AFFILIATION) @@ -1026,7 +934,6 @@ public abstract class BaseTest { public final static String USER_6_PASSWORD = "junit5"; @SuppressWarnings("java:S2068") public final static String USER_6_DATABASE_PASSWORD = "*C20EF5C6875857DEFA9BE6E9B62DD76AAAE51882" /* junit5 */; - public final static String USER_6_EMAIL = "system@ossdip.at"; public final static Boolean USER_6_VERIFIED = true; public final static Boolean USER_6_ENABLED = true; public final static Boolean USER_6_IS_INTERNAL = false; @@ -1044,7 +951,6 @@ public abstract class BaseTest { public final static UserDetails USER_6_DETAILS = UserDetailsDto.builder() .id(USER_6_ID.toString()) .username(USER_6_USERNAME) - .email(USER_6_EMAIL) .password(USER_6_PASSWORD) .authorities(AUTHORITY_DEFAULT_RESEARCHER_AUTHORITIES) .build(); @@ -1137,8 +1043,6 @@ public abstract class BaseTest { .build())); public final static Long CONTAINER_1_ID = 1L; - public final static ContainerImage CONTAINER_1_IMAGE = IMAGE_1; - public final static ImageDto CONTAINER_1_IMAGE_DTO = IMAGE_1_DTO; public final static String CONTAINER_1_NAME = "u01"; public final static String CONTAINER_1_INTERNALNAME = "dbrepo-userdb-u01"; public final static String CONTAINER_1_UI_HOST = "localhost"; @@ -1157,7 +1061,7 @@ public abstract class BaseTest { .id(CONTAINER_1_ID) .name(CONTAINER_1_NAME) .internalName(CONTAINER_1_INTERNALNAME) - .image(CONTAINER_1_IMAGE) + .image(IMAGE_1) .created(CONTAINER_1_CREATED) .host(CONTAINER_1_HOST) .port(CONTAINER_1_PORT) @@ -1173,7 +1077,7 @@ public abstract class BaseTest { .id(CONTAINER_1_ID) .name(CONTAINER_1_NAME) .internalName(CONTAINER_1_INTERNALNAME) - .image(CONTAINER_1_IMAGE_DTO) + .image(IMAGE_1_DTO) .host(CONTAINER_1_HOST) .port(CONTAINER_1_PORT) .build(); @@ -1187,16 +1091,16 @@ public abstract class BaseTest { .image(IMAGE_1_BRIEF_DTO) .build(); - public final static PrivilegedContainerDto CONTAINER_1_PRIVILEGED_DTO = PrivilegedContainerDto.builder() + public final static ContainerDto CONTAINER_1_PRIVILEGED_DTO = ContainerDto.builder() .id(CONTAINER_1_ID) .name(CONTAINER_1_NAME) .internalName(CONTAINER_1_INTERNALNAME) - .image(CONTAINER_1_IMAGE_DTO) + .image(IMAGE_1_DTO) .host(CONTAINER_1_HOST) .port(CONTAINER_1_PORT) + .lastRetrieved(Instant.now()) .username(CONTAINER_1_PRIVILEGED_USERNAME) .password(CONTAINER_1_PRIVILEGED_PASSWORD) - .lastRetrieved(Instant.now()) .build(); public final static Long CONTAINER_2_ID = 2L; @@ -1243,16 +1147,16 @@ public abstract class BaseTest { .quota(CONTAINER_2_QUOTA) .build(); - public final static PrivilegedContainerDto CONTAINER_2_PRIVILEGED_DTO = PrivilegedContainerDto.builder() + public final static ContainerDto CONTAINER_2_PRIVILEGED_DTO = ContainerDto.builder() .id(CONTAINER_2_ID) .name(CONTAINER_2_NAME) .internalName(CONTAINER_2_INTERNALNAME) .image(CONTAINER_2_IMAGE_DTO) .host(CONTAINER_2_HOST) .port(CONTAINER_2_PORT) + .lastRetrieved(Instant.now()) .username(CONTAINER_2_PRIVILEGED_USERNAME) .password(CONTAINER_2_PRIVILEGED_PASSWORD) - .lastRetrieved(Instant.now()) .build(); public final static Long CONTAINER_3_ID = 3L; @@ -1331,18 +1235,15 @@ public abstract class BaseTest { public final static String DATABASE_1_EXCHANGE = "dbrepo"; public final static Instant DATABASE_1_CREATED = Instant.ofEpochSecond(1677399741L) /* 2023-02-26 08:22:21 (UTC) */; public final static Instant DATABASE_1_LAST_MODIFIED = Instant.ofEpochSecond(1677399741L) /* 2023-02-26 08:22:21 (UTC) */; - public final static UUID DATABASE_1_OWNER = USER_1_ID; public final static UUID DATABASE_1_CREATED_BY = USER_1_ID; - public final static UserDto DATABASE_1_CREATOR_DTO = USER_1_DTO; - public final static UserDto DATABASE_1_OWNER_DTO = USER_1_DTO; - public final static DatabaseCreateDto DATABASE_1_CREATE = DatabaseCreateDto.builder() + public final static CreateDatabaseDto DATABASE_1_CREATE = CreateDatabaseDto.builder() .name(DATABASE_1_NAME) .isPublic(DATABASE_1_PUBLIC) .cid(CONTAINER_1_ID) .build(); - public final static CreateDatabaseDto DATABASE_1_CREATE_INTERNAL = CreateDatabaseDto.builder() + public final static at.tuwien.api.database.internal.CreateDatabaseDto DATABASE_1_CREATE_INTERNAL = at.tuwien.api.database.internal.CreateDatabaseDto.builder() .internalName(DATABASE_1_INTERNALNAME) .containerId(CONTAINER_1_ID) .username(USER_1_USERNAME) @@ -1364,7 +1265,7 @@ public abstract class BaseTest { public final static UUID DATABASE_2_OWNER = USER_2_ID; public final static UUID DATABASE_2_CREATOR = USER_2_ID; - public final static DatabaseCreateDto DATABASE_2_CREATE = DatabaseCreateDto.builder() + public final static CreateDatabaseDto DATABASE_2_CREATE = CreateDatabaseDto.builder() .name(DATABASE_2_NAME) .isPublic(DATABASE_2_PUBLIC) .cid(CONTAINER_1_ID) @@ -1384,16 +1285,43 @@ public abstract class BaseTest { public final static DatabaseDto DATABASE_3_DTO = DatabaseDto.builder() .id(DATABASE_3_ID) .isPublic(DATABASE_3_PUBLIC) + .isSchemaPublic(DATABASE_3_SCHEMA_PUBLIC) .name(DATABASE_3_NAME) - .container(CONTAINER_1_BRIEF_DTO) .internalName(DATABASE_3_INTERNALNAME) + .owner(USER_3_BRIEF_DTO) + .container(CONTAINER_1_DTO) .exchangeName(DATABASE_3_EXCHANGE) - .tables(new LinkedList<>()) /* TABLE_3, TABLE_3, TABLE_3 */ - .views(new LinkedList<>()) + .tables(new LinkedList<>()) /* TABLE_8_DTO */ + .views(new LinkedList<>()) /* VIEW_5_DTO */ + .identifiers(new LinkedList<>()) /* IDENTIFIER_6_DTO */ + .build(); + + public final static DatabaseDto DATABASE_3_PRIVILEGED_DTO = DatabaseDto.builder() + .id(DATABASE_3_ID) + .isPublic(DATABASE_3_PUBLIC) + .isSchemaPublic(DATABASE_3_SCHEMA_PUBLIC) + .name(DATABASE_3_NAME) + .internalName(DATABASE_3_INTERNALNAME) + .owner(USER_3_BRIEF_DTO) + .container(CONTAINER_1_PRIVILEGED_DTO) + .exchangeName(DATABASE_3_EXCHANGE) + .tables(new LinkedList<>()) /* TABLE_8_DTO */ + .views(new LinkedList<>()) /* VIEW_5_DTO */ + .identifiers(new LinkedList<>()) /* IDENTIFIER_6_DTO */ + .lastRetrieved(Instant.now()) + .build(); + + public final static DatabaseBriefDto DATABASE_3_BRIEF_DTO = DatabaseBriefDto.builder() + .id(DATABASE_3_ID) + .isPublic(DATABASE_3_PUBLIC) + .isSchemaPublic(DATABASE_3_SCHEMA_PUBLIC) + .name(DATABASE_3_NAME) + .internalName(DATABASE_3_INTERNALNAME) + .ownerId(USER_3_ID) .identifiers(new LinkedList<>()) .build(); - public final static DatabaseCreateDto DATABASE_3_CREATE = DatabaseCreateDto.builder() + public final static CreateDatabaseDto DATABASE_3_CREATE = CreateDatabaseDto.builder() .name(DATABASE_3_NAME) .isPublic(DATABASE_3_PUBLIC) .cid(CONTAINER_1_ID) @@ -1411,183 +1339,211 @@ public abstract class BaseTest { public final static UUID DATABASE_4_OWNER = USER_4_ID; public final static UUID DATABASE_4_CREATOR = USER_4_ID; + public final static DatabaseBriefDto DATABASE_4_BRIEF_DTO = DatabaseBriefDto.builder() + .id(DATABASE_4_ID) + .isPublic(DATABASE_4_PUBLIC) + .isSchemaPublic(DATABASE_4_SCHEMA_PUBLIC) + .name(DATABASE_4_NAME) + .description(DATABASE_4_DESCRIPTION) + .internalName(DATABASE_4_INTERNALNAME) + .ownerId(USER_4_ID) + .identifiers(new LinkedList<>()) + .build(); + public final static DatabaseDto DATABASE_4_DTO = DatabaseDto.builder() .id(DATABASE_4_ID) .isPublic(DATABASE_4_PUBLIC) .isSchemaPublic(DATABASE_4_SCHEMA_PUBLIC) .name(DATABASE_4_NAME) + .container(CONTAINER_2_DTO) .description(DATABASE_4_DESCRIPTION) .internalName(DATABASE_4_INTERNALNAME) .exchangeName(DATABASE_4_EXCHANGE) .owner(USER_4_BRIEF_DTO) - .tables(new LinkedList<>()) + .tables(new LinkedList<>()) /* TABLE_9_DTO */ .views(new LinkedList<>()) - .identifiers(new LinkedList<>()) + .identifiers(new LinkedList<>()) /* IDENTIFIER_7_DTO */ .build(); - public final static TableCreateDto TABLE_0_CREATE_DTO = TableCreateDto.builder() + public final static DatabaseDto DATABASE_4_PRIVILEGED_DTO = DatabaseDto.builder() + .id(DATABASE_4_ID) + .isPublic(DATABASE_4_PUBLIC) + .isSchemaPublic(DATABASE_4_SCHEMA_PUBLIC) + .name(DATABASE_4_NAME) + .container(CONTAINER_2_PRIVILEGED_DTO) + .description(DATABASE_4_DESCRIPTION) + .internalName(DATABASE_4_INTERNALNAME) + .exchangeName(DATABASE_4_EXCHANGE) + .owner(USER_4_BRIEF_DTO) + .tables(new LinkedList<>()) /* TABLE_9_DTO */ + .views(new LinkedList<>()) + .identifiers(new LinkedList<>()) /* IDENTIFIER_7_DTO */ + .lastRetrieved(Instant.now()) + .build(); + + public final static CreateTableDto TABLE_0_CREATE_DTO = CreateTableDto.builder() .name("full") .description("full example") - .constraints(ConstraintsCreateDto.builder() + .constraints(CreateTableConstraintsDto.builder() .uniques(new LinkedList<>()) .foreignKeys(new LinkedList<>()) .build()) - .columns(List.of(ColumnCreateDto.builder() + .columns(List.of(CreateTableColumnDto.builder() .name("col1a") .type(ColumnTypeDto.CHAR) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col1b") .type(ColumnTypeDto.CHAR) .nullAllowed(true) .size(50L) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col2a") .type(ColumnTypeDto.VARCHAR) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col2b") .type(ColumnTypeDto.VARCHAR) .nullAllowed(true) .size(1024L) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col3") .type(ColumnTypeDto.BINARY) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col4") .type(ColumnTypeDto.VARBINARY) .nullAllowed(true) .size(200L) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col5") .type(ColumnTypeDto.TINYBLOB) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col6") .type(ColumnTypeDto.TINYTEXT) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col7") .type(ColumnTypeDto.TEXT) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col8") .type(ColumnTypeDto.BLOB) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col9") .type(ColumnTypeDto.MEDIUMTEXT) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col10") .type(ColumnTypeDto.MEDIUMBLOB) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col11") .type(ColumnTypeDto.LONGTEXT) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col12") .type(ColumnTypeDto.LONGBLOB) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col13") .type(ColumnTypeDto.ENUM) .nullAllowed(true) .enums(new LinkedList<>(List.of("val1", "val2"))) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col14") .type(ColumnTypeDto.SET) .nullAllowed(true) .sets(new LinkedList<>(List.of("val1", "val2"))) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col15") .type(ColumnTypeDto.BIT) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col16") .type(ColumnTypeDto.TINYINT) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col17") .type(ColumnTypeDto.BOOL) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col18") .type(ColumnTypeDto.SMALLINT) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col19") .type(ColumnTypeDto.MEDIUMINT) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col20") .type(ColumnTypeDto.INT) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col21") .type(ColumnTypeDto.BIGINT) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col22") .type(ColumnTypeDto.FLOAT) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col23") .type(ColumnTypeDto.DOUBLE) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col24") .type(ColumnTypeDto.DECIMAL) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col25") .type(ColumnTypeDto.DATE) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col26") .type(ColumnTypeDto.DATETIME) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col27") .type(ColumnTypeDto.TIMESTAMP) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col28") .type(ColumnTypeDto.TIME) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("col29") .type(ColumnTypeDto.YEAR) .nullAllowed(true) @@ -1612,10 +1568,9 @@ public abstract class BaseTest { public final static Instant TABLE_1_CREATED = Instant.ofEpochSecond(1677399975L) /* 2023-02-26 08:26:15 (UTC) */; public final static Instant TABLE_1_LAST_MODIFIED = Instant.ofEpochSecond(1677399975L) /* 2023-02-26 08:26:15 (UTC) */; - public final static PrivilegedTableDto TABLE_1_PRIVILEGED_DTO = PrivilegedTableDto.builder() + public final static TableDto TABLE_1_PRIVILEGED_DTO = TableDto.builder() .id(TABLE_1_ID) .tdbid(DATABASE_1_ID) - .database(null) /* DATABASE_1_PRIVILEGED_DTO */ .internalName(TABLE_1_INTERNAL_NAME) .isVersioned(TABLE_1_VERSIONED) .isPublic(TABLE_1_SCHEMA_PUBLIC) @@ -1633,6 +1588,7 @@ public abstract class BaseTest { .dataLength(TABLE_1_DATA_LENGTH) .maxDataLength(TABLE_1_MAX_DATA_LENGTH) .lastRetrieved(Instant.now()) + .database(null) /* DATABASE_1_PRIVILEGED_DTO */ .build(); public final static Table TABLE_1 = Table.builder() @@ -1672,7 +1628,7 @@ public abstract class BaseTest { .routingKey(TABLE_1_ROUTING_KEY) .identifiers(new LinkedList<>()) .columns(new LinkedList<>() /* TABLE_1_COLUMNS_DTO */) - .constraints(null) /* TABLE_1_CONSTRAINT_DTO */ + .constraints(null) /* TABLE_1_CONSTRAINTS_DTO */ .owner(USER_1_BRIEF_DTO) .avgRowLength(TABLE_1_AVG_ROW_LENGTH) .numRows(TABLE_1_NUM_ROWS) @@ -1826,10 +1782,9 @@ public abstract class BaseTest { .maxDataLength(TABLE_2_MAX_DATA_LENGTH) .build(); - public final static PrivilegedTableDto TABLE_2_PRIVILEGED_DTO = PrivilegedTableDto.builder() + public final static TableDto TABLE_2_PRIVILEGED_DTO = TableDto.builder() .id(TABLE_2_ID) .tdbid(DATABASE_1_ID) - .database(null) /* DATABASE_1_PRIVILEGED_DTO */ .internalName(TABLE_2_INTERNALNAME) .isVersioned(TABLE_2_VERSIONED) .isPublic(TABLE_2_IS_PUBLIC) @@ -1847,6 +1802,7 @@ public abstract class BaseTest { .dataLength(TABLE_2_DATA_LENGTH) .maxDataLength(TABLE_2_MAX_DATA_LENGTH) .lastRetrieved(Instant.now()) + .database(null) /* DATABASE_1_PRIVILEGED_DTO */ .build(); public final static TableDto TABLE_2_DTO = TableDto.builder() @@ -1953,32 +1909,32 @@ public abstract class BaseTest { .ownedBy(USER_3_ID) .build(); - public final static ConstraintsCreateDto TABLE_3_CONSTRAINTS_CREATE_DTO = ConstraintsCreateDto.builder() + public final static CreateTableConstraintsDto TABLE_3_CONSTRAINTS_CREATE_DTO = CreateTableConstraintsDto.builder() .checks(new LinkedHashSet<>()) .primaryKey(new LinkedHashSet<>()) .foreignKeys(new LinkedList<>()) .uniques(new LinkedList<>()) .build(); - public final static ConstraintsCreateDto TABLE_3_CONSTRAINTS_INVALID_CREATE_DTO = ConstraintsCreateDto.builder() + public final static CreateTableConstraintsDto TABLE_3_CONSTRAINTS_INVALID_CREATE_DTO = CreateTableConstraintsDto.builder() .checks(new LinkedHashSet<>()) .primaryKey(new LinkedHashSet<>()) // <<<< .uniques(new LinkedList<>()) - .foreignKeys(List.of(ForeignKeyCreateDto.builder() + .foreignKeys(List.of(CreateForeignKeyDto.builder() .referencedTable("weather_location") .columns(new LinkedList<>(List.of("fahrzeug"))) .referencedColumns(new LinkedList<>(List.of("doesnotexist"))) .build())) .build(); - public final static TableCreateDto TABLE_3_CREATE_DTO = TableCreateDto.builder() + public final static CreateTableDto TABLE_3_CREATE_DTO = CreateTableDto.builder() .name(TABLE_3_NAME) .description(TABLE_3_DESCRIPTION) .columns(new LinkedList<>()) .constraints(TABLE_3_CONSTRAINTS_CREATE_DTO) .build(); - public final static TableCreateDto TABLE_3_INVALID_CREATE_DTO = TableCreateDto.builder() + public final static CreateTableDto TABLE_3_INVALID_CREATE_DTO = CreateTableDto.builder() .name(TABLE_3_NAME) .description(TABLE_3_DESCRIPTION) .columns(new LinkedList<>()) @@ -2036,10 +1992,9 @@ public abstract class BaseTest { .owner(USER_1_BRIEF_DTO) .build(); - public final static PrivilegedTableDto TABLE_5_PRIVILEGED_DTO = PrivilegedTableDto.builder() + public final static TableDto TABLE_5_PRIVILEGED_DTO = TableDto.builder() .id(TABLE_5_ID) .tdbid(DATABASE_2_ID) - .database(null) /* DATABASE_2_PRIVILEGED_DTO */ .internalName(TABLE_5_INTERNALNAME) .isVersioned(TABLE_5_VERSIONED) .isPublic(TABLE_5_IS_PUBLIC) @@ -2077,7 +2032,7 @@ public abstract class BaseTest { public final static String TABLE_6_INTERNALNAME = "names"; public final static Boolean TABLE_6_VERSIONED = true; public final static Boolean TABLE_6_IS_PUBLIC = true; - public final static Boolean TABLE_6_SCHEMA_PUBLIC = true; + public final static Boolean TABLE_6_SCHEMA_PUBLIC = false; public final static Boolean TABLE_6_PROCESSED_CONSTRAINTS = true; public final static String TABLE_6_DESCRIPTION = "Some names dataset"; public final static String TABLE_6_QUEUE_NAME = TABLE_6_INTERNALNAME; @@ -2196,9 +2151,8 @@ public abstract class BaseTest { public final static String TABLE_4_NAME = "Sensor 2"; public final static String TABLE_4_INTERNALNAME = "sensor_2"; public final static Boolean TABLE_4_VERSIONED = true; - public final static Boolean TABLE_4_IS_PUBLIC = false; + public final static Boolean TABLE_4_IS_PUBLIC = true; public final static Boolean TABLE_4_SCHEMA_PUBLIC = false; - public final static Boolean TABLE_4_PROCESSED_CONSTRAINTS = true; public final static String TABLE_4_DESCRIPTION = "Hello sensor"; public final static String TABLE_4_QUEUE_NAME = TABLE_4_INTERNALNAME; public final static String TABLE_4_ROUTING_KEY = "dbrepo\\." + DATABASE_1_ID + "\\." + TABLE_4_ID; @@ -2252,6 +2206,28 @@ public abstract class BaseTest { .maxDataLength(TABLE_4_MAX_DATA_LENGTH) .build(); + public final static TableDto TABLE_4_PRIVILEGED_DTO = TableDto.builder() + .id(TABLE_4_ID) + .tdbid(DATABASE_1_ID) + .internalName(TABLE_4_INTERNALNAME) + .description(TABLE_4_DESCRIPTION) + .name(TABLE_4_NAME) + .queueName(TABLE_4_QUEUE_NAME) + .routingKey(TABLE_4_ROUTING_KEY) + .database(null) /* DATABASE_1_DTO */ + .columns(new LinkedList<>()) /* TABLE_4_COLUMNS_DTO */ + .constraints(null) /* TABLE_4_CONSTRAINTS_DTO */ + .isVersioned(TABLE_4_VERSIONED) + .isPublic(TABLE_4_IS_PUBLIC) + .isSchemaPublic(TABLE_4_SCHEMA_PUBLIC) + .owner(USER_1_BRIEF_DTO) + .avgRowLength(TABLE_4_AVG_ROW_LENGTH) + .numRows(TABLE_4_NUM_ROWS) + .dataLength(TABLE_4_DATA_LENGTH) + .maxDataLength(TABLE_4_MAX_DATA_LENGTH) + .lastRetrieved(Instant.now()) + .build(); + public final static TableBriefDto TABLE_4_BRIEF_DTO = TableBriefDto.builder() .id(TABLE_4_ID) .databaseId(DATABASE_1_ID) @@ -2294,12 +2270,12 @@ public abstract class BaseTest { .isNullAllowed(true) .build()); - public final static List<ColumnCreateDto> TABLE_4_COLUMNS_CREATE_DTO = List.of(ColumnCreateDto.builder() + public final static List<CreateTableColumnDto> TABLE_4_COLUMNS_CREATE_DTO = List.of(CreateTableColumnDto.builder() .name("Timestamp") .type(ColumnTypeDto.TIMESTAMP) .nullAllowed(false) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Value") .type(ColumnTypeDto.DECIMAL) .nullAllowed(true) @@ -2307,14 +2283,14 @@ public abstract class BaseTest { .d(10L) .build()); - public final static ConstraintsCreateDto TABLE_4_CONSTRAINTS_CREATE_DTO = ConstraintsCreateDto.builder() + public final static CreateTableConstraintsDto TABLE_4_CONSTRAINTS_CREATE_DTO = CreateTableConstraintsDto.builder() .checks(new LinkedHashSet<>()) .primaryKey(new LinkedHashSet<>(Set.of("Timestamp"))) .foreignKeys(new LinkedList<>()) .uniques(new LinkedList<>(List.of(List.of("Timestamp")))) .build(); - public final static TableCreateDto TABLE_4_CREATE_DTO = TableCreateDto.builder() + public final static CreateTableDto TABLE_4_CREATE_DTO = CreateTableDto.builder() .name(TABLE_4_NAME) .description(TABLE_4_DESCRIPTION) .columns(TABLE_4_COLUMNS_CREATE_DTO) @@ -2354,7 +2330,6 @@ public abstract class BaseTest { public final static Boolean TABLE_8_VERSIONED = true; public final static Boolean TABLE_8_IS_PUBLIC = false; public final static Boolean TABLE_8_SCHEMA_PUBLIC = false; - public final static Boolean TABLE_8_PROCESSED_CONSTRAINTS = true; public final static String TABLE_8_DESCRIPTION = "Hello mfcc"; public final static String TABLE_8_QUEUE_NAME = TABLE_8_INTERNAL_NAME; public final static String TABLE_8_ROUTING_KEY = "dbrepo\\." + DATABASE_3_ID + "\\." + TABLE_8_ID; @@ -2407,7 +2382,7 @@ public abstract class BaseTest { .ownedBy(USER_1_ID) .build(); - public final static PrivilegedTableDto TABLE_8_PRIVILEGED_DTO = PrivilegedTableDto.builder() + public final static TableDto TABLE_8_PRIVILEGED_DTO = TableDto.builder() .id(TABLE_8_ID) .tdbid(TABLE_8_DATABASE_ID) .internalName(TABLE_8_INTERNAL_NAME) @@ -2483,7 +2458,7 @@ public abstract class BaseTest { .ownedBy(USER_1_ID) .build(); - public final static PrivilegedTableDto TABLE_9_PRIVILEGED_DTO = PrivilegedTableDto.builder() + public final static TableDto TABLE_9_PRIVILEGED_DTO = TableDto.builder() .id(TABLE_9_ID) .tdbid(TABLE_9_DATABASE_ID) .internalName(TABLE_9_INTERNAL_NAME) @@ -2918,6 +2893,33 @@ public abstract class BaseTest { .resultNumber(3L) .build(); + public final static ViewDto QUERY_1_VIEW_DTO = ViewDto.builder() + .vdbid(QUERY_1_DATABASE_ID) + .query(QUERY_1_STATEMENT) + .queryHash(QUERY_1_QUERY_HASH) + .owner(USER_1_BRIEF_DTO) + .columns(new LinkedList<>(List.of(ViewColumnDto.builder() + .name("id") + .internalName("id") + .build(), + ViewColumnDto.builder() + .name("date") + .internalName("date") + .build(), + ViewColumnDto.builder() + .name("location") + .internalName("location") + .build(), + ViewColumnDto.builder() + .name("mintemp") + .internalName("mintemp") + .build(), + ViewColumnDto.builder() + .name("rainfall") + .internalName("rainfall") + .build()))) + .build(); + public final static QueryBriefDto QUERY_1_BRIEF_DTO = QueryBriefDto.builder() .id(QUERY_1_ID) .databaseId(QUERY_1_DATABASE_ID) @@ -2979,7 +2981,7 @@ public abstract class BaseTest { .isPersisted(QUERY_3_PERSISTED) .resultNumber(2L) .build(); - + public final static Long QUERY_7_ID = 7L; public final static String QUERY_7_STATEMENT = "SELECT id, date, a.location, lat, lng FROM weather_aus a JOIN weather_location l on a.location = l.location WHERE date = '2008-12-01'"; public final static String QUERY_7_QUERY_HASH = "df7da3801dfb5c191ff6711d79ce6455f3c09ec8323ce1ff7208ab85387263f5"; @@ -3089,6 +3091,21 @@ public abstract class BaseTest { .owner(USER_1_BRIEF_DTO) .build(); + public final static ViewDto QUERY_5_VIEW_DTO = ViewDto.builder() + .vdbid(DATABASE_3_ID) + .query(QUERY_5_STATEMENT) + .queryHash(QUERY_5_QUERY_HASH) + .owner(USER_1_BRIEF_DTO) + .columns(new LinkedList<>(List.of(ViewColumnDto.builder() + .name("id") + .internalName("id") + .build(), + ViewColumnDto.builder() + .name("value") + .internalName("value") + .build()))) + .build(); + public final static List<Map<String, Object>> QUERY_5_RESULT_DTO = new LinkedList<>(List.of( Map.of("id", BigInteger.valueOf(1L), "value", 11.2), Map.of("id", BigInteger.valueOf(2L), "value", 11.3), @@ -3191,32 +3208,32 @@ public abstract class BaseTest { .isNullAllowed(true) .build()); - public final static List<ColumnCreateDto> TABLE_1_COLUMNS_CREATE_DTO = List.of(ColumnCreateDto.builder() + public final static List<CreateTableColumnDto> TABLE_1_COLUMNS_CREATE_DTO = List.of(CreateTableColumnDto.builder() .name("id") .type(ColumnTypeDto.BIGINT) .nullAllowed(false) .enums(null) .sets(null) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Date") .type(ColumnTypeDto.DATE) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Location") .type(ColumnTypeDto.VARCHAR) .size(255L) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("MinTemp") .type(ColumnTypeDto.DECIMAL) .size(10L) .d(0L) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Rainfall") .type(ColumnTypeDto.DECIMAL) .size(10L) @@ -3226,21 +3243,21 @@ public abstract class BaseTest { .unitUri(UNIT_1_URI) .build()); - public final static ConstraintsCreateDto TABLE_1_CONSTRAINTS_CREATE_DTO = ConstraintsCreateDto.builder() + public final static CreateTableConstraintsDto TABLE_1_CONSTRAINTS_CREATE_DTO = CreateTableConstraintsDto.builder() .checks(new LinkedHashSet<>()) .primaryKey(new LinkedHashSet<>(List.of("id"))) .foreignKeys(new LinkedList<>()) .uniques(new LinkedList<>(List.of(List.of("date")))) .build(); - public final static ConstraintsCreateDto TABLE_1_CONSTRAINTS_CREATE_INVALID_DTO = ConstraintsCreateDto.builder() + public final static CreateTableConstraintsDto TABLE_1_CONSTRAINTS_CREATE_INVALID_DTO = CreateTableConstraintsDto.builder() .checks(new LinkedHashSet<>()) .primaryKey(new LinkedHashSet<>()) .foreignKeys(new LinkedList<>()) .uniques(new LinkedList<>(List.of(List.of("date")))) .build(); - public final static TableCreateDto TABLE_1_CREATE_DTO = TableCreateDto.builder() + public final static CreateTableDto TABLE_1_CREATE_DTO = CreateTableDto.builder() .name(TABLE_1_NAME) .description(TABLE_1_DESCRIPTION) .columns(TABLE_1_COLUMNS_CREATE_DTO) @@ -3360,6 +3377,31 @@ public abstract class BaseTest { .sets(null) .build()); + public final static List<ColumnBriefDto> TABLE_2_COLUMNS_BRIEF_DTO = List.of(ColumnBriefDto.builder() + .id(COLUMN_2_1_ID) + .tableId(TABLE_2_ID) + .databaseId(DATABASE_1_ID) + .name("location") + .internalName("location") + .columnType(ColumnTypeDto.VARCHAR) + .build(), + ColumnBriefDto.builder() + .id(COLUMN_2_2_ID) + .tableId(TABLE_2_ID) + .databaseId(DATABASE_1_ID) + .name("lat") + .internalName("lat") + .columnType(ColumnTypeDto.DOUBLE) + .build(), + ColumnBriefDto.builder() + .id(COLUMN_2_3_ID) + .tableId(TABLE_2_ID) + .databaseId(DATABASE_1_ID) + .name("lng") + .internalName("lng") + .columnType(ColumnTypeDto.DOUBLE) + .build()); + public final static Long COLUMN_3_1_ID = 9L; public final static Long COLUMN_3_2_ID = 10L; @@ -4638,137 +4680,137 @@ public abstract class BaseTest { .isNullAllowed(true) .build()); - public final static List<ForeignKeyCreateDto> TABLE_5_FOREIGN_KEYS_INVALID_CREATE = List.of(ForeignKeyCreateDto.builder() + public final static List<CreateForeignKeyDto> TABLE_5_FOREIGN_KEYS_INVALID_CREATE = List.of(CreateForeignKeyDto.builder() .columns(new LinkedList<>(List.of("somecolumn"))) .referencedTable("sometable") .referencedColumns(new LinkedList<>(List.of("someothercolumn"))) .build()); - public final static ConstraintsCreateDto TABLE_5_CONSTRAINTS_INVALID_CREATE = ConstraintsCreateDto.builder() + public final static CreateTableConstraintsDto TABLE_5_CONSTRAINTS_INVALID_CREATE = CreateTableConstraintsDto.builder() .foreignKeys(TABLE_5_FOREIGN_KEYS_INVALID_CREATE) .build(); - public final static List<ColumnCreateDto> TABLE_5_COLUMNS_CREATE = List.of(ColumnCreateDto.builder() + public final static List<CreateTableColumnDto> TABLE_5_COLUMNS_CREATE = List.of(CreateTableColumnDto.builder() .name("id") .type(ColumnTypeDto.BIGINT) .nullAllowed(false) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Animal Name") .type(ColumnTypeDto.VARCHAR) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Hair") .type(ColumnTypeDto.BOOL) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Feathers") .type(ColumnTypeDto.BOOL) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Bread") .type(ColumnTypeDto.BOOL) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Eggs") .type(ColumnTypeDto.BOOL) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Milk") .type(ColumnTypeDto.BOOL) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Water") .type(ColumnTypeDto.BOOL) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Airborne") .type(ColumnTypeDto.BOOL) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Waterborne") .type(ColumnTypeDto.BOOL) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Aquantic") .type(ColumnTypeDto.BOOL) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Predator") .type(ColumnTypeDto.BOOL) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Backbone") .type(ColumnTypeDto.BOOL) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Breathes") .type(ColumnTypeDto.BOOL) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Venomous") .type(ColumnTypeDto.BOOL) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Fin") .type(ColumnTypeDto.BOOL) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Legs") .type(ColumnTypeDto.INT) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Tail") .type(ColumnTypeDto.DECIMAL) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Domestic") .type(ColumnTypeDto.BOOL) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Catsize") .type(ColumnTypeDto.BOOL) .nullAllowed(true) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("Class Type") .type(ColumnTypeDto.DECIMAL) .nullAllowed(true) .build()); - public final static ConstraintsCreateDto TABLE_5_CREATE_CONSTRAINTS_DTO = ConstraintsCreateDto.builder() + public final static CreateTableConstraintsDto TABLE_5_CREATE_CONSTRAINTS_DTO = CreateTableConstraintsDto.builder() .primaryKey(Set.of("id")) .uniques(new LinkedList<>(List.of(List.of("id")))) .checks(new LinkedHashSet<>()) .foreignKeys(new LinkedList<>()) .build(); - public final static TableCreateDto TABLE_5_CREATE_DTO = TableCreateDto.builder() + public final static CreateTableDto TABLE_5_CREATE_DTO = CreateTableDto.builder() .name(TABLE_5_NAME) .description(TABLE_5_DESCRIPTION) .columns(TABLE_5_COLUMNS_CREATE) .constraints(TABLE_5_CREATE_CONSTRAINTS_DTO) .build(); - public final static TableCreateDto TABLE_5_INVALID_CREATE_DTO = TableCreateDto.builder() + public final static CreateTableDto TABLE_5_INVALID_CREATE_DTO = CreateTableDto.builder() .name(TABLE_5_NAME) .description(TABLE_5_DESCRIPTION) .columns(TABLE_5_COLUMNS_CREATE) @@ -4895,7 +4937,7 @@ public abstract class BaseTest { public final static List<List<String>> TABLE_6_UNIQUES_CREATE = List.of( List.of("firstname", "lastname")); - public final static List<ForeignKeyCreateDto> TABLE_6_FOREIGN_KEYS_CREATE = List.of(ForeignKeyCreateDto.builder() + public final static List<CreateForeignKeyDto> TABLE_6_FOREIGN_KEYS_CREATE = List.of(CreateForeignKeyDto.builder() .columns(new LinkedList<>(List.of("ref_id"))) .referencedTable("zoo") .referencedColumns(new LinkedList<>(List.of("id"))) @@ -4903,27 +4945,27 @@ public abstract class BaseTest { public final static Set<String> TABLE_6_CHECKS_CREATE = Set.of("firstname != lastname"); - public final static ConstraintsCreateDto TABLE_6_CONSTRAINTS_CREATE = ConstraintsCreateDto.builder() + public final static CreateTableConstraintsDto TABLE_6_CONSTRAINTS_CREATE = CreateTableConstraintsDto.builder() .uniques(TABLE_6_UNIQUES_CREATE) .foreignKeys(TABLE_6_FOREIGN_KEYS_CREATE) .checks(TABLE_6_CHECKS_CREATE) .primaryKey(Set.of("id")) .build(); - public final static List<ColumnCreateDto> TABLE_6_COLUMNS_CREATE = List.of( - ColumnCreateDto.builder() + public final static List<CreateTableColumnDto> TABLE_6_COLUMNS_CREATE = List.of( + CreateTableColumnDto.builder() .name("name_id") .type(ColumnTypeDto.BIGINT) .nullAllowed(false) .build(), - ColumnCreateDto.builder() + CreateTableColumnDto.builder() .name("zoo_id") .type(ColumnTypeDto.BIGINT) .size(255L) .nullAllowed(false) .build()); - public final static TableCreateDto TABLE_6_CREATE_DTO = TableCreateDto.builder() + public final static CreateTableDto TABLE_6_CREATE_DTO = CreateTableDto.builder() .name(TABLE_6_NAME) .description(TABLE_6_DESCRIPTION) .columns(TABLE_6_COLUMNS_CREATE) @@ -4992,8 +5034,8 @@ public abstract class BaseTest { public final static String VIEW_1_INTERNAL_NAME = "junit"; public final static Long VIEW_1_CONTAINER_ID = CONTAINER_1_ID; public final static Long VIEW_1_DATABASE_ID = DATABASE_1_ID; - public final static Boolean VIEW_1_PUBLIC = true; - public final static Boolean VIEW_1_SCHEMA_PUBLIC = true; + public final static Boolean VIEW_1_PUBLIC = false; + public final static Boolean VIEW_1_SCHEMA_PUBLIC = false; public final static String VIEW_1_QUERY = "select `location`, `lat`, `lng` from `weather_location`"; public final static String VIEW_1_QUERY_HASH = "dc81a6877c7c51a6a6f406e1fc2a255e44a0d49a20548596e0d583c3eb849c23"; @@ -5117,10 +5159,9 @@ public abstract class BaseTest { .columns(VIEW_1_COLUMNS_DTO) .build(); - public final static PrivilegedViewDto VIEW_1_PRIVILEGED_DTO = PrivilegedViewDto.builder() + public final static ViewDto VIEW_1_PRIVILEGED_DTO = ViewDto.builder() .id(VIEW_1_ID) .isInitialView(VIEW_1_INITIAL_VIEW) - .database(null) /* DATABASE_1_PRIVILEGED_DTO */ .name(VIEW_1_NAME) .internalName(VIEW_1_INTERNAL_NAME) .vdbid(VIEW_1_DATABASE_ID) @@ -5130,6 +5171,7 @@ public abstract class BaseTest { .queryHash(VIEW_1_QUERY_HASH) .columns(VIEW_1_COLUMNS_DTO) .lastRetrieved(Instant.now()) + .database(null) /* DATABASE_1_PRIVILEGED_DTO */ .build(); public final static ViewBriefDto VIEW_1_BRIEF_DTO = ViewBriefDto.builder() @@ -5145,7 +5187,7 @@ public abstract class BaseTest { .queryHash(VIEW_1_QUERY_HASH) .build(); - public final static ViewCreateDto VIEW_1_CREATE_DTO = ViewCreateDto.builder() + public final static CreateViewDto VIEW_1_CREATE_DTO = CreateViewDto.builder() .isPublic(VIEW_1_PUBLIC) .name(VIEW_1_NAME) .query(VIEW_1_QUERY) @@ -5279,10 +5321,9 @@ public abstract class BaseTest { .owner(USER_1_BRIEF_DTO) .build(); - public final static PrivilegedViewDto VIEW_2_PRIVILEGED_DTO = PrivilegedViewDto.builder() + public final static ViewDto VIEW_2_PRIVILEGED_DTO = ViewDto.builder() .id(VIEW_2_ID) .isInitialView(VIEW_2_INITIAL_VIEW) - .database(null) /* DATABASE_1_PRIVILEGED_DTO */ .name(VIEW_2_NAME) .internalName(VIEW_2_INTERNAL_NAME) .vdbid(VIEW_2_DATABASE_ID) @@ -5293,6 +5334,7 @@ public abstract class BaseTest { .queryHash(VIEW_2_QUERY_HASH) .columns(VIEW_2_COLUMNS_DTO) .lastRetrieved(Instant.now()) + .database(null) /* DATABASE_1_PRIVILEGED_DTO */ .build(); public final static ViewBriefDto VIEW_2_BRIEF_DTO = ViewBriefDto.builder() @@ -5314,7 +5356,7 @@ public abstract class BaseTest { public final static String VIEW_3_INTERNAL_NAME = "junit3"; 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 Boolean VIEW_3_PUBLIC = true; public final static Boolean VIEW_3_SCHEMA_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` and m.`date` = w.`date`"; public final static String VIEW_3_QUERY_HASH = "bbbaa56a5206b3dc3e6cf9301b0db9344eb6f19b100c7b88550ffb597a0bd255"; @@ -5380,10 +5422,9 @@ public abstract class BaseTest { .owner(USER_1) .build(); - public final static PrivilegedViewDto VIEW_3_PRIVILEGED_DTO = PrivilegedViewDto.builder() + public final static ViewDto VIEW_3_PRIVILEGED_DTO = ViewDto.builder() .id(VIEW_3_ID) .isInitialView(VIEW_3_INITIAL_VIEW) - .database(null) /* DATABASE_1_PRIVILEGED_DTO */ .name(VIEW_3_NAME) .internalName(VIEW_3_INTERNAL_NAME) .vdbid(VIEW_3_DATABASE_ID) @@ -5394,6 +5435,7 @@ public abstract class BaseTest { .queryHash(VIEW_3_QUERY_HASH) .columns(VIEW_3_COLUMNS_DTO) .lastRetrieved(Instant.now()) + .database(null) /* DATABASE_1_PRIVILEGED_DTO */ .build(); public final static List<ViewColumn> VIEW_3_COLUMNS = List.of( @@ -5476,7 +5518,7 @@ public abstract class BaseTest { public final static Long VIEW_4_TABLE_ID = TABLE_5_ID; public final static Table VIEW_4_TABLE = TABLE_5; public final static Boolean VIEW_4_PUBLIC = true; - public final static Boolean VIEW_4_SCHEMA_PUBLIC = true; + public final static Boolean VIEW_4_SCHEMA_PUBLIC = false; public final static String VIEW_4_QUERY = "SELECT `animal_name`, `hair`, `feathers`, `eggs`, `milk`, `airborne`, `aquatic`, `predator`, `backbone`, `breathes`, `venomous`, `fins`, `legs`, `tail`, `domestic`, `catsize`, `class_type` FROM `zoo` WHERE `class_type` = 1"; public final static String VIEW_4_QUERY_HASH = "3561cd0bb0b0e94d6f15ae602134252a5760d09d660a71a4fb015b6991c8ba0b"; @@ -6111,13 +6153,13 @@ public abstract class BaseTest { .language(IDENTIFIER_1_TITLE_1_LANG_DTO) .build(); - public final static IdentifierSaveTitleDto IDENTIFIER_1_TITLE_1_CREATE_DTO = IdentifierSaveTitleDto.builder() + public final static SaveIdentifierTitleDto IDENTIFIER_1_TITLE_1_CREATE_DTO = SaveIdentifierTitleDto.builder() .title(IDENTIFIER_1_TITLE_1_TITLE) .titleType(IDENTIFIER_1_TITLE_1_TYPE_DTO) .language(IDENTIFIER_1_TITLE_1_LANG_DTO) .build(); - public final static IdentifierSaveTitleDto IDENTIFIER_1_TITLE_1_UPDATE_DTO = IdentifierSaveTitleDto.builder() + public final static SaveIdentifierTitleDto IDENTIFIER_1_TITLE_1_UPDATE_DTO = SaveIdentifierTitleDto.builder() .title(IDENTIFIER_1_TITLE_1_TITLE_MODIFY) .titleType(IDENTIFIER_1_TITLE_1_TYPE_DTO) .language(IDENTIFIER_1_TITLE_1_LANG_DTO) @@ -6153,13 +6195,13 @@ public abstract class BaseTest { .language(IDENTIFIER_1_TITLE_2_LANG_DTO) .build(); - public final static IdentifierSaveTitleDto IDENTIFIER_1_TITLE_2_CREATE_DTO = IdentifierSaveTitleDto.builder() + public final static SaveIdentifierTitleDto IDENTIFIER_1_TITLE_2_CREATE_DTO = SaveIdentifierTitleDto.builder() .title(IDENTIFIER_1_TITLE_2_TITLE) .titleType(IDENTIFIER_1_TITLE_2_TYPE_DTO) .language(IDENTIFIER_1_TITLE_2_LANG_DTO) .build(); - public final static IdentifierSaveTitleDto IDENTIFIER_1_TITLE_2_UPDATE_DTO = IdentifierSaveTitleDto.builder() + public final static SaveIdentifierTitleDto IDENTIFIER_1_TITLE_2_UPDATE_DTO = SaveIdentifierTitleDto.builder() .title(IDENTIFIER_1_TITLE_2_TITLE_MODIFY) .titleType(IDENTIFIER_1_TITLE_2_TYPE_DTO) .language(IDENTIFIER_1_TITLE_2_LANG_DTO) @@ -6195,7 +6237,7 @@ public abstract class BaseTest { .language(IDENTIFIER_1_DESCRIPTION_1_LANG_DTO) .build(); - public final static IdentifierSaveDescriptionDto IDENTIFIER_1_DESCRIPTION_1_CREATE_DTO = IdentifierSaveDescriptionDto.builder() + public final static SaveIdentifierDescriptionDto IDENTIFIER_1_DESCRIPTION_1_CREATE_DTO = SaveIdentifierDescriptionDto.builder() .id(null) .description(IDENTIFIER_1_DESCRIPTION_1_DESCRIPTION) .descriptionType(IDENTIFIER_1_DESCRIPTION_1_TYPE_DTO) @@ -6243,7 +6285,7 @@ public abstract class BaseTest { .affiliationIdentifierSchemeUri(IDENTIFIER_1_CREATOR_1_AFFILIATION_IDENTIFIER_SCHEME_URI) .build(); - public final static CreatorSaveDto IDENTIFIER_1_CREATOR_1_CREATE_DTO = CreatorSaveDto.builder() + public final static SaveIdentifierCreatorDto IDENTIFIER_1_CREATOR_1_CREATE_DTO = SaveIdentifierCreatorDto.builder() .id(null) .firstname(IDENTIFIER_1_CREATOR_1_FIRSTNAME) .lastname(IDENTIFIER_1_CREATOR_1_LASTNAME) @@ -6280,7 +6322,7 @@ public abstract class BaseTest { .awardTitle(FUNDER_1_AWARD_TITLE) .build(); - public final static IdentifierFunderSaveDto IDENTIFIER_1_FUNDER_1_CREATE_DTO = IdentifierFunderSaveDto.builder() + public final static SaveIdentifierFunderDto IDENTIFIER_1_FUNDER_1_CREATE_DTO = SaveIdentifierFunderDto.builder() .funderName(FUNDER_1_NAME) .funderIdentifier(FUNDER_1_IDENTIFIER) .funderIdentifierType(FUNDER_1_IDENTIFIER_TYPE_DTO) @@ -6385,7 +6427,7 @@ public abstract class BaseTest { .status(IDENTIFIER_1_STATUS_TYPE_DTO) .build(); - public final static IdentifierCreateDto IDENTIFIER_1_CREATE_DTO = IdentifierCreateDto.builder() + public final static CreateIdentifierDto IDENTIFIER_1_CREATE_DTO = CreateIdentifierDto.builder() .databaseId(IDENTIFIER_1_DATABASE_ID) .type(IDENTIFIER_1_TYPE_DTO) .publicationYear(IDENTIFIER_1_PUBLICATION_YEAR) @@ -6402,7 +6444,7 @@ public abstract class BaseTest { .funders(new LinkedList<>(List.of(IDENTIFIER_1_FUNDER_1_CREATE_DTO))) .build(); - public final static IdentifierCreateDto IDENTIFIER_1_CREATE_WITH_DOI_DTO = IdentifierCreateDto.builder() + public final static CreateIdentifierDto IDENTIFIER_1_CREATE_WITH_DOI_DTO = CreateIdentifierDto.builder() .databaseId(IDENTIFIER_1_DATABASE_ID) .type(IDENTIFIER_1_TYPE_DTO) .doi(IDENTIFIER_1_DOI) @@ -6494,7 +6536,7 @@ public abstract class BaseTest { .titleType(IDENTIFIER_5_TITLE_1_TYPE_DTO) .build(); - public final static IdentifierSaveTitleDto IDENTIFIER_5_TITLE_1_CREATE_DTO = IdentifierSaveTitleDto.builder() + public final static SaveIdentifierTitleDto IDENTIFIER_5_TITLE_1_CREATE_DTO = SaveIdentifierTitleDto.builder() .title(IDENTIFIER_5_TITLE_1_TITLE) .language(IDENTIFIER_5_TITLE_1_LANG_DTO) .titleType(IDENTIFIER_5_TITLE_1_TYPE_DTO) @@ -6522,7 +6564,7 @@ public abstract class BaseTest { .descriptionType(IDENTIFIER_5_DESCRIPTION_1_TYPE_DTO) .build(); - public final static IdentifierSaveDescriptionDto IDENTIFIER_5_DESCRIPTION_1_CREATE_DTO = IdentifierSaveDescriptionDto.builder() + public final static SaveIdentifierDescriptionDto IDENTIFIER_5_DESCRIPTION_1_CREATE_DTO = SaveIdentifierDescriptionDto.builder() .id(null) .description(IDENTIFIER_5_DESCRIPTION_1_DESCRIPTION) .language(IDENTIFIER_5_DESCRIPTION_1_LANG_DTO) @@ -6557,7 +6599,7 @@ public abstract class BaseTest { .affiliationIdentifierSchemeUri(CREATOR_1_AFFIL_URI) .build(); - public final static CreatorSaveDto IDENTIFIER_5_CREATOR_1_CREATE_DTO = CreatorSaveDto.builder() + public final static SaveIdentifierCreatorDto IDENTIFIER_5_CREATOR_1_CREATE_DTO = SaveIdentifierCreatorDto.builder() .firstname(CREATOR_1_FIRSTNAME) .lastname(CREATOR_1_LASTNAME) .creatorName(CREATOR_1_NAME) @@ -6566,7 +6608,7 @@ public abstract class BaseTest { .affiliation(CREATOR_1_AFFIL) .build(); - public final static CreatorSaveDto IDENTIFIER_5_CREATOR_1_MODIFY_DTO = CreatorSaveDto.builder() + public final static SaveIdentifierCreatorDto IDENTIFIER_5_CREATOR_1_MODIFY_DTO = SaveIdentifierCreatorDto.builder() .firstname(CREATOR_1_FIRSTNAME) .lastname(CREATOR_1_LASTNAME) .creatorName(CREATOR_1_NAME) @@ -6597,7 +6639,7 @@ public abstract class BaseTest { .affiliation(CREATOR_2_AFFIL) .build(); - public final static CreatorSaveDto IDENTIFIER_5_CREATOR_2_CREATE_DTO = CreatorSaveDto.builder() + public final static SaveIdentifierCreatorDto IDENTIFIER_5_CREATOR_2_CREATE_DTO = SaveIdentifierCreatorDto.builder() .firstname(CREATOR_2_FIRSTNAME) .lastname(CREATOR_2_LASTNAME) .creatorName(CREATOR_2_NAME) @@ -6606,7 +6648,7 @@ public abstract class BaseTest { .affiliation(CREATOR_2_AFFIL) .build(); - public final static CreatorSaveDto IDENTIFIER_5_CREATOR_2_MODIFY_DTO = CreatorSaveDto.builder() + public final static SaveIdentifierCreatorDto IDENTIFIER_5_CREATOR_2_MODIFY_DTO = SaveIdentifierCreatorDto.builder() .firstname(CREATOR_2_FIRSTNAME) .lastname(CREATOR_2_LASTNAME) .creatorName(CREATOR_2_NAME) @@ -6690,13 +6732,13 @@ public abstract class BaseTest { .value(RELATED_IDENTIFIER_5_VALUE) .build(); - public final static RelatedIdentifierSaveDto IDENTIFIER_1_RELATED_IDENTIFIER_5_CREATE_DTO = RelatedIdentifierSaveDto.builder() + public final static SaveRelatedIdentifierDto IDENTIFIER_1_RELATED_IDENTIFIER_5_CREATE_DTO = SaveRelatedIdentifierDto.builder() .value(RELATED_IDENTIFIER_5_VALUE) .type(RELATED_IDENTIFIER_5_TYPE_DTO) .relation(RELATED_IDENTIFIER_5_RELATION_TYPE_DTO) .build(); - public final static IdentifierCreateDto IDENTIFIER_5_CREATE_DTO = IdentifierCreateDto.builder() + public final static CreateIdentifierDto IDENTIFIER_5_CREATE_DTO = CreateIdentifierDto.builder() .databaseId(IDENTIFIER_5_DATABASE_ID) .publicationYear(IDENTIFIER_5_PUBLICATION_YEAR) .publisher(IDENTIFIER_5_PUBLISHER) @@ -6765,7 +6807,7 @@ public abstract class BaseTest { .language(IDENTIFIER_6_TITLE_1_LANG_DTO) .build(); - public final static IdentifierSaveTitleDto IDENTIFIER_6_TITLE_1_CREATE_DTO = IdentifierSaveTitleDto.builder() + public final static SaveIdentifierTitleDto IDENTIFIER_6_TITLE_1_CREATE_DTO = SaveIdentifierTitleDto.builder() .title(IDENTIFIER_6_TITLE_1_TITLE_MODIFY) .language(IDENTIFIER_6_TITLE_1_LANG_DTO) .build(); @@ -6795,7 +6837,7 @@ public abstract class BaseTest { .language(IDENTIFIER_6_DESCRIPTION_1_LANG_DTO) .build(); - public final static IdentifierSaveDescriptionDto IDENTIFIER_6_DESCRIPTION_1_CREATE_DTO = IdentifierSaveDescriptionDto.builder() + public final static SaveIdentifierDescriptionDto IDENTIFIER_6_DESCRIPTION_1_CREATE_DTO = SaveIdentifierDescriptionDto.builder() .id(null) .description(IDENTIFIER_6_DESCRIPTION_1_DESCRIPTION_MODIFY) .language(IDENTIFIER_6_DESCRIPTION_1_LANG_DTO) @@ -6829,7 +6871,7 @@ public abstract class BaseTest { .affiliationIdentifierSchemeUri(CREATOR_1_AFFIL_URI) .build(); - public final static CreatorSaveDto IDENTIFIER_6_CREATOR_1_CREATE_DTO = CreatorSaveDto.builder() + public final static SaveIdentifierCreatorDto IDENTIFIER_6_CREATOR_1_CREATE_DTO = SaveIdentifierCreatorDto.builder() .firstname(CREATOR_1_FIRSTNAME) .lastname(CREATOR_1_LASTNAME) .creatorName(CREATOR_1_NAME) @@ -6840,7 +6882,7 @@ public abstract class BaseTest { .affiliationIdentifierScheme(CREATOR_1_AFFIL_TYPE_DTO) .build(); - public final static CreatorSaveDto IDENTIFIER_6_CREATOR_1_MODIFY_DTO = CreatorSaveDto.builder() + public final static SaveIdentifierCreatorDto IDENTIFIER_6_CREATOR_1_MODIFY_DTO = SaveIdentifierCreatorDto.builder() .firstname(CREATOR_1_FIRSTNAME) .lastname(CREATOR_1_LASTNAME) .creatorName(CREATOR_1_NAME) @@ -6964,7 +7006,7 @@ public abstract class BaseTest { .status(IDENTIFIER_6_STATUS_TYPE_DTO) .build(); - public final static IdentifierCreateDto IDENTIFIER_6_CREATE_DTO = IdentifierCreateDto.builder() + public final static CreateIdentifierDto IDENTIFIER_6_CREATE_DTO = CreateIdentifierDto.builder() .databaseId(IDENTIFIER_6_DATABASE_ID) .publicationYear(IDENTIFIER_6_PUBLICATION_YEAR) .publisher(IDENTIFIER_6_PUBLISHER) @@ -7059,7 +7101,7 @@ public abstract class BaseTest { .status(IDENTIFIER_7_STATUS_TYPE_DTO) .build(); - public final static CreatorSaveDto IDENTIFIER_7_CREATOR_1_CREATE_DTO = CreatorSaveDto.builder() + public final static SaveIdentifierCreatorDto IDENTIFIER_7_CREATOR_1_CREATE_DTO = SaveIdentifierCreatorDto.builder() .firstname(CREATOR_1_FIRSTNAME) .lastname(CREATOR_1_LASTNAME) .creatorName(CREATOR_1_NAME) @@ -7069,7 +7111,7 @@ public abstract class BaseTest { .affiliationIdentifier(CREATOR_1_AFFIL_ROR) .build(); - public final static IdentifierCreateDto IDENTIFIER_7_CREATE_DTO = IdentifierCreateDto.builder() + public final static CreateIdentifierDto IDENTIFIER_7_CREATE_DTO = CreateIdentifierDto.builder() .databaseId(IDENTIFIER_7_DATABASE_ID) .publicationYear(IDENTIFIER_7_PUBLICATION_YEAR) .publisher(IDENTIFIER_7_PUBLISHER) @@ -7112,7 +7154,7 @@ public abstract class BaseTest { public final static IdentifierStatusTypeDto IDENTIFIER_2_STATUS_TYPE_DTO = IdentifierStatusTypeDto.PUBLISHED; public final static UUID IDENTIFIER_2_CREATED_BY = USER_1_ID; - public final static IdentifierCreateDto IDENTIFIER_2_CREATE_DTO = IdentifierCreateDto.builder() + public final static CreateIdentifierDto IDENTIFIER_2_CREATE_DTO = CreateIdentifierDto.builder() .databaseId(IDENTIFIER_2_DATABASE_ID) .queryId(IDENTIFIER_2_QUERY_ID) .type(IDENTIFIER_2_TYPE_DTO) @@ -7284,7 +7326,7 @@ public abstract class BaseTest { .status(IDENTIFIER_3_STATUS_TYPE_DTO) .build(); - public final static IdentifierCreateDto IDENTIFIER_3_CREATE_DTO = IdentifierCreateDto.builder() + public final static CreateIdentifierDto IDENTIFIER_3_CREATE_DTO = CreateIdentifierDto.builder() .databaseId(IDENTIFIER_3_DATABASE_ID) .viewId(IDENTIFIER_3_VIEW_ID) .type(IDENTIFIER_3_TYPE_DTO) @@ -7383,7 +7425,7 @@ public abstract class BaseTest { .status(IDENTIFIER_4_STATUS_TYPE_DTO) .build(); - public final static IdentifierCreateDto IDENTIFIER_4_CREATE_DTO = IdentifierCreateDto.builder() + public final static CreateIdentifierDto IDENTIFIER_4_CREATE_DTO = CreateIdentifierDto.builder() .databaseId(IDENTIFIER_4_DATABASE_ID) .publicationYear(IDENTIFIER_4_PUBLICATION_YEAR) .publisher(IDENTIFIER_4_PUBLISHER) @@ -7502,7 +7544,7 @@ public abstract class BaseTest { .lastModified(DATABASE_1_LAST_MODIFIED) .ownedBy(DATABASE_1_CREATED_BY) .owner(USER_1) - .ownedBy(DATABASE_1_OWNER) + .ownedBy(USER_1_ID) .owner(USER_1) .image(new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) .contactPerson(USER_1_ID) @@ -7517,16 +7559,18 @@ public abstract class BaseTest { public final static DatabaseDto DATABASE_1_DTO = DatabaseDto.builder() .id(DATABASE_1_ID) .isPublic(DATABASE_1_PUBLIC) + .isSchemaPublic(DATABASE_1_SCHEMA_PUBLIC) .name(DATABASE_1_NAME) - .container(CONTAINER_1_BRIEF_DTO) + .container(CONTAINER_1_DTO) .internalName(DATABASE_1_INTERNALNAME) .exchangeName(DATABASE_1_EXCHANGE) - .identifiers(new LinkedList<>(List.of(IDENTIFIER_1_BRIEF_DTO, IDENTIFIER_2_BRIEF_DTO, IDENTIFIER_3_BRIEF_DTO, IDENTIFIER_4_BRIEF_DTO))) - .tables(new LinkedList<>(List.of(TABLE_1_BRIEF_DTO, TABLE_2_BRIEF_DTO, TABLE_3_BRIEF_DTO, TABLE_4_BRIEF_DTO))) - .views(new LinkedList<>(List.of(VIEW_1_BRIEF_DTO, VIEW_2_BRIEF_DTO, VIEW_3_BRIEF_DTO))) + .identifiers(new LinkedList<>(List.of(IDENTIFIER_1_DTO, IDENTIFIER_2_DTO, IDENTIFIER_3_DTO, IDENTIFIER_4_DTO))) + .tables(new LinkedList<>(List.of(TABLE_1_DTO, TABLE_2_DTO, TABLE_3_DTO, TABLE_4_DTO))) + .views(new LinkedList<>(List.of(VIEW_1_DTO, VIEW_2_DTO, VIEW_3_DTO))) + .owner(USER_1_BRIEF_DTO) .build(); - public final static PrivilegedDatabaseDto DATABASE_1_PRIVILEGED_DTO = PrivilegedDatabaseDto.builder() + public final static DatabaseDto DATABASE_1_PRIVILEGED_DTO = DatabaseDto.builder() .id(DATABASE_1_ID) .isPublic(DATABASE_1_PUBLIC) .isSchemaPublic(DATABASE_1_SCHEMA_PUBLIC) @@ -7534,6 +7578,7 @@ public abstract class BaseTest { .container(CONTAINER_1_PRIVILEGED_DTO) .internalName(DATABASE_1_INTERNALNAME) .exchangeName(DATABASE_1_EXCHANGE) + .accesses(new LinkedList<>(List.of())) /* DATABASE_1_USER_1_READ_ACCESS_DTO */ .identifiers(new LinkedList<>(List.of(IDENTIFIER_1_DTO, IDENTIFIER_2_DTO, IDENTIFIER_3_DTO, IDENTIFIER_4_DTO))) .tables(new LinkedList<>(List.of(TABLE_1_DTO, TABLE_2_DTO, TABLE_3_DTO, TABLE_4_DTO))) .views(new LinkedList<>(List.of(VIEW_1_DTO, VIEW_2_DTO, VIEW_3_DTO))) @@ -7541,6 +7586,15 @@ public abstract class BaseTest { .lastRetrieved(Instant.now()) .build(); + public final static DatabaseBriefDto DATABASE_1_BRIEF_DTO = DatabaseBriefDto.builder() + .id(DATABASE_1_ID) + .isPublic(DATABASE_1_PUBLIC) + .isSchemaPublic(DATABASE_1_SCHEMA_PUBLIC) + .name(DATABASE_1_NAME) + .internalName(DATABASE_1_INTERNALNAME) + .identifiers(new LinkedList<>(List.of(IDENTIFIER_1_BRIEF_DTO, IDENTIFIER_2_BRIEF_DTO, IDENTIFIER_3_BRIEF_DTO, IDENTIFIER_4_BRIEF_DTO))) + .build(); + public final static DatabaseAccess DATABASE_1_USER_1_READ_ACCESS = DatabaseAccess.builder() .type(AccessType.READ) .hdbid(DATABASE_1_ID) @@ -7672,12 +7726,12 @@ public abstract class BaseTest { .identifiers(new LinkedList<>()) .build(); - public final static PrivilegedDatabaseDto DATABASE_2_PRIVILEGED_DTO = PrivilegedDatabaseDto.builder() + public final static DatabaseDto DATABASE_2_DTO = DatabaseDto.builder() .id(DATABASE_2_ID) .isPublic(DATABASE_2_PUBLIC) .isSchemaPublic(DATABASE_2_SCHEMA_PUBLIC) .name(DATABASE_2_NAME) - .container(CONTAINER_1_PRIVILEGED_DTO) + .container(CONTAINER_1_DTO) .internalName(DATABASE_2_INTERNALNAME) .exchangeName(DATABASE_2_EXCHANGE) .identifiers(new LinkedList<>(List.of(IDENTIFIER_5_DTO))) @@ -7687,18 +7741,29 @@ public abstract class BaseTest { .lastRetrieved(Instant.now()) .build(); - public final static DatabaseDto DATABASE_2_DTO = DatabaseDto.builder() + public final static DatabaseDto DATABASE_2_PRIVILEGED_DTO = DatabaseDto.builder() .id(DATABASE_2_ID) .isPublic(DATABASE_2_PUBLIC) + .isSchemaPublic(DATABASE_2_SCHEMA_PUBLIC) .name(DATABASE_2_NAME) - .container(CONTAINER_1_BRIEF_DTO) + .container(CONTAINER_1_PRIVILEGED_DTO) .internalName(DATABASE_2_INTERNALNAME) .exchangeName(DATABASE_2_EXCHANGE) - .identifiers(new LinkedList<>(List.of(IDENTIFIER_5_BRIEF_DTO))) - .tables(new LinkedList<>(List.of(TABLE_5_BRIEF_DTO, TABLE_6_BRIEF_DTO, TABLE_7_BRIEF_DTO))) - .views(new LinkedList<>(List.of(VIEW_4_BRIEF_DTO))) - .identifiers(new LinkedList<>()) + .identifiers(new LinkedList<>(List.of(IDENTIFIER_5_DTO))) + .tables(new LinkedList<>(List.of(TABLE_5_DTO, TABLE_6_DTO, TABLE_7_DTO))) + .views(new LinkedList<>(List.of(VIEW_4_DTO))) .owner(USER_2_BRIEF_DTO) + .lastRetrieved(Instant.now()) + .build(); + + public final static DatabaseBriefDto DATABASE_2_BRIEF_DTO = DatabaseBriefDto.builder() + .id(DATABASE_2_ID) + .isPublic(DATABASE_2_PUBLIC) + .isSchemaPublic(DATABASE_2_SCHEMA_PUBLIC) + .name(DATABASE_2_NAME) + .internalName(DATABASE_2_INTERNALNAME) + .identifiers(new LinkedList<>(List.of(IDENTIFIER_5_BRIEF_DTO))) + .ownerId(USER_2_ID) .build(); public final static DatabaseAccess DATABASE_2_USER_1_READ_ACCESS = DatabaseAccess.builder() @@ -7855,6 +7920,13 @@ public abstract class BaseTest { .user(USER_1) .build(); + public final static DatabaseAccessDto DATABASE_3_USER_1_WRITE_ALL_ACCESS_DTO = DatabaseAccessDto.builder() + .type(AccessTypeDto.WRITE_ALL) + .hdbid(DATABASE_3_ID) + .huserid(USER_1_ID) + .user(USER_1_BRIEF_DTO) + .build(); + public final static DatabaseAccess DATABASE_3_USER_2_READ_ACCESS = DatabaseAccess.builder() .type(AccessType.READ) .hdbid(DATABASE_3_ID) @@ -7924,21 +7996,6 @@ public abstract class BaseTest { .user(USER_3_BRIEF_DTO) .build(); - public final static PrivilegedDatabaseDto DATABASE_3_PRIVILEGED_DTO = PrivilegedDatabaseDto.builder() - .id(DATABASE_3_ID) - .isPublic(DATABASE_3_PUBLIC) - .isSchemaPublic(DATABASE_3_SCHEMA_PUBLIC) - .name(DATABASE_3_NAME) - .container(CONTAINER_1_PRIVILEGED_DTO) - .internalName(DATABASE_3_INTERNALNAME) - .exchangeName(DATABASE_3_EXCHANGE) - .identifiers(new LinkedList<>(List.of(IDENTIFIER_6_DTO))) - .tables(new LinkedList<>(List.of(TABLE_8_DTO))) - .views(new LinkedList<>(List.of(VIEW_5_DTO))) - .owner(USER_3_BRIEF_DTO) - .lastRetrieved(Instant.now()) - .build(); - public final static Identifier IDENTIFIER_7 = Identifier.builder() .id(IDENTIFIER_7_ID) .descriptions(new LinkedList<>()) @@ -7985,21 +8042,6 @@ public abstract class BaseTest { .identifiers(new LinkedList<>()) .build(); - public final static PrivilegedDatabaseDto DATABASE_4_PRIVILEGED_DTO = PrivilegedDatabaseDto.builder() - .id(DATABASE_4_ID) - .isPublic(DATABASE_4_PUBLIC) - .isSchemaPublic(DATABASE_4_SCHEMA_PUBLIC) - .name(DATABASE_4_NAME) - .container(CONTAINER_1_PRIVILEGED_DTO) - .internalName(DATABASE_4_INTERNALNAME) - .exchangeName(DATABASE_4_EXCHANGE) - .identifiers(new LinkedList<>(List.of(IDENTIFIER_7_DTO))) - .tables(new LinkedList<>(List.of(TABLE_9_DTO))) - .views(new LinkedList<>(List.of())) - .owner(USER_3_BRIEF_DTO) - .lastRetrieved(Instant.now()) - .build(); - public final static DatabaseAccess DATABASE_4_USER_1_READ_ACCESS = DatabaseAccess.builder() .type(AccessType.READ) .hdbid(DATABASE_4_ID) @@ -8081,9 +8123,9 @@ public abstract class BaseTest { .foreignKeys(new LinkedList<>()) .uniques(new LinkedList<>()) .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder() + .id(1L) .table(TABLE_1_BRIEF_DTO) .column(TABLE_1_COLUMNS_BRIEF_0_DTO) - .id(1L) .build()))) .build(); @@ -8136,7 +8178,7 @@ public abstract class BaseTest { .id(1L) .table(TABLE_2_BRIEF_DTO) .name("uk_1") - .columns(new LinkedList<>(List.of(TABLE_2_COLUMNS_DTO.get(1)))) + .columns(new LinkedList<>(List.of(TABLE_2_COLUMNS_BRIEF_DTO.get(1)))) .build()))) .primaryKey(new LinkedHashSet<>(Set.of(PrimaryKeyDto.builder() .table(TABLE_2_BRIEF_DTO) diff --git a/dbrepo-search-service/Pipfile b/dbrepo-search-service/Pipfile index ec74a381be4f01297cf01d2f638182ba2a8a1d9d..3ae299480180796fb640802d582aaf2745f876ca 100644 --- a/dbrepo-search-service/Pipfile +++ b/dbrepo-search-service/Pipfile @@ -18,7 +18,7 @@ jwt = "~=1.3" testcontainers-opensearch = "*" pytest = "*" rdflib = "*" -dbrepo = {path = "./lib/dbrepo-1.6.1.tar.gz"} +dbrepo = {path = "./lib/dbrepo-1.6.3.tar.gz"} gunicorn = "*" [dev-packages] diff --git a/dbrepo-search-service/Pipfile.lock b/dbrepo-search-service/Pipfile.lock index c0508dd3daf66ff03c848411ae47f1698da81014..6c62e03b928bcd62b443395c39dcdef902fe488d 100644 --- a/dbrepo-search-service/Pipfile.lock +++ b/dbrepo-search-service/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "a0682b0583cfc91d643a307a7dce7a524e7f7c29dbf2c9c5e9a6f16eb5f5ee91" + "sha256": "2ff9fc673f1fb1e5dc272aa711f4e730088fa0188b44449db042abf99b6c4db7" }, "pipfile-spec": 6, "requires": { @@ -124,11 +124,11 @@ }, "attrs": { "hashes": [ - "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", - "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308" + "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e", + "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a" ], "markers": "python_version >= '3.8'", - "version": "==24.3.0" + "version": "==25.1.0" }, "blinker": { "hashes": [ @@ -360,9 +360,9 @@ }, "dbrepo": { "hashes": [ - "sha256:a08b6eb49c108466b231c1b2cae5be501043fe4208a782899ce103105e22e3c6" + "sha256:ac99f4bd19961f08665abd513e4d9452fcea5554f122457840e95f90698bab4d" ], - "path": "./lib/dbrepo-1.6.1.tar.gz" + "path": "./lib/dbrepo-1.6.3.tar.gz" }, "docker": { "hashes": [ @@ -739,11 +739,11 @@ }, "mistune": { "hashes": [ - "sha256:b05198cf6d671b3deba6c87ec6cf0d4eb7b72c524636eddb6dbf13823b52cee1", - "sha256:dbcac2f78292b9dc066cd03b7a3a26b62d85f8159f2ea5fd28e55df79908d667" + "sha256:02106ac2aa4f66e769debbfa028509a275069dcffce0dfa578edd7b991ee700a", + "sha256:e0740d635f515119f7d1feb6f9b192ee60f0cc649f80a8f944f905706a21654c" ], "markers": "python_version >= '3.8'", - "version": "==3.1.0" + "version": "==3.1.1" }, "multidict": { "hashes": [ @@ -845,64 +845,64 @@ }, "numpy": { "hashes": [ - "sha256:059e6a747ae84fce488c3ee397cee7e5f905fd1bda5fb18c66bc41807ff119b2", - "sha256:08ef779aed40dbc52729d6ffe7dd51df85796a702afbf68a4f4e41fafdc8bda5", - "sha256:164a829b6aacf79ca47ba4814b130c4020b202522a93d7bff2202bfb33b61c60", - "sha256:26c9c4382b19fcfbbed3238a14abf7ff223890ea1936b8890f058e7ba35e8d71", - "sha256:27f5cdf9f493b35f7e41e8368e7d7b4bbafaf9660cba53fb21d2cd174ec09631", - "sha256:31b89fa67a8042e96715c68e071a1200c4e172f93b0fbe01a14c0ff3ff820fc8", - "sha256:32cb94448be47c500d2c7a95f93e2f21a01f1fd05dd2beea1ccd049bb6001cd2", - "sha256:360137f8fb1b753c5cde3ac388597ad680eccbbbb3865ab65efea062c4a1fd16", - "sha256:3683a8d166f2692664262fd4900f207791d005fb088d7fdb973cc8d663626faa", - "sha256:38efc1e56b73cc9b182fe55e56e63b044dd26a72128fd2fbd502f75555d92591", - "sha256:3d03883435a19794e41f147612a77a8f56d4e52822337844fff3d4040a142964", - "sha256:3ecc47cd7f6ea0336042be87d9e7da378e5c7e9b3c8ad0f7c966f714fc10d821", - "sha256:40f9e544c1c56ba8f1cf7686a8c9b5bb249e665d40d626a23899ba6d5d9e1484", - "sha256:4250888bcb96617e00bfa28ac24850a83c9f3a16db471eca2ee1f1714df0f957", - "sha256:4511d9e6071452b944207c8ce46ad2f897307910b402ea5fa975da32e0102800", - "sha256:45681fd7128c8ad1c379f0ca0776a8b0c6583d2f69889ddac01559dfe4390918", - "sha256:48fd472630715e1c1c89bf1feab55c29098cb403cc184b4859f9c86d4fcb6a95", - "sha256:4c86e2a209199ead7ee0af65e1d9992d1dce7e1f63c4b9a616500f93820658d0", - "sha256:4dfda918a13cc4f81e9118dea249e192ab167a0bb1966272d5503e39234d694e", - "sha256:5062dc1a4e32a10dc2b8b13cedd58988261416e811c1dc4dbdea4f57eea61b0d", - "sha256:51faf345324db860b515d3f364eaa93d0e0551a88d6218a7d61286554d190d73", - "sha256:526fc406ab991a340744aad7e25251dd47a6720a685fa3331e5c59fef5282a59", - "sha256:53c09385ff0b72ba79d8715683c1168c12e0b6e84fb0372e97553d1ea91efe51", - "sha256:55ba24ebe208344aa7a00e4482f65742969a039c2acfcb910bc6fcd776eb4355", - "sha256:5b6c390bfaef8c45a260554888966618328d30e72173697e5cabe6b285fb2348", - "sha256:5c5cc0cbabe9452038ed984d05ac87910f89370b9242371bd9079cb4af61811e", - "sha256:5edb4e4caf751c1518e6a26a83501fda79bff41cc59dac48d70e6d65d4ec4440", - "sha256:61048b4a49b1c93fe13426e04e04fdf5a03f456616f6e98c7576144677598675", - "sha256:676f4eebf6b2d430300f1f4f4c2461685f8269f94c89698d832cdf9277f30b84", - "sha256:67d4cda6fa6ffa073b08c8372aa5fa767ceb10c9a0587c707505a6d426f4e046", - "sha256:694f9e921a0c8f252980e85bce61ebbd07ed2b7d4fa72d0e4246f2f8aa6642ab", - "sha256:733585f9f4b62e9b3528dd1070ec4f52b8acf64215b60a845fa13ebd73cd0712", - "sha256:7671dc19c7019103ca44e8d94917eba8534c76133523ca8406822efdd19c9308", - "sha256:780077d95eafc2ccc3ced969db22377b3864e5b9a0ea5eb347cc93b3ea900315", - "sha256:7ba9cc93a91d86365a5d270dee221fdc04fb68d7478e6bf6af650de78a8339e3", - "sha256:89b16a18e7bba224ce5114db863e7029803c179979e1af6ad6a6b11f70545008", - "sha256:9036d6365d13b6cbe8f27a0eaf73ddcc070cae584e5ff94bb45e3e9d729feab5", - "sha256:93cf4e045bae74c90ca833cba583c14b62cb4ba2cba0abd2b141ab52548247e2", - "sha256:9ad014faa93dbb52c80d8f4d3dcf855865c876c9660cb9bd7553843dd03a4b1e", - "sha256:9b1d07b53b78bf84a96898c1bc139ad7f10fda7423f5fd158fd0f47ec5e01ac7", - "sha256:a7746f235c47abc72b102d3bce9977714c2444bdfaea7888d241b4c4bb6a78bf", - "sha256:aa3017c40d513ccac9621a2364f939d39e550c542eb2a894b4c8da92b38896ab", - "sha256:b34d87e8a3090ea626003f87f9392b3929a7bbf4104a05b6667348b6bd4bf1cd", - "sha256:b541032178a718c165a49638d28272b771053f628382d5e9d1c93df23ff58dbf", - "sha256:ba5511d8f31c033a5fcbda22dd5c813630af98c70b2661f2d2c654ae3cdfcfc8", - "sha256:bc8a37ad5b22c08e2dbd27df2b3ef7e5c0864235805b1e718a235bcb200cf1cb", - "sha256:bff7d8ec20f5f42607599f9994770fa65d76edca264a87b5e4ea5629bce12268", - "sha256:c1ad395cf254c4fbb5b2132fee391f361a6e8c1adbd28f2cd8e79308a615fe9d", - "sha256:f1d09e520217618e76396377c81fba6f290d5f926f50c35f3a5f72b01a0da780", - "sha256:f3eac17d9ec51be534685ba877b6ab5edc3ab7ec95c8f163e5d7b39859524716", - "sha256:f419290bc8968a46c4933158c91a0012b7a99bb2e465d5ef5293879742f8797e", - "sha256:f62aa6ee4eb43b024b0e5a01cf65a0bb078ef8c395e8713c6e8a12a697144528", - "sha256:f74e6fdeb9a265624ec3a3918430205dff1df7e95a230779746a6af78bc615af", - "sha256:f9b57eaa3b0cd8db52049ed0330747b0364e899e8a606a624813452b8203d5f7", - "sha256:fce4f615f8ca31b2e61aa0eb5865a21e14f5629515c9151850aa936c02a1ee51" + "sha256:02935e2c3c0c6cbe9c7955a8efa8908dd4221d7755644c59d1bba28b94fd334f", + "sha256:0349b025e15ea9d05c3d63f9657707a4e1d471128a3b1d876c095f328f8ff7f0", + "sha256:09d6a2032faf25e8d0cadde7fd6145118ac55d2740132c1d845f98721b5ebcfd", + "sha256:0bc61b307655d1a7f9f4b043628b9f2b721e80839914ede634e3d485913e1fb2", + "sha256:0eec19f8af947a61e968d5429f0bd92fec46d92b0008d0a6685b40d6adf8a4f4", + "sha256:106397dbbb1896f99e044efc90360d098b3335060375c26aa89c0d8a97c5f648", + "sha256:128c41c085cab8a85dc29e66ed88c05613dccf6bc28b3866cd16050a2f5448be", + "sha256:149d1113ac15005652e8d0d3f6fd599360e1a708a4f98e43c9c77834a28238cb", + "sha256:159ff6ee4c4a36a23fe01b7c3d07bd8c14cc433d9720f977fcd52c13c0098160", + "sha256:22ea3bb552ade325530e72a0c557cdf2dea8914d3a5e1fecf58fa5dbcc6f43cd", + "sha256:23ae9f0c2d889b7b2d88a3791f6c09e2ef827c2446f1c4a3e3e76328ee4afd9a", + "sha256:250c16b277e3b809ac20d1f590716597481061b514223c7badb7a0f9993c7f84", + "sha256:2ec6c689c61df613b783aeb21f945c4cbe6c51c28cb70aae8430577ab39f163e", + "sha256:2ffbb1acd69fdf8e89dd60ef6182ca90a743620957afb7066385a7bbe88dc748", + "sha256:3074634ea4d6df66be04f6728ee1d173cfded75d002c75fac79503a880bf3825", + "sha256:356ca982c188acbfa6af0d694284d8cf20e95b1c3d0aefa8929376fea9146f60", + "sha256:3fbe72d347fbc59f94124125e73fc4976a06927ebc503ec5afbfb35f193cd957", + "sha256:40c7ff5da22cd391944a28c6a9c638a5eef77fcf71d6e3a79e1d9d9e82752715", + "sha256:41184c416143defa34cc8eb9d070b0a5ba4f13a0fa96a709e20584638254b317", + "sha256:451e854cfae0febe723077bd0cf0a4302a5d84ff25f0bfece8f29206c7bed02e", + "sha256:4525b88c11906d5ab1b0ec1f290996c0020dd318af8b49acaa46f198b1ffc283", + "sha256:463247edcee4a5537841d5350bc87fe8e92d7dd0e8c71c995d2c6eecb8208278", + "sha256:4dbd80e453bd34bd003b16bd802fac70ad76bd463f81f0c518d1245b1c55e3d9", + "sha256:57b4012e04cc12b78590a334907e01b3a85efb2107df2b8733ff1ed05fce71de", + "sha256:5a8c863ceacae696aff37d1fd636121f1a512117652e5dfb86031c8d84836369", + "sha256:5acea83b801e98541619af398cc0109ff48016955cc0818f478ee9ef1c5c3dcb", + "sha256:642199e98af1bd2b6aeb8ecf726972d238c9877b0f6e8221ee5ab945ec8a2189", + "sha256:64bd6e1762cd7f0986a740fee4dff927b9ec2c5e4d9a28d056eb17d332158014", + "sha256:6d9fc9d812c81e6168b6d405bf00b8d6739a7f72ef22a9214c4241e0dc70b323", + "sha256:7079129b64cb78bdc8d611d1fd7e8002c0a2565da6a47c4df8062349fee90e3e", + "sha256:7dca87ca328f5ea7dafc907c5ec100d187911f94825f8700caac0b3f4c384b49", + "sha256:860fd59990c37c3ef913c3ae390b3929d005243acca1a86facb0773e2d8d9e50", + "sha256:8e6da5cffbbe571f93588f562ed130ea63ee206d12851b60819512dd3e1ba50d", + "sha256:8ec0636d3f7d68520afc6ac2dc4b8341ddb725039de042faf0e311599f54eb37", + "sha256:9491100aba630910489c1d0158034e1c9a6546f0b1340f716d522dc103788e39", + "sha256:97b974d3ba0fb4612b77ed35d7627490e8e3dff56ab41454d9e8b23448940576", + "sha256:995f9e8181723852ca458e22de5d9b7d3ba4da3f11cc1cb113f093b271d7965a", + "sha256:9dd47ff0cb2a656ad69c38da850df3454da88ee9a6fde0ba79acceee0e79daba", + "sha256:9fad446ad0bc886855ddf5909cbf8cb5d0faa637aaa6277fb4b19ade134ab3c7", + "sha256:a972cec723e0563aa0823ee2ab1df0cb196ed0778f173b381c871a03719d4826", + "sha256:ac9bea18d6d58a995fac1b2cb4488e17eceeac413af014b1dd26170b766d8467", + "sha256:b0531f0b0e07643eb089df4c509d30d72c9ef40defa53e41363eca8a8cc61495", + "sha256:b208cfd4f5fe34e1535c08983a1a6803fdbc7a1e86cf13dd0c61de0b51a0aadc", + "sha256:b3482cb7b3325faa5f6bc179649406058253d91ceda359c104dac0ad320e1391", + "sha256:b6fb9c32a91ec32a689ec6410def76443e3c750e7cfc3fb2206b985ffb2b85f0", + "sha256:b78ea78450fd96a498f50ee096f69c75379af5138f7881a51355ab0e11286c97", + "sha256:bd249bc894af67cbd8bad2c22e7cbcd46cf87ddfca1f1289d1e7e54868cc785c", + "sha256:c7d1fd447e33ee20c1f33f2c8e6634211124a9aabde3c617687d8b739aa69eac", + "sha256:d0bbe7dd86dca64854f4b6ce2ea5c60b51e36dfd597300057cf473d3615f2369", + "sha256:d6d6a0910c3b4368d89dde073e630882cdb266755565155bc33520283b2d9df8", + "sha256:da1eeb460ecce8d5b8608826595c777728cdf28ce7b5a5a8c8ac8d949beadcf2", + "sha256:e0c8854b09bc4de7b041148d8550d3bd712b5c21ff6a8ed308085f190235d7ff", + "sha256:e0d4142eb40ca6f94539e4db929410f2a46052a0fe7a2c1c59f6179c39938d2a", + "sha256:e9e82dcb3f2ebbc8cb5ce1102d5f1c5ed236bf8a11730fb45ba82e2841ec21df", + "sha256:ed6906f61834d687738d25988ae117683705636936cc605be0bb208b23df4d8f" ], "markers": "python_version == '3.11'", - "version": "==2.2.1" + "version": "==2.2.2" }, "opensearch-py": { "hashes": [ @@ -1099,11 +1099,11 @@ }, "pydantic": { "hashes": [ - "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff", - "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53" + "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584", + "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236" ], "markers": "python_version >= '3.8'", - "version": "==2.10.5" + "version": "==2.10.6" }, "pydantic-core": { "hashes": [ @@ -1321,20 +1321,20 @@ }, "rdflib": { "hashes": [ - "sha256:4fc8f6d50b199dc38fbc5256370f038c1cedca6102ccbde4e37c0fd2b7f36e65", - "sha256:5a694a64f48a751079999c37dccf91a6210077d845d09adf7c3ce23a876265a7" + "sha256:5402310a9f0f3c07d453d73fd0ad6ba35616286fe95d3670db2b725f3f539673", + "sha256:f3dcb4c106a8cd9e060d92f43d593d09ebc3d07adc244f4c7315856a12e383ee" ], "index": "pypi", - "markers": "python_version >= '3.9' and python_version < '4'", - "version": "==7.1.2" + "markers": "python_full_version >= '3.8.1' and python_full_version < '4.0.0'", + "version": "==7.1.3" }, "referencing": { "hashes": [ - "sha256:363d9c65f080d0d70bc41c721dce3c7f3e77fc09f269cd5c8813da18069a6794", - "sha256:ca2e6492769e3602957e9b831b94211599d2aade9477f5d44110d2530cf9aade" + "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", + "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0" ], "markers": "python_version >= '3.9'", - "version": "==0.36.1" + "version": "==0.36.2" }, "requests": { "hashes": [ @@ -1574,11 +1574,11 @@ }, "tzdata": { "hashes": [ - "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc", - "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd" + "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694", + "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639" ], "markers": "python_version >= '2'", - "version": "==2024.2" + "version": "==2025.1" }, "urllib3": { "hashes": [ diff --git a/dbrepo-search-service/init/Pipfile b/dbrepo-search-service/init/Pipfile index 77bab3e84c036d88689f0431bf63dc2f5fe4d099..b74ed7bc40da1da1c51c401b53a1da2676fb739e 100644 --- a/dbrepo-search-service/init/Pipfile +++ b/dbrepo-search-service/init/Pipfile @@ -9,7 +9,7 @@ opensearch-py = "~=2.2" python-dotenv = "~=1.0" testcontainers-opensearch = "*" pytest = "*" -dbrepo = {path = "./lib/dbrepo-1.6.1.tar.gz"} +dbrepo = {path = "./lib/dbrepo-1.6.3.tar.gz"} rdflib = "*" [dev-packages] diff --git a/dbrepo-search-service/init/Pipfile.lock b/dbrepo-search-service/init/Pipfile.lock index bf53ace7e7551b8e0961373d6ab23e49ff53f300..039873e7c5ffd4b2e5c6352027f7f501254ce5c6 100644 --- a/dbrepo-search-service/init/Pipfile.lock +++ b/dbrepo-search-service/init/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "9edba52503b8604b267d52e41954beba012143b1e47f56aaae553cdcaf054e55" + "sha256": "dac534d1eb6a0942c0e296c8a58491847c65d3ca23315039a3725591c86f694f" }, "pipfile-spec": 6, "requires": { @@ -124,11 +124,11 @@ }, "attrs": { "hashes": [ - "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", - "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308" + "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e", + "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a" ], "markers": "python_version >= '3.8'", - "version": "==24.3.0" + "version": "==25.1.0" }, "blinker": { "hashes": [ @@ -254,10 +254,9 @@ }, "dbrepo": { "hashes": [ - "sha256:251f3c2088bbd289cee86d5394b1e62e29aa081f994dd0845d895e3330f6a106" + "sha256:ac99f4bd19961f08665abd513e4d9452fcea5554f122457840e95f90698bab4d" ], - "path": "./lib/dbrepo-1.6.1.tar.gz", - "version": "==1.6.1" + "path": "./lib/dbrepo-1.6.3.tar.gz" }, "docker": { "hashes": [ @@ -279,6 +278,7 @@ "sha256:f69fcd559dc907ed196ab9df0e48471709175e696d6e698dd4dbe940f96ce66b" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==2.3.3" }, "frozenlist": { @@ -578,64 +578,64 @@ }, "numpy": { "hashes": [ - "sha256:059e6a747ae84fce488c3ee397cee7e5f905fd1bda5fb18c66bc41807ff119b2", - "sha256:08ef779aed40dbc52729d6ffe7dd51df85796a702afbf68a4f4e41fafdc8bda5", - "sha256:164a829b6aacf79ca47ba4814b130c4020b202522a93d7bff2202bfb33b61c60", - "sha256:26c9c4382b19fcfbbed3238a14abf7ff223890ea1936b8890f058e7ba35e8d71", - "sha256:27f5cdf9f493b35f7e41e8368e7d7b4bbafaf9660cba53fb21d2cd174ec09631", - "sha256:31b89fa67a8042e96715c68e071a1200c4e172f93b0fbe01a14c0ff3ff820fc8", - "sha256:32cb94448be47c500d2c7a95f93e2f21a01f1fd05dd2beea1ccd049bb6001cd2", - "sha256:360137f8fb1b753c5cde3ac388597ad680eccbbbb3865ab65efea062c4a1fd16", - "sha256:3683a8d166f2692664262fd4900f207791d005fb088d7fdb973cc8d663626faa", - "sha256:38efc1e56b73cc9b182fe55e56e63b044dd26a72128fd2fbd502f75555d92591", - "sha256:3d03883435a19794e41f147612a77a8f56d4e52822337844fff3d4040a142964", - "sha256:3ecc47cd7f6ea0336042be87d9e7da378e5c7e9b3c8ad0f7c966f714fc10d821", - "sha256:40f9e544c1c56ba8f1cf7686a8c9b5bb249e665d40d626a23899ba6d5d9e1484", - "sha256:4250888bcb96617e00bfa28ac24850a83c9f3a16db471eca2ee1f1714df0f957", - "sha256:4511d9e6071452b944207c8ce46ad2f897307910b402ea5fa975da32e0102800", - "sha256:45681fd7128c8ad1c379f0ca0776a8b0c6583d2f69889ddac01559dfe4390918", - "sha256:48fd472630715e1c1c89bf1feab55c29098cb403cc184b4859f9c86d4fcb6a95", - "sha256:4c86e2a209199ead7ee0af65e1d9992d1dce7e1f63c4b9a616500f93820658d0", - "sha256:4dfda918a13cc4f81e9118dea249e192ab167a0bb1966272d5503e39234d694e", - "sha256:5062dc1a4e32a10dc2b8b13cedd58988261416e811c1dc4dbdea4f57eea61b0d", - "sha256:51faf345324db860b515d3f364eaa93d0e0551a88d6218a7d61286554d190d73", - "sha256:526fc406ab991a340744aad7e25251dd47a6720a685fa3331e5c59fef5282a59", - "sha256:53c09385ff0b72ba79d8715683c1168c12e0b6e84fb0372e97553d1ea91efe51", - "sha256:55ba24ebe208344aa7a00e4482f65742969a039c2acfcb910bc6fcd776eb4355", - "sha256:5b6c390bfaef8c45a260554888966618328d30e72173697e5cabe6b285fb2348", - "sha256:5c5cc0cbabe9452038ed984d05ac87910f89370b9242371bd9079cb4af61811e", - "sha256:5edb4e4caf751c1518e6a26a83501fda79bff41cc59dac48d70e6d65d4ec4440", - "sha256:61048b4a49b1c93fe13426e04e04fdf5a03f456616f6e98c7576144677598675", - "sha256:676f4eebf6b2d430300f1f4f4c2461685f8269f94c89698d832cdf9277f30b84", - "sha256:67d4cda6fa6ffa073b08c8372aa5fa767ceb10c9a0587c707505a6d426f4e046", - "sha256:694f9e921a0c8f252980e85bce61ebbd07ed2b7d4fa72d0e4246f2f8aa6642ab", - "sha256:733585f9f4b62e9b3528dd1070ec4f52b8acf64215b60a845fa13ebd73cd0712", - "sha256:7671dc19c7019103ca44e8d94917eba8534c76133523ca8406822efdd19c9308", - "sha256:780077d95eafc2ccc3ced969db22377b3864e5b9a0ea5eb347cc93b3ea900315", - "sha256:7ba9cc93a91d86365a5d270dee221fdc04fb68d7478e6bf6af650de78a8339e3", - "sha256:89b16a18e7bba224ce5114db863e7029803c179979e1af6ad6a6b11f70545008", - "sha256:9036d6365d13b6cbe8f27a0eaf73ddcc070cae584e5ff94bb45e3e9d729feab5", - "sha256:93cf4e045bae74c90ca833cba583c14b62cb4ba2cba0abd2b141ab52548247e2", - "sha256:9ad014faa93dbb52c80d8f4d3dcf855865c876c9660cb9bd7553843dd03a4b1e", - "sha256:9b1d07b53b78bf84a96898c1bc139ad7f10fda7423f5fd158fd0f47ec5e01ac7", - "sha256:a7746f235c47abc72b102d3bce9977714c2444bdfaea7888d241b4c4bb6a78bf", - "sha256:aa3017c40d513ccac9621a2364f939d39e550c542eb2a894b4c8da92b38896ab", - "sha256:b34d87e8a3090ea626003f87f9392b3929a7bbf4104a05b6667348b6bd4bf1cd", - "sha256:b541032178a718c165a49638d28272b771053f628382d5e9d1c93df23ff58dbf", - "sha256:ba5511d8f31c033a5fcbda22dd5c813630af98c70b2661f2d2c654ae3cdfcfc8", - "sha256:bc8a37ad5b22c08e2dbd27df2b3ef7e5c0864235805b1e718a235bcb200cf1cb", - "sha256:bff7d8ec20f5f42607599f9994770fa65d76edca264a87b5e4ea5629bce12268", - "sha256:c1ad395cf254c4fbb5b2132fee391f361a6e8c1adbd28f2cd8e79308a615fe9d", - "sha256:f1d09e520217618e76396377c81fba6f290d5f926f50c35f3a5f72b01a0da780", - "sha256:f3eac17d9ec51be534685ba877b6ab5edc3ab7ec95c8f163e5d7b39859524716", - "sha256:f419290bc8968a46c4933158c91a0012b7a99bb2e465d5ef5293879742f8797e", - "sha256:f62aa6ee4eb43b024b0e5a01cf65a0bb078ef8c395e8713c6e8a12a697144528", - "sha256:f74e6fdeb9a265624ec3a3918430205dff1df7e95a230779746a6af78bc615af", - "sha256:f9b57eaa3b0cd8db52049ed0330747b0364e899e8a606a624813452b8203d5f7", - "sha256:fce4f615f8ca31b2e61aa0eb5865a21e14f5629515c9151850aa936c02a1ee51" + "sha256:02935e2c3c0c6cbe9c7955a8efa8908dd4221d7755644c59d1bba28b94fd334f", + "sha256:0349b025e15ea9d05c3d63f9657707a4e1d471128a3b1d876c095f328f8ff7f0", + "sha256:09d6a2032faf25e8d0cadde7fd6145118ac55d2740132c1d845f98721b5ebcfd", + "sha256:0bc61b307655d1a7f9f4b043628b9f2b721e80839914ede634e3d485913e1fb2", + "sha256:0eec19f8af947a61e968d5429f0bd92fec46d92b0008d0a6685b40d6adf8a4f4", + "sha256:106397dbbb1896f99e044efc90360d098b3335060375c26aa89c0d8a97c5f648", + "sha256:128c41c085cab8a85dc29e66ed88c05613dccf6bc28b3866cd16050a2f5448be", + "sha256:149d1113ac15005652e8d0d3f6fd599360e1a708a4f98e43c9c77834a28238cb", + "sha256:159ff6ee4c4a36a23fe01b7c3d07bd8c14cc433d9720f977fcd52c13c0098160", + "sha256:22ea3bb552ade325530e72a0c557cdf2dea8914d3a5e1fecf58fa5dbcc6f43cd", + "sha256:23ae9f0c2d889b7b2d88a3791f6c09e2ef827c2446f1c4a3e3e76328ee4afd9a", + "sha256:250c16b277e3b809ac20d1f590716597481061b514223c7badb7a0f9993c7f84", + "sha256:2ec6c689c61df613b783aeb21f945c4cbe6c51c28cb70aae8430577ab39f163e", + "sha256:2ffbb1acd69fdf8e89dd60ef6182ca90a743620957afb7066385a7bbe88dc748", + "sha256:3074634ea4d6df66be04f6728ee1d173cfded75d002c75fac79503a880bf3825", + "sha256:356ca982c188acbfa6af0d694284d8cf20e95b1c3d0aefa8929376fea9146f60", + "sha256:3fbe72d347fbc59f94124125e73fc4976a06927ebc503ec5afbfb35f193cd957", + "sha256:40c7ff5da22cd391944a28c6a9c638a5eef77fcf71d6e3a79e1d9d9e82752715", + "sha256:41184c416143defa34cc8eb9d070b0a5ba4f13a0fa96a709e20584638254b317", + "sha256:451e854cfae0febe723077bd0cf0a4302a5d84ff25f0bfece8f29206c7bed02e", + "sha256:4525b88c11906d5ab1b0ec1f290996c0020dd318af8b49acaa46f198b1ffc283", + "sha256:463247edcee4a5537841d5350bc87fe8e92d7dd0e8c71c995d2c6eecb8208278", + "sha256:4dbd80e453bd34bd003b16bd802fac70ad76bd463f81f0c518d1245b1c55e3d9", + "sha256:57b4012e04cc12b78590a334907e01b3a85efb2107df2b8733ff1ed05fce71de", + "sha256:5a8c863ceacae696aff37d1fd636121f1a512117652e5dfb86031c8d84836369", + "sha256:5acea83b801e98541619af398cc0109ff48016955cc0818f478ee9ef1c5c3dcb", + "sha256:642199e98af1bd2b6aeb8ecf726972d238c9877b0f6e8221ee5ab945ec8a2189", + "sha256:64bd6e1762cd7f0986a740fee4dff927b9ec2c5e4d9a28d056eb17d332158014", + "sha256:6d9fc9d812c81e6168b6d405bf00b8d6739a7f72ef22a9214c4241e0dc70b323", + "sha256:7079129b64cb78bdc8d611d1fd7e8002c0a2565da6a47c4df8062349fee90e3e", + "sha256:7dca87ca328f5ea7dafc907c5ec100d187911f94825f8700caac0b3f4c384b49", + "sha256:860fd59990c37c3ef913c3ae390b3929d005243acca1a86facb0773e2d8d9e50", + "sha256:8e6da5cffbbe571f93588f562ed130ea63ee206d12851b60819512dd3e1ba50d", + "sha256:8ec0636d3f7d68520afc6ac2dc4b8341ddb725039de042faf0e311599f54eb37", + "sha256:9491100aba630910489c1d0158034e1c9a6546f0b1340f716d522dc103788e39", + "sha256:97b974d3ba0fb4612b77ed35d7627490e8e3dff56ab41454d9e8b23448940576", + "sha256:995f9e8181723852ca458e22de5d9b7d3ba4da3f11cc1cb113f093b271d7965a", + "sha256:9dd47ff0cb2a656ad69c38da850df3454da88ee9a6fde0ba79acceee0e79daba", + "sha256:9fad446ad0bc886855ddf5909cbf8cb5d0faa637aaa6277fb4b19ade134ab3c7", + "sha256:a972cec723e0563aa0823ee2ab1df0cb196ed0778f173b381c871a03719d4826", + "sha256:ac9bea18d6d58a995fac1b2cb4488e17eceeac413af014b1dd26170b766d8467", + "sha256:b0531f0b0e07643eb089df4c509d30d72c9ef40defa53e41363eca8a8cc61495", + "sha256:b208cfd4f5fe34e1535c08983a1a6803fdbc7a1e86cf13dd0c61de0b51a0aadc", + "sha256:b3482cb7b3325faa5f6bc179649406058253d91ceda359c104dac0ad320e1391", + "sha256:b6fb9c32a91ec32a689ec6410def76443e3c750e7cfc3fb2206b985ffb2b85f0", + "sha256:b78ea78450fd96a498f50ee096f69c75379af5138f7881a51355ab0e11286c97", + "sha256:bd249bc894af67cbd8bad2c22e7cbcd46cf87ddfca1f1289d1e7e54868cc785c", + "sha256:c7d1fd447e33ee20c1f33f2c8e6634211124a9aabde3c617687d8b739aa69eac", + "sha256:d0bbe7dd86dca64854f4b6ce2ea5c60b51e36dfd597300057cf473d3615f2369", + "sha256:d6d6a0910c3b4368d89dde073e630882cdb266755565155bc33520283b2d9df8", + "sha256:da1eeb460ecce8d5b8608826595c777728cdf28ce7b5a5a8c8ac8d949beadcf2", + "sha256:e0c8854b09bc4de7b041148d8550d3bd712b5c21ff6a8ed308085f190235d7ff", + "sha256:e0d4142eb40ca6f94539e4db929410f2a46052a0fe7a2c1c59f6179c39938d2a", + "sha256:e9e82dcb3f2ebbc8cb5ce1102d5f1c5ed236bf8a11730fb45ba82e2841ec21df", + "sha256:ed6906f61834d687738d25988ae117683705636936cc605be0bb208b23df4d8f" ], "markers": "python_version == '3.11'", - "version": "==2.2.1" + "version": "==2.2.2" }, "opensearch-py": { "hashes": [ @@ -643,6 +643,7 @@ "sha256:6598df0bc7a003294edd0ba88a331e0793acbb8c910c43edf398791e3b2eccda" ], "index": "pypi", + "markers": "python_version >= '3.8' and python_version < '4'", "version": "==2.8.0" }, "packaging": { @@ -807,11 +808,11 @@ }, "pydantic": { "hashes": [ - "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff", - "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53" + "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584", + "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236" ], "markers": "python_version >= '3.8'", - "version": "==2.10.5" + "version": "==2.10.6" }, "pydantic-core": { "hashes": [ @@ -933,6 +934,7 @@ "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==8.3.4" }, "python-dateutil": { @@ -949,6 +951,7 @@ "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==1.0.1" }, "pytz": { @@ -960,11 +963,12 @@ }, "rdflib": { "hashes": [ - "sha256:4fc8f6d50b199dc38fbc5256370f038c1cedca6102ccbde4e37c0fd2b7f36e65", - "sha256:5a694a64f48a751079999c37dccf91a6210077d845d09adf7c3ce23a876265a7" + "sha256:5402310a9f0f3c07d453d73fd0ad6ba35616286fe95d3670db2b725f3f539673", + "sha256:f3dcb4c106a8cd9e060d92f43d593d09ebc3d07adc244f4c7315856a12e383ee" ], "index": "pypi", - "version": "==7.1.2" + "markers": "python_full_version >= '3.8.1' and python_full_version < '4.0.0'", + "version": "==7.1.3" }, "requests": { "hashes": [ @@ -994,6 +998,7 @@ "sha256:0bdf270b5b7f53915832f7c31dd2bd3ffdc20b534ea6b32231cc7003049bd0e1" ], "index": "pypi", + "markers": "python_version >= '3.7'", "version": "==0.0.1rc1" }, "tinydb": { @@ -1022,11 +1027,11 @@ }, "tzdata": { "hashes": [ - "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc", - "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd" + "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694", + "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639" ], "markers": "python_version >= '2'", - "version": "==2024.2" + "version": "==2025.1" }, "urllib3": { "hashes": [ @@ -1285,6 +1290,7 @@ "sha256:fd34e7b3405f0cc7ab03d54a334c17a9e802897580d964bd8c2001f4b9fd488f" ], "index": "pypi", + "markers": "python_version >= '3.9'", "version": "==7.6.10" }, "iniconfig": { @@ -1317,6 +1323,7 @@ "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761" ], "index": "pypi", + "markers": "python_version >= '3.8'", "version": "==8.3.4" } } diff --git a/dbrepo-search-service/init/lib/dbrepo-1.6.0.tar.gz b/dbrepo-search-service/init/lib/dbrepo-1.6.0.tar.gz deleted file mode 100644 index 80c2ba74f662e7b02895122a37e301fde2157b82..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/init/lib/dbrepo-1.6.0.tar.gz and /dev/null differ diff --git a/dbrepo-search-service/init/lib/dbrepo-1.6.1.tar.gz b/dbrepo-search-service/init/lib/dbrepo-1.6.1.tar.gz deleted file mode 100644 index 7914db1bb84dddf85611cda3b766c0c0cdc094c7..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/init/lib/dbrepo-1.6.1.tar.gz and /dev/null differ diff --git a/dbrepo-search-service/init/lib/dbrepo-1.6.3-py3-none-any.whl b/dbrepo-search-service/init/lib/dbrepo-1.6.3-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..b7f45eecc067d496a9d39d189e619ac7524c66b1 Binary files /dev/null and b/dbrepo-search-service/init/lib/dbrepo-1.6.3-py3-none-any.whl differ diff --git a/dbrepo-search-service/init/lib/dbrepo-1.6.3.tar.gz b/dbrepo-search-service/init/lib/dbrepo-1.6.3.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..2aa4f75ed8dd08245bd29d34c151dbe9b7eb2253 Binary files /dev/null and b/dbrepo-search-service/init/lib/dbrepo-1.6.3.tar.gz differ diff --git a/dbrepo-search-service/lib/dbrepo-1.6.0.tar.gz b/dbrepo-search-service/lib/dbrepo-1.6.0.tar.gz deleted file mode 100644 index 80c2ba74f662e7b02895122a37e301fde2157b82..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/lib/dbrepo-1.6.0.tar.gz and /dev/null differ diff --git a/dbrepo-search-service/lib/dbrepo-1.6.1.tar.gz b/dbrepo-search-service/lib/dbrepo-1.6.1.tar.gz deleted file mode 100644 index 7914db1bb84dddf85611cda3b766c0c0cdc094c7..0000000000000000000000000000000000000000 Binary files a/dbrepo-search-service/lib/dbrepo-1.6.1.tar.gz and /dev/null differ diff --git a/dbrepo-search-service/lib/dbrepo-1.6.3-py3-none-any.whl b/dbrepo-search-service/lib/dbrepo-1.6.3-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..b7f45eecc067d496a9d39d189e619ac7524c66b1 Binary files /dev/null and b/dbrepo-search-service/lib/dbrepo-1.6.3-py3-none-any.whl differ diff --git a/dbrepo-search-service/lib/dbrepo-1.6.3.tar.gz b/dbrepo-search-service/lib/dbrepo-1.6.3.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..2aa4f75ed8dd08245bd29d34c151dbe9b7eb2253 Binary files /dev/null and b/dbrepo-search-service/lib/dbrepo-1.6.3.tar.gz differ diff --git a/dbrepo-search-service/test/test_opensearch_client.py b/dbrepo-search-service/test/test_opensearch_client.py index 9da77adfde53e155dddc36f364bea9d974964125..edbdff683dff0f66319d87fb064fdeab6931bca0 100644 --- a/dbrepo-search-service/test/test_opensearch_client.py +++ b/dbrepo-search-service/test/test_opensearch_client.py @@ -2,7 +2,7 @@ import unittest import opensearchpy from dbrepo.api.dto import Database, Table, Column, ColumnType, Constraints, PrimaryKey, \ - TableMinimal, ColumnMinimal, ConceptBrief, UnitBrief, UserBrief, ContainerBrief, ImageBrief + ConceptBrief, UnitBrief, UserBrief, ContainerBrief, ImageBrief, TableBrief, ColumnBrief from opensearchpy import NotFoundError from app import app @@ -57,10 +57,6 @@ class OpenSearchClientTest(unittest.TestCase): def test_update_database_succeeds(self): with app.app_context(): - # mock - OpenSearchClient().update_database(database_id=req.id, data=req) - - # test req.tables = [Table(id=1, name="Test Table", internal_name="test_table", @@ -71,10 +67,20 @@ class OpenSearchClientTest(unittest.TestCase): database_id=req.id, constraints=Constraints(uniques=[], foreign_keys=[], checks=[], primary_key=[PrimaryKey(id=1, - table=TableMinimal(id=1, - database_id=req.id), - column=ColumnMinimal(id=1, table_id=1, - database_id=req.id))]), + table=TableBrief(id=1, + database_id=req.id, + name="Test Table", + internal_name="test_table", + is_public=True, + is_schema_public=True, + is_versioned=True, + owned_by="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502"), + column=ColumnBrief(id=1, + name="ID", + database_id=req.id, + table_id=1, + internal_name="id", + type=ColumnType.BIGINT))]), is_versioned=True, owner=UserBrief(id="c6b71ef5-2d2f-48b2-9d79-b8f23a3a0502", username="foo"), columns=[Column(id=1, @@ -85,6 +91,10 @@ class OpenSearchClientTest(unittest.TestCase): internal_name="id", type=ColumnType.BIGINT, is_null_allowed=False)])] + # mock + OpenSearchClient().update_database(database_id=req.id, data=req) + + # test database = OpenSearchClient().update_database(database_id=req.id, data=req) self.assertEqual(1, database.id) self.assertEqual("Test", database.name) diff --git a/dbrepo-ui/bun.lockb b/dbrepo-ui/bun.lockb index 45a8c51c621dab127458d68a4493b23d2df9f88d..7ee1d3897245ee94212d8bfb6a6b97556b64f1d2 100755 Binary files a/dbrepo-ui/bun.lockb and b/dbrepo-ui/bun.lockb differ diff --git a/dbrepo-ui/components/JumboBox.vue b/dbrepo-ui/components/JumboBox.vue index d2b804f819f22782ba4895c601c8b2ea118ce4e3..5a26ec6139bff1a1b816c2acce1dc3fb08cd7207 100644 --- a/dbrepo-ui/components/JumboBox.vue +++ b/dbrepo-ui/components/JumboBox.vue @@ -21,6 +21,7 @@ </v-row> </div> </template> + <script> export default { props: { diff --git a/dbrepo-ui/components/Loading.vue b/dbrepo-ui/components/Loading.vue index 743701ab6724dba40d6baa0cb0cfafcb26061556..84094bfef8773aa306d977e6f0f7cbb4cca1dde9 100644 --- a/dbrepo-ui/components/Loading.vue +++ b/dbrepo-ui/components/Loading.vue @@ -7,6 +7,7 @@ indeterminate /> </v-list-item-title> </template> + <script> export default { props: { diff --git a/dbrepo-ui/components/OntologiesList.vue b/dbrepo-ui/components/OntologiesList.vue deleted file mode 100644 index c7120cac4a1e58e4a1f22c651f77aebcaf002584..0000000000000000000000000000000000000000 --- a/dbrepo-ui/components/OntologiesList.vue +++ /dev/null @@ -1,73 +0,0 @@ -<template> - <div> - <v-card - v-for="(ontology, idx) in ontologies" - :key="idx" - :to="`/semantic/ontology/${ontology.id}`" - variant="flat" - rounded="0"> - <v-divider - class="mx-4" /> - <v-card-title> - {{ ontology.prefix }} - </v-card-title> - <v-card-subtitle> - {{ ontology.uri }} - </v-card-subtitle> - <v-card-text> - <div - class="db-tags"> - <v-chip - v-if="ontology.sparql" - size="small" - color="success" - text="SPARQL" - variant="outlined" /> - <v-chip - v-if="ontology.rdf" - size="small" - text="RDF" - variant="outlined" /> - </div> - </v-card-text> - </v-card> - </div> -</template> - -<script> -import { useUserStore } from '@/stores/user.js' -import { useCacheStore } from '@/stores/cache.js' - -export default { - data () { - return { - userStore: useUserStore(), - cacheStore: useCacheStore() - } - }, - computed: { - token () { - return this.userStore.getToken - }, - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles - }, - ontologies () { - return this.cacheStore.getOntologies - } - }, - mounted () { - }, - methods: { - } -} -</script> - -<style> -.db-tags .v-chip:not(:first-child) { - margin-left: 4px; -} -</style> diff --git a/dbrepo-ui/components/ResourceStatus.vue b/dbrepo-ui/components/ResourceStatus.vue index 5167d899ea6e73c150db478f8fc3b063a3ba1e12..6db6d25385359ee82086b510537107fb3d0d0f31 100644 --- a/dbrepo-ui/components/ResourceStatus.vue +++ b/dbrepo-ui/components/ResourceStatus.vue @@ -5,7 +5,7 @@ v-if="!inline" :size="size" :color="color" - variant="outlined"> + :variant="chipVariant"> {{ status }} </v-chip> <span @@ -14,6 +14,7 @@ </span> </span> </template> + <script> export default { props: { @@ -38,6 +39,9 @@ export default { if (!this.resource) { return null } + if (this.hasIdentifier) { + return 'pid' + } if (!this.resource.is_public && !this.resource.is_schema_public) { return 'draft' } else if(!this.resource.is_public && this.resource.is_schema_public) { @@ -53,7 +57,19 @@ export default { } return this.$t(`pages.database.status.${this.mode}`) }, + hasIdentifier () { + return this.resource.identifiers?.length > 0 + }, + chipVariant () { + if (this.hasIdentifier) { + return 'tonal' + } + return 'outlined' + }, color () { + if (this.hasIdentifier) { + return 'info' + } switch (this.mode) { case 'schema': case 'data': diff --git a/dbrepo-ui/components/TimeDrift.vue b/dbrepo-ui/components/TimeDrift.vue deleted file mode 100644 index 2f2555f9f84f107dff1ffd12ad75533d388c1f62..0000000000000000000000000000000000000000 --- a/dbrepo-ui/components/TimeDrift.vue +++ /dev/null @@ -1,44 +0,0 @@ -<template> - <v-alert - v-cloak - v-if="timestamp && offSeconds > 3" - class="banner" - border="start" - type="warning"> - {{ $t('error.data.drift') + ' ' + offSeconds + 's' }} - </v-alert> -</template> - -<script> -import { formatTimestamp, timestampsToHumanDifference } from '@/utils' - -export default { - data () { - return { - timestamp: null - } - }, - computed: { - drift () { - return this.timestampsToHumanDifference(Date.now(), this.timestamp) - }, - offSeconds () { - if (!this.timestamp) { - return null - } - return (Date.now().valueOf() - Date.parse(this.timestamp)) / 1000 - } - }, - mounted() { - const databaseService = useDatabaseService() - databaseService.getServerTime() - .then((timestamp) => { - this.timestamp = timestamp - }) - }, - methods: { - formatTimestamp, - timestampsToHumanDifference - } -} -</script> diff --git a/dbrepo-ui/components/database/DatabaseToolbar.vue b/dbrepo-ui/components/database/DatabaseToolbar.vue index 4177ae592cbae97090d0b109c576137b0ee74cbc..3e661cd754b98ca94519bda6a7f4ad49d4ff0378 100644 --- a/dbrepo-ui/components/database/DatabaseToolbar.vue +++ b/dbrepo-ui/components/database/DatabaseToolbar.vue @@ -83,7 +83,6 @@ <script> import { useCacheStore } from '@/stores/cache.js' -import { useUserStore } from '@/stores/user.js' import ResourceStatus from '@/components/ResourceStatus.vue' export default { @@ -94,8 +93,7 @@ export default { return { tab: null, error: false, - cacheStore: useCacheStore(), - userStore: useUserStore() + cacheStore: useCacheStore() } }, computed: { @@ -103,13 +101,13 @@ export default { return this.cacheStore.getDatabase }, access () { - return this.userStore.getAccess - }, - user () { - return this.userStore.getUser + return this.cacheStore.getAccess }, roles () { - return this.userStore.getRoles + return this.cacheStore.getRoles + }, + cacheUser () { + return this.cacheStore.getUser }, isContrastTheme () { return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') @@ -141,12 +139,6 @@ export default { } return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own' }, - canImportCsv () { - if (!this.user || !this.hasWriteAccess) { - return false - } - return this.roles.includes('insert-table-data') - }, canCreateSubset () { if (!this.database) { return false @@ -157,22 +149,22 @@ export default { return this.hasReadAccess }, canCreateView () { - if (!this.user || !this.isOwner) { + if (!this.cacheUser || !this.isOwner || !this.roles) { return false } return this.roles.includes('create-database-view') }, canCreateTable () { - if (!this.user || !this.hasWriteAccess) { + if (!this.cacheUser || !this.hasWriteAccess || !this.roles) { return false } return this.roles.includes('create-table') }, isOwner () { - if (!this.database || !this.user) { + if (!this.database || !this.cacheUser) { return false } - return this.database.owner.username === this.user.username + return this.database.owner.id === this.cacheUser.uid }, buttonVariant () { const runtimeConfig = useRuntimeConfig() diff --git a/dbrepo-ui/components/dialogs/EditTuple.vue b/dbrepo-ui/components/dialogs/EditTuple.vue index 3290d230d1bf216bd2f212c4fbe9c683901e4b96..75e824ed4316bad96843a57694b245d4caf01682 100644 --- a/dbrepo-ui/components/dialogs/EditTuple.vue +++ b/dbrepo-ui/components/dialogs/EditTuple.vue @@ -3,7 +3,7 @@ <v-form ref="form" v-model="valid" - @submit.prevent="submit"> + @submit.prevent="validate"> <v-card :title="title" :subtitle="this.$t('toolbars.table.data.subtitle')" @@ -17,12 +17,10 @@ <v-text-field v-if="isNumber(column)" v-model.number="tuple[column.internal_name]" - :disabled="!edit" persistent-hint :variant="inputVariant" :label="column.internal_name" :hint="hint(column)" - :rules="rules(column)" :required="required(column)" type="number"> <template @@ -48,11 +46,9 @@ <v-text-field v-if="isTextField(column)" v-model="tuple[column.internal_name]" - :disabled="disabled(column)" :clearable="!required(column)" :counter="maxLength(column) !== null" :maxlength="maxLength(column)" - :rules="rules(column)" :required="required(column)" persistent-hint :variant="inputVariant" @@ -82,10 +78,8 @@ <v-text-field v-if="isFloatingPoint(column)" v-model="tuple[column.internal_name]" - :disabled="disabled(column)" step=".1" :clearable="!required(column)" - :rules="rules(column)" :required="required(column)" persistent-hint :variant="inputVariant" @@ -115,10 +109,8 @@ <v-textarea v-if="isTextArea(column)" v-model="tuple[column.internal_name]" - :disabled="disabled(column)" rows="3" :clearable="!required(column)" - :rules="rules(column)" :required="required(column)" persistent-hint :variant="inputVariant" @@ -155,7 +147,6 @@ :variant="inputVariant" :label="column.internal_name" :hint="hint(column)" - :rules="rules(column)" :required="required(column)" :clearable="!required(column)" :items="isSet(column) ? column.sets : column.enums"> @@ -186,7 +177,6 @@ :variant="inputVariant" :label="column.internal_name" :hint="hint(column)" - :rules="rules(column)" :required="required(column)" :items="bools" :clearable="!required(column)"> @@ -322,10 +312,10 @@ export default { cacheStore: useCacheStore() } }, - mounted() { + mounted () { this.fetchContainer() - this.$refs.form.validate() this.oldTuple = Object.assign({}, this.tuple) + this.validate() }, computed: { database () { @@ -358,8 +348,17 @@ export default { return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.button.contrast : runtimeConfig.public.variant.button.normal } }, + watch: { + tuple: { + handler () { + this.validate() + }, + deep: true + } + }, methods: { - submit () { + validate () { + console.debug('validate form') this.$refs.form.validate() }, cancel () { @@ -425,18 +424,6 @@ export default { isTimeField (column) { return ['date', 'datetime', 'timestamp', 'time', 'year'].includes(column.type) }, - rules (column) { - if (column.is_null_allowed) { - return [] - } - const rules = [] - rules.push(v => v !== null || this.$t('validation.required')) - if (column.type === 'decimal' || column.type === 'double') { - rules.push(v => !(!v || v.split('.')[0].length > column.size) || `${this.$t('pages.table.subpages.data.float.max')} ${column.size} ${this.$t('pages.table.subpages.data.float.before')}`) - rules.push(v => !(!v || (column.d && v.split('.')[1].length > column.d)) || `${this.$t('pages.table.subpages.data.float.max')} ${column.d} ${this.$t('pages.table.subpages.data.float.after')}`) - } - return rules - }, maxLength (column) { if (!this.isTextField(column) || column.size === null) { return null @@ -446,9 +433,6 @@ export default { required (column) { return column.is_null_allowed === false }, - disabled (column) { - return (this.edit && column.is_primary_key) || !this.edit - }, updateTuple () { const constraints = {} this.primaryKeyColumns diff --git a/dbrepo-ui/components/identifier/Banner.vue b/dbrepo-ui/components/identifier/Banner.vue index 1450347c412727830e07f4fc1e11b857ab22c346..63c2a7153a03d4dd6742920e2e32d0813bbd9036 100644 --- a/dbrepo-ui/components/identifier/Banner.vue +++ b/dbrepo-ui/components/identifier/Banner.vue @@ -3,6 +3,7 @@ {{ prefix }}: <a :href="href">{{ displayName }}</a> </div> </template> + <script> export default { props: { @@ -23,7 +24,7 @@ export default { return identifierService.identifierToDisplayName(this.identifier) }, href () { - if (!this.identifier || (this.identifier.status && this.identifier.status !== 'published')) { + if (!this.identifier) { return null } const identifierService = useIdentifierService() diff --git a/dbrepo-ui/components/identifier/Citation.vue b/dbrepo-ui/components/identifier/Citation.vue index 5722351f0ab1d3697783f3f0f82c54c5452981d4..9ee434c943da8c011e0bfece1c88c06b525845a9 100644 --- a/dbrepo-ui/components/identifier/Citation.vue +++ b/dbrepo-ui/components/identifier/Citation.vue @@ -4,7 +4,7 @@ <v-col v-if="!loading" md="10"> - <pre>{{ citation }}</pre> + {{ citation }} </v-col> <v-col v-if="!$vuetify.display.mdAndDown" diff --git a/dbrepo-ui/components/identifier/Persist.vue b/dbrepo-ui/components/identifier/Persist.vue index 3dba450e634c6db374ccd28bd327ff2823756f3e..f37c5c6d7d9893562d94393fe6aa19ab3b448d79 100644 --- a/dbrepo-ui/components/identifier/Persist.vue +++ b/dbrepo-ui/components/identifier/Persist.vue @@ -12,6 +12,7 @@ <v-spacer /> <v-btn v-if="canSave" + class="mr-2" :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-content-save-outline' : null" color="secondary" variant="flat" @@ -22,7 +23,7 @@ @click="createOrSave"/> <v-btn v-if="canRemove" - class="ml-2" + class="mr-2" :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-delete' : null" color="error" variant="flat" @@ -32,7 +33,7 @@ @click="remove" /> <v-btn v-if="canPublish" - class="ml-2" + class="mr-2" :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-content-save-outline' : null" color="primary" variant="flat" @@ -138,14 +139,6 @@ :color="canShiftUp(creator, i) ? 'tertiary' : ''" :variant="buttonVariant" @click="shiftDown(i)" /> - <v-btn - v-if="canInsertSelf" - class="mr-2" - size="small" - color="secondary" - variant="flat" - :text="$t('pages.identifier.subpages.create.creators.insert.text')" - @click="insertSelf(creator)" /> <v-btn v-if="i > 0" size="small" @@ -830,7 +823,6 @@ <script> import { formatYearUTC, formatMonthUTC, formatDayUTC, languages } from '@/utils' import { useCacheStore } from '@/stores/cache.js' -import { useUserStore } from '@/stores/user.js' import { MerkleJson } from 'merkle-json' export default { @@ -962,16 +954,15 @@ export default { { value: 'IsObsoletedBy' }, { value: 'Obsoletes' } ], - cacheStore: useCacheStore(), - userStore: useUserStore() + cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser + cacheUser () { + return this.cacheStore.getUser }, roles () { - return this.userStore.getRoles + return this.cacheStore.getRoles }, isSubset () { return this.type === 'subset' @@ -1045,23 +1036,14 @@ export default { } } }, - isUpdate () { - return 'id' in this.identifier && this.identifier.id - }, - canInsertSelf () { - if (!this.user) { - return false - } - return this.user.given_name || this.user.family_name || this.user.attributes.affiliation || this.user.attributes.orcid - }, isCreator () { - if (!this.user || !this.identifier) { + if (!this.cacheUser || !this.identifier) { return false } - if (!this.identifier.creator) { + if (!this.identifier.owner) { return true } - return this.identifier.creator.id === this.user.id + return this.identifier.owner.id === this.cacheUser.uid }, formValid () { /* somehow Vue3/Vuetify3 validation form is broken for arrays */ @@ -1123,10 +1105,10 @@ export default { return this.roles.includes('create-identifier') && !this.isPublished }, canRemove () { - if (!this.roles || !this.identifier || !this.identifier.creator || !this.user) { + if (!this.roles || !this.identifier || !this.identifier.owner || !this.cacheUser) { return false } - return this.roles.includes('delete-identifier') && this.identifier.creator.id === this.user.id && !this.isPublished + return this.roles.includes('delete-identifier') && this.identifier.owner.id === this.cacheUser.uid && !this.isPublished }, canPublish () { if (!this.roles || !this.identifier || !this.roles.includes('publish-identifier') || this.isPublished || !this.identifier.id) { @@ -1494,15 +1476,15 @@ export default { if (this.isPublished) { return false } - if (this.user.attributes.orcid) { - creator.name_identifier = this.user.attributes.orcid + if (this.cacheUser.attributes.orcid) { + creator.name_identifier = this.cacheUser.attributes.orcid this.retrieveCreator(creator) return } - creator.firstname = this.user.given_name - creator.lastname = this.user.family_name + creator.firstname = this.cacheUser.given_name + creator.lastname = this.cacheUser.family_name creator.creator_name = (creator.lastname ? creator.lastname + ', ' : '') + creator.firstname - creator.affiliation = this.user.attributes.affiliation + creator.affiliation = this.cacheUser.attributes.affiliation }, canShiftUp (creator, idx) { if (this.isPublished) { diff --git a/dbrepo-ui/components/identifier/Select.vue b/dbrepo-ui/components/identifier/Select.vue index 4404a09635c6833e609f74c4f685988550dc97c8..e5572866140858970c5141d40591af3dda5c389a 100644 --- a/dbrepo-ui/components/identifier/Select.vue +++ b/dbrepo-ui/components/identifier/Select.vue @@ -8,7 +8,7 @@ :color="color(identifier)" :variant="listVariant" :href="href(identifier)" - :title="formatTimestampUTCLabel(identifier.created)" + :title="title(identifier)" lines="two"> <v-list-item-subtitle> <Banner @@ -43,8 +43,6 @@ <script> import Banner from '@/components/identifier/Banner.vue' -import { formatTimestampUTCLabel } from '@/utils' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -61,32 +59,31 @@ export default { identifier: { type: Object, default () { - return {} + return null } } }, data () { return { idx: null, - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles + cacheUser () { + return this.cacheStore.getUser }, displayIdentifiers () { - if (!this.identifiers) { - return [] + if (!this.identifiers || this.identifiers.length === 0) { + if (!this.identifier) { + return [] + } + return [this.identifier] } - if (!this.user) { + if (!this.cacheUser) { return this.identifiers.filter(i => i.status === 'published') } - return this.identifiers.filter(i => i.status === 'published' || i.owner.id === this.user.id) + return this.identifiers.filter(i => i.status === 'published' || i.owner.id === this.cacheUser.uid) }, listVariant () { const runtimeConfig = useRuntimeConfig() @@ -105,8 +102,10 @@ export default { this.init() }, methods: { - formatTimestampUTCLabel, href (identifier) { + if (!identifier) { + return null + } if (identifier.status === 'published') { return `/pid/${identifier.id}` } @@ -121,6 +120,13 @@ export default { return `/database/${identifier.database_id}/view/${identifier.view_id}/persist/${identifier.id}` } }, + title (identifier) { + if (!identifier) { + return null + } + const identifierService = useIdentifierService() + return identifierService.identifierPreferEnglishTitle(identifier) + }, isActive (identifier) { if (!identifier) { return false diff --git a/dbrepo-ui/components/identifier/Summary.vue b/dbrepo-ui/components/identifier/Summary.vue index 655a7bb907c9f8a6b868e280097033b157cd893c..6ef120599b515fece88870ad832ed23a508e4ebe 100644 --- a/dbrepo-ui/components/identifier/Summary.vue +++ b/dbrepo-ui/components/identifier/Summary.vue @@ -170,10 +170,10 @@ export default { }, computed: { access () { - return this.userStore.getAccess.value + return this.cacheStore.getAccess }, database () { - return this.cacheStore.getDatabase.value + return this.cacheStore.getDatabase }, pid () { return `/pid/${this.database.identifier.id}` diff --git a/dbrepo-ui/components/subset/Builder.vue b/dbrepo-ui/components/subset/Builder.vue index b45881479cb5243861ab8137a99999def787e551..f670700f2f23aa2a08a6ecf8004fecfb899c6c00 100644 --- a/dbrepo-ui/components/subset/Builder.vue +++ b/dbrepo-ui/components/subset/Builder.vue @@ -31,14 +31,12 @@ :text="$t('pages.subset.subpages.create.expert.text')" /> </v-tabs> </v-toolbar> - <TimeDrift /> <v-card rounded="0" variant="flat"> <v-card-text> <v-form ref="form" - v-model="valid" @submit.prevent> <v-row v-if="isView" @@ -74,7 +72,7 @@ required clearable :rules="[ - v => !!v || $t('validation.required') + v => v !== null || $t('validation.required') ]" :label="$t('pages.database.resource.data.label')" :hint="$t('pages.database.resource.data.hint')" /> @@ -89,7 +87,7 @@ required clearable :rules="[ - v => !!v || $t('validation.required') + v => v !== null || $t('validation.required') ]" :label="$t('pages.database.resource.schema.label')" :hint="$t('pages.database.resource.schema.hint', { resource: 'subset', schema: 'query' })" /> @@ -304,18 +302,15 @@ </template> <script> -import TimeDrift from '@/components/TimeDrift.vue' import Raw from '@/components/subset/Raw.vue' import Results from '@/components/subset/Results.vue' import { useCacheStore } from '@/stores/cache.js' -import { useUserStore } from '@/stores/user.js' import { format } from 'sql-formatter' export default { components: { Raw, Results, - TimeDrift }, props: { mode: { @@ -359,8 +354,7 @@ export default { tabs: 0, loadingQuery: false, loadingColumns: false, - cacheStore: useCacheStore(), - userStore: useUserStore() + cacheStore: useCacheStore() } }, computed: { @@ -388,9 +382,6 @@ export default { } return this.database.container.image.data_types }, - user () { - return this.userStore.getUser - }, viewNames () { if (!this.database) { return [] @@ -449,7 +440,7 @@ export default { if (this.isView) { return this.view.name !== null && this.view.is_public !== null && this.view.query !== null } - return this.sql !== null && !this.sql.includes(';') + return this.sql !== null && this.sql !== '' && !this.sql.includes(';') }, inputVariant () { const runtimeConfig = useRuntimeConfig() @@ -473,7 +464,7 @@ export default { if (!this.table) { return } - this.fetchTableColumns(this.table.id) + this.fetchTableColumns(this.table?.id) } }, mounted () { @@ -550,13 +541,24 @@ export default { this.view.query = this.sql const viewService = useViewService() viewService.create(this.$route.params.database_id, this.view) - .then(async (view) => { - this.resultId = view.id - this.cacheStore.reloadDatabase() - const toast = useToastInstance() - toast.success(this.$t('success.view.create')) - await this.$router.push(`/database/${this.$route.params.database_id}/view/${view.id}/data`) - this.loadingQuery = false + .then((simpleView) => { + this.resultId = simpleView.id + viewService.findOne(this.$route.params.database_id, simpleView.id) + .then(async (view) => { + this.cacheStore.setView(view) + const toast = useToastInstance() + toast.success(this.$t('success.view.create')) + await this.$router.push(`/database/${this.$route.params.database_id}/view/${view.id}/data`) + this.loadingQuery = false + }) + .catch(({code}) => { + this.loadingQuery = false + const toast = useToastInstance() + if (typeof code !== 'string') { + return + } + toast.error(this.$t(code)) + }) }) .catch(({code}) => { this.loadingQuery = false diff --git a/dbrepo-ui/components/subset/Results.vue b/dbrepo-ui/components/subset/Results.vue index e558186daf15c186dfdc085a844799815e3756a4..661c7d1a3d6e7502cf349a63cc695cf7d593f427 100644 --- a/dbrepo-ui/components/subset/Results.vue +++ b/dbrepo-ui/components/subset/Results.vue @@ -80,23 +80,6 @@ export default { } }, methods: { - executeFirstTime (parent, sql, timestamp) { - this.loading++ - const payload = { - statement: sql, - timestamp - } - const queryService = useQueryService() - queryService.execute(this.$route.params.database_id, payload, this.options.page - 1, this.options.itemsPerPage) - .then((result) => { - this.mapResults(result) - parent.resultId = result.id - this.id = result.id - }) - .finally(() => { - this.loading-- - }) - }, reExecute (id) { if (id === null) { return @@ -110,9 +93,13 @@ export default { this.id = id this.loadingExecute = false }) - .catch(({code}) => { + .catch(({code, message}) => { this.loadingExecute = false const toast = useToastInstance() + if (message) { + toast.error(message) + return + } if (typeof code !== 'string') { return } @@ -129,9 +116,13 @@ export default { this.id = id this.loadingExecute = false }) - .catch(({code}) => { + .catch(({code, message}) => { this.loadingExecute = false const toast = useToastInstance() + if (message) { + toast.error(message) + return + } if (typeof code !== 'string') { return } @@ -148,9 +139,13 @@ export default { this.id = id this.loadingExecute = false }) - .catch(({code}) => { + .catch(({code, message}) => { this.loadingExecute = false const toast = useToastInstance() + if (message) { + toast.error(message) + return + } if (typeof code !== 'string') { return } diff --git a/dbrepo-ui/components/subset/SubsetList.vue b/dbrepo-ui/components/subset/SubsetList.vue index 6908b2b4381d88d7b5a7a19ce540b4c88c633e0e..df0948372eed1dbf60260b6f3bd835e51dd93d2a 100644 --- a/dbrepo-ui/components/subset/SubsetList.vue +++ b/dbrepo-ui/components/subset/SubsetList.vue @@ -14,28 +14,20 @@ <Loading /> </v-list-item> <div - v-for="(item, i) in subsets" + v-for="(subset, i) in subsets" :key="`q-${i}`"> <v-divider v-if="i !== 0" class="mx-4" /> <v-list> <v-list-item lines="two" - :title="title(item)" - :subtitle="subtitle(item)" - :class="clazz(item)" - :to="link(item)" - :href="link(item)"> + :title="title(subset)" + :subtitle="subtitle(subset)" + :class="clazz(subset)" + :to="link(subset)" + :href="link(subset)"> <template v-slot:append> - <v-tooltip - v-if="hasPublishedIdentifier(item)" - :text="$t('pages.identifier.pid.title')" - left> - <template v-slot:activator="{ props }"> - <v-icon - color="primary" - v-bind="props">mdi-identifier</v-icon> - </template> - </v-tooltip> + <ResourceStatus + :resource="subset" /> </template> </v-list-item> </v-list> @@ -45,8 +37,6 @@ </template> <script> -import { formatTimestampUTCLabel } from '@/utils' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -55,14 +45,10 @@ export default { loadingSubsets: false, loadingIdentifiers: false, subsets: [], - cacheStore: useCacheStore(), - userStore: useUserStore() + cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, @@ -130,7 +116,6 @@ export default { } } </script> - <style lang="scss" scoped> .pid-icon { flex: 0 !important; diff --git a/dbrepo-ui/components/subset/SubsetToolbar.vue b/dbrepo-ui/components/subset/SubsetToolbar.vue index 874e691c5f15766d7b4a0fb4809eb19058418c9c..e6026090978a3745af50b7e9a3e7a559ae5363a5 100644 --- a/dbrepo-ui/components/subset/SubsetToolbar.vue +++ b/dbrepo-ui/components/subset/SubsetToolbar.vue @@ -35,7 +35,6 @@ variant="flat" class="mr-2" :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-content-save-outline' : null" - :disabled="!executionUTC" :to="`/database/${$route.params.database_id}/subset/${$route.params.subset_id}/persist`"> {{ ($vuetify.display.lgAndUp ? $t('toolbars.subset.pid.xl') + ' ' : '') + $t('toolbars.subset.pid.permanent') }} </v-btn> @@ -59,7 +58,6 @@ <script> import DownloadButton from '@/components/identifier/DownloadButton.vue' import { formatTimestampUTCLabel } from '@/utils' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -72,7 +70,6 @@ export default { loading: false, loadingSave: false, downloadLoading: false, - userStore: useUserStore(), cacheStore: useCacheStore() } }, @@ -87,17 +84,14 @@ export default { return this.cacheStore.getDatabase }, access () { - return this.userStore.getAccess - }, - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles + return this.cacheStore.getAccess }, subset () { return this.cacheStore.getSubset }, + cacheUser () { + return this.cacheStore.getUser + }, identifiers () { if (!this.subset) { return [] @@ -118,9 +112,7 @@ export default { if (this.pid) { const filter = this.identifiers.filter(i => i.id === Number(this.pid)) if (filter.length > 0) { - const identifier = filter[0] - console.debug('identifier set according to route pid', identifier) - return identifier + return filter[0] } } return this.identifiers[0] @@ -155,10 +147,10 @@ export default { return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own' }, canGetPid () { - if (!this.user || !this.subset || !this.database) { + if (!this.cacheUser || !this.subset || !this.database) { return false } - return this.database.owner.id === this.user.id || (this.subset.owner.id === this.user.id && this.hasReadAccess) + return this.database.owner.id === this.cacheUser.uid || (this.subset.owner.id === this.cacheUser.uid && this.hasReadAccess) }, title () { if (!this.identifier) { @@ -177,8 +169,9 @@ export default { this.loadingSave = true const queryService = useQueryService() queryService.update(this.$route.params.database_id, this.$route.params.subset_id, { persist: true }) - .then((subset) => { - this.subset = subset + .then(() => { + const cacheStore = useCacheStore() + cacheStore.reloadSubset() this.loadingSave = false }) .catch(() => { @@ -192,8 +185,10 @@ export default { this.loadingSave = true const queryService = useQueryService() queryService.update(this.$route.params.database_id, this.$route.params.subset_id, { persist: false }) - .then((subset) => { - this.subset = subset + .then(() => { + const cacheStore = useCacheStore() + cacheStore.reloadSubset() + this.loadingSave = false }) .catch(() => { this.loadingSave = false diff --git a/dbrepo-ui/components/table/TableList.vue b/dbrepo-ui/components/table/TableList.vue index b78e20ae3a6d423a90a636f119d96e4b406ea45d..5f87090b85855cdc7d6113a9de97bbea18106484 100644 --- a/dbrepo-ui/components/table/TableList.vue +++ b/dbrepo-ui/components/table/TableList.vue @@ -21,16 +21,6 @@ <template v-slot:append> <ResourceStatus :resource="table" /> - <v-tooltip - v-if="hasPublishedIdentifier(table)" - :text="$t('pages.identifier.pid.title')" - left> - <template v-slot:activator="{ props }"> - <v-icon - color="primary" - v-bind="props">mdi-identifier</v-icon> - </template> - </v-tooltip> </template> </v-list-item> </v-list> @@ -40,7 +30,6 @@ <script> import { formatTimestampUTCLabel } from '@/utils' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -74,19 +63,15 @@ export default { { value: 'string', title: 'Character Varying' }, { value: 'text', title: 'Text' } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, tables () { if (!this.database) { diff --git a/dbrepo-ui/components/table/TableToolbar.vue b/dbrepo-ui/components/table/TableToolbar.vue index d6fd4868eae0e65a52d932339ba5bbab6e3ad56f..e09cd67cba31e8d3aaec7e9055078fa354bd4ded 100644 --- a/dbrepo-ui/components/table/TableToolbar.vue +++ b/dbrepo-ui/components/table/TableToolbar.vue @@ -80,7 +80,6 @@ <script> import EditTuple from '@/components/dialogs/EditTuple.vue' import { useCacheStore } from '@/stores/cache.js' -import { useUserStore } from '@/stores/user.js' export default { components: { @@ -93,8 +92,7 @@ export default { error: false, edit: false, dropTableDialog: false, - cacheStore: useCacheStore(), - userStore: useUserStore() + cacheStore: useCacheStore() } }, computed: { @@ -105,39 +103,42 @@ export default { return this.cacheStore.getTable }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess + }, + cacheUser () { + return this.cacheStore.getUser + }, + roles () { + return this.cacheStore.getRoles }, hasReadAccess () { if (!this.access) { return false } - return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own' - }, - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles + const userService = useUserService() + return userService.hasReadAccess(this.access) }, canUpdateTable () { - if (!this.roles || !this.user || !this.table) { + if (!this.roles || !this.cacheUser || !this.table) { return false } - return this.roles.includes('update-table') && this.table.owner.id === this.user.id + return this.roles.includes('update-table') && this.table.owner.id === this.cacheUser.uid }, canExecuteQuery () { - if (!this.roles || !this.table || !this.user) { + if (!this.roles || !this.table || !this.cacheUser) { return false } - const userService = useUserService() - return userService.hasReadAccess(this.access) && this.roles.includes('execute-query') + return this.hasReadAccess && this.roles.includes('execute-query') + }, + isOwner () { + const databaseService = useDatabaseService() + return databaseService.isOwner(this.database, this.cacheUser) }, canCreateView () { - if (!this.roles || !this.table || !this.user) { + if (!this.roles || !this.table || !this.cacheUser) { return false } - const databaseService = useDatabaseService() - return databaseService.isOwner(this.database, this.user) && this.roles.includes('create-database-view') + return this.isOwner && this.roles.includes('create-database-view') }, canViewData () { if (!this.table) { @@ -146,10 +147,10 @@ export default { if (this.table.is_public) { return true } - if (!this.user) { + if (!this.cacheUser) { return false } - return this.hasReadAccess || this.table.owner.id === this.user.id || this.database.owner.id === this.user.id + return this.hasReadAccess || this.table.owner.id === this.cacheUser.uid || this.database.owner.id === this.cacheUser.uid }, canViewSchema () { if (!this.table) { @@ -158,22 +159,22 @@ export default { if (this.table.is_schema_public) { return true } - if (!this.user) { + if (!this.cacheUser) { return false } - return this.hasReadAccess || this.table.owner.id === this.user.id || this.database.owner.id === this.user.id + return this.hasReadAccess || this.table.owner.id === this.cacheUser.uid || this.database.owner.id === this.cacheUser.uid }, canImportCsv () { - if (!this.roles || !this.table || !this.user) { + if (!this.roles || !this.table || !this.cacheUser) { return false } return this.roles.includes('insert-table-data') }, canGetPid () { - if (!this.user || !this.table || !this.database) { + if (!this.cacheUser || !this.table || !this.database) { return false } - return this.database.owner.id === this.user.id || this.table.owner.id === this.user.id + return this.hasReadAccess && this.database.owner.id === this.cacheUser.uid || this.table.owner.id === this.cacheUser.uid }, buttonVariant () { const runtimeConfig = useRuntimeConfig() diff --git a/dbrepo-ui/components/user/UserToolbar.vue b/dbrepo-ui/components/user/UserToolbar.vue index e5a20c75a3230d80dc3e6f63c27c5bb6a743a463..54210130d32f9c1cbe73378138e6c0db28c8cc88 100644 --- a/dbrepo-ui/components/user/UserToolbar.vue +++ b/dbrepo-ui/components/user/UserToolbar.vue @@ -1,6 +1,9 @@ <template> - <div> - <v-toolbar title="Settings" flat> + <div + v-if="loggedIn"> + <v-toolbar + title="Settings" + flat> <template v-slot:extension> <v-tabs v-model="tab" @@ -11,31 +14,20 @@ <v-tab :text="$t('toolbars.user.authentication')" to="/user/authentication" /> - <v-tab - :text="$t('toolbars.user.developer')" - to="/user/developer" /> </v-tabs> </template> </v-toolbar> </div> </template> +<script setup> +const { loggedIn } = useOidcAuth() +</script> <script> -import { useUserStore } from '@/stores/user.js' - export default { data () { return { tab: null, - userStore: useUserStore() - } - }, - computed: { - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles } } } diff --git a/dbrepo-ui/components/view/ViewList.vue b/dbrepo-ui/components/view/ViewList.vue index d6539bd253cb7ef40c202633db53d564ec1e6269..afa3067921b10d1c1f2fe6d78cac4e9c7781bebe 100644 --- a/dbrepo-ui/components/view/ViewList.vue +++ b/dbrepo-ui/components/view/ViewList.vue @@ -16,16 +16,6 @@ <template v-slot:append> <ResourceStatus :resource="view" /> - <v-tooltip - v-if="hasPublishedIdentifier(view)" - :text="$t('pages.identifier.pid.title')" - left> - <template v-slot:activator="{ props }"> - <v-icon - color="primary" - v-bind="props">mdi-identifier</v-icon> - </template> - </v-tooltip> </template> </v-list-item> </v-list> @@ -34,7 +24,6 @@ </template> <script> -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -43,14 +32,10 @@ export default { loading: false, loadingDetails: false, error: false, - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, diff --git a/dbrepo-ui/components/view/ViewToolbar.vue b/dbrepo-ui/components/view/ViewToolbar.vue index 4ed83ff43fa777f9f8f663cf020d89d5d58456cd..d9e0bfb6bf6740c19aac53f6b3ac8cc374be7011 100644 --- a/dbrepo-ui/components/view/ViewToolbar.vue +++ b/dbrepo-ui/components/view/ViewToolbar.vue @@ -57,7 +57,6 @@ </template> <script> -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' import CreateOntology from '@/components/dialogs/CreateOntology.vue' import ViewVisibility from '@/components/dialogs/ViewVisibility.vue' @@ -73,7 +72,6 @@ export default { loading: false, loadingDelete: false, updateViewDialog: false, - userStore: useUserStore(), cacheStore: useCacheStore() } }, @@ -91,6 +89,12 @@ export default { view () { return this.cacheStore.getView }, + cacheUser () { + return this.cacheStore.getUser + }, + roles () { + return this.cacheStore.getRoles + }, canViewData () { if (!this.view) { return false @@ -98,10 +102,10 @@ export default { if (this.view.is_public) { return true } - if (!this.user) { + if (!this.cacheUser) { return false } - return this.hasReadAccess || this.view.owner.id === this.user.id || this.database.owner.id === this.user.id + return this.hasReadAccess || this.view.owner.id === this.cacheUser.uid || this.database.owner.id === this.cacheUser.uid }, canViewSchema () { if (!this.view) { @@ -110,32 +114,26 @@ export default { if (this.view.is_schema_public) { return true } - if (!this.user) { + if (!this.cacheUser) { return false } - return this.hasReadAccess || this.view.owner.id === this.user.id || this.database.owner.id === this.user.id + return this.hasReadAccess || this.view.owner.id === this.cacheUser.uid || this.database.owner.id === this.cacheUser.uid }, canViewSettings () { - if (!this.user || !this.view) { + if (!this.cacheUser || !this.view) { return false } - return this.view.owner.id === this.user.id + return this.view.owner.id === this.cacheUser.uid }, canCreatePid () { - if (!this.roles || !this.user || !this.view) { + if (!this.roles || !this.cacheUser || !this.view) { return false } - const userService = useUserService() - return this.roles.includes('create-identifier') && userService.hasReadAccess(this.access) + const cacheUserService = useUserService() + return cacheUserService.hasReadAccess(this.access) && this.roles.includes('create-identifier') }, access () { - return this.userStore.getAccess - }, - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles + return this.cacheStore.getAccess }, hasReadAccess () { if (!this.access) { diff --git a/dbrepo-ui/composables/axios-instance.ts b/dbrepo-ui/composables/axios-instance.ts index 95edea3c28d5c12f1f2422ccf8b457e409c5b459..ca7a7b111cf70cf92524f5459808277e4b14144e 100644 --- a/dbrepo-ui/composables/axios-instance.ts +++ b/dbrepo-ui/composables/axios-instance.ts @@ -1,11 +1,9 @@ import axios, {type AxiosInstance} from 'axios' -import {useUserStore} from '@/stores/user' let instance: AxiosInstance | null = null; export const useAxiosInstance = () => { const config = useRuntimeConfig() - const userStore = useUserStore() if (!instance) { instance = axios.create({ timeout: 90_000, @@ -18,38 +16,16 @@ export const useAxiosInstance = () => { baseURL: config.public.api.client }); instance.interceptors.request.use((config) => { - const token = userStore.getToken - const refreshToken = userStore.getRefreshToken - if (!token || !refreshToken) { + const { loggedIn, user, login, logout } = useOidcAuth() + if (!loggedIn) { return config } - const authenticationService = useAuthenticationService() - if (authenticationService.isExpiredToken(refreshToken)) { - console.warn('Refresh token is expired: trigger logout of user') - userStore.logout() + const { accessToken } = user.value + if (!accessToken) { return config } - if (!authenticationService.isExpiredToken(token)) { - config.headers.Authorization = `Bearer ${token}` - return config - } - console.warn('Access token expired: request a new one') - const userService = useUserService() - return userService.refreshToken(refreshToken) - .then((response: KeycloakOpenIdTokenDto) => { - userStore.setToken(response.access_token) - userStore.setRefreshToken(response.refresh_token) - console.debug('new access token expires:', authenticationService.tokenToExpiryDate(response.access_token)) - config.headers.Authorization = `Bearer ${response.access_token}` - return config - }) - .catch((error: ApiErrorDto) => { - if (error.code === 'error.user.credentials') { - console.warn('User session expired.') - userStore.logout() - } - return config - }); + config.headers.Authorization = `Bearer ${accessToken}` + return config }) } return instance; diff --git a/dbrepo-ui/composables/database-service.ts b/dbrepo-ui/composables/database-service.ts index 7956f7b4dff6cb748733fd381275dd6d0622b60c..f318e073054d6a4283b654bbae985b4f903aec00 100644 --- a/dbrepo-ui/composables/database-service.ts +++ b/dbrepo-ui/composables/database-service.ts @@ -66,23 +66,6 @@ export const useDatabaseService = (): any => { }); } - async function getServerTime(): Promise<Date> { - const axios = useAxiosInstance(); - console.debug('find server time'); - return new Promise<Date>((resolve, reject) => { - axios.head<Date>('/api/database') - .then((response) => { - const date: Date = new Date(response.headers['Date']) - console.info(`Found ${date} server time`); - resolve(date); - }) - .catch((error) => { - console.error('Failed to find server time', error); - reject(axiosErrorToApiError(error)); - }); - }); - } - async function findOne(id: number, rawError: boolean = false): Promise<DatabaseDto | null> { const axios = useAxiosInstance(); console.debug('find database with id', id); @@ -239,16 +222,12 @@ export const useDatabaseService = (): any => { refreshTablesMetadata, refreshViewsMetadata, findOne, - findPreviewImage, - findCount, - getServerTime, updateVisibility, updateImage, updateOwner, create, databaseToOwner, databaseToContact, - databaseToJsonLd, isOwner } } diff --git a/dbrepo-ui/composables/identifier-service.ts b/dbrepo-ui/composables/identifier-service.ts index 3853d9df751aef86b62e2cb30394cf0be1896efb..6875a7cb7b2c168ecfb7357cc314219792930bf8 100644 --- a/dbrepo-ui/composables/identifier-service.ts +++ b/dbrepo-ui/composables/identifier-service.ts @@ -24,7 +24,7 @@ export const useIdentifierService = (): any => { } async function create(data: IdentifierSaveDto): Promise<IdentifierDto> { - const axios= useAxiosInstance() + const axios = useAxiosInstance() console.debug('create identifier') return new Promise<IdentifierDto>((resolve, reject) => { axios.post<IdentifierDto>('/api/identifier', data) @@ -40,7 +40,7 @@ export const useIdentifierService = (): any => { } async function save(data: IdentifierSaveDto): Promise<IdentifierDto> { - const axios= useAxiosInstance() + const axios = useAxiosInstance() console.debug('save identifier', data.id) return new Promise<IdentifierDto>((resolve, reject) => { axios.put<IdentifierDto>(`/api/identifier/${data.id}`, data) @@ -103,7 +103,7 @@ export const useIdentifierService = (): any => { }) } - function identifierToCreators(identifier: IdentifierDto) { + function identifierToCreators(identifier: IdentifierDto): string | null { if (!identifier) { return null } @@ -241,13 +241,28 @@ export const useIdentifierService = (): any => { if (!data || !data.titles || data.titles.length === 0) { return null } - const filtered = data.titles.filter(d => d.language && d.language === 'en') + const filtered = data.titles.filter((d) => d.language && d.language === 'en') if (filtered.length === 0) { - return data.titles[0].title + const title = data.titles[0] + return title.title } return filtered[0].title } + function identifierToResourceUrl(identifier: IdentifierDto): string | null { + const config = useRuntimeConfig() + switch (identifier.type) { + case 1: + return `${config.public.api.client}/api/database/${identifier.database_id}/subset/${identifier.subset_id}/data` + case 2: + return `${config.public.api.client}/api/database/${identifier.database_id}/table/${identifier.table_id}/data` + case 3: + return `${config.public.api.client}/api/database/${identifier.database_id}/view/${identifier.view_id}/data` + default: + return null + } + } + function identifierToUrl(data: IdentifierDto): string | null { if (!data) { return null @@ -315,244 +330,48 @@ export const useIdentifierService = (): any => { return jsonLd } - function identifierToHasPartJsonLd(identifier: IdentifierDto) { - return { - '@type': 'Dataset', - name: identifierPreferEnglishTitle(identifier), - description: identifierPreferEnglishDescription(identifier), - identifier: identifierToUrl(identifier), - citation: identifierToUrl(identifier), - temporalCoverage: identifier.publication_year, - version: identifier.created - } - } - - function databaseToServerHead(database: DatabaseDto) { - if (!database) { - return + function identifiersToServerHead(identifiers: IdentifierBriefDto[]): any { + if (!identifiers || !identifiers[0]) { + return null } - const config = useRuntimeConfig() + const identifier = identifiers[0] /* Google Rich Results */ const json: any = { '@context': 'https://schema.org/', '@type': 'Dataset', - url: `${config.public.api.client}/database/${database.id}/info`, - citation: `${config.public.api.client}/database/${database.id}/info`, + url: identifierToUrl(identifier), + citation: identifierToUrl(identifier), hasPart: [], - version: database.created + identifier: identifiers.map(i => identifierToUrl(i)), + creator: identifier.creators.map((c) => creatorToCreatorJsonLd(c)), + temporalCoverage: identifier.publication_year } - /* FAIR Signposting */ - const meta: any [] = [] - if (database.identifiers.length > 0) { - const identifier = database.identifiers[0] - const partIdentifiers: IdentifierDto[] = [] - if (database.subsets.length > 0) { - database.subsets.forEach((s) => { - partIdentifiers.push(s) - }) - } - if (database.tables.length > 0) { - database.tables.forEach((t) => { - if (t.identifiers.length > 0) { - t.identifiers.forEach(i => partIdentifiers.push(i)) - } - }) - } - if (database.views.length > 0) { - database.views.forEach((v) => { - if (v.identifiers.length > 0) { - v.identifiers.forEach(i => partIdentifiers.push(i)) - } - }) - } + if (identifier.titles.length > 0) { json['name'] = identifierPreferEnglishTitle(identifier) - json['description'] = identifierPreferEnglishDescription(identifier) - json['identifier'] = database.identifiers.map(i => identifierToUrl(i)) - json['license'] = identifierToPreferFirstLicenseUri(identifier) - json['creator'] = identifier.creators.map(c => creatorToCreatorJsonLd(c)) - json['citation'] = identifierToUrl(identifier) - json['hasPart'] = partIdentifiers.map(i => identifierToHasPartJsonLd(i)) - json['temporalCoverage'] = identifier.publication_year - meta.push({rel: 'cite-as', href: identifierToUrl(identifier)}) - identifier.creators.forEach((c: CreatorDto) => { - if (c.name_identifier) { - meta.push({rel: 'author', href: c.name_identifier}) - } - }) - meta.push({rel: 'describedby', type: 'application/x-bibtex', href: identifierToUrl(identifier)}) - meta.push({rel: 'describedby', type: 'application/vnd.datacite.datacite+json', href: identifierToUrl(identifier)}) - if (identifier.licenses) { - identifier.licenses.forEach((l: LicenseDto) => meta.push({rel: 'license', href: l.uri})) - } - } - return { - script: [ - { - type: 'application/ld+json', - innerHTML: json - } - ], - link: meta } - } - - function subsetToServerHead(subset: QueryDto) { - const config = useRuntimeConfig() - /* Google Rich Results */ - const json: any = { - '@context': 'https://schema.org/', - '@type': 'Dataset', - description: subset.query, - url: `${config.public.api.client}/database/${subset.database_id}/info`, - citation: `${config.public.api.client}/database/${subset.database_id}/info`, - hasPart: [], - version: subset.created - } - /* FAIR Signposting */ - const meta: any[] = [] - if (subset.identifiers.length > 0) { - const identifier = subset.identifiers[0] - json['name'] = identifierPreferEnglishTitle(identifier) + if (identifier.descriptions.length > 0) { json['description'] = identifierPreferEnglishDescription(identifier) - json['identifier'] = subset.identifiers.map(i => identifierToUrl(i)) - json['license'] = identifierToPreferFirstLicenseUri(identifier) - json['creator'] = identifier.creators.map(c => creatorToCreatorJsonLd(c)) - json['citation'] = identifierToUrl(identifier) - json['temporalCoverage'] = identifier.publication_year - meta.push({rel: 'cite-as', href: identifierToUrl(identifier)}) - identifier.creators.forEach((c: CreatorDto) => { - if (c.name_identifier) { - meta.push({rel: 'author', href: c.name_identifier}) - } - }) - meta.push({rel: 'describedby', type: 'application/x-bibtex', href: identifierToUrl(identifier)}) - meta.push({rel: 'describedby', type: 'application/vnd.datacite.datacite+json', href: identifierToUrl(identifier)}) - if (identifier.licenses) { - identifier.licenses.forEach((l: LicenseDto) => meta.push({rel: 'license', href: l.uri})) - } - meta.push({ - rel: 'item', - type: 'application/json', - href: `${config.public.api.client}/api/database/${subset.database_id}/subset/${subset.id}/data` - }) - meta.push({ - rel: 'item', - type: 'text/csv', - href: `${config.public.api.client}/api/database/${subset.database_id}/subset/${subset.id}/data` - }) - } - return { - script: [ - { - type: 'application/ld+json', - innerHTML: json - } - ], - link: meta - } - } - - function tableToServerHead(table: TableDto) { - const config = useRuntimeConfig() - /* Google Rich Results */ - const json: any = { - '@context': 'https://schema.org/', - '@type': 'Dataset', - description: table.description, - url: `${config.public.api.client}/database/${table.database_id}/table/${table.id}/info`, - citation: `${config.public.api.client}/database/${table.database_id}/table/${table.id}/info`, - hasPart: [], - version: table.created } /* FAIR Signposting */ const meta: any[] = [] - if (table.identifiers.length > 0) { - const identifier: IdentifierDto = table.identifiers[0] - json['name'] = identifierPreferEnglishTitle(identifier) - json['description'] = identifierPreferEnglishDescription(identifier) - json['identifier'] = table.identifiers.map((i: IdentifierDto) => identifierToUrl(i)) - json['license'] = identifierToPreferFirstLicenseUri(identifier) - json['creator'] = identifier.creators.map((c: CreatorDto) => creatorToCreatorJsonLd(c)) - json['citation'] = identifierToUrl(identifier) - json['temporalCoverage'] = identifier.publication_year - meta.push({rel: 'cite-as', href: identifierToUrl(identifier)}) - identifier.creators.forEach((c: CreatorDto): void => { - if (c.name_identifier) { - meta.push({rel: 'author', href: c.name_identifier}) - } - }) - meta.push({rel: 'describedby', type: 'application/x-bibtex', href: identifierToUrl(identifier)}) - meta.push({rel: 'describedby', type: 'application/vnd.datacite.datacite+json', href: identifierToUrl(identifier)}) - if (identifier.licenses) { - identifier.licenses.forEach((l: LicenseDto) => meta.push({rel: 'license', href: l.uri})) + meta.push({rel: 'cite-as', href: identifierToUrl(identifier)}) + identifier.creators.forEach((c: CreatorDto) => { + if (c.name_identifier) { + meta.push({rel: 'author', href: c.name_identifier}) } - meta.push({ - rel: 'item', - type: 'application/json', - href: `${config.public.api.client}/api/database/${table.database_id}/table/${table.id}/data` - }) - meta.push({ - rel: 'item', - type: 'text/csv', - href: `${config.public.api.client}/api/database/${table.database_id}/table/${table.id}/data` - }) - } - return { - script: [ - { - type: 'application/ld+json', - innerHTML: json - } - ], - link: meta - } - } - - function viewToServerHead(view: ViewDto) { - const config = useRuntimeConfig() - /* Google Rich Results */ - const json: any = { - '@context': 'https://schema.org/', - '@type': 'Dataset', - description: view.query, - url: `${config.public.api.client}/database/${view.database_id}/table/${view.id}/info`, - citation: `${config.public.api.client}/database/${view.database_id}/table/${view.id}/info`, - hasPart: [], - version: view.created - } - /* FAIR Signposting */ - const meta: any[] = [] - if (view.identifiers.length > 0) { - const identifier = view.identifiers[0] - json['name'] = identifierPreferEnglishTitle(identifier) - json['description'] = identifierPreferEnglishDescription(identifier) - json['identifier'] = view.identifiers.map(i => identifierToUrl(i)) - json['license'] = identifierToPreferFirstLicenseUri(identifier) - json['creator'] = identifier.creators.map(c => creatorToCreatorJsonLd(c)) - json['citation'] = identifierToUrl(identifier) - json['temporalCoverage'] = identifier.publication_year - meta.push({rel: 'cite-as', href: identifierToUrl(identifier)}) - identifier.creators.forEach((c: CreatorDto) => { - if (c.name_identifier) { - meta.push({rel: 'author', href: c.name_identifier}) - } - }) - meta.push({rel: 'describedby', type: 'application/x-bibtex', href: identifierToUrl(identifier)}) - meta.push({rel: 'describedby', type: 'application/vnd.datacite.datacite+json', href: identifierToUrl(identifier)}) - if (identifier.licenses) { - identifier.licenses.forEach((l: LicenseDto) => meta.push({rel: 'license', href: l.uri})) - } - meta.push({ - rel: 'item', - type: 'application/json', - href: `${config.public.api.client}/api/database/${view.database_id}/view/${view.id}/data` - }) - meta.push({ - rel: 'item', - type: 'text/csv', - href: `${config.public.api.client}/api/database/${view.database_id}/view/${view.id}/data` - }) - } + }) + meta.push({rel: 'describedby', type: 'application/x-bibtex', href: identifierToUrl(identifier)}) + meta.push({rel: 'describedby', type: 'application/vnd.datacite.datacite+json', href: identifierToUrl(identifier)}) + meta.push({ + rel: 'item', + type: 'application/json', + href: identifierToResourceUrl(identifier) + }) + meta.push({ + rel: 'item', + type: 'text/csv', + href: identifierToResourceUrl(identifier) + }) return { script: [ { @@ -564,56 +383,15 @@ export const useIdentifierService = (): any => { } } - function databaseToServerSeoMeta(database: DatabaseDto) { - const json: any = { - ogTitle: database.name - } - if (database.identifiers.length > 0) { - const identifier = database.identifiers[0] - json['ogTitle'] = identifierPreferEnglishTitle(identifier) - json['description'] = identifierPreferEnglishDescription(identifier) - json['ogDescription'] = identifierPreferEnglishDescription(identifier) - } - return json - } - - function subsetToServerSeoMeta(subset: QueryDto) { - const json: any = { - description: subset.query - } - if (subset.identifiers.length > 0) { - const identifier = subset.identifiers[0] - json['ogTitle'] = identifierPreferEnglishTitle(identifier) - json['description'] = identifierPreferEnglishDescription(identifier) - json['ogDescription'] = identifierPreferEnglishDescription(identifier) - } - return json - } - - function tableToServerSeoMeta(table: TableDto) { - const json: any = { - ogTitle: table.name, - description: table.description - } - if (table.identifiers.length > 0) { - const identifier = table.identifiers[0] - json['ogTitle'] = identifierPreferEnglishTitle(identifier) - json['description'] = identifierPreferEnglishDescription(identifier) - json['ogDescription'] = identifierPreferEnglishDescription(identifier) + function identifiersToServerSeoMeta(identifiers: IdentifierBriefDto[]): any | null { + if (!identifiers|| !identifiers[0]) { + return null } - return json - } - - function viewToServerSeoMeta(view: ViewDto) { + const identifier = identifiers[0] const json: any = { - ogTitle: view.name, - description: view.query - } - if (view.identifiers.length > 0) { - const identifier = view.identifiers[0] - json['ogTitle'] = identifierPreferEnglishTitle(identifier) - json['description'] = identifierPreferEnglishDescription(identifier) - json['ogDescription'] = identifierPreferEnglishDescription(identifier) + ogTitle: identifierPreferEnglishTitle(identifier), + ogDescription: identifierPreferEnglishDescription(identifier), + description: identifierPreferEnglishDescription(identifier) } return json } @@ -633,13 +411,7 @@ export const useIdentifierService = (): any => { identifierToUrl, identifierToDisplayName, identifierToDisplayAcronym, - databaseToServerHead, - subsetToServerHead, - tableToServerHead, - viewToServerHead, - databaseToServerSeoMeta, - subsetToServerSeoMeta, - tableToServerSeoMeta, - viewToServerSeoMeta, + identifiersToServerHead, + identifiersToServerSeoMeta } } diff --git a/dbrepo-ui/composables/query-service.ts b/dbrepo-ui/composables/query-service.ts index 119915de2785763d549bdf3bf2d97379811f8fed..e314993ecd233c486198f7995dff4da5389eb06f 100644 --- a/dbrepo-ui/composables/query-service.ts +++ b/dbrepo-ui/composables/query-service.ts @@ -161,12 +161,12 @@ export const useQueryService = (): any => { } } sql += ` \`${clause.params[0]}\` ${clause.params[1]} ` - const filteredType = types.filter(t => t.value === filteredColumn[0].column_type) + const filteredType = types.filter(t => t.value === filteredColumn[0].type) if (filteredType.length === 0) { return { error: true, reason: 'exists', - column: filteredColumn[0].column_type, + column: filteredColumn[0].type, raw: null, formatted: null } @@ -175,7 +175,7 @@ export const useQueryService = (): any => { return { error: true, reason: 'build', - column: filteredColumn[0].column_type, + column: filteredColumn[0].type, raw: null, formatted: null } diff --git a/dbrepo-ui/composables/table-service.ts b/dbrepo-ui/composables/table-service.ts index ca757c7451d70c4bd1fffc36b72c6a23d7fdde58..5f290745245b46a8ce395a489f62aa9171800d5a 100644 --- a/dbrepo-ui/composables/table-service.ts +++ b/dbrepo-ui/composables/table-service.ts @@ -9,7 +9,7 @@ export const useTableService = (): any => { return new Promise<TableBriefDto>((resolve, reject) => { axios.get<TableBriefDto>(`/api/database/${databaseId}/table`) .then((response) => { - console.info('Found tables(s)') + console.info(`Found ${response.data.length} tables(s)`) resolve(response.data) }) .catch((error) => { @@ -25,7 +25,7 @@ export const useTableService = (): any => { return new Promise<TableDto>((resolve, reject) => { axios.get<TableDto>(`/api/database/${databaseId}/table/${tableId}`) .then((response) => { - console.info('Found table with id', tableId, 'in database with id', databaseId); + console.info('Found table'); resolve(response.data) }) .catch((error) => { @@ -41,7 +41,7 @@ export const useTableService = (): any => { return new Promise<ColumnDto>((resolve, reject) => { axios.put<ColumnDto>(`/api/database/${databaseId}/table/${tableId}/column/${columnId}`, data) .then((response) => { - console.info('Updated column with id', columnId, 'table with id', tableId, 'in database with id', databaseId); + console.info('Updated column'); resolve(response.data) }) .catch((error) => { @@ -57,7 +57,7 @@ export const useTableService = (): any => { return new Promise<TableDto>((resolve, reject) => { axios.put<TableDto>(`/api/database/${databaseId}/table/${tableId}`, data) .then((response) => { - console.info('Updated table with id', tableId, 'in database with id', databaseId); + console.info('Updated table'); resolve(response.data) }) .catch((error) => { @@ -73,7 +73,7 @@ export const useTableService = (): any => { return new Promise<ImportDto>((resolve, reject) => { axios.post<ImportDto>(`/api/database/${databaseId}/table/${tableId}/data/import`, data) .then((response) => { - console.info('Imported csv to table with id', tableId, 'in database with id', databaseId) + console.info('Imported csv to table') resolve(response.data) }) .catch((error) => { @@ -89,7 +89,7 @@ export const useTableService = (): any => { return new Promise<QueryResultDto>((resolve, reject) => { axios.get<QueryResultDto>(`/api/database/${databaseId}/table/${tableId}/data`, { params: mapFilter(timestamp, page, size) }) .then((response) => { - console.info('Got data for table with id', tableId, 'in database with id', databaseId) + console.info('Got data for table') const result: QueryResultDto = { id: tableId, headers: response.headers['x-headers'] ? response.headers['x-headers'].split(',') : [], @@ -111,7 +111,7 @@ export const useTableService = (): any => { axios.head<void>(`/api/database/${databaseId}/table/${tableId}/data`, { params: mapFilter(timestamp, null, null) }) .then((response: AxiosResponse<void>) => { const count: number = Number(response.headers['x-count']) - console.info('Found' + count + 'in table with id', tableId, 'in database with id', databaseId) + console.info(`Found ${count} tuple(s)`) resolve(count) }) .catch((error) => { @@ -134,7 +134,7 @@ export const useTableService = (): any => { return new Promise<QueryResultDto>((resolve, reject) => { axios.get<QueryResultDto>(`/api/database/${databaseId}/table/${tableId}/export`, config) .then((response) => { - console.info('Exported data for table with id', tableId, 'in database with id', databaseId) + console.info('Exported data for table') resolve(response.data) }) .catch((error) => { @@ -150,7 +150,7 @@ export const useTableService = (): any => { return new Promise<TableDto>((resolve, reject) => { axios.post<TableDto>(`/api/database/${databaseId}/table`, data) .then((response) => { - console.info('Created table in database with id', databaseId) + console.info('Created table') resolve(response.data) }) .catch((error: AxiosError) => { @@ -166,7 +166,7 @@ export const useTableService = (): any => { return new Promise<void>((resolve, reject) => { axios.delete<void>(`/api/database/${databaseId}/table/${tableId}`) .then((response) => { - console.info('Deleted table with id', tableId, 'in database with id', databaseId) + console.info('Deleted table') resolve(response.data) }) .catch((error) => { @@ -182,7 +182,7 @@ export const useTableService = (): any => { return new Promise<void>((resolve, reject) => { axios.delete<void>(`/api/database/${databaseId}/table/${tableId}`, {data}) .then((response) => { - console.info('Deleted tuple(s) in table with id', tableId, 'in database with id', databaseId) + console.info(`Deleted tuple(s)`) resolve(response.data) }) .catch((error) => { @@ -198,7 +198,7 @@ export const useTableService = (): any => { return new Promise<TableHistoryDto[]>((resolve, reject) => { axios.get<TableHistoryDto[]>(`/api/database/${databaseId}/table/${tableId}/history`) .then((response) => { - console.info('Loaded history of table with id', tableId, 'in database with id', databaseId) + console.info('Loaded history of table') resolve(response.data) }) .catch((error) => { @@ -214,7 +214,7 @@ export const useTableService = (): any => { return new Promise<TableColumnEntityDto[]>((resolve, reject) => { axios.get<TableColumnEntityDto[]>(`/api/database/${databaseId}/table/${tableId}/column/${columnId}/suggest`) .then((response) => { - console.info('Suggested semantic entities for table column with id', columnId, 'of table with id', tableId, 'of database with id', databaseId) + console.info('Suggested semantic entities') resolve(response.data) }) .catch((error) => { @@ -255,7 +255,7 @@ export const useTableService = (): any => { if (!table || !user) { return false } - return table.owner.id === user.id + return table.owner.id === user.uid } function tableNameToInternalName(name: string) { diff --git a/dbrepo-ui/composables/upload-service.ts b/dbrepo-ui/composables/upload-service.ts index f7a6964d58cba007c3aa7e515f362349ca0a4f4a..ee0bdd5dc029a061ee102a9e526933ef7ca26413 100644 --- a/dbrepo-ui/composables/upload-service.ts +++ b/dbrepo-ui/composables/upload-service.ts @@ -1,11 +1,9 @@ import * as tus from 'tus-js-client' import {useCacheStore} from '@/stores/cache' -import {useUserStore} from '@/stores/user' export const useUploadService = (): any => { function create (data: File) { - const userStore = useUserStore() const config = useRuntimeConfig() const endpoint = config.public.upload.client return new Promise<string>((resolve, reject) => { @@ -13,10 +11,16 @@ export const useUploadService = (): any => { console.error('Your browser does not support uploads!') return } + const { loggedIn, user, login, logout } = useOidcAuth() + if (!loggedIn || !user.value?.accessToken) { + console.error('Please login to use the upload!') + return + } + const { accessToken } = user.value const uploadClient: tus.Upload = new tus.Upload(data, { endpoint, headers: { - 'Authorization': `Bearer ${userStore.getToken}` + 'Authorization': `Bearer ${accessToken}` }, retryDelays: [0, 3000, 5000, 10000, 20000], onError (error) { diff --git a/dbrepo-ui/composables/user-service.ts b/dbrepo-ui/composables/user-service.ts index e68b914e0e5bd5cfc410b82213e18f3eb0fa32ab..3425dbaa5c7d77d927798914b8a4fdac6123c166 100644 --- a/dbrepo-ui/composables/user-service.ts +++ b/dbrepo-ui/composables/user-service.ts @@ -80,32 +80,6 @@ export const useUserService = (): any => { }) } - async function obtainToken(username: string, password: string): Promise<KeycloakOpenIdTokenDto> { - console.debug('obtain user token for user with username', username) - return new Promise<KeycloakOpenIdTokenDto>((resolve, reject) => { - const config = useRuntimeConfig() - const userStore = useUserStore() - const instance = axios.create({ - timeout: 90_000, - params: {}, - baseURL: config.public.api.client - }) - instance.post<KeycloakOpenIdTokenDto>('/api/user/token', {username, password}) - .then((response) => { - console.info('Obtained user token') - // eslint-disable-next-line camelcase - const {access_token, refresh_token} = response.data - userStore.setToken(access_token) - userStore.setRefreshToken(refresh_token) - userStore.setRoles(tokenToRoles(access_token)) - resolve(response.data) - }).catch((error) => { - console.error('Failed to obtain user token', error) - reject(axiosErrorToApiError(error)) - }) - }) - } - async function refreshToken(refreshToken: string): Promise<KeycloakOpenIdTokenDto> { console.debug('refresh user token') return new Promise<KeycloakOpenIdTokenDto>((resolve, reject) => { @@ -136,21 +110,6 @@ export const useUserService = (): any => { return data.realm_access.roles || [] } - function tokenToUserId(token: string): string { - const data: Token = jwtDecode<Token>(token) - return data.uid - } - - function userInfoToUser(data: UserDto) { - const obj: UserDto = Object.assign({}, data) - obj.attributes = { - theme: data.attributes.theme, - orcid: data.attributes.orcid, - affiliation: data.attributes.affiliation - } - return obj - } - function nameIdentifierToNameIdentifierScheme(nameIdentifier: string) { if (nameIdentifier.includes('orcid.org')) { return 'ORCID' @@ -182,13 +141,13 @@ export const useUserService = (): any => { } function hasWriteAccess(table: TableDto, access: DatabaseAccessDto, user: UserDto): boolean { - if (!table || !access) { + if (!table || !access || !user) { return false } if (access.type === 'write_all') { return true } - return access.type === 'write_own' && table.owner.id === user.id + return access.type === 'write_own' && table.owner.id === user.uid } return { @@ -197,11 +156,6 @@ export const useUserService = (): any => { update, create, updatePassword, - obtainToken, - refreshToken, - tokenToRoles, - tokenToUserId, - userInfoToUser, nameIdentifierToNameIdentifierScheme, userToFullName, hasReadAccess, diff --git a/dbrepo-ui/dto/index.ts b/dbrepo-ui/dto/index.ts index 9171734aa350f242d2f38b0d0d0f795871f0306d..605a7c0db9984525632570c70e76dd542845f225 100644 --- a/dbrepo-ui/dto/index.ts +++ b/dbrepo-ui/dto/index.ts @@ -224,7 +224,11 @@ interface IdentifierFunderSaveDto { interface IdentifierDto { id: number; - type: string; + database_id: number | null; + query_id: number | null; + table_id: number | null; + view_id: number | null; + type: IdentifierTypeDto; titles: IdentifierTitleDto[] | []; descriptions: IdentifierDescriptionDto[] | []; funders: IdentifierFunderDto[] | []; @@ -236,23 +240,43 @@ interface IdentifierDto { licenses: LicenseDto[] | []; creators: CreatorDto[] | []; created: Date; - database_id: number | null; - query_id: number | null; - table_id: number | null; - view_id: number | null; query_normalized: string | null; related_identifiers: RelatedIdentifierDto[] | []; query_hash: string | null; result_hash: string | null; - /** - * @deprecated - */ result_number: number | null; publication_day: number | null; publication_month: number | null; - value: string | null; publication_year: number; - last_modified: Date; +} + +enum IdentifierTypeDto { + database, + subset, + table, + view +} + +enum IdentifierStatusTypeDto { + draft, + published +} + +interface IdentifierBriefDto { + id: number; + database_id: number | null; + query_id: number | null; + table_id: number | null; + view_id: number | null; + type: IdentifierTypeDto; + creators: CreatorBriefDto[] | []; + titles: IdentifierTitleDto[] | []; + description: IdentifierDescriptionDto[] | []; + doi: string | null; + publisher: string; + publication_year: number; + status: IdentifierStatusTypeDto; + owned_by: string; } interface IdentifierTitleDto { @@ -279,19 +303,35 @@ interface IdentifierFunderDto { award_title: string; } +enum NameTypeDto { + Personal, + Organizational +} + interface CreatorDto { id: number; firstname: string; lastname: string; affiliation: string; creator_name: string; - name_type: string; - name_identifier: string; - name_identifier_scheme: string; - name_identifier_scheme_uri: string; - affiliation_identifier: string; - affiliation_identifier_scheme: string; - affiliation_identifier_scheme_uri: string; + name_type: NameTypeDto | null; + name_identifier: string | null; + name_identifier_scheme: string | null; + name_identifier_scheme_uri: string | null; + affiliation_identifier: string | null; + affiliation_identifier_scheme: string | null; + affiliation_identifier_scheme_uri: string | null; +} + +interface CreatorBriefDto { + id: number; + affiliation: string; + creator_name: string; + name_type: NameTypeDto | null; + name_identifier: string | null; + name_identifier_scheme: string | null; + affiliation_identifier: string | null; + affiliation_identifier_scheme: string | null; } interface RelatedIdentifierDto { @@ -342,7 +382,6 @@ interface ColumnDto { database_id: number; table_id: number; internal_name: string; - date_format: ImageDateDto; is_primary_key: boolean; index_length: number; length: number; diff --git a/dbrepo-ui/layouts/default.vue b/dbrepo-ui/layouts/default.vue index 0ad4cb818d353d283c15d0cc7c6240fec513a54b..3ac8e32f900e9b2b95cfb5ab3dc6929a5aae7684 100644 --- a/dbrepo-ui/layouts/default.vue +++ b/dbrepo-ui/layouts/default.vue @@ -96,29 +96,22 @@ @click:append-inner="retrieve" /> <v-spacer /> <v-btn - v-if="!user" + v-if="!loggedIn" class="mr-2" color="secondary" variant="flat" + :loading="loadingLogin" :prepend-icon="$vuetify.display.mdAndUp ? 'mdi-login' : null" - to="/login"> + @click="loadingLogin=true;login()"> {{ $t('navigation.login') }} </v-btn> <v-btn - v-if="!user" - color="primary" - variant="flat" - :prepend-icon="$vuetify.display.mdAndUp ? 'mdi-account-plus' : null" - to="/signup"> - {{ $t('navigation.signup') }} - </v-btn> - <v-btn - v-if="user" + v-if="cacheUser" to="/user" variant="plain" - :text="user.username" /> + :text="cacheUser.preferred_username" /> <v-menu - v-if="user" + v-if="loggedIn" location="bottom"> <template v-slot:activator="{ props }"> <v-btn @@ -127,20 +120,19 @@ </template> <v-list> <v-list-item - v-if="user" + v-if="cacheUser" exact - :to="`/search?type=database&owner.username=${user.username}`"> + :to="`/search?type=database&owner.username=${cacheUser.username}`"> {{ $t('navigation.databases') + ' ' + $t('navigation.mine')}} </v-list-item> <v-list-item - v-if="user" + v-if="cacheUser" exact - :to="`/search?type=identifier&identifiers.creator.username=${user.username}`"> + :to="`/search?type=identifier&identifiers.creator.username=${cacheUser.username}`"> {{ $t('navigation.identifiers') + ' ' + $t('navigation.mine') }} </v-list-item> <v-list-item - v-if="user" - @click="logout"> + @click="logout()"> {{ $t('navigation.logout') }} </v-list-item> </v-list> @@ -161,10 +153,13 @@ </template> <script setup> -import { ref } from 'vue' +import { useCacheStore } from '@/stores/cache.js' +const { loggedIn, user, login, logout } = useOidcAuth() +const cacheStore = useCacheStore() +cacheStore.setUser(loggedIn ? user.value?.userInfo : null) +cacheStore.setRoles(loggedIn ? user.value?.claims?.realm_access?.roles : []) const runtimeConfig = useRuntimeConfig() -const config = ref(runtimeConfig) useServerHead({ title: runtimeConfig.public.title, meta: [ @@ -175,9 +170,9 @@ useServerHead({ </script> <script> import JumboBox from '@/components/JumboBox.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' import { errorCodeKey, makeError } from '@/utils' +import {useNuxtApp} from "#app"; export default { components: { @@ -189,6 +184,7 @@ export default { model: null, query: null, loading: true, + loadingLogin: false, databaseError: null, accessError: null, searchResults: [], @@ -197,26 +193,13 @@ export default { loadingSearch: false, loadingDatabases: false, search: null, - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - token () { - return this.userStore.getToken - }, - user () { - return this.userStore.getUser - }, - locale () { - return this.userStore.getLocale - }, messages () { return this.cacheStore.getMessages }, - access () { - return this.userStore.getAccess - }, table () { return this.cacheStore.getTable }, @@ -229,6 +212,18 @@ export default { database () { return this.cacheStore.getDatabase }, + access () { + return this.cacheStore.getAccess + }, + roles () { + return this.cacheStore.getRoles + }, + cacheUser () { + return this.cacheStore.getUser + }, + identifier () { + return this.cacheStore.getIdentifier + }, resource () { if (!this.$route.params.database_id) { return null @@ -244,9 +239,6 @@ export default { } return 'database' }, - roles () { - return this.userStore.getRoles - }, version () { return this.$config.public.version }, @@ -260,22 +252,25 @@ export default { return this.$config.public.commit.substr(0, 8) }, error () { + if (this.identifier) { + return null + } if (this.databaseError) { return this.databaseError } if (this.accessError) { return this.accessError } - if (!this.user) { + if (!this.cacheUser) { return null } - if (this.table && !this.table.is_public && !this.table.is_schema_public && this.table.owner.id !== this.user.id) { + if (this.table && !this.table.is_public && !this.table.is_schema_public && !this.access) { return makeError(403, null, null) } - if (this.view && !this.view.is_public && !this.view.is_schema_public && this.view.owner.id !== this.user.id) { + if (this.view && !this.view.is_public && !this.view.is_schema_public && !this.access) { return makeError(403, null, null) } - if (this.subset && !this.subset.is_public && !this.subset.is_schema_public && this.subset.owner.id !== this.user.id) { + if (this.subset && !this.subset.is_public && !this.subset.is_schema_public && !this.access) { return makeError(403, null, null) } return null @@ -287,41 +282,53 @@ export default { return this.roles.includes('list-ontologies') }, canListContainers () { - if (!this.roles) { - return false - } - return this.roles.includes('list-containers') + return this.cacheUser }, logo () { return this.$config.public.logo }, + locale () { + return this.cacheStore.getLocale + }, searchVariant () { const runtimeConfig = useRuntimeConfig() return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.input.contrast : 'solo-filled' - }, + } }, watch: { '$route.params': { handler (newObj, oldObj) { + if (import.meta.server) { + return + } if (!newObj.database_id) { this.databaseError = null this.accessError = null this.cacheStore.setTable(null) this.cacheStore.setView(null) this.cacheStore.setSubset(null) + this.cacheStore.setAccess(null) + this.cacheStore.setIdentifier(null) return } - if (import.meta.server) { - return + if (this.identifier) { + if (newObj.query_id && this.identifier.query_id !== Number(newObj.query_id)) { + this.cacheStore.setIdentifier(null) + } else if (newObj.table_id && this.identifier.table_id !== Number(newObj.table_id)) { + this.cacheStore.setIdentifier(null) + } else if (newObj.view_id && this.identifier.view_id !== Number(newObj.view_id)) { + this.cacheStore.setIdentifier(null) + } + if (this.$route.query.pid && this.identifier.id !== Number(this.$route.query.pid)) { + this.cacheStore.setIdentifier(null) + } } /* load database and optional access */ + this.cacheStore.setRouteAccess(newObj.database_id, this.cacheUser?.uid) this.cacheStore.setRouteDatabase(newObj.database_id) .catch((error) => { this.databaseError = error }) - if (this.user) { - this.userStore.setRouteAccess(newObj.database_id) - } /* load table */ if (newObj.table_id) { this.cacheStore.setRouteTable(newObj.database_id, newObj.table_id) @@ -346,43 +353,33 @@ export default { } }, mounted () { - this.initEnvironment() if (this.$route.query && this.$route.query.q) { this.search = this.$route.query.q } - if (!this.user) { + if (!this.cacheUser) { return } this.setTheme() + this.setLocale() this.cacheStore.reloadMessages() }, methods: { - errorCodeKey, - login () { - const redirect = ![undefined, '/', '/login'].includes(this.$router.currentRoute.path) - this.$router.push({ path: '/login', query: redirect ? { redirect: this.$router.currentRoute.path } : {} }) - }, - logout () { - this.$vuetify.theme.global.name = 'tuwThemeLight' - this.userStore.logout() - this.$router.push('/database') - }, retrieve () { console.debug('performing fuzzy search') this.$router.push({ path: '/search', query: { q: this.search } }) }, - initEnvironment () { - if (this.token && !this.user) { - console.error('Something went wrong with loading the user: reset user cache') - this.userStore.logout() - } + setLocale () { if (!this.locale) { - this.userStore.setLocale('en') + this.cacheStore.setLocale('en') + return } this.$i18n.locale = this.locale }, setTheme () { - switch (this.user.attributes.theme) { + if (!this.cacheUser?.theme) { + return + } + switch (this.cacheUser.theme) { case 'dark': this.$vuetify.theme.global.name = 'tuwThemeDark' break @@ -396,10 +393,6 @@ export default { this.$vuetify.theme.global.name = 'tuwThemeDarkContrast' break } - }, - setLocale (code) { - this.userStore.setLocale(code) - this.$i18n.locale = this.locale } } } diff --git a/dbrepo-ui/locales/en-US.json b/dbrepo-ui/locales/en-US.json index 2e94f572ec68f7f3c595254ed5c9a5e14099e623..07ac0163ef086dd1915d90daf5cf7aabc59695d4 100644 --- a/dbrepo-ui/locales/en-US.json +++ b/dbrepo-ui/locales/en-US.json @@ -606,10 +606,10 @@ }, "status": { "title": "Status", - "public": "Public", + "public": "Visible", "data": "Data-only", "schema": "Schema-only", - "draft": "Draft" + "draft": "Hidden" }, "resource": { "data": { diff --git a/dbrepo-ui/nuxt.config.ts b/dbrepo-ui/nuxt.config.ts index 4bce6ec5c5b3dc7f025734d9bf15d8e914123f79..b3da7bd98c657513e85c64cd51fac4c118d433b7 100644 --- a/dbrepo-ui/nuxt.config.ts +++ b/dbrepo-ui/nuxt.config.ts @@ -3,7 +3,7 @@ import vuetify from 'vite-plugin-vuetify' const proxy: any = {} -/* proxies the backend calls, >>NOT<< the frontend calls (clicking) */ +/* proxies the backend calls, >>NOT<< the frontend calls */ if (process.env.NODE_ENV === 'development') { const api = 'http://localhost' proxy['/api'] = api @@ -14,7 +14,14 @@ if (process.env.NODE_ENV === 'development') { '^/pid': '/pid' } } + process.env.VERSION = 'bun-dev' process.env.NUXT_PUBLIC_API_SERVER = api + process.env.NUXT_OIDC_PROVIDERS_KEYCLOAK_AUTHORIZATION_URL = api + '/realms/dbrepo/protocol/openid-connect/auth' + process.env.NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_REDIRECT_URI = api + ':3001' + process.env.NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_URL = api + '/realms/dbrepo/protocol/openid-connect/logout' + process.env.NUXT_OIDC_PROVIDERS_KEYCLOAK_REDIRECT_URI = api + ':3001/auth/keycloak/callback' + process.env.NUXT_OIDC_PROVIDERS_KEYCLOAK_TOKEN_URL = api + '/realms/dbrepo/protocol/openid-connect/token' + process.env.NUXT_OIDC_PROVIDERS_KEYCLOAK_USER_INFO_URL = api + '/realms/dbrepo/protocol/openid-connect/userinfo' } /** @@ -107,11 +114,37 @@ export default defineNuxtConfig({ port: 3001 }, + oidc: { + defaultProvider: 'keycloak', + providers: { + keycloak: { + audience: 'account', + authorizationUrl: '', + baseUrl: 'http://localhost/realms/dbrepo', + clientId: 'dbrepo-client', + clientSecret: 'MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG', + exposeAccessToken: true, + logoutRedirectUri: '', + logoutUrl: '', + optionalClaims: ['realm_access'], + redirectUri: 'http://localhost', + scope: ['openid', 'roles'], + tokenUrl: '', + userInfoUrl: '' + }, + }, + middleware: { + globalMiddlewareEnabled: false, + customLoginPage: false + }, + }, + modules: [ - '@artmizu/nuxt-prometheus', + ['@artmizu/nuxt-prometheus', {verbose: false}], '@nuxtjs/i18n', '@pinia/nuxt', '@pinia-plugin-persistedstate/nuxt', + 'nuxt-oidc-auth', async (options, nuxt) => { nuxt.hooks.hook('vite:extendConfig', config => config.plugins.push( vuetify() @@ -160,6 +193,8 @@ export default defineNuxtConfig({ }, }, - devtools: {enabled: true}, - compatibilityDate: '2024-07-24' + devtools: { + enabled: false + }, + compatibilityDate: '2025-01-25' }) diff --git a/dbrepo-ui/package.json b/dbrepo-ui/package.json index a1354778200ebabb28a575e204e264e6bd155774..d7d4917e9f45f113156951746486755d91ae7bed 100644 --- a/dbrepo-ui/package.json +++ b/dbrepo-ui/package.json @@ -4,7 +4,7 @@ "type": "module", "scripts": { "build": "nuxt build", - "dev": "VERSION=bun-dev NODE_ENV=development nuxt dev", + "dev": "NODE_ENV=development nuxt dev", "generate": "nuxt generate", "preview": "nuxt preview", "postinstall": "nuxt prepare", @@ -28,6 +28,7 @@ "merkle-json": "^2.6.0", "moment": "^2.30.1", "nuxt": "^3.10.3", + "nuxt-oidc-auth": "^1.0.0-beta.5", "parse-md": "^3.0.3", "pinia": "^2.1.7", "qs": "^6.11.2", diff --git a/dbrepo-ui/pages/container/index.vue b/dbrepo-ui/pages/container/index.vue index 360ce1543fdf086d60d568ed066ccca1f7c04537..20fed36801c24184664744ccf8b06eecba358c33 100644 --- a/dbrepo-ui/pages/container/index.vue +++ b/dbrepo-ui/pages/container/index.vue @@ -1,5 +1,6 @@ <template> - <div> + <div + v-if="loggedIn"> <v-toolbar flat :title="$t('pages.container.title')"> @@ -11,6 +12,9 @@ </div> </template> +<script setup> +const { loggedIn } = useOidcAuth() +</script> <script> import ContainerList from '@/components/container/ContainerList.vue' @@ -25,19 +29,19 @@ export default { containers: [] } }, - computed: { - roles () { - return this.userStore.getRoles - }, - }, mounted () { - this.loading = true - const containerService = useContainerService(); - containerService.findAll() - .then((containers) => { - this.containers = containers - this.loading = false - }) + this.fetchContainers() + }, + methods: { + fetchContainers () { + this.loading = true + const containerService = useContainerService(); + containerService.findAll() + .then((containers) => { + this.containers = containers + this.loading = false + }) + } } } </script> diff --git a/dbrepo-ui/pages/database/[database_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/info.vue index 6e1e35aabb3b2c150f532edf8c8fea5af610088c..025cc9c4c438523c876c346f6ccb219933a5362c 100644 --- a/dbrepo-ui/pages/database/[database_id]/info.vue +++ b/dbrepo-ui/pages/database/[database_id]/info.vue @@ -1,26 +1,27 @@ <template> <div - v-if="canViewSchema"> + v-if="identifier || canViewInfo"> <DatabaseToolbar /> <v-window v-model="tab"> <v-window-item value="1"> <Summary - v-if="hasIdentifier" + v-if="identifier" :identifier="identifier" /> <v-card - v-if="hasIdentifier" + v-if="identifier" variant="flat" rounded="0"> <v-card-text> <Select - :identifiers="filteredIdentifiers" + :identifiers="identifiers" :identifier="identifier" /> </v-card-text> </v-card> <v-divider - v-if="hasIdentifier" /> + v-if="identifier" /> <v-card + v-if="canViewInfo" :title="$t('pages.database.title')" variant="flat" rounded="0"> @@ -94,7 +95,7 @@ <div> <UserBadge :user="database.owner" - :other-user="user" /> + :other-user="cacheUser" /> </div> </v-list-item> <v-list-item @@ -104,7 +105,7 @@ <div> <UserBadge :user="database.contact" - :other-user="user" /> + :other-user="cacheUser" /> </div> </v-list-item> </v-list> @@ -163,13 +164,30 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const config = useRuntimeConfig() +const { pid } = useRoute().query +const { database_id } = useRoute().params +const { data } = await useFetch(`${config.public.api.client}/api/identifier?dbid=${database_id}&type=database&status=published`) + +if (data.value && data.value.length > 0) { + const identifierService = useIdentifierService() + useServerHead(identifierService.identifiersToServerHead(data.value)) + useServerSeoMeta(identifierService.identifiersToServerSeoMeta(data.value)) +} +const identifier = ref(data.value && data.value.length > 0 ? (pid && data.value.filter(i => i.id === Number(pid)).length > 0 ? data.value.filter(i => i.id === Number(pid))[0] : data.value[0]) : null) + +const cacheStore = useCacheStore() +cacheStore.setIdentifier(identifier) +</script> <script> import DatabaseToolbar from '@/components/database/DatabaseToolbar.vue' import Summary from '@/components/identifier/Summary.vue' import Select from '@/components/identifier/Select.vue' import UserBadge from '@/components/user/UserBadge.vue' import { sizeToHumanLabel } from '@/utils' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -197,7 +215,6 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, @@ -206,7 +223,7 @@ export default { return 0 }, description () { - if (!this.hasIdentifier) { + if (!this.identifier) { return '' } return this.database.identifier.description @@ -218,46 +235,25 @@ export default { return this.$config.public.database.image.height }, publisher () { - if (!this.hasIdentifier) { + if (!this.identifier) { return '' } return this.database.identifier.publisher }, - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, - roles () { - return this.userStore.getRoles + cacheUser () { + return this.cacheStore.getUser }, - identifiers () { - if (!this.database) { - return [] - } - return this.database.identifiers + access () { + return this.cacheStore.getAccess }, - filteredIdentifiers () { - if (!this.identifiers) { + identifiers () { + if (!this.database || !this.database.identifiers) { return [] } - if (!this.user) { - return this.identifiers.filter(i => i.status === 'published') - } - return this.identifiers.filter(i => i.status === 'published' || i.owner.id === this.user.id) - }, - identifier () { - if (this.pid) { - const filter = this.filteredIdentifiers.filter(i => i.id === Number(this.pid)) - if (filter.length > 0) { - return filter[0] - } - } - return this.filteredIdentifiers[0] - }, - access () { - return this.userStore.getAccess + return this.database.identifiers.filter(i => i.query_id === Number(this.$route.params.subset_id)) }, pid () { return this.$route.query.pid @@ -300,9 +296,6 @@ export default { const databaseService = useDatabaseService() return databaseService.databaseToOwner(this.database) }, - hasIdentifier () { - return this.identifier - }, accessDescription () { if (!this.access) { return @@ -335,12 +328,19 @@ export default { } return this.database.preview_image }, - canViewSchema () { - if (this.error) { + canViewInfo () { + if (!this.database) { return false } - return this.database - } + if (this.database.is_public || this.database.is_schema_public) { + return true + } + if (!this.access) { + return false + } + const userService = useUserService() + return userService.hasReadAccess(this.access) + }, } } </script> diff --git a/dbrepo-ui/pages/database/[database_id]/persist/[identifier_id]/index.vue b/dbrepo-ui/pages/database/[database_id]/persist/[identifier_id]/index.vue index a57b439b216ae4743fd4bda292dc53e5f7e05a69..505a7651232b071a03dd2b7ea481ff306e8dc3b4 100644 --- a/dbrepo-ui/pages/database/[database_id]/persist/[identifier_id]/index.vue +++ b/dbrepo-ui/pages/database/[database_id]/persist/[identifier_id]/index.vue @@ -1,6 +1,6 @@ <template> <div - v-if="canCreateIdentifier || canUpdateIdentifier"> + v-if="canPersistIdentifier || canUpdateIdentifier"> <Persist type="database" :database="database" /> @@ -9,9 +9,8 @@ </template> <script> -import Persist from '~/components/identifier/Persist.vue' -import { useUserStore } from '~/stores/user.js' -import { useCacheStore } from '~/stores/cache.js' +import Persist from '@/components/identifier/Persist.vue' +import { useCacheStore } from '@/stores/cache.js' export default { components: { @@ -39,34 +38,53 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { + database () { + return this.cacheStore.getDatabase + }, roles () { - return this.userStore.getRoles + return this.cacheStore.getRoles }, - user () { - return this.userStore.getUser + cacheUser () { + return this.cacheStore.getUser }, - database () { - return this.cacheStore.getDatabase + access () { + return this.cacheStore.getAccess + }, + identifier () { + if (!this.database) { + return false + } + const filter = this.database.identifiers.filter(i => i.id === Number(this.$route.params.identifier_id)) + return filter.length === 1 ? filter[0] : null }, - canCreateIdentifier () { - if (!this.roles) { + canPersistIdentifier () { + if (!this.database || !this.roles || !this.cacheUser || !this.access) { return false } if (this.roles.includes('create-foreign-identifier')) { return true } - return this.roles.includes('create-identifier') + if (!this.roles.includes('create-identifier')) { + return false + } + const userService = useUserService() + return userService.hasReadAccess(this.access) && this.database.owner.id === this.cacheUser.uid }, canUpdateIdentifier () { - if (!this.roles) { + if (!this.identifier || !this.roles) { + return false + } + if (this.roles.includes('modify-identifier-metadata')) { + return true + } + if (!this.roles.includes('create-identifier')) { return false } - return this.roles.includes('modify-identifier-metadata') + return this.identifier.owner.id === this.cacheUser.uid } } } diff --git a/dbrepo-ui/pages/database/[database_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/persist/index.vue index df675d262e8e116b0c4252d74fe6878681388acb..b66e8d706de8f4d87dd44baff8e7ded81aa7fffa 100644 --- a/dbrepo-ui/pages/database/[database_id]/persist/index.vue +++ b/dbrepo-ui/pages/database/[database_id]/persist/index.vue @@ -1,6 +1,6 @@ <template> <div - v-if="canCreateIdentifier || canUpdateIdentifier"> + v-if="canPersistIdentifier"> <Persist type="database" :database="database" /> @@ -9,9 +9,8 @@ </template> <script> -import Persist from '~/components/identifier/Persist.vue' -import { useUserStore } from '~/stores/user.js' -import { useCacheStore } from '~/stores/cache.js' +import Persist from '@/components/identifier/Persist.vue' +import { useCacheStore } from '@/stores/cache.js' export default { components: { @@ -35,46 +34,40 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - roles () { - return this.userStore.getRoles - }, - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, - hasIdentifier () { - if (this.database && 'identifier' in this.database && this.database.identifier) { - return 'id' in this.database.identifier - } - return false + cacheUser () { + return this.cacheStore.getUser + }, + roles () { + return this.cacheStore.getRoles + }, + access () { + return this.cacheStore.getAccess }, isOwner () { - if (!this.database || !this.user) { + if (!this.database || !this.cacheUser) { return false } - return this.database.owner.username === this.user.username + return this.database.owner.id === this.cacheUser.uid }, - canCreateIdentifier () { - if (!this.roles || this.hasIdentifier) { + canPersistIdentifier () { + if (!this.database || !this.roles || !this.cacheUser || !this.access) { return false } if (this.roles.includes('create-foreign-identifier')) { return true } - return this.roles.includes('create-identifier') && this.isOwner - }, - canUpdateIdentifier () { - if (!this.roles) { + if (!this.roles.includes('create-identifier')) { return false } - return this.hasIdentifier && this.roles.includes('modify-identifier-metadata') + const userService = useUserService() + return userService.hasReadAccess(this.access) && this.database.owner.id === this.cacheUser.uid } } } diff --git a/dbrepo-ui/pages/database/[database_id]/settings.vue b/dbrepo-ui/pages/database/[database_id]/settings.vue index d0fb517daebc37d65c3d18f1faed9f631a0ecff0..8905ede1d2f88c8b2411f65655c4443827c23315 100644 --- a/dbrepo-ui/pages/database/[database_id]/settings.vue +++ b/dbrepo-ui/pages/database/[database_id]/settings.vue @@ -1,14 +1,13 @@ <template> <div - v-if="canView"> + v-if="canViewSettings"> <DatabaseToolbar ref="toolbar" /> <v-window - v-if="user" v-model="tab"> <v-window-item> <v-card - v-if="isOwner && canModifyImage" + v-if="canModifyImage" variant="flat" rounded="0" :title="$t('pages.database.subpages.settings.title')" @@ -89,7 +88,6 @@ </v-card> <v-divider /> <v-card - v-if="isOwner" variant="flat" rounded="0" :title="$t('pages.database.subpages.access.title')" @@ -106,7 +104,7 @@ </template> <template v-slot:item.action="{ item }"> <v-btn - v-if="item && item.user && item.user.username !== user.username" + v-if="item && item.user && item.user.username !== cacheUser.username" size="x-small" variant="flat" color="warning" @@ -247,7 +245,6 @@ <script> import DatabaseToolbar from '@/components/database/DatabaseToolbar.vue' import EditAccess from '@/components/dialogs/EditAccess.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -323,7 +320,6 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, @@ -335,34 +331,22 @@ export default { return this.cacheStore.getDatabase }, access () { - return this.userStore.getAccess - }, - token () { - return this.userStore.getToken + return this.cacheStore.getAccess }, roles () { - return this.userStore.getRoles + return this.cacheStore.getRoles }, - user () { - return this.userStore.getUser + cacheUser () { + return this.cacheStore.getUser }, uploadProgress () { return this.cacheStore.getUploadProgress }, - isOwner () { - if (!this.database || !this.user) { - return false - } - if (this.database.owner.id === null || this.user.id === null) { - return false - } - return this.database.owner.id === this.user.id - }, isSameOwner () { - if (!this.modifyOwner || !this.user) { + if (!this.modifyOwner || !this.cacheUser) { return false } - return this.modifyOwner.id === this.user.id + return this.modifyOwner.id === this.cacheUser.uid }, isSameVisibility () { if (!this.modifyVisibility || !this.database) { @@ -371,46 +355,47 @@ export default { return this.modifyVisibility.is_public === this.database.is_public && this.modifyVisibility.is_schema_public === this.database.is_schema_public }, canModifyVisibility () { - if (!this.isOwner) { + if (!this.roles) { return false } return this.roles.includes('modify-database-visibility') }, canModifyOwnership () { - if (!this.isOwner) { + if (!this.roles) { return false } return this.roles.includes('modify-database-owner') }, canUpdateScheme () { - if (!this.isOwner) { + if (!this.roles) { return false } return this.roles.includes('find-database') }, canModifyAccess () { - if (!this.isOwner) { + if (!this.roles) { return false } return this.roles.includes('update-database-access') }, canCreateAccess () { - if (!this.isOwner) { + if (!this.roles) { return false } return this.roles.includes('create-database-access') }, canModifyImage () { - if (!this.isOwner) { + if (!this.roles) { return false } return this.roles.includes('modify-database-image') }, - canView () { - if (this.error) { + canViewSettings () { + if (!this.database || !this.cacheUser || !this.access) { return false } - return this.database + const userService = useUserService() + return userService.hasReadAccess(this.access) && this.database.owner.id === this.cacheUser.uid }, previewImage () { if (this.file) { @@ -477,7 +462,7 @@ export default { .then((database) => { const toast = useToastInstance() toast.success(this.$t('success.database.visibility')) - this.cacheStore.setDatabase(database) + this.cacheStore.reloadDatabase() }) .catch(() => { this.loading = false diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/data.vue index f96b6e41758eb2a6e25d6ea3425dfb3c2ea043b3..682fc59b98fa61b0b3fb15af227960050e5d94cb 100644 --- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/data.vue +++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/data.vue @@ -1,5 +1,6 @@ <template> - <div> + <div + v-if="canViewSubsetData"> <SubsetToolbar /> <v-toolbar color="secondary" @@ -17,7 +18,7 @@ </v-toolbar-title> <v-spacer /> <v-btn - v-if="canDownload" + v-if="canViewSubsetData" :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-download' : null" variant="flat" :loading="downloadLoading" @@ -96,30 +97,31 @@ export default { subset () { return this.cacheStore.getSubset }, + access () { + return this.cacheStore.getAccess + }, executionUTC () { if (!this.subset) { return null } return formatTimestampUTCLabel(this.subset.created) }, - canDownload () { - if (!this.result_visibility || !this.subset.id) { - return false - } - return this.subset.id - }, - result_visibility () { + canViewSubsetData () { if (!this.database || !this.subset) { return false } if (this.database.is_public) { return true } - return this.subset.owner.username === this.username - }, + if (!this.access) { + return false + } + const userService = useUserService() + return userService.hasReadAccess(this.access) + } }, mounted () { - this.loadResult() + this.loadSubset() }, methods: { loadSubset () { @@ -128,7 +130,9 @@ export default { queryService.findOne(this.$route.params.database_id, this.$route.params.subset_id) .then((subset) => { this.subset = subset - this.loadResult() + this.$refs.queryResults.reExecute(subset.id) + this.$refs.queryResults.reExecuteCount(subset.id) + this.loadingSubset = false }) .catch(() => { this.loadingSubset = false @@ -137,12 +141,6 @@ export default { this.loadingSubset = false }) }, - loadResult () { - if (this.subset) { - this.$refs.queryResults.reExecute(this.subset.id) - this.$refs.queryResults.reExecuteCount(this.subset.id) - } - }, download () { this.downloadLoading = true const queryService = useQueryService() diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue index f067fbadb4a190aff0843e289281971997426772..db5d45b4610de195f2a16d213eea60674c8dcf86 100644 --- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue +++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/info.vue @@ -1,36 +1,29 @@ <template> - <div> + <div + v-if="identifier || canViewInfo"> <SubsetToolbar /> <v-card variant="flat" rounded="0"> <Summary - v-if="hasIdentifier" + v-if="identifier" :identifier="identifier" /> <v-card-text - v-if="hasIdentifier"> + v-if="identifier"> <Select :identifiers="identifiers" :identifier="identifier" /> </v-card-text> </v-card> <v-divider - v-if="subset && identifier" /> + v-if="canViewInfo && identifier" /> <v-card + v-if="canViewInfo" variant="flat" rounded="0" :title="$t('pages.subset.title')"> <v-card-text> <v-list - v-if="!subset" - lines="two" - dense> - <v-skeleton-loader - type="list-item-three-line" - width="50%" /> - </v-list> - <v-list - v-else-if="subset" lines="two" dense> <v-list-item @@ -50,7 +43,9 @@ v-if="subset.creator" :title="$t('pages.subset.creator.title')" density="compact"> - <UserBadge :user="subset.creator" :other-user="user" /> + <UserBadge + :user="subset.creator" + :other-user="cacheUser" /> </v-list-item> <v-list-item :title="$t('pages.subset.query.title')" @@ -86,13 +81,30 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const config = useRuntimeConfig() +const { pid } = useRoute().query +const { database_id, subset_id } = useRoute().params +const { data } = await useFetch(`${config.public.api.client}/api/identifier?dbid=${database_id}&qid=${subset_id}&type=subset&status=published`) + +if (data.value && data.value.length > 0) { + const identifierService = useIdentifierService() + useServerHead(identifierService.identifiersToServerHead(data.value)) + useServerSeoMeta(identifierService.identifiersToServerSeoMeta(data.value)) +} +const identifier = ref(data.value && data.value.length > 0 ? (pid && data.value.filter(i => i.id === Number(pid)).length > 0 ? data.value.filter(i => i.id === Number(pid))[0] : data.value[0]) : null) + +const cacheStore = useCacheStore() +cacheStore.setIdentifier(identifier) +</script> <script> import Summary from '@/components/identifier/Summary.vue' import SubsetToolbar from '@/components/subset/SubsetToolbar.vue' import Select from '@/components/identifier/Select.vue' import UserBadge from '@/components/user/UserBadge.vue' import { formatTimestampUTCLabel } from '@/utils' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -134,7 +146,6 @@ export default { downloadLoading: false, error: false, promises: [], - userStore: useUserStore(), cacheStore: useCacheStore() } }, @@ -145,35 +156,33 @@ export default { database () { return this.cacheStore.getDatabase }, - access () { - return this.userStore.getAccess + cacheUser () { + return this.cacheStore.getUser }, subset () { return this.cacheStore.getSubset }, - user () { - return this.userStore.getUser - }, identifiers () { - if (!this.database || !this.database.subsets || this.database.subsets.length === 0) { + if (!this.database || !this.database.subsets) { return [] } - return this.database.subsets.filter(s => s.query_id === Number(this.$route.params.subset_id)) - }, - hasIdentifier () { - return this.identifiers.length > 0 + return this.database.subsets.filter(i => i.query_id === Number(this.$route.params.subset_id)) }, - identifier () { - if (this.pid) { - const filter = this.identifiers.filter(i => i.id === Number(this.pid)) - if (filter.length > 0) { - return filter[0] - } + canViewInfo () { + if (!this.database) { + return false + } + if (this.database.is_public || this.database.is_schema_public) { + return true + } + if (!this.access) { + return false } - return this.identifiers[0] + const userService = useUserService() + return userService.hasReadAccess(this.access) }, title () { - if (!this.hasIdentifier) { + if (!this.identifier) { return null } const enTitle = this.identifier.titles.filter(t => t.language).filter(t => t.language === 'en') diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/[identifier_id]/index.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/[identifier_id]/index.vue index b15ecb3292520979e550f68c7c16ef873638b124..78878a0015f61ea3dadf38258b747b20fa8e94d9 100644 --- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/[identifier_id]/index.vue +++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/[identifier_id]/index.vue @@ -1,6 +1,6 @@ <template> <div - v-if="canCreateIdentifier || canUpdateIdentifier"> + v-if="canPersistIdentifier || canUpdateIdentifier"> <Persist type="subset" :database="database" /> @@ -9,9 +9,8 @@ </template> <script> -import Persist from '~/components/identifier/Persist.vue' -import { useUserStore } from '~/stores/user.js' -import { useCacheStore } from '~/stores/cache.js' +import Persist from '@/components/identifier/Persist.vue' +import { useCacheStore } from '@/stores/cache.js' export default { components: { @@ -47,34 +46,56 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { + database () { + return this.cacheStore.getDatabase + }, roles () { - return this.userStore.getRoles + return this.cacheStore.getRoles }, - user () { - return this.userStore.getUser + subset () { + return this.cacheStore.getSubset }, - database () { - return this.cacheStore.getDatabase + access () { + return this.cacheStore.getAccess + }, + cacheUser () { + return this.cacheStore.getUser }, - canCreateIdentifier () { - if (!this.roles) { + identifier () { + if (!this.subset) { + return false + } + const filter = this.subset.identifiers.filter(i => i.id === Number(this.$route.params.identifier_id)) + return filter.length === 1 ? filter[0] : null + }, + canPersistIdentifier () { + if (!this.subset || !this.roles || !this.cacheUser || !this.access) { return false } if (this.roles.includes('create-foreign-identifier')) { return true } - return this.roles.includes('create-identifier') + if (!this.roles.includes('create-identifier')) { + return false + } + const userService = useUserService() + return userService.hasReadAccess(this.access) && this.subset.owner.id === this.cacheUser.uid }, canUpdateIdentifier () { - if (!this.roles) { + if (!this.identifier || !this.roles) { + return false + } + if (this.roles.includes('modify-identifier-metadata')) { + return true + } + if (!this.roles.includes('create-identifier')) { return false } - return this.roles.includes('modify-identifier-metadata') + return this.identifier.owner.id === this.cacheUser.uid } } } diff --git a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/index.vue index 07be66bc73911c9bd7580991ef2c71c6d36de5bc..88209f50188e473e306a826674051de883e83b3f 100644 --- a/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/index.vue +++ b/dbrepo-ui/pages/database/[database_id]/subset/[subset_id]/persist/index.vue @@ -1,18 +1,17 @@ <template> <div - v-if="canPersistQuery"> + v-if="canPersistIdentifier"> <Persist type="subset" :database="database" - :query="query" /> + :query="subset" /> <v-breadcrumbs :items="items" class="pa-0 mt-2" /> </div> </template> <script> -import Persist from '~/components/identifier/Persist.vue' -import { useUserStore } from '~/stores/user.js' -import { useCacheStore } from '~/stores/cache.js' +import Persist from '@/components/identifier/Persist.vue' +import { useCacheStore } from '@/stores/cache.js' export default { components: { @@ -21,8 +20,6 @@ export default { data () { return { loading: false, - loadingQuery: false, - query: null, isAuthorizationError: false, items: [ { @@ -47,51 +44,37 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - roles () { - return this.userStore.getRoles - }, database () { return this.cacheStore.getDatabase }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess + }, + subset () { + return this.cacheStore.getSubset + }, + roles () { + return this.cacheStore.getRoles + }, + cacheUser () { + return this.cacheStore.getUser }, - canPersistQuery () { - if (this.loadingQuery || !this.query) { + canPersistIdentifier () { + if (!this.subset || !this.roles || !this.cacheUser || !this.access) { + return false + } + if (this.roles.includes('create-foreign-identifier')) { + return true + } + if (!this.roles.includes('create-identifier')) { return false } const userService = useUserService() - return userService.hasReadAccess(this.access) - } - }, - mounted () { - this.loadQuery() - }, - methods: { - loadQuery () { - this.loadingQuery = true - return new Promise((resolve, reject) => { - const queryService = useQueryService() - queryService.findOne(this.$route.params.database_id, this.$route.params.subset_id) - .then((query) => { - this.query = query - resolve(query) - }) - .catch((error) => { - if (error.response.status === 405) { - this.isAuthorizationError = true - } - reject(error) - }) - .finally(() => { - this.loadingQuery = false - }) - }) + return userService.hasReadAccess(this.access) && this.subset.owner.id === this.cacheUser.uid } } } diff --git a/dbrepo-ui/pages/database/[database_id]/subset/create.vue b/dbrepo-ui/pages/database/[database_id]/subset/create.vue index 0fb591f9f8307018da13539491089c68c2a9ba16..c3d07bba1570ef6e116ff0bb5e18145104526175 100644 --- a/dbrepo-ui/pages/database/[database_id]/subset/create.vue +++ b/dbrepo-ui/pages/database/[database_id]/subset/create.vue @@ -7,7 +7,6 @@ </template> <script> -import { useUserStore } from '@/stores/user.js' import Builder from '@/components/subset/Builder.vue' import {useCacheStore} from '@/stores/cache.js' @@ -36,28 +35,15 @@ export default { disabled: true } ], - cacheStore: useCacheStore(), - userStore: useUserStore() + cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles - }, database () { return this.cacheStore.getDatabase }, access () { - return this.userStore.getAccess - }, - hasReadAccess () { - if (!this.access) { - return false - } - return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own' + return this.cacheStore.getAccess }, canCreateSubset () { if (!this.database) { @@ -66,7 +52,11 @@ export default { if (this.database.is_public) { return true } - return this.hasReadAccess + if (!this.access) { + return false + } + const userService = useUserService() + return userService.hasReadAccess(this.access) } } } diff --git a/dbrepo-ui/pages/database/[database_id]/subset/index.vue b/dbrepo-ui/pages/database/[database_id]/subset/index.vue index 2f68604881a0e222dbd280a5c54ff375ca8c0825..d98a8ba2afc6f26466c50e31acfc10ed0f32acd3 100644 --- a/dbrepo-ui/pages/database/[database_id]/subset/index.vue +++ b/dbrepo-ui/pages/database/[database_id]/subset/index.vue @@ -39,11 +39,21 @@ export default { database () { return this.cacheStore.getDatabase }, + access () { + return this.cacheStore.getAccess + }, canViewSchema () { - if (this.error) { + if (!this.database) { + return false + } + if (this.database.is_schema_public) { + return true + } + if (!this.access) { return false } - return this.database + const userService = useUserService() + return userService.hasReadAccess(this.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 2e76d4ebd4a62d0744813740d7c4b55e950d54ca..13ee3951c80fae3bb0a3f8391133b53aec57bf79 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 @@ -53,7 +53,6 @@ class="ml-2 mr-2" @click.stop="pick" /> </v-toolbar> - <TimeDrift /> <v-card v-if="error" variant="flat"> @@ -81,6 +80,7 @@ @close="pickVersion" /> </v-dialog> <v-dialog + v-if="loggedIn" v-model="addTupleDialog" persistent max-width="640"> @@ -91,6 +91,7 @@ @close="close" /> </v-dialog> <v-dialog + v-if="loggedIn" v-model="editTupleDialog" persistent max-width="640"> @@ -104,12 +105,13 @@ </div> </template> +<script setup> +const { loggedIn } = useOidcAuth() +</script> <script> import TableHistory from '@/components/table/TableHistory.vue' -import TimeDrift from '@/components/TimeDrift.vue' import TableToolbar from '@/components/table/TableToolbar.vue' import { formatTimestamp } from '@/utils' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' import EditTuple from '@/components/dialogs/EditTuple.vue' import BlobDownload from '@/components/table/BlobDownload.vue' @@ -121,12 +123,12 @@ export default { BlobDownload, EditTuple, TableHistory, - TableToolbar, - TimeDrift + TableToolbar }, data () { return { loading: true, + error: false, loadingData: false, loadingCount: false, loadingDelete: false, @@ -178,31 +180,24 @@ export default { ], headers: [], rows: [], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - roles () { - return this.userStore.getRoles - }, database () { return this.cacheStore.getDatabase }, table () { return this.cacheStore.getTable }, - user () { - return this.userStore.getUser + roles () { + return this.cacheStore.getRoles }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, - hasReadAccess () { - if (!this.access) { - return false - } - return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own' + cacheUser () { + return this.cacheStore.getUser }, title () { return (this.version ? this.$t('toolbars.database.history') : this.$t('toolbars.database.current')) + ' ' + this.versionFormatted @@ -228,15 +223,6 @@ export default { } return this.version.substring(0, 10) + 'T' + this.version.substring(11, 19) + 'Z' }, - canModify () { - if (!this.user || !this.access || !this.table) { - return false - } - if (this.access.type === 'write_own' && this.table.owner.id === this.user.id) { - return true - } - return this.access.type === 'write_all' - }, primaryKeyColumns () { if (!this.table) { return [] @@ -244,47 +230,45 @@ export default { return this.table.constraints.primary_key.map(pk => pk.column) }, canViewTableData () { - if (this.error) { - return false - } if (!this.table) { return false } if (this.table.is_public) { return true } - if (!this.roles || !this.roles.includes('view-table-data')) { + if (!this.roles || !this.roles.includes('view-table-data') || !this.access) { return false } - return this.hasReadAccess + const userService = useUserService() + return userService.hasReadAccess(this.access) }, canAddTuple () { if (!this.roles) { return false } const userService = useUserService() - return userService.hasWriteAccess(this.table, this.access, this.user) && this.roles.includes('insert-table-data') + return userService.hasWriteAccess(this.table, this.access, this.cacheUser) && this.roles.includes('insert-table-data') }, canSelectTuples () { if (!this.roles) { return false } const userService = useUserService() - return userService.hasWriteAccess(this.table, this.access, this.user) && this.roles.includes('insert-table-data') + return userService.hasWriteAccess(this.table, this.access, this.cacheUser) && this.roles.includes('insert-table-data') }, canEditTuple () { if (!this.roles || this.selection === null || this.selection.length !== 1) { return false } const userService = useUserService() - return userService.hasWriteAccess(this.table, this.access, this.user) && this.roles.includes('insert-table-data') + return userService.hasWriteAccess(this.table, this.access, this.cacheUser) && this.roles.includes('insert-table-data') }, canDeleteTuple () { if (!this.roles || this.selection === null || this.selection.length < 1) { return false } const userService = useUserService() - return userService.hasWriteAccess(this.table, this.access, this.user) && this.roles.includes('delete-table-data') + return userService.hasWriteAccess(this.table, this.access, this.cacheUser) && this.roles.includes('delete-table-data') } }, watch: { diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/import.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/import.vue index 4cf0057ea429438ca08282a63ac27f182f80baf0..efbcd6accf7d3d896769241a7de0d1325a30b3a4 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/import.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/import.vue @@ -30,7 +30,6 @@ <script> import TableImport from '@/components/table/TableImport.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -69,19 +68,21 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser + table () { + return this.cacheStore.getTable }, roles () { - return this.userStore.getRoles + return this.cacheStore.getRoles }, - table () { - return this.cacheStore.getTable + cacheUser () { + return this.cacheStore.getUser + }, + access () { + return this.cacheStore.getAccess }, title () { if (!this.table) { @@ -90,10 +91,11 @@ export default { return this.$t('pages.table.import.title') + ' ' + this.table.name }, canInsertTableData () { - if (!this.roles) { + if (!this.table || !this.access || !this.cacheUser || !this.roles || !this.roles.includes('insert-table-data')) { return false } - return this.roles.includes('insert-table-data') + const userService = useUserService() + return userService.hasWriteAccess(this.table, this.access, this.cacheUser) } } } diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue index 916c72b85052ce54c71d0bfa3cbe67708d606b0a..687358f0290177012dc89f36e23666d6dd6d48d0 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/info.vue @@ -1,15 +1,14 @@ <template> <div - v-if="canViewSchema"> + v-if="identifier || canViewInfo"> <TableToolbar :selection="selection" /> <v-card + v-if="identifier" variant="flat"> <Summary - v-if="hasIdentifier" :identifier="identifier" /> - <v-card-text - v-if="hasIdentifier"> + <v-card-text> <Select :identifiers="identifiers" :identifier="identifier" /> @@ -18,6 +17,7 @@ <v-divider v-if="identifier" /> <v-card + v-if="canViewInfo" variant="flat" rounded="0" :title="$t('pages.table.title')"> @@ -64,7 +64,7 @@ :title="$t('pages.table.owner.title')"> <UserBadge :user="table.owner" - :other-user="user" /> + :other-user="cacheUser" /> </v-list-item> </v-list> </v-card-text> @@ -118,12 +118,29 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const config = useRuntimeConfig() +const { pid } = useRoute().query +const { database_id, table_id } = useRoute().params +const { data } = await useFetch(`${config.public.api.client}/api/identifier?dbid=${database_id}&tid=${table_id}&type=table&status=published`) + +if (data.value && data.value.length > 0) { + const identifierService = useIdentifierService() + useServerHead(identifierService.identifiersToServerHead(data.value)) + useServerSeoMeta(identifierService.identifiersToServerSeoMeta(data.value)) +} +const identifier = ref(data.value && data.value.length > 0 ? (pid && data.value.filter(i => i.id === Number(pid)).length > 0 ? data.value.filter(i => i.id === Number(pid))[0] : data.value[0]) : null) + +const cacheStore = useCacheStore() +cacheStore.setIdentifier(identifier) +</script> <script> import TableToolbar from '@/components/table/TableToolbar.vue' import Select from '@/components/identifier/Select.vue' import Summary from '@/components/identifier/Summary.vue' import UserBadge from '@/components/user/UserBadge.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -165,7 +182,6 @@ export default { loading: false, exchange: null, queue: null, - userStore: useUserStore(), cacheStore: useCacheStore() } }, @@ -173,50 +189,47 @@ export default { pid () { return this.$route.query.pid }, - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, table () { return this.cacheStore.getTable }, + cacheUser () { + return this.cacheStore.getUser + }, roles () { - return this.userStore.getRoles + return this.cacheStore.getRoles }, canRead () { if (this.database && this.database.is_public) { return true } - if (!this.user || !this.access) { + if (!this.access) { return false } - return this.access.type === 'read' || this.access.type === 'write_own' || this.access.type === 'write_all' + const userService = useUserService() + return userService.hasReadAccess(this.access) }, - canViewSchema () { - if (this.error) { - return false - } + canViewInfo () { if (!this.table) { return false } - if (this.table.is_schema_public || this.table.is_public) { + if (this.table.is_public || this.table.is_schema_public) { return true } - if (!this.user) { + if (!this.access) { return false } - return this.hasReadAccess || this.table.owner.id === this.user.id || this.database.owner.id === this.user.id + const userService = useUserService() + return userService.hasReadAccess(this.access) }, canWrite () { - if (!this.table || !this.user || !this.access) { - return false - } - return (this.access.type === 'write_own' && this.table.owned_by === this.user.id) || this.access.type === 'write_all' + const userService = useUserService() + return userService.hasWriteAccess(this.table, this.access, this.cacheUser) }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, hasDescription () { return this.table && this.table.description @@ -228,31 +241,10 @@ export default { return this.roles.includes('insert-table-data') }, identifiers () { - if (!this.table || !this.table.identifiers || this.table.identifiers.length === 0) { - return [] - } - return this.table.identifiers - }, - filteredIdentifiers () { - if (!this.identifiers) { + if (!this.table || !this.table.identifiers) { return [] } - if (!this.user) { - return this.identifiers.filter(i => i.status === 'published') - } - return this.identifiers.filter(i => i.status === 'published' || i.owned_by === this.user.id) - }, - identifier () { - if (this.pid) { - const filter = this.filteredIdentifiers.filter(i => i.id === Number(this.pid)) - if (filter.length > 0) { - return filter[0] - } - } - return this.filteredIdentifiers[0] - }, - hasIdentifier () { - return this.identifier + return this.table.identifiers.filter(i => i.query_id === Number(this.$route.params.subset_id)) }, brokerExtraInfo () { return this.$config.public.broker.extra diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/[identifier_id]/index.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/[identifier_id]/index.vue index 663b2a5550d7875e1da0c3ed86fab1f24f359350..e2d16e8db44efb0f558fa2c42e1225fc9e6b8355 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/[identifier_id]/index.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/[identifier_id]/index.vue @@ -1,6 +1,6 @@ <template> <div - v-if="canCreateIdentifier || canUpdateIdentifier"> + v-if="canPersistIdentifier || canUpdateIdentifier"> <Persist type="table" :database="database" /> <v-breadcrumbs :items="items" class="pa-0 mt-2" /> </div> @@ -8,7 +8,6 @@ <script> import Persist from '@/components/identifier/Persist.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -45,34 +44,56 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { + database () { + return this.cacheStore.getDatabase + }, roles () { - return this.userStore.getRoles + return this.cacheStore.getRoles }, - user () { - return this.userStore.getUser + table () { + return this.cacheStore.getTable }, - database () { - return this.cacheStore.getDatabase + cacheUser () { + return this.cacheStore.getUser + }, + access () { + return this.cacheStore.getAccess }, - canCreateIdentifier () { - if (!this.roles) { + identifier () { + if (!this.table) { + return false + } + const filter = this.table.identifiers.filter(i => i.id === Number(this.$route.params.identifier_id)) + return filter.length === 1 ? filter[0] : null + }, + canPersistIdentifier () { + if (!this.table || !this.roles || !this.cacheUser || !this.access) { return false } if (this.roles.includes('create-foreign-identifier')) { return true } - return this.roles.includes('create-identifier') + if (!this.roles.includes('create-identifier')) { + return false + } + const userService = useUserService() + return userService.hasReadAccess(this.access) && this.table.owner.id === this.cacheUser.uid }, canUpdateIdentifier () { - if (!this.roles) { + if (!this.identifier || !this.roles) { + return false + } + if (this.roles.includes('modify-identifier-metadata')) { + return true + } + if (!this.roles.includes('create-identifier')) { return false } - return this.roles.includes('modify-identifier-metadata') + return this.identifier.owner.id === this.cacheUser.uid } } } diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/index.vue index 250fedaa5d4676dc6c304d3d71aa9b3a23b21ffc..6c26187fa23ff0669bad399b57e3ab48b15ec061 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/index.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/persist/index.vue @@ -1,6 +1,6 @@ <template> <div - v-if="canPersistTable"> + v-if="canPersistIdentifier"> <Persist type="table" :database="database" @@ -13,7 +13,6 @@ <script> import Persist from '@/components/identifier/Persist.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -48,29 +47,37 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - roles () { - return this.userStore.getRoles - }, database () { return this.cacheStore.getDatabase }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, table () { return this.cacheStore.getTable }, - canPersistTable () { - if (!this.table) { + roles () { + return this.cacheStore.getRoles + }, + cacheUser () { + return this.cacheStore.getUser + }, + canPersistIdentifier () { + if (!this.table || !this.roles || !this.cacheUser || !this.access) { + return false + } + if (this.roles.includes('create-foreign-identifier')) { + return true + } + if (!this.roles.includes('create-identifier')) { return false } const userService = useUserService() - return userService.hasReadAccess(this.access) + return userService.hasReadAccess(this.access) && this.table.owner.id === this.cacheUser.uid } } } diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue index 0c6a60e15b9c052656a61e9d71ec3fcd3d944cb2..ac48b40644823b9393b26608a0cfa5e56790d03a 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue @@ -120,9 +120,11 @@ </div> </template> +<script setup> +const { loggedIn } = useOidcAuth() +</script> <script> import TableToolbar from '@/components/table/TableToolbar.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -168,14 +170,10 @@ export default { { value: 'description', title: this.$t('pages.table.subpages.schema.description.title') }, ], dateColumns: [], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, @@ -183,7 +181,13 @@ export default { return this.cacheStore.getTable }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess + }, + cacheUser () { + return this.cacheStore.getUser + }, + roles () { + return this.cacheStore.getRoles }, hasReadAccess () { if (!this.access) { @@ -191,29 +195,24 @@ export default { } return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own' }, - roles () { - return this.userStore.getRoles - }, canViewSchema () { - if (this.error) { - return false - } if (!this.table) { return false } if (this.table.is_schema_public) { return true } - if (!this.user) { + if (!this.access) { return false } - return this.hasReadAccess || this.table.owner.id === this.user.id || this.database.owner.id === this.user.id + const userService = useUserService() + return userService.hasReadAccess(this.access) }, primaryKeysColumns () { return this.table.constraints.primary_key.map(pk => pk.column.internal_name).join(', ') }, canAssignSemanticInformation () { - if (!this.user) { + if (!this.cacheUser || !this.roles) { return false } if (this.roles.includes('modify-foreign-table-column-semantics')) { @@ -222,7 +221,7 @@ export default { if (!this.access) { return false } - return this.roles.includes('modify-table-column-semantics') && (this.access.type === 'write_all' || this.table.owner.username === this.user.username) + return this.roles.includes('modify-table-column-semantics') && (this.access.type === 'write_all' || this.table.owner.id === this.cacheUser.uid) }, inputVariant () { const runtimeConfig = useRuntimeConfig() diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue index 3d718d57398324f1099ceff42b80d80a55cf18b5..0f0a8feab62a7fb065c3ecb6af6b63b83a9884be 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/settings.vue @@ -3,7 +3,6 @@ v-if="canUpdateTable"> <TableToolbar /> <v-window - v-if="user" v-model="tab"> <v-window-item> <v-form @@ -23,9 +22,6 @@ <v-textarea v-model="modify.description" rows="2" - :rules="[ - v => !max(v, 180) || ($t('validation.max-length') + 180), - ]" clearable counter="180" persistent-counter @@ -116,7 +112,6 @@ <script> import TableToolbar from '@/components/table/TableToolbar.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' import { max } from '@/utils' @@ -127,7 +122,7 @@ export default { data () { return { tab: 0, - valid: false, + valid: true, loading: false, modify: { description: null, @@ -175,14 +170,10 @@ export default { { value: 'description', title: this.$t('pages.table.subpages.schema.description.title') }, ], dateColumns: [], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, @@ -190,47 +181,39 @@ export default { return this.cacheStore.getTable }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, - hasReadAccess () { - if (!this.access) { - return false - } - return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own' + cacheUser () { + return this.cacheStore.getUser }, roles () { - return this.userStore.getRoles + return this.cacheStore.getRoles }, isChange () { if (!this.table) { return false } - if (this.table.is_public !== this.modify.is_public) { + if (this.table.is_public !== this.modify.is_public || this.table.is_schema_public !== this.modify.is_schema_public) { return true } - return this.table.is_schema_public !== this.modify.is_schema_public + return this.table.description !== this.modify.description }, canUpdateTable () { - if (!this.roles || !this.user || !this.table) { - return false - } - return this.roles.includes('update-table') && this.table.owner.id === this.user.id - }, - canModifyVisibility () { - if (!this.roles || !this.user || !this.table) { + if (!this.cacheUser || !this.table || !this.access || !this.roles || !this.roles.includes('update-table')) { return false } - return this.roles.includes('update-table') && this.table.owner.id === this.user.id + const userService = useUserService() + return userService.hasReadAccess(this.access) && this.table.owner.id === this.cacheUser.uid }, canDropTable () { - if (!this.roles || !this.table || !this.user) { + if (!this.roles || !this.table || !this.cacheUser) { return false } if (this.roles.includes('delete-foreign-table')) { return true } const tableService = useTableService() - return tableService.isOwner(this.table, this.user) && this.roles.includes('delete-table') && this.table.identifiers.length === 0 + return tableService.isOwner(this.table, this.cacheUser) && this.roles.includes('delete-table') && this.table.identifiers.length === 0 }, inputVariant () { const runtimeConfig = useRuntimeConfig() diff --git a/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue b/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue index df74cc6e7046e90f6e5e9844769a2e1e8f45e372..24aed7f2ffc6b77edfae4a90e1c4dc7607f97955 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/create/dataset.vue @@ -92,9 +92,6 @@ <v-textarea v-model="tableCreate.description" rows="2" - :rules="[ - v => (!!v || v.length <= 180) || ($t('validation.max-length') + 180), - ]" clearable counter="180" persistent-counter @@ -219,10 +216,9 @@ </div> </template> -<script> + <script> import TableSchema from '@/components/table/TableSchema.vue' import { notEmpty } from '@/utils' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -304,7 +300,6 @@ export default { loading: false, url: null, columns: [], - userStore: useUserStore(), cacheStore: useCacheStore() } }, @@ -316,15 +311,12 @@ export default { this.tableCreate.is_schema_public = this.database.is_schema_public }, computed: { - user() { - return this.userStore.getUser - }, - roles() { - return this.userStore.getRoles - }, database() { return this.cacheStore.getDatabase }, + roles () { + return this.cacheStore.getRoles + }, generatedTableName() { if (!this.tableCreate.name) { return null diff --git a/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue b/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue index c900ba31aa104dcc1ce5e3250dd0bb5a2b92f6fa..804ae03c15072719f7612fd46eeca80d45b1a2b8 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/create/schema.vue @@ -70,9 +70,6 @@ <v-textarea v-model="tableCreate.description" rows="2" - :rules="[ - v => (!v || v.length <= 180) || $t('validation.max-length') + 180 - ]" clearable counter="180" persistent-counter @@ -188,7 +185,6 @@ <script> import TableSchema from '@/components/table/TableSchema.vue' import { notEmpty } from '@/utils' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -247,7 +243,6 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, @@ -259,15 +254,12 @@ export default { const tableService = useTableService() return tableService.tableNameToInternalName(this.tableCreate.name) }, - roles () { - return this.userStore.getRoles - }, - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, + roles () { + return this.cacheStore.getRoles + }, canCreateTable () { if (!this.roles) { return false diff --git a/dbrepo-ui/pages/database/[database_id]/table/index.vue b/dbrepo-ui/pages/database/[database_id]/table/index.vue index ae3e3c13f1b173b62514e1ee8887fd648e3f65a1..c2a2b76206918a0882c7e041aa3f38fb19ccfe12 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/index.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/index.vue @@ -48,11 +48,18 @@ export default { database () { return this.cacheStore.getDatabase }, + access () { + return this.cacheStore.getAccess + }, canViewSchema () { - if (this.error) { + if (!this.database) { return false } - return this.database + if (this.database.is_schema_public) { + return true + } + const userService = useUserService() + return userService.hasReadAccess(this.access) } } } diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue index 54c54dad00d4764383c8d38e979870391680d563..f732661f369710b4637f01952f5fab930e9e4812 100644 --- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue +++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue @@ -22,7 +22,6 @@ :loading="loadingData" @click="reload" /> </v-toolbar> - <TimeDrift /> <v-card tile> <QueryResults id="query-results" @@ -35,14 +34,11 @@ </template> <script> -import TimeDrift from '@/components/TimeDrift.vue' import QueryResults from '@/components/subset/Results.vue' -import { useUserStore } from '@/stores/user.js' export default { components: { - QueryResults, - TimeDrift + QueryResults }, data () { return { @@ -70,14 +66,10 @@ export default { disabled: true } ], - cacheStore: useCacheStore(), - userStore: useUserStore() + cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, @@ -85,13 +77,10 @@ export default { return this.cacheStore.getView }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, - hasReadAccess () { - if (!this.access) { - return false - } - return this.access.type === 'read' || this.access.type === 'write_own' || this.access.type === 'write_all' + cacheUser () { + return this.cacheStore.getUser }, canReadData () { if (!this.view) { @@ -100,10 +89,11 @@ export default { if (this.view.is_public) { return true } - if (!this.user) { + if (!this.access) { return false } - return this.view.owner.id === this.user.id || this.hasReadAccess + const userService = useUserService() + return userService.hasReadAccess(this.access) }, }, mounted () { diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue index c9865a1b4abbefd3bd07361b7c6a5a5ff86b0834..3c0c40e33ce7546e351ea3252a051a0ebb56049e 100644 --- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue +++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/info.vue @@ -1,25 +1,25 @@ <template> <div - v-if="canViewView"> + v-if="identifier || canViewInfo"> <ViewToolbar /> <v-window v-model="tab"> - <v-window-item - v-if="view"> + <v-window-item> <v-card variant="flat"> <Summary - v-if="hasIdentifier" + v-if="identifier" :identifier="identifier" /> <v-card-text - v-if="hasIdentifier"> + v-if="identifier"> <Select :identifiers="identifiers" :identifier="identifier" /> </v-card-text> </v-card> <v-divider - v-if="hasIdentifier" /> + v-if="identifier" /> <v-card + v-if="canViewInfo" :title="$t('pages.view.title')" variant="flat"> <v-card-text> @@ -39,7 +39,7 @@ <UserBadge v-if="view" :user="view.owner" - :other-user="user" /> + :other-user="cacheUser" /> <v-skeleton-loader v-else type="subtitle" @@ -59,13 +59,30 @@ </div> </template> +<script setup> +import { ref } from 'vue' + +const config = useRuntimeConfig() +const { pid } = useRoute().query +const { database_id, view_id } = useRoute().params +const { data } = await useFetch(`${config.public.api.client}/api/identifier?dbid=${database_id}&vid=${view_id}&type=view&status=published`) + +if (data.value && data.value.length > 0) { + const identifierService = useIdentifierService() + useServerHead(identifierService.identifiersToServerHead(data.value)) + useServerSeoMeta(identifierService.identifiersToServerSeoMeta(data.value)) +} +const identifier = ref(data.value && data.value.length > 0 ? (pid && data.value.filter(i => i.id === Number(pid)).length > 0 ? data.value.filter(i => i.id === Number(pid))[0] : data.value[0]) : null) + +const cacheStore = useCacheStore() +cacheStore.setIdentifier(identifier) +</script> <script> import ViewToolbar from '@/components/view/ViewToolbar.vue' import Summary from '@/components/identifier/Summary.vue' import Select from '@/components/identifier/Select.vue' import UserBadge from '@/components/user/UserBadge.vue' import { formatTimestampUTCLabel } from '@/utils' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -103,55 +120,30 @@ export default { } ], error: false, - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles - }, database () { return this.cacheStore.getDatabase }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, view () { return this.cacheStore.getView }, - hasReadAccess () { - if (!this.access) { - return false - } - return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own' + roles () { + return this.cacheStore.getRoles }, - identifiers () { - if (!this.view) { - return [] - } - return this.view.identifiers + cacheUser () { + return this.cacheStore.getUser }, - filteredIdentifiers () { - if (!this.identifiers) { + identifiers () { + if (!this.view || !this.view.identifiers) { return [] } - if (!this.user) { - return this.identifiers.filter(i => i.status === 'published') - } - return this.identifiers.filter(i => i.status === 'published' || i.owner.id === this.user.id) - }, - identifier () { - if (this.pid) { - const filter = this.filteredIdentifiers.filter(i => i.id === Number(this.pid)) - if (filter.length > 0) { - return filter[0] - } - } - return this.filteredIdentifiers[0] + return this.view.identifiers.filter(i => i.query_id === Number(this.$route.params.subset_id)) }, views () { if (!this.database) { @@ -162,9 +154,6 @@ export default { pid () { return this.$route.query.pid }, - hasIdentifier () { - return this.identifier - }, creator () { if (!this.view) { return null @@ -172,17 +161,18 @@ export default { const userService = useUserService() return userService.userToFullName(this.view.creator) }, - canViewView () { + canViewInfo () { if (!this.view) { return false } if (this.view.is_public) { return true } - if (!this.user) { + if (!this.access) { return false } - return this.hasReadAccess || this.view.owner.id === this.user.id || this.database.owner.id === this.user.id + const userService = useUserService() + return userService.hasReadAccess(this.access) } }, methods: { diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/[identifier_id]/index.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/[identifier_id]/index.vue index 8c1f24c2a166150bd1dc3903dfa984c435815f9b..540bbbdb5e454c725c6d5b9dc6a1da6498e5f8bc 100644 --- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/[identifier_id]/index.vue +++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/[identifier_id]/index.vue @@ -1,6 +1,6 @@ <template> <div - v-if="canCreateIdentifier || canUpdateIdentifier"> + v-if="canPersistIdentifier || canUpdateIdentifier"> <Persist type="view" :database="database" /> @@ -10,7 +10,6 @@ <script> import Persist from '@/components/identifier/Persist.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -47,34 +46,56 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { + database () { + return this.cacheStore.getDatabase + }, roles () { - return this.userStore.getRoles + return this.cacheStore.getRoles }, - user () { - return this.userStore.getUser + view () { + return this.cacheStore.getView }, - database () { - return this.cacheStore.getDatabase + access () { + return this.cacheStore.getAccess + }, + cacheUser () { + return this.cacheStore.getUser }, - canCreateIdentifier () { - if (!this.roles) { + identifier () { + if (!this.view) { + return false + } + const filter = this.view.identifiers.filter(i => i.id === Number(this.$route.params.identifier_id)) + return filter.length === 1 ? filter[0] : null + }, + canPersistIdentifier () { + if (!this.view || !this.roles || !this.cacheUser || !this.access) { return false } if (this.roles.includes('create-foreign-identifier')) { return true } - return this.roles.includes('create-identifier') + if (!this.roles.includes('create-identifier')) { + return false + } + const userService = useUserService() + return userService.hasReadAccess(this.access) && this.view.owner.id === this.cacheUser.uid }, canUpdateIdentifier () { - if (!this.roles) { + if (!this.identifier || !this.roles) { + return false + } + if (this.roles.includes('modify-identifier-metadata')) { + return true + } + if (!this.roles.includes('create-identifier')) { return false } - return this.roles.includes('modify-identifier-metadata') + return this.identifier.owner.id === this.cacheUser.uid } } } diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/index.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/index.vue index b76d076645e05ef7123215c578d20b489924d523..ed8067d21327f2e0a069733fb9873b7912a5a32e 100644 --- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/index.vue +++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/persist/index.vue @@ -1,6 +1,6 @@ <template> <div - v-if="canPersistView"> + v-if="canPersistIdentifier"> <Persist type="view" :database="database" @@ -11,7 +11,6 @@ <script> import Persist from '@/components/identifier/Persist.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -45,32 +44,37 @@ export default { disabled: true } ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - roles () { - return this.userStore.getRoles - }, database () { return this.cacheStore.getDatabase }, + access () { + return this.cacheStore.getAccess + }, + cacheUser () { + return this.cacheStore.getUser + }, view () { - if (!this.database) { - return null - } - return this.database.views.filter(v => v.id === Number(this.$route.params.view_id))[0] + return this.cacheStore.getView }, - access () { - return this.userStore.getAccess + roles () { + return this.cacheStore.getRoles }, - canPersistView () { - if (!this.view) { + canPersistIdentifier () { + if (!this.view || !this.roles || !this.cacheUser || !this.access) { + return false + } + if (this.roles.includes('create-foreign-identifier')) { + return true + } + if (!this.roles.includes('create-identifier')) { return false } const userService = useUserService() - return userService.hasReadAccess(this.access) + return userService.hasReadAccess(this.access) && this.view.owner.id === this.cacheUser.uid } } } diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/schema.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/schema.vue index 477654f656c9dbc5361315d323b8cc638add6ca9..5b35faf3a5250c712a6e9b7f442a6e779863b42c 100644 --- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/schema.vue +++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/schema.vue @@ -53,7 +53,6 @@ <script> import TableToolbar from '@/components/table/TableToolbar.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -95,14 +94,10 @@ export default { { value: 'is_null_allowed', title: this.$t('pages.table.subpages.schema.nullable.title') }, { value: 'description', title: this.$t('pages.table.subpages.schema.description.title') }, ], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, @@ -110,13 +105,13 @@ export default { return this.cacheStore.getView }, access () { - return this.userStore.getAccess + return this.cacheStore.getAccess }, - hasReadAccess () { - if (!this.access) { - return false - } - return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own' + roles () { + return this.cacheStore.getRoles + }, + cacheUser () { + return this.cacheStore.getUser }, canViewSchema () { if (!this.view) { @@ -125,13 +120,11 @@ export default { if (this.view.is_schema_public) { return true } - if (!this.user) { + if (!this.access) { return false } - return this.hasReadAccess || this.view.owner.id === this.user.id || this.database.owner.id === this.user.id - }, - roles () { - return this.userStore.getRoles + const userService = useUserService() + return userService.hasReadAccess(this.access) }, inputVariant () { const runtimeConfig = useRuntimeConfig() diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/settings.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/settings.vue index 18d73d05768d1a45b36eed9a58ea7841235554b3..d027a4347b5300025f83d23adba52d78278a443f 100644 --- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/settings.vue +++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/settings.vue @@ -92,7 +92,6 @@ <script> import ViewToolbar from '@/components/view/ViewToolbar.vue' -import { useUserStore } from '@/stores/user.js' import { useCacheStore } from '@/stores/cache.js' export default { @@ -148,14 +147,10 @@ export default { { value: 'description', title: this.$t('pages.table.subpages.schema.description.title') }, ], dateColumns: [], - userStore: useUserStore(), cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser - }, database () { return this.cacheStore.getDatabase }, @@ -163,16 +158,13 @@ export default { return this.cacheStore.getView }, access () { - return this.userStore.getAccess - }, - hasReadAccess () { - if (!this.access) { - return false - } - return this.access.type === 'read' || this.access.type === 'write_all' || this.access.type === 'write_own' + return this.cacheStore.getAccess }, roles () { - return this.userStore.getRoles + return this.cacheStore.getRoles + }, + cacheUser () { + return this.cacheStore.getUser }, isChange () { if (!this.view) { @@ -184,22 +176,23 @@ export default { return this.view.is_schema_public !== this.modify.is_schema_public }, canUpdateVisibility () { - if (!this.roles || !this.user || !this.view) { + if (!this.roles || !this.cacheUser || !this.view) { return false } - return this.roles.includes('modify-view-visibility') && this.view.owner.id === this.user.id + return this.roles.includes('modify-view-visibility') && this.view.owner.id === this.cacheUser.uid }, canDeleteView () { - if (!this.roles || !this.user || !this.view) { + if (!this.roles || !this.cacheUser || !this.view) { return false } - return this.roles.includes('delete-database-view') && this.view.owner.id === this.user.id + return this.roles.includes('delete-database-view') && this.view.owner.id === this.cacheUser.uid }, canViewSettings () { - if (!this.user || !this.view) { + if (!this.view || !this.access || !this.cacheUser) { return false } - return this.view.owner.id === this.user.id + const userService = useUserService() + return userService.hasReadAccess(this.access) && this.view.owner.id === this.cacheUser.uid }, inputVariant () { const runtimeConfig = useRuntimeConfig() diff --git a/dbrepo-ui/pages/database/[database_id]/view/create.vue b/dbrepo-ui/pages/database/[database_id]/view/create.vue index 47b56cfbad81968d056d028cc48758d250efc612..a834bdb5c90340d247dbb3df880acbec8dc4a08f 100644 --- a/dbrepo-ui/pages/database/[database_id]/view/create.vue +++ b/dbrepo-ui/pages/database/[database_id]/view/create.vue @@ -8,7 +8,7 @@ <script> import Builder from '@/components/subset/Builder.vue' -import { useUserStore } from '@/stores/user.js' +import { useCacheStore } from '@/stores/cache.js' export default { components: { @@ -35,21 +35,22 @@ export default { disabled: true } ], - userStore: useUserStore() + cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser + access () { + return this.cacheStore.getAccess }, roles () { - return this.userStore.getRoles + return this.cacheStore.getRoles }, canCreateView () { - if (!this.roles) { + if (!this.roles || !this.roles.includes('create-database-view')) { return false } - return this.roles.includes('create-database-view') + const userService = useUserService() + return userService.hasReadAccess(this.access) } } } diff --git a/dbrepo-ui/pages/database/[database_id]/view/index.vue b/dbrepo-ui/pages/database/[database_id]/view/index.vue index 64f777dce3f905f19d2ff8f16e5e4b3de80fd277..b2a2c17a1afe0553777e21e593b8865bfb63efc9 100644 --- a/dbrepo-ui/pages/database/[database_id]/view/index.vue +++ b/dbrepo-ui/pages/database/[database_id]/view/index.vue @@ -48,11 +48,18 @@ export default { database () { return this.cacheStore.getDatabase }, + access () { + return this.cacheStore.getAccess + }, canViewSchema () { - if (this.error) { + if (!this.database) { return false } - return this.database + if (this.database.is_schema_public) { + return true + } + const userService = useUserService() + return userService.hasReadAccess(this.access) } } } diff --git a/dbrepo-ui/pages/index.vue b/dbrepo-ui/pages/index.vue index 1c30c25e5c7e9edfd52861ca568c492ce39f13a7..9e5e20186dcdd58ab66662b5aca827e2682df121 100644 --- a/dbrepo-ui/pages/index.vue +++ b/dbrepo-ui/pages/index.vue @@ -30,7 +30,7 @@ <script> import DatabaseList from '@/components/database/DatabaseList.vue' import DatabaseCreate from '@/components/database/DatabaseCreate.vue' -import { useUserStore } from '@/stores/user.js' +import { useCacheStore } from '@/stores/cache.js' export default { components: { @@ -42,12 +42,12 @@ export default { loading: true, dialog: null, databases: [], - userStore: useUserStore() + cacheStore: useCacheStore() } }, computed: { roles () { - return this.userStore.getRoles + return this.cacheStore.getRoles }, canCreateDatabase () { if (!this.roles) { @@ -57,17 +57,20 @@ export default { } }, mounted () { - this.loading = true - const databaseService = useDatabaseService(); - databaseService.findAll() - .then((databases) => { - this.databases = databases - this.loading = false - }) + this.fetchDatabases() }, methods: { closed () { this.dialog = false + }, + fetchDatabases () { + this.loading = true + const databaseService = useDatabaseService() + databaseService.findAll() + .then((databases) => { + this.databases = databases + this.loading = false + }) } } } diff --git a/dbrepo-ui/pages/login.vue b/dbrepo-ui/pages/login.vue deleted file mode 100644 index 532a221c4823cfd8be39fd53e94c34426311260a..0000000000000000000000000000000000000000 --- a/dbrepo-ui/pages/login.vue +++ /dev/null @@ -1,160 +0,0 @@ -<template> - <div> - <v-toolbar - v-if="!user" - variant="flat" - :title="$t('pages.login.name')"> - </v-toolbar> - <v-card - rounded="0" - variant="flat"> - <v-card-text> - <v-form - v-if="!user" - ref="form" - v-model="valid" - @submit.prevent="submit"> - <v-row - dense> - <v-col - md="8"> - <v-text-field - v-model="username" - autocomplete="off" - autofocus - required - name="username" - persistent-hint - :rules="[v => !!v || $t('validation.required')]" - :label="$t('pages.login.username.label')" - :hint="$t('pages.login.username.hint')"/> - </v-col> - </v-row> - <v-row - dense> - <v-col - md="8"> - <v-text-field - v-model="password" - autocomplete="off" - type="password" - required - name="password" - persistent-hint - :rules="[v => !!v || $t('validation.required')]" - :label="$t('pages.login.password.label')" - :hint="$t('pages.login.password.hint')"/> - </v-col> - </v-row> - <v-row> - <v-col - md="8"> - <v-btn - id="login" - class="mb-2" - :disabled="!valid" - color="primary" - variant="flat" - type="submit" - name="submit" - :loading="loading" - :text="$t('pages.login.submit.label')" - @click="login"/> - </v-col> - </v-row> - </v-form> - </v-card-text> - <v-card-actions> - <v-spacer/> - <v-btn - v-for="(link, i) in loginLinks" - :key="`li-${i}`" - variant="plain" - size="small" - :text="link.text" - :href="link.href"/> - </v-card-actions> - </v-card> - </div> -</template> - -<script> -import {useUserStore} from '@/stores/user.js' - -export default { - data() { - return { - loading: false, - valid: false, - username: null, - password: null, - userStore: useUserStore() - } - }, - computed: { - user() { - return this.userStore.getUser - }, - loginLinks() { - if (!this.$config.public.links) { - return [] - } - return Object.keys(this.$config.public.links).map(key => { - return this.$config.public.links[key] - }) - } - }, - methods: { - submit() { - this.$refs.form.validate() - }, - login() { - this.loading = true - const userService = useUserService() - userService.obtainToken(this.username, this.password) - .then((data) => { - const userId = userService.tokenToUserId(data.access_token) - userService.findOne(userId) - .then((user) => { - const toast = useToastInstance() - toast.success(this.$t('success.user.login', { username : user.username })) - switch (user.attributes.theme) { - case 'dark': - this.$vuetify.theme.global.name = 'tuwThemeDark' - break - case 'light': - this.$vuetify.theme.global.name = 'tuwThemeLight' - break - case 'light-contrast': - this.$vuetify.theme.global.name = 'tuwThemeLightContrast' - break - case 'dark-contrast': - this.$vuetify.theme.global.name = 'tuwThemeDarkContrast' - break - } - this.userStore.setUser(user) - this.$router.push('/database') - }) - .catch(({code}) => { - const toast = useToastInstance() - if (typeof code !== 'string') { - return - } - toast.error(this.$t(code)) - }) - }) - .catch(({code}) => { - this.loading = false - const toast = useToastInstance() - if (typeof code !== 'string') { - return - } - toast.error(this.$t(code)) - }) - .finally(() => { - this.loading = false - }) - } - } -} -</script> diff --git a/dbrepo-ui/pages/search.vue b/dbrepo-ui/pages/search.vue index 15475b212bc724e0e55d9f0765461990e574618e..507f81b731407a3059e61f7956368d25481de9a0 100644 --- a/dbrepo-ui/pages/search.vue +++ b/dbrepo-ui/pages/search.vue @@ -65,7 +65,6 @@ <script> import AdvancedSearch from '@/components/search/AdvancedSearch.vue' -import { useUserStore } from '@/stores/user.js' export default { components: { @@ -75,14 +74,10 @@ export default { return { results: [], type: 'database', - loading: false, - userStore: useUserStore() + loading: false } }, computed: { - roles () { - return this.userStore.getRoles - }, q () { if (!this.$route.query || !this.$route.query.q) { return null @@ -92,12 +87,6 @@ export default { header () { return `${this.results.length} ${this.results.length !== 1 ? this.$t('toolbars.search.results') : this.$t('toolbars.search.result')}` }, - canCreateDatabase () { - if (!this.roles) { - return false - } - return this.roles.includes('create-database') - }, isDatabaseSearch () { return this.type === 'database' } diff --git a/dbrepo-ui/pages/semantic/index.vue b/dbrepo-ui/pages/semantic/index.vue deleted file mode 100644 index db555b4c0d4778401e6988015b1064cc8bd0c82e..0000000000000000000000000000000000000000 --- a/dbrepo-ui/pages/semantic/index.vue +++ /dev/null @@ -1,194 +0,0 @@ -<template> - <div v-if="canListOntologies"> - <v-toolbar flat> - <v-toolbar-title> - {{ $t('pages.semantics.title') }} - </v-toolbar-title> - <v-spacer /> - <v-btn - v-if="canListOntologies" - to="/semantic/ontology" - variant="flat" - :text="ontologies.length + ' ' + $t('toolbars.semantic.ontologies.text')" - color="secondary" /> - <template v-slot:extension> - <v-tabs - v-model="tab" - color="primary"> - <v-tab> - {{ $t('toolbars.semantic.ontologies.concepts') }} - </v-tab> - <v-tab> - {{ $t('toolbars.semantic.ontologies.units') }} - </v-tab> - </v-tabs> - </template> - </v-toolbar> - <v-card flat> - <v-card-text> - <v-data-table - :headers="headers" - :items="rows" - :options.sync="options" - :server-items-length="total" - :footer-props="footerProps" - :items-per-page-options="footerProps.itemsPerPageOptions"> - <template v-slot:item.uri="{ item }"> - <a :href="item.uri" - target="_blank"> - {{ item.uri }} - </a> - </template> - <template v-slot:item.action="{ item }"> - <v-btn - small - :disabled="disabled(item)" - :text="$t('pages.semantics.usages.text')" - @click="view(item)" /> - </template> - </v-data-table> - </v-card-text> - </v-card> - <v-dialog - v-model="viewSemanticEntityDialog" - max-width="640"> - <ViewSemanticEntity - :mode="mode" - :entity="entity" - @close="close" /> - </v-dialog> - <v-breadcrumbs - :items="items" - class="pa-0 mt-2" /> - </div> -</template> - -<script> -import ViewSemanticEntity from '@/components/dialogs/ViewSemanticEntity.vue' -import { useUserStore } from '@/stores/user.js' -import { useCacheStore } from '@/stores/cache.js' - -export default { - components: { - ViewSemanticEntity - }, - data () { - return { - loadingConcepts: false, - loadingUnits: false, - entity: null, - viewSemanticEntityDialog: false, - headers: [ - { text: 'URI', value: 'uri' }, - { text: 'Name', value: 'name' }, - { text: 'Description', value: 'description' }, - { text: 'Usages', value: 'usages' }, - { text: null, value: 'action' } - ], - options: { - page: 1, - itemsPerPage: 10 - }, - total: -1, - footerProps: { - itemsPerPageOptions: [10, 25, 50, 100] - }, - tab: 0, - tabs: [ - 'concepts', 'units' - ], - concepts: [], - units: [], - createOntologyDialog: false, - items: [ - { - title: `${this.$t('navigation.semantics')}`, - to: '/semantic' - } - ], - userStore: useUserStore(), - cacheStore: useCacheStore() - } - }, - computed: { - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles - }, - ontologies () { - return this.cacheStore.getOntologies - }, - rows () { - return this.tab === 0 ? this.concepts : this.units - }, - mode () { - return this.tab === 0 ? 'concept' : 'unit' - }, - canListOntologies () { - if (!this.roles) { - return false - } - return this.roles.includes('list-ontologies') - } - }, - mounted () { - this.loadUnits() - this.loadConcepts() - }, - methods: { - loadConcepts () { - this.loadingConcepts = true - const conceptService = useConceptService() - conceptService.findAll() - .then((concepts) => { - concepts = concepts.map((column) => { - column.usages = column.columns.length - return column - }) - this.concepts = concepts - }) - .catch(() => { - this.loadingConcepts = false - }) - .finally(() => { - this.loadingConcepts = false - }) - }, - loadUnits () { - this.loadingUnits = true - const unitService = useUnitService() - unitService.findAll() - .then((units) => { - units = units.map((unit) => { - unit.usages = unit.columns.length - return unit - }) - this.units = units - }) - .catch(() => { - this.loadingUnits = false - }) - .finally(() => { - this.loadingUnits = false - }) - }, - disabled (item) { - return !item.usages || this.usages === 0 - }, - view (entity) { - this.entity = entity - this.viewSemanticEntityDialog = true - }, - close (event) { - if (this.mode === 'unit') { - this.loadUnits() - } else if (this.mode === 'concept') { - this.loadConcepts() - } - this.viewSemanticEntityDialog = false - } - } -} -</script> diff --git a/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue b/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue deleted file mode 100644 index 14749460c931c70c8430a28e51a7aa3c13d26ed1..0000000000000000000000000000000000000000 --- a/dbrepo-ui/pages/semantic/ontology/_ontology_id/index.vue +++ /dev/null @@ -1,273 +0,0 @@ -<template> - <div - v-if="canListOntologies"> - <v-toolbar flat> - <v-toolbar-title> - <v-btn - id="back-btn" - plain - class="mr-2" - to="/semantic/ontology"> - <v-icon left>mdi-arrow-left</v-icon> - </v-btn> - </v-toolbar-title> - <v-toolbar-title> - <v-skeleton-loader - v-if="loading" - type="text" - class="skeleton-small" /> - <span v-if="!loading"> - Ontology - <a - v-if="ontology" - :href="ontology.uri" - target="_blank"> - {{ ontology.uri }} - </a> - </span> - </v-toolbar-title> - <v-spacer /> - <v-toolbar-title> - <v-btn - v-if="canDeleteOntology" - :loading="loadingDelete" - color="error" - @click="deleteOntology"> - Delete Ontology - </v-btn> - </v-toolbar-title> - </v-toolbar> - <v-form ref="form" v-model="valid" autocomplete="off" @submit.prevent="submit"> - <v-card v-if="ontology" variant="flat"> - <v-card-text> - <v-row dense> - <v-col cols="6"> - <v-text-field - id="prefix" - v-model="ontologyChangeDto.prefix" - name="prefix" - label="Prefix *" - hint="Only lowercase alphanumeric letters, max. 8" - autofocus - :rules="[ - v => notEmpty(v) || $t('validation.required'), - v => validPrefix(v) || $t('validation.prefix.pattern'), - v => validPrefixLength(v,1,8) || $t('validation.prefix.length'), - v => validPrefixNotExists(v) || $t('validation.prefix.exists') - ]" - required /> - </v-col> - </v-row> - <v-row dense> - <v-col cols="6"> - <v-text-field - id="uri" - v-model="ontologyChangeDto.uri" - name="uri" - label="URI *" - :rules="[ - v => notEmpty(v) || $t('validation.required'), - v => validUri(v) || $t('validation.uri.pattern'), - v => validUriNotExists(v) || $t('validation.uri.exists') - ]" - required /> - </v-col> - </v-row> - <v-row dense> - <v-col cols="6"> - <v-text-field - id="sparql-endpoint" - v-model="ontologyChangeDto.sparql_endpoint" - name="sparql-endpoint" - label="SPARQL Endpoint" - :rules="[ - v => validUriOptional(v) || $t('validation.uri.pattern') - ]" /> - </v-col> - </v-row> - </v-card-text> - <v-card-actions> - <v-btn - id="createDB" - class="mb-2 ml-2" - :disabled="!valid || loading" - color="primary" - type="submit" - :loading="loading" - @click="save"> - Update - </v-btn> - </v-card-actions> - </v-card> - </v-form> - <v-breadcrumbs :items="items" class="pa-0 mt-2" /> - </div> -</template> - -<script> -import { notEmpty } from '@/utils' -import { useUserStore } from '@/stores/user.js' -import { useCacheStore } from '@/stores/cache.js' - -export default { - data () { - return { - loading: false, - loadingDelete: false, - ontology: null, - ontologyChangeDto: { - uri: null, - prefix: null, - sparql_endpoint: null - }, - valid: false, - createOntologyDialog: false, - items: [ - { text: `${this.$t('layout.semantics')}`, to: '/semantic', activeClass: '' }, - { text: `${this.$t('layout.ontologies')}`, to: '/semantic/ontology', activeClass: '' }, - { text: `${this.$route.params.ontology_id}`, to: `/semantic/ontology/${this.$route.params.ontology_id}`, activeClass: '' } - ], - userStore: useUserStore(), - cacheStore: useCacheStore() - } - }, - computed: { - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles - }, - ontologies () { - return this.cacheStore.getOntologies - }, - canListOntologies () { - if (!this.roles) { - return false - } - return this.roles.includes('list-ontologies') - }, - canDeleteOntology () { - if (!this.roles) { - return false - } - return this.roles.includes('delete-ontology') - } - }, - mounted () { - this.loadOntology() - }, - methods: { - loadOntology () { - this.loading = true - const ontologyService = useOntologyService() - ontologyService.findOne(this.$route.params.ontology_id) - .then((ontology) => { - this.ontology = ontology - this.ontologyChangeDto = Object.assign({}, ontology) - }) - .catch(() => { - this.loading = false - }) - .finally(() => { - this.loading = false - }) - }, - deleteOntology () { - this.loadingDelete = true - const ontologyService = useOntologyService() - ontologyService.remove(this.$route.params.ontology_id) - .then(async () => { - // await this.$store.dispatch('reloadOntologies') - await this.$router.push('/semantic/ontology') - }) - .catch(() => { - this.loadingDelete = false - }) - .finally(() => { - this.loadingDelete = false - }) - }, - save () { - this.loading = true - const payload = { - uri: this.ontologyChangeDto.uri, - prefix: this.ontologyChangeDto.prefix, - sparql_endpoint: this.ontologyChangeDto.sparql_endpoint - } - const ontologyService = useOntologyService() - ontologyService.update(this.$route.params.ontology_id, payload) - .then(() => { - this.loadOntology() - // this.$store.dispatch('reloadOntologies') - const toast = useToastInstance() - toast.success('Successfully update ontology!') - }) - .catch(() => { - this.loading = false - }) - .finally(() => { - this.loading = false - }) - }, - validPrefix (str) { - if (!str) { - return false - } - return str.match(/[a-z0-9]+/g) - }, - validPrefixLength (str, min, max) { - if (!str) { - return false - } - return str.length > min && str.length <= max - }, - validPrefixNotExists (str) { - const ontologies = this.ontologies.filter(o => o.prefix === str) - if (ontologies && ontologies.length !== 0) { - /* same prefix is fine for the same ontology, but not for others */ - return ontologies[0].id === this.ontology.id - } - return !this.ontologies.map(o => o.prefix).includes(str) - }, - validUriNotExists (str) { - const ontologies = this.ontologies.filter(o => o.uri === str) - if (ontologies && ontologies.length !== 0) { - /* same uri is fine for the same ontology, but not for others */ - return ontologies[0].id === this.ontology.id - } - return !this.ontologies.map(o => o.uri).includes(str) - }, - validUriOptional (str) { - if (!str) { - return true - } - return this.validUri(str) - }, - validUri (str) { - if (!str) { - return false - } - return str.match(/^https?:\/\//g) - }, - close (event) { - if (event.success) { - // this.$store.dispatch('reloadOntologies') - } - this.createOntologyDialog = false - }, - submit () { - this.$refs.form.validate() - }, - notEmpty - } -} -</script> -<style> -.skeleton-medium > div { - width: 200px !important; -} -.skeleton-xsmall > div { - width: 50px !important; -} -</style> diff --git a/dbrepo-ui/pages/semantic/ontology/index.vue b/dbrepo-ui/pages/semantic/ontology/index.vue deleted file mode 100644 index 36898d90739c2d219e9f9987c02527e2409a676f..0000000000000000000000000000000000000000 --- a/dbrepo-ui/pages/semantic/ontology/index.vue +++ /dev/null @@ -1,96 +0,0 @@ -<template> - <div v-if="canListOntologies"> - <v-toolbar flat> - <v-btn - variant="plain" - size="small" - icon="mdi-arrow-left" - to="/semantic" /> - <v-toolbar-title> - {{ ontologies.length + ' ' + $t('toolbars.semantic.ontologies.title') }} - </v-toolbar-title> - <v-spacer /> - <v-btn - v-if="canCreateOntology" - color="secondary" - variant="flat" - name="create-ontology" - prepend-icon="mdi-plus" - :text="$t('toolbars.semantic.ontology.text')" - @click.stop="createOntologyDialog = true" /> - </v-toolbar> - <OntologiesList /> - <v-dialog - v-model="createOntologyDialog" - persistent - max-width="640"> - <CreateOntology ref="ont" @close="close" /> - </v-dialog> - <v-breadcrumbs :items="items" class="pa-0 mt-2" /> - </div> -</template> - -<script> -import OntologiesList from '@/components/OntologiesList.vue' -import CreateOntology from '@/components/dialogs/CreateOntology.vue' -import { useUserStore } from '@/stores/user.js' -import { useCacheStore } from '@/stores/cache.js' - -export default { - components: { - OntologiesList, - CreateOntology - }, - data () { - return { - createOntologyDialog: false, - items: [ - { - title: `${this.$t('navigation.semantics')}`, - to: '/semantic' - }, - { - title: `${this.$t('navigation.ontologies')}`, - to: '/semantic/ontology' - } - ], - userStore: useUserStore(), - cacheStore: useCacheStore() - } - }, - computed: { - token () { - return this.userStore.getToken - }, - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles - }, - ontologies () { - return this.cacheStore.getOntologies - }, - canListOntologies () { - if (!this.roles) { - return false - } - return this.roles.includes('list-ontologies') - }, - canCreateOntology () { - if (!this.roles) { - return false - } - return this.roles.includes('create-ontology') - } - }, - methods: { - close (event) { - if (event.success) { - // this.$store.dispatch('reloadOntologies') - } - this.createOntologyDialog = false - } - } -} -</script> diff --git a/dbrepo-ui/pages/signup.vue b/dbrepo-ui/pages/signup.vue deleted file mode 100644 index 54c00602256c7815d8aff0b255214e66836bc727..0000000000000000000000000000000000000000 --- a/dbrepo-ui/pages/signup.vue +++ /dev/null @@ -1,163 +0,0 @@ -<template> - <div> - <v-toolbar - :title="$t('pages.signup.name')" - flat /> - <v-form - ref="form" - v-model="valid" - @submit.prevent="submit"> - <v-card - variant="flat" - rounded="0"> - <v-card-text> - <v-row dense> - <v-col sm="6"> - <v-text-field - v-model="createAccount.email" - type="email" - autocomplete="off" - autofocus - required - name="email" - :rules="[v => !!v || $t('validation.required')]" - :hint="$t('pages.signup.email.hint')" - :label="$t('pages.signup.email.label')" /> - </v-col> - </v-row> - <v-row dense> - <v-col sm="6"> - <v-text-field - v-model="createAccount.username" - autocomplete="off" - required - name="username" - :rules="[v => !!v || $t('validation.required'), - v => /^[a-z0-9]{3,}$/.test(v) || $t('validation.user.pattern'), - v => !usernames.includes(v) || $t('validation.user.exists')]" - persistent-hint - :hint="$t('pages.signup.username.hint')" - :label="$t('pages.signup.username.label')" /> - </v-col> - </v-row> - <v-row dense> - <v-col sm="6"> - <v-text-field - v-model="createAccount.password" - autocomplete="off" - required - name="password" - :rules="[ - v => !!v || $t('validation.required') - ]" - type="password" - persistent-hint - :label="$t('pages.signup.password.label')" - :hint="$t('pages.signup.password.hint')" /> - </v-col> - </v-row> - <v-row dense> - <v-col sm="6"> - <v-text-field - v-model="password2" - autocomplete="off" - required - name="password-confirm" - :rules="[ - v => !!v || $t('validation.required') - ]" - :error-messages="password2 && password2 !== this.createAccount.password ? [this.$t('validation.matching')] : []" - type="password" - persistent-hint - :label="$t('pages.signup.confirm.label')" - :hint="$t('pages.signup.confirm.hint')" /> - </v-col> - </v-row> - </v-card-text> - <v-card-text> - <v-btn - id="login" - variant="flat" - :disabled="!valid" - color="primary" - type="submit" - name="submit" - :text="$t('pages.signup.submit.label')" - :loading="loading" - @click="register" /> - </v-card-text> - </v-card> - </v-form> - </div> -</template> - -<script> -export default { - data () { - return { - loading: false, - loadingUsers: false, - usernames: [], - error: false, // XXX: `error` is never changed - valid: false, - password2: null, - privacy: false, - consent: false, - createAccount: { - username: null, - email: null, - password: null - } - } - }, - mounted () { - this.loadUsers() - }, - methods: { - submit () { - this.$refs.form.validate() - }, - register () { - this.loading = true - const userService = useUserService() - userService.create(this.createAccount) - .then(() => { - const toast = useToastInstance() - toast.success(this.$t('success.signup')) - this.$router.push('/login') - this.loading = false - }) - .catch(({code}) => { - this.loading = false - const toast = useToastInstance() - if (typeof code !== 'string') { - return - } - toast.error(this.$t(code)) - }) - .finally(() => { - this.loading = false - }) - }, - loadUsers () { - this.loadingUsers = true - const userService = useUserService() - userService.findAll() - .then((users) => { - this.usernames = users.map(u => u.username) - }) - .catch(({code}) => { - this.loadingUsers = false - const toast = useToastInstance() - if (typeof code !== 'string') { - return - } - toast.error(this.$t(code)) - }) - .finally(() => { - this.loadingUsers = false - }) - } - } -} -</script> diff --git a/dbrepo-ui/pages/user/authentication.vue b/dbrepo-ui/pages/user/authentication.vue index 3a43421a709560b3e841760620321f0c640275f9..50008d3c5dab56111fb15ae7a6164e1a591af1f9 100644 --- a/dbrepo-ui/pages/user/authentication.vue +++ b/dbrepo-ui/pages/user/authentication.vue @@ -1,5 +1,6 @@ <template> - <div> + <div + v-if="loggedIn"> <UserToolbar /> <v-window v-model="tab"> <v-window-item> @@ -10,8 +11,7 @@ rounded="0"> <v-card-text> <v-form - v-model="valid2" - @submit.prevent="submit"> + v-model="valid2"> <v-row dense> <v-col md="6"> <v-text-field @@ -60,9 +60,12 @@ </div> </template> +<script setup> +const { loggedIn } = useOidcAuth() +</script> <script> import UserToolbar from '@/components/user/UserToolbar.vue' -import { useUserStore } from '@/stores/user.js' +import { useCacheStore } from '@/stores/cache.js' export default { components: { @@ -88,12 +91,12 @@ export default { email: null, password: null, password2: null, - userStore: useUserStore() + cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser + cacheUser () { + return this.cacheStore.getUser }, inputVariant () { const runtimeConfig = useRuntimeConfig() @@ -104,15 +107,11 @@ export default { return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.button.contrast : runtimeConfig.public.variant.button.normal } }, - mounted () { - }, methods: { - submit () { - }, changePassword () { this.loadingUpdate = true const userService = useUserService() - userService.updatePassword(this.user.id, {'password': this.password}) + userService.updatePassword(this.cacheUser.uid, {'password': this.password}) .then(() => { const toast = useToastInstance() toast.success(this.$t('success.user.password')) diff --git a/dbrepo-ui/pages/user/developer.vue b/dbrepo-ui/pages/user/developer.vue deleted file mode 100644 index de52a490aff050b7a7a92c1870645301bf68b9d3..0000000000000000000000000000000000000000 --- a/dbrepo-ui/pages/user/developer.vue +++ /dev/null @@ -1,230 +0,0 @@ -<template> - <div> - <UserToolbar /> - <v-window - v-model="tab"> - <v-window-item> - <v-card - v-if="canHandleMessages" - :title="$t('pages.settings.subpages.developer.maintenance.title')" - rounded="0" - variant="flat"> - <v-data-table - :headers="headers" - :items="messages" - :loading="loadingMessages" - :items-per-page="10"> - <template v-slot:item.action="{ item }"> - <v-btn - size="x-small" - variant="flat" - :text="$t('pages.settings.subpages.developer.maintenance.modify.text')" - @click="modifyMessage(item)" /> - </template> - </v-data-table> - <v-card-text> - <v-btn - size="small" - variant="flat" - :text="$t('pages.settings.subpages.developer.maintenance.add.text')" - :disabled="!canCreateMessage" - @click="createMessage" /> - </v-card-text> - </v-card> - <v-divider - v-if="canHandleMessages" /> - <v-card - :title="$t('pages.settings.subpages.developer.token.title')" - :subtitle="$t('pages.settings.subpages.developer.token.subtitle')" - variant="flat" - rounded="0"> - <v-card-text> - <v-row dense> - <v-col xl="4"> - <v-text-field - v-model="accessTokenField" - disabled - :variant="inputVariant" - :label="$t('pages.settings.subpages.developer.token.access.label')" /> - </v-col> - <v-col xl="2"> - <v-text-field - v-model="tokenExpiry" - disabled - :variant="inputVariant" - :label="expiryLabel(token)" /> - </v-col> - </v-row> - <v-row dense> - <v-col xl="4"> - <v-text-field - v-model="refreshTokenField" - disabled - :variant="inputVariant" - :label="$t('pages.settings.subpages.developer.token.refresh.label')" /> - </v-col> - <v-col xl="2"> - <v-text-field - v-model="refreshTokenExpiry" - disabled - :variant="inputVariant" - :label="expiryLabel(refreshToken)" /> - </v-col> - </v-row> - </v-card-text> - </v-card> - </v-window-item> - </v-window> - <v-breadcrumbs :items="items" class="pa-0 mt-2" /> - <v-dialog - v-model="dialog" - persistent - max-width="640"> - <EditMaintenanceMessage - :id="messageId" - @close-dialog="closeDialog" /> - </v-dialog> - </div> -</template> - -<script> -import UserToolbar from '@/components/user/UserToolbar.vue' -import EditMaintenanceMessage from '@/components/dialogs/EditMaintenanceMessage.vue' -import { formatTimestampUTCLabel, isActiveMessage, timestampsToHumanDifference } from '@/utils' -import { useUserStore } from '@/stores/user.js' -import { useCacheStore } from '@/stores/cache.js' - -export default { - components: { - UserToolbar, - EditMaintenanceMessage - }, - data () { - return { - tab: 0, - accessTokenField: null, - refreshTokenField: null, - headers: [ - { title: this.$t('pages.settings.subpages.developer.maintenance.active'), value: 'active' }, - { title: this.$t('pages.settings.subpages.developer.maintenance.type'), value: 'type' }, - { title: this.$t('pages.settings.subpages.developer.maintenance.message'), value: 'message' }, - { title: this.$t('pages.settings.subpages.developer.maintenance.action'), value: 'action' } - ], - items: [ - { - title: this.$t('navigation.user'), - to: '/user' - }, - { - title: this.$t('toolbars.user.developer'), - to: `/user/developer`, - disabled: true - } - ], - messages: [], - loadingMessages: false, - dialog: false, - messageId: null, - userStore: useUserStore(), - cacheStore: useCacheStore() - } - }, - computed: { - token () { - return this.userStore.getToken - }, - tokenExpiry () { - if (!this.token) { - return null - } - const authenticationService = useAuthenticationService() - return formatTimestampUTCLabel(authenticationService.tokenToExpiryDate(this.token)) - }, - refreshToken () { - return this.userStore.getRefreshToken - }, - refreshTokenExpiry () { - if (!this.refreshToken) { - return null - } - const authenticationService = useAuthenticationService() - return formatTimestampUTCLabel(authenticationService.tokenToExpiryDate(this.refreshToken)) - }, - user () { - return this.userStore.getUser - }, - roles () { - return this.userStore.getRoles - }, - canCreateMessage () { - if (!this.roles) { - return false - } - return this.roles.includes('create-maintenance-message') - }, - canModifyMessage () { - if (!this.roles) { - return false - } - return this.roles.includes('modify-maintenance-message') - }, - canHandleMessages () { - return this.canCreateMessage || this.canModifyMessage - }, - inputVariant () { - const runtimeConfig = useRuntimeConfig() - return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.input.contrast : runtimeConfig.public.variant.input.normal - }, - buttonVariant () { - const runtimeConfig = useRuntimeConfig() - return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.button.contrast : runtimeConfig.public.variant.button.normal - } - }, - mounted () { - this.loadMessages() - if (!this.token || !this.refreshToken) { - return - } - this.accessTokenField = this.token - this.refreshTokenField = this.refreshToken - }, - methods: { - submit () { - }, - modifyMessage (message) { - this.messageId = message.id - this.dialog = true - }, - createMessage () { - this.messageId = null - this.dialog = true - }, - expiryLabel (token) { - const authenticationService = useAuthenticationService() - return this.$t('pages.settings.subpages.developer.token.expiry') + ' ' + timestampsToHumanDifference(Date.now(), authenticationService.tokenToExpiryDate(token)) - }, - loadMessages () { - const messageService = useMessageService() - messageService.findAll() - .then((messages) => { - this.messages = messages.map((message) => { - message.active = isActiveMessage(message) ? '● true' : 'false' - return message - }) - }) - .catch(() => { - this.loadingMessages = false - }) - .finally(() => { - this.loadingMessages = false - }) - }, - closeDialog (event) { - if (event.success) { - this.cacheStore.reloadMessages() - } - this.dialog = false - } - } -} -</script> diff --git a/dbrepo-ui/pages/user/index.vue b/dbrepo-ui/pages/user/index.vue index accae861052044324dc08ae48f6858e643172c5f..aa8ee559441bfdc4dd29380d77a98662c476ed79 100644 --- a/dbrepo-ui/pages/user/index.vue +++ b/dbrepo-ui/pages/user/index.vue @@ -3,24 +3,10 @@ </template> <script> -import { useUserStore } from '@/stores/user.js' - export default { - data () { - return { - userStore: useUserStore() - } - }, - computed: { - token () { - return this.userStore.getToken - }, - user () { - return this.userStore.getUser - } - }, mounted () { - if (!this.user) { + const { loggedIn } = useOidcAuth() + if (!loggedIn) { return } this.$router.push('/user/info') diff --git a/dbrepo-ui/pages/user/info.vue b/dbrepo-ui/pages/user/info.vue index 9b94dde4dad312bb648e992efbc38120798bf869..470b7bc438a0211d80ad44f06411f1da7f54dddc 100644 --- a/dbrepo-ui/pages/user/info.vue +++ b/dbrepo-ui/pages/user/info.vue @@ -1,9 +1,12 @@ <template> - <div> + <div + v-if="loggedIn"> <UserToolbar /> - <v-window v-model="tab"> + <v-window + v-model="tab"> <v-window-item> - <v-form v-model="valid1" @submit.prevent="submit"> + <v-form + v-model="valid1"> <v-card :title="$t('pages.user.subpages.info.title')" :subtitle="$t('pages.user.subpages.info.subtitle')" @@ -19,10 +22,12 @@ :label="$t('pages.user.subpages.info.id.label')" /> </v-col> </v-row> - <v-row dense> + <v-row + v-if="cacheUser" + dense> <v-col md="6"> <v-text-field - v-model="model.username" + v-model="cacheUser.preferred_username" disabled :variant="inputVariant" :label="$t('pages.user.subpages.info.username.label')" /> @@ -122,9 +127,12 @@ </div> </template> +<script setup> +const { loggedIn } = useOidcAuth() +</script> <script> import UserToolbar from '@/components/user/UserToolbar.vue' -import { useUserStore } from '@/stores/user.js' +import { useCacheStore } from '@/stores/cache.js' export default { components: { @@ -138,15 +146,16 @@ export default { error: false, loadingUpdate: false, loadingTheme: false, - theme: null, orcidLoading: false, model: { id: null, - username: null, + preferred_username: null, firstname: null, lastname: null, theme: null, - language: null + language: null, + orcid: null, + affiliation: null }, themes: [ { name: this.$t('pages.user.subpages.theme.light'), value: 'light' }, @@ -169,23 +178,23 @@ export default { disabled: true } ], - userStore: useUserStore() + cacheStore: useCacheStore() } }, computed: { - user () { - return this.userStore.getUser + locale () { + return this.cacheStore.getLocale }, roles () { - return this.userStore.getRoles + return this.cacheStore.getRoles }, - locale () { - return this.userStore.getLocale - }, - canModifyTheme () { - return this.roles.includes('modify-user-theme') + cacheUser () { + return this.cacheStore.getUser }, canModifyInformation () { + if (!this.roles) { + return false + } return this.roles.includes('modify-user-information') }, inputVariant () { @@ -201,8 +210,6 @@ export default { this.init() }, methods: { - submit () { - }, updateInfo () { this.loadingUpdate = true const payload = { @@ -211,17 +218,16 @@ export default { orcid: this.model.orcid, affiliation: this.model.affiliation, theme: this.model.theme, - language: this.model.language, + language: this.model.language } const userService = useUserService() - userService.update(this.user.id, payload) + userService.update(this.cacheUser.uid, payload) .then((user) => { console.info('Updated user information') const toast = useToastInstance() toast.success(this.$t('success.user.info')) - this.userStore.setUser(user) /* language */ - this.userStore.setLocale(this.model.language) + this.cacheStore.setLocale(this.model.language) this.$i18n.locale = this.locale /* theme */ switch (this.model.theme) { @@ -247,18 +253,18 @@ export default { }) }, init () { - if (!this.user) { + if (!this.cacheUser) { return } this.model = { - id: this.user.id, - username: this.user.username, - firstname: this.user.given_name, - lastname: this.user.family_name, - orcid: this.user.attributes.orcid, - affiliation: this.user.attributes.affiliation, - theme: this.user.attributes.theme, - language: this.user.attributes.language + id: this.cacheUser.uid, + username: this.cacheUser.username, + firstname: this.cacheUser.given_name, + lastname: this.cacheUser.family_name, + orcid: this.cacheUser.orcid, + affiliation: this.cacheUser.affiliation, + theme: this.cacheUser.theme ? this.cacheUser.theme : 'light', + language: this.cacheUser.language ? this.cacheUser.language : 'en' } }, retrieve () { diff --git a/dbrepo-ui/stores/cache.js b/dbrepo-ui/stores/cache.js index 3574b24d7c6300b884f7874726254e3c805393b3..c2e34f48bbc9bedc8d4afc31c9158963a9450749 100644 --- a/dbrepo-ui/stores/cache.js +++ b/dbrepo-ui/stores/cache.js @@ -7,9 +7,14 @@ export const useCacheStore = defineStore('cache', { database: null, table: null, view: null, + access: null, subset: null, + locale: null, + identifier: null, ontologies: [], messages: [], + user: null, + roles: [], uploadProgress: null } }, @@ -17,9 +22,14 @@ export const useCacheStore = defineStore('cache', { getDatabase: (state) => state.database, getTable: (state) => state.table, getView: (state) => state.view, + getAccess: (state) => state.access, getSubset: (state) => state.subset, + getLocale: (state) => state.locale, + getIdentifier: (state) => state.identifier, getOntologies: (state) => state.ontologies, getMessages: (state) => state.messages, + getUser: (state) => state.user, + getRoles: (state) => state.roles, getUploadProgress: (state) => state.uploadProgress, }, actions: { @@ -32,12 +42,27 @@ export const useCacheStore = defineStore('cache', { setView(view) { this.view = view }, + setAccess(access) { + this.access = access + }, setSubset(subset) { this.subset = subset }, + setLocale(locale) { + this.locale = locale + }, + setIdentifier(identifier) { + this.identifier = identifier + }, setOntologies(ontologies) { this.ontologies = ontologies }, + setUser(user) { + this.user = user + }, + setRoles(roles) { + this.roles = roles + }, setUploadProgress(uploadProgress) { this.uploadProgress = uploadProgress }, @@ -81,6 +106,14 @@ export const useCacheStore = defineStore('cache', { console.error('Failed to reload view', error) }) }, + reloadSubset() { + const queryService = useQueryService() + queryService.findOne(this.subset.database_id, this.subset.id) + .then(subset => this.subset = subset) + .catch((error) => { + console.error('Failed to reload subset', error) + }) + }, setRouteDatabase (databaseId) { return new Promise((resolve, reject) => { if (!databaseId) { @@ -102,17 +135,24 @@ export const useCacheStore = defineStore('cache', { setRouteTable(databaseId, tableId) { if (!databaseId || !tableId) { this.table = null - console.error('Cannot set route table: missing database id', databaseId, 'or table id', tableId) return } const tableService = useTableService() tableService.findOne(databaseId, tableId) .then(table => this.table = table) }, + setRouteAccess(databaseId, userId) { + if (!databaseId || !userId) { + this.access = null + return + } + const accessService = useAccessService() + accessService.findOne(databaseId, userId) + .then(access => this.access = access) + }, setRouteView(databaseId, viewId) { if (!databaseId || !viewId) { this.view = null - console.error('Cannot set route view: database view id', databaseId, 'or view id', viewId) return } const viewService = useViewService() @@ -122,7 +162,6 @@ export const useCacheStore = defineStore('cache', { setRouteSubset(databaseId, subsetId) { if (!databaseId || !subsetId) { this.subset = null - console.error('Cannot set route subset: missing database id', databaseId, 'or subset id', subsetId) return } const subsetService = useQueryService() diff --git a/dbrepo-ui/stores/user.js b/dbrepo-ui/stores/user.js deleted file mode 100644 index 522ce02a06ed1c695897d92a73c2682d791b499a..0000000000000000000000000000000000000000 --- a/dbrepo-ui/stores/user.js +++ /dev/null @@ -1,60 +0,0 @@ -import {defineStore} from 'pinia' - -export const useUserStore = defineStore('user', { - persist: true, - state: () => { - return { - /** @type String */ - token: null, - /** @type String */ - refreshToken: null, - roles: [], - user: null, - access: null, - locale: null - } - }, - getters: { - getToken: (state) => state.token, - getRefreshToken: (state) => state.refreshToken, - getRoles: (state) => state.roles, - getUser: (state) => state.user, - getAccess: (state) => state.access, - getLocale: (state) => state.locale - }, - actions: { - setToken(token) { - this.token = token - }, - setRefreshToken(refreshToken) { - this.refreshToken = refreshToken - }, - setRoles(roles) { - this.roles = roles - }, - setUser(user) { - this.user = user - }, - setAccess(access) { - this.access = access - }, - setLocale (locale) { - this.locale = locale - }, - logout() { - this.token = null - this.refreshToken = null - this.roles = [] - this.user = null - this.access = null - }, - setRouteAccess(databaseId) { - if (!databaseId || !this.user || !this.user.id) { - return - } - const accessService = useAccessService() - accessService.findOne(databaseId, this.user.id) - .then(access => this.access = access) - } - } -}) diff --git a/dbrepo-upload-service/pom.xml b/dbrepo-upload-service/pom.xml index f2bea092361406c7f933a5c26f8eadb0ecbcb131..20f379e32e7e58ab53dedc75c230071a2759c3cd 100644 --- a/dbrepo-upload-service/pom.xml +++ b/dbrepo-upload-service/pom.xml @@ -11,7 +11,7 @@ <groupId>at.tuwien</groupId> <artifactId>dbrepo-upload-service</artifactId> <name>dbrepo-upload-service</name> - <version>1.6.1</version> + <version>1.6.3</version> <url>https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6/</url> <developers> diff --git a/dbrepo-upload-service/pre-create.sh b/dbrepo-upload-service/pre-create.sh index 536a2e63e060c32db1882bbaad7f4de02cc3d2f7..2d6eb4f861297db095e9dcf5268ed858fde7cd6d 100755 --- a/dbrepo-upload-service/pre-create.sh +++ b/dbrepo-upload-service/pre-create.sh @@ -1,6 +1,6 @@ #!/bin/bash REQUEST_RAW=$(cat /dev/stdin) -AUTH_SERVICE_ENDPOINT="${AUTH_SERVICE_ENDPOINT:-http://auth-service:8080}" +METADATA_SERVICE_ENDPOINT="${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080}" echo "[DEBUG] [pre-create hook] request started" >&2 if [ "$(echo "$REQUEST_RAW" | jq '.Event.HTTPRequest.Header | has("Authorization")')" == "false" ]; then @@ -21,11 +21,11 @@ END exit 0 fi -echo "[DEBUG] [pre-create hook] request has 'Authorization' header present" >&2 +echo "[DEBUG] [pre-create hook] request has 'Authorization' header p resent" >&2 BEARER="$(echo "$REQUEST_RAW" | jq -r '.Event.HTTPRequest.Header.Authorization[0]')" -echo "[DEBUG] [pre-create hook] attempting to contact ${AUTH_SERVICE_ENDPOINT}" >&2 -if [ ! "$(wget -O- --quiet --header "Authorization: ${BEARER}" ${AUTH_SERVICE_ENDPOINT}/realms/dbrepo/protocol/openid-connect/userinfo)" ]; then + +if [ ! "$(wget -O- --quiet --header='Authorization: ${BEARER}' ${METADATA_SERVICE_ENDPOINT}/api/license)" ]; then echo "[ERROR] [pre-create hook] Unauthorized" >&2 cat <<END { diff --git a/dbrepo-upload-service/src/test/java/at/tuwien/config/GatewayConfig.java b/dbrepo-upload-service/src/test/java/at/tuwien/config/GatewayConfig.java index e360cecfdc106386a1229cfd12de189a8b57d60c..601229b5e5ae64da214820b2f91396a926d77884 100644 --- a/dbrepo-upload-service/src/test/java/at/tuwien/config/GatewayConfig.java +++ b/dbrepo-upload-service/src/test/java/at/tuwien/config/GatewayConfig.java @@ -1,13 +1,11 @@ package at.tuwien.config; -import at.tuwien.interceptor.KeycloakInterceptor; import lombok.Getter; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; -import org.springframework.web.util.DefaultUriBuilderFactory; @Log4j2 @Getter @@ -28,13 +26,4 @@ public class GatewayConfig { return new RestTemplate(); } - @Bean("keycloakRestTemplate") - public RestTemplate keycloakRestTemplate() { - final RestTemplate restTemplate = new RestTemplate(); - restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(keycloakEndpoint)); - restTemplate.getInterceptors() - .add(new KeycloakInterceptor(restTemplate(), keycloakUsername, keycloakPassword, keycloakEndpoint)); - return restTemplate; - } - } diff --git a/dbrepo-upload-service/src/test/java/at/tuwien/config/KeycloakConfig.java b/dbrepo-upload-service/src/test/java/at/tuwien/config/KeycloakConfig.java index 01be743daa98d258391d3d9c4e6bdec7aa4f8773..6243cb3ab5ecffc614cf71391886cae1852d30a2 100644 --- a/dbrepo-upload-service/src/test/java/at/tuwien/config/KeycloakConfig.java +++ b/dbrepo-upload-service/src/test/java/at/tuwien/config/KeycloakConfig.java @@ -1,25 +1,11 @@ package at.tuwien.config; -import at.tuwien.api.auth.KeycloakErrorDto; -import at.tuwien.api.keycloak.UserCreateDto; -import at.tuwien.api.keycloak.UserDto; -import at.tuwien.exception.AuthServiceConnectionException; -import at.tuwien.exception.AuthServiceException; -import at.tuwien.exception.EmailExistsException; -import at.tuwien.exception.UserExistsException; import lombok.Getter; import lombok.extern.log4j.Log4j2; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; +import org.keycloak.admin.client.Keycloak; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.HttpServerErrorException; -import org.springframework.web.client.RestTemplate; @Log4j2 @Getter @@ -29,55 +15,9 @@ public class KeycloakConfig { @Value("${dbrepo.endpoints.keycloak}") private String keycloakEndpoint; - @Autowired - @Qualifier("keycloakRestTemplate") - private RestTemplate keycloakRestTemplate; - - public Boolean existsByUsername(String username) throws AuthServiceException, AuthServiceConnectionException { - final String path = "/admin/realms/dbrepo/users/?username=" + username; - final ResponseEntity<UserDto[]> response; - try { - response = keycloakRestTemplate.exchange(path, HttpMethod.GET, HttpEntity.EMPTY, UserDto[].class); - } catch (HttpServerErrorException e) { - log.error("Failed to find user: {}", e.getMessage()); - throw new AuthServiceConnectionException("Service unavailable", e); - } catch (Exception e) { - log.error("Failed to find user: unexpected response: {}", e.getMessage()); - throw new AuthServiceException("Unexpected result", e); - } - final UserDto[] body = response.getBody(); - if (body == null || body.length != 1) { - log.error("Failed to find user with username {}", username); - return false; - } - return true; - } - - public void createUser(UserCreateDto data) throws UserExistsException, EmailExistsException, - AuthServiceConnectionException, AuthServiceException { - final String path = "/admin/realms/dbrepo/users"; - final ResponseEntity<Void> response; - try { - response = keycloakRestTemplate.exchange(path, HttpMethod.POST, new HttpEntity<>(data), Void.class); - } catch (HttpServerErrorException e) { - log.error("Failed to create user: {}", e.getMessage()); - throw new AuthServiceConnectionException("Service unavailable", e); - } catch (HttpClientErrorException.Conflict e) { - if (e.getResponseBodyAsByteArray() != null && e.getResponseBodyAsByteArray().length > 0) { - final KeycloakErrorDto error = e.getResponseBodyAs(KeycloakErrorDto.class); - if (error != null && error.getErrorMessage().contains("same email")) { - log.error("Failed to create user: email exists: {}", e.getMessage()); - throw new EmailExistsException("E-Mail exists", e); - } - } - log.error("Failed to create user: user exists: {}", e.getMessage()); - throw new UserExistsException("User exists", e); - } - if (!response.getStatusCode().equals(HttpStatus.CREATED)) { - log.error("Failed to create user: unexpected status: {}", response.getStatusCode().value()); - throw new AuthServiceException("Unexpected status: " + response.getStatusCode().value()); - } - log.debug("Created user {} at auth service", data.getUsername()); + @Bean + public Keycloak keycloak() { + return Keycloak.getInstance(keycloakEndpoint, "master", "admin", "admin", "admin-cli"); } } diff --git a/dbrepo-upload-service/src/test/java/at/tuwien/mapper/MetadataMapper.java b/dbrepo-upload-service/src/test/java/at/tuwien/mapper/MetadataMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..c6b5d429e7b87b1a3a4759167f794ad183311883 --- /dev/null +++ b/dbrepo-upload-service/src/test/java/at/tuwien/mapper/MetadataMapper.java @@ -0,0 +1,22 @@ +package at.tuwien.mapper; + + +import at.tuwien.api.keycloak.UserCreateDto; +import at.tuwien.api.user.external.ExternalResultType; +import org.keycloak.representations.idm.UserRepresentation; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; + +import java.util.LinkedList; + +@Mapper(componentModel = "spring", imports = {LinkedList.class, ExternalResultType.class}) +public interface MetadataMapper { + + org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MetadataMapper.class); + + @Mappings({ + @Mapping(target = "attributes", ignore = true) + }) + UserRepresentation userCreateDtoToUserRepresentation(UserCreateDto data); +} diff --git a/dbrepo-upload-service/src/test/java/at/tuwien/service/UploadServiceIntegrationTest.java b/dbrepo-upload-service/src/test/java/at/tuwien/service/UploadServiceIntegrationTest.java index 30fd6752c3b37a20487aa4133aefdefcbdf3e4b0..052d028d39478f3f8a61b2639bf8bfe8487af9ba 100644 --- a/dbrepo-upload-service/src/test/java/at/tuwien/service/UploadServiceIntegrationTest.java +++ b/dbrepo-upload-service/src/test/java/at/tuwien/service/UploadServiceIntegrationTest.java @@ -7,11 +7,9 @@ import at.tuwien.api.keycloak.UserCreateDto; import at.tuwien.config.KeycloakConfig; import at.tuwien.config.TusdConfig; import at.tuwien.config.TusdContainerConfig; -import at.tuwien.exception.AuthServiceConnectionException; import at.tuwien.exception.AuthServiceException; -import at.tuwien.exception.EmailExistsException; -import at.tuwien.exception.UserExistsException; import at.tuwien.interceptor.KeycloakInterceptor; +import at.tuwien.util.KeycloakUtil; import com.github.dockerjava.api.model.ExposedPort; import dasniko.testcontainers.keycloak.KeycloakContainer; import lombok.extern.log4j.Log4j2; @@ -20,7 +18,10 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.*; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -33,7 +34,6 @@ import org.testcontainers.junit.jupiter.Testcontainers; import java.util.List; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @Log4j2 @@ -48,6 +48,9 @@ public class UploadServiceIntegrationTest { @Autowired private TusdConfig tusdConfig; + @Autowired + private KeycloakUtil keycloakUtil; + @Autowired private KeycloakConfig keycloakConfig; @@ -55,7 +58,7 @@ public class UploadServiceIntegrationTest { private static TusdContainerConfig.TusdContainer tusdContainer = TusdContainerConfig.TusdContainer.getInstance(); @Container - private static KeycloakContainer keycloakContainer = new KeycloakContainer("quay.io/keycloak/keycloak:24.0") + private static KeycloakContainer keycloakContainer = new KeycloakContainer("quay.io/keycloak/keycloak:26.0") .withImagePullPolicy(PullPolicy.alwaysPull()) .withRealmImportFile("init/dbrepo-realm.json") .withEnv("KC_HOSTNAME_STRICT_HTTPS", "false") @@ -69,9 +72,8 @@ public class UploadServiceIntegrationTest { } @BeforeEach - public void beforeEach() throws UserExistsException, AuthServiceException, AuthServiceConnectionException, - EmailExistsException { - if (keycloakConfig.existsByUsername(keycloakContainer.getAdminUsername())) { + public void beforeEach() throws AuthServiceException { + if (keycloakUtil.existsByUsername(keycloakContainer.getAdminUsername())) { return; } final UserCreateDto payload = UserCreateDto.builder() @@ -82,7 +84,7 @@ public class UploadServiceIntegrationTest { .value(keycloakContainer.getAdminPassword()) .build())) .build(); - keycloakConfig.createUser(payload); + keycloakUtil.createUser(payload); } @Test diff --git a/dbrepo-upload-service/src/test/java/at/tuwien/util/KeycloakUtil.java b/dbrepo-upload-service/src/test/java/at/tuwien/util/KeycloakUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..b7c24cab9d5221f893e2e1fceb3f378b59e6d684 --- /dev/null +++ b/dbrepo-upload-service/src/test/java/at/tuwien/util/KeycloakUtil.java @@ -0,0 +1,46 @@ +package at.tuwien.util; + +import at.tuwien.api.keycloak.UserCreateDto; +import at.tuwien.exception.AuthServiceException; +import at.tuwien.mapper.MetadataMapper; +import jakarta.ws.rs.core.Response; +import lombok.extern.log4j.Log4j2; +import org.keycloak.admin.client.Keycloak; +import org.keycloak.representations.idm.UserRepresentation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +@Log4j2 +public class KeycloakUtil { + + + private final MetadataMapper metadataMapper; + private final Keycloak keycloak; + + @Autowired + public KeycloakUtil(MetadataMapper metadataMapper, Keycloak keycloak) { + this.metadataMapper = metadataMapper; + this.keycloak = keycloak; + } + + public void createUser(UserCreateDto data) throws AuthServiceException { + final UserRepresentation user = metadataMapper.userCreateDtoToUserRepresentation(data); + try (Response response = keycloak.realm("dbrepo") + .users() + .create(user)) { + if (response.getStatus() != 200) { + log.error("Failed to delete user: unexpected response status: {}", response.getStatus()); + throw new AuthServiceException("Unexpected response status: " + response.getStatus()); + } + } + log.info("Created user at auth service"); + } + + public boolean existsByUsername(String username) { + return keycloak.realm("dbrepo") + .users() + .search(username) + .isEmpty(); + } +} diff --git a/docker-compose.yml b/docker-compose.yml index 5a0d1a4242d9ca2f7f0f8cd97617def35e65cd6a..9176f6404a06df5e30269f4a0dde4d8e4483ebd8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -80,20 +80,25 @@ services: restart: "no" container_name: dbrepo-auth-service hostname: auth-service - image: bitnami/keycloak:24.0.5-debian-12-r8 + image: bitnami/keycloak:26.0.4-debian-12-r0 volumes: - ./dbrepo-auth-service/import-realms.sh:/docker-entrypoint-initdb.d/import-realms.sh - ./dbrepo-auth-service/master-realm.json:/opt/keycloak/data/import/master-realm.json - ./dbrepo-auth-service/dbrepo-realm.json:/opt/keycloak/data/import/dbrepo-realm.json + - ./dbrepo-auth-service/listeners/target/create-event-listener.jar:/opt/bitnami/keycloak/providers/create-event-listener.jar ports: - "8080:8080" environment: + KEYCLOAK_ENABLE_HEALTH_ENDPOINTS: "true" KEYCLOAK_ENABLE_HTTPS: "false" KEYCLOAK_ENABLE_STATISTICS: "true" KEYCLOAK_DATABASE_HOST: "auth-db" KEYCLOAK_DATABASE_NAME: "${AUTH_DB_NAME:-keycloak}" KEYCLOAK_DATABASE_USER: "${AUTH_DB_USERNAME:-keycloak}" KEYCLOAK_DATABASE_PASSWORD: "${AUTH_DB_PASSWORD:-dbrepo}" + METADATA_SERVICE_ENDPOINT: "${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080}/api/user" + SYSTEM_USERNAME: "${SYSTEM_USERNAME:-admin}" + SYSTEM_PASSWORD: "${SYSTEM_PASSWORD:-admin}" healthcheck: test: curl -fsS http://localhost:8080/realms/master interval: 10s @@ -110,8 +115,8 @@ services: dbrepo-auth-service-init: init: true restart: "no" - image: dbrepo-auth-service-init:latest container_name: dbrepo-auth-service-init + image: dbrepo-auth-service-init:latest build: context: ./dbrepo-auth-service/init network: host @@ -331,6 +336,14 @@ services: NUXT_PUBLIC_API_CLIENT: "${BASE_URL:-http://localhost}" NUXT_PUBLIC_API_SERVER: "${BASE_URL:-http://localhost}" NUXT_PUBLIC_UPLOAD_CLIENT: "${BASE_URL:-http://localhost}/api/upload/files" + NUXT_OIDC_PROVIDERS_KEYCLOAK_AUTHORIZATION_URL: "${BASE_URL:-http://localhost}/realms/dbrepo/protocol/openid-connect/auth" + NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_ID: "${AUTH_SERVICE_CLIENT:-dbrepo-client}" + NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_SECRET: "${AUTH_SERVICE_CLIENT:-MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG}" + NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_REDIRECT_URI: "${BASE_URL:-http://localhost}" + NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_URL: "${BASE_URL:-http://localhost}/realms/dbrepo/protocol/openid-connect/logout" + NUXT_OIDC_PROVIDERS_KEYCLOAK_REDIRECT_URI: "${BASE_URL:-http://localhost}/auth/keycloak/callback" + NUXT_OIDC_PROVIDERS_KEYCLOAK_TOKEN_URL: "${BASE_URL:-http://localhost}/realms/dbrepo/protocol/openid-connect/token" + NUXT_OIDC_PROVIDERS_KEYCLOAK_USER_INFO_URL: "${BASE_URL:-http://localhost}/realms/dbrepo/protocol/openid-connect/userinfo" depends_on: dbrepo-search-service: condition: service_healthy @@ -341,6 +354,8 @@ services: interval: 10s timeout: 5s retries: 12 + extra_hosts: + - "localhost:host-gateway" logging: driver: json-file @@ -475,7 +490,7 @@ services: LDAP_ADMIN_PASSWORD: "${IDENTITY_SERVICE_ADMIN_PASSWORD:-admin}" LDAP_ROOT: "${IDENTITY_SERVICE_ROOT:-dc=dbrepo,dc=at}" healthcheck: - test: test -f /opt/bitnami/grafana/tmp/grafana.pid + test: curl -fsSL --head http://127.0.0.1:3000 interval: 10s timeout: 5s retries: 12 @@ -523,6 +538,7 @@ services: AWS_ACCESS_KEY_ID: "${S3_ACCESS_KEY_ID:-seaweedfsadmin}" AWS_SECRET_ACCESS_KEY: "${S3_SECRET_ACCESS_KEY:-seaweedfsadmin}" AWS_REGION: "${STORAGE_REGION_NAME:-default}" + METADATA_SERVICE_ENDPOINT: "${METADATA_SERVICE_ENDPOINT:-http://metadata-service:8080}" depends_on: dbrepo-storage-service: condition: service_healthy diff --git a/helm/dbrepo/Chart.lock b/helm/dbrepo/Chart.lock index b18ee6f5f6f9fa67da970a2779fd6a33ca3974a1..297b4b1a9287732c869533cd2f2fe261ae43f4a5 100644 --- a/helm/dbrepo/Chart.lock +++ b/helm/dbrepo/Chart.lock @@ -4,7 +4,7 @@ dependencies: version: 1.4.0 - name: keycloak repository: https://charts.bitnami.com/bitnami - version: 21.6.1 + version: 24.0.3 - name: mariadb-galera repository: https://charts.bitnami.com/bitnami version: 13.2.7 @@ -26,5 +26,5 @@ dependencies: - name: nginx repository: https://charts.bitnami.com/bitnami version: 18.3.1 -digest: sha256:414c043a3751945d7bd5b02fa00ee0464bee7f08efb469e00a5f059cdbff03b5 -generated: "2025-01-19T17:22:48.686050629+01:00" +digest: sha256:aa148a5f656ad17971203ea710206117d6de6f27b6940f9d532a6c5762e5df25 +generated: "2025-02-04T22:01:27.370259572+01:00" diff --git a/helm/dbrepo/Chart.yaml b/helm/dbrepo/Chart.yaml index 22d1865df5866213c931df8b2b522af33137c1e6..99f8a84d23b7808e81dd94a337655594abf1721f 100644 --- a/helm/dbrepo/Chart.yaml +++ b/helm/dbrepo/Chart.yaml @@ -7,8 +7,8 @@ description: Helm Chart for installing DBRepo sources: - https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services type: application -version: "1.6.1" -appVersion: "1.6.1" +version: "1.6.3" +appVersion: "1.6.3" keywords: - dbrepo maintainers: @@ -24,7 +24,7 @@ dependencies: condition: searchdb.enabled - name: keycloak alias: authservice - version: 21.6.1 # app version: 24.0.5 + version: 24.0.3 # app version: 26.0.4 repository: https://charts.bitnami.com/bitnami condition: authservice.enabled - name: mariadb-galera diff --git a/helm/dbrepo/README.md b/helm/dbrepo/README.md index 7c613aaebc7a68b53f7df511ec85d66e00b489ca..a45297396372cc5580e4f065e4f7172929ba7c5a 100644 --- a/helm/dbrepo/README.md +++ b/helm/dbrepo/README.md @@ -11,7 +11,7 @@ sample [ for your deployment and update the variables, especially `hostname`. ```bash -helm install my-release "oci://registry.datalab.tuwien.ac.at/dbrepo/helm/dbrepo" --values ./values.yaml --version "1.6.1" +helm install my-release "oci://registry.datalab.tuwien.ac.at/dbrepo/helm/dbrepo" --values ./values.yaml --version "1.6.3" ``` ## Prerequisites @@ -28,7 +28,7 @@ helm install my-release "oci://registry.datalab.tuwien.ac.at/dbrepo/helm/dbrepo" To install the chart with the release name `my-release`: ```bash -helm install my-release "oci://oci://registry.datalab.tuwien.ac.at/dbrepo/helm" --values ./values.yaml --version "1.6.1" +helm install my-release "oci://oci://registry.datalab.tuwien.ac.at/dbrepo/helm" --values ./values.yaml --version "1.6.3" ``` The command deploys DBRepo on the Kubernetes cluster in the default configuration. The Parameters section lists the @@ -86,6 +86,7 @@ The command removes all the Kubernetes components associated with the chart and | `authservice.enabled` | Enable the Auth Service. | `true` | | `authservice.image.debug` | Set the logging level to `trace`. Otherwise, set to `info`. | `false` | | `authservice.endpoint` | The hostname for the microservices. | `http://auth-service` | +| `authservice.production` | Start Keycloak with production profile. | `true` | | `authservice.resourcesPreset` | The container resource presets | `small` | | `authservice.jwt.pubkey` | The JWT public key from the `dbrepo-client`. | `MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB` | | `authservice.tls.enabled` | Enable TLS/SSL communication. Required for HTTPS. | `true` | @@ -388,7 +389,7 @@ mqtt.prefetch = 10 | `ui.public.pid.default.publisher` | The default dataset publisher for persisted identifiers. | `Example University` | | `ui.public.doi.enabled` | Enable the display that DOIs are minted. | `false` | | `ui.public.doi.endpoint` | The DOI proxy. | `https://doi.org` | -| `ui.replicaCount` | The number of replicas. | `2` | +| `ui.replicaCount` | The number of replicas. | `1` | ### Dashboard Service diff --git a/helm/dbrepo/charts/keycloak-21.6.1.tgz b/helm/dbrepo/charts/keycloak-21.6.1.tgz deleted file mode 100644 index 6479f5943846dee589d3ec90bbda649a8d7b72fe..0000000000000000000000000000000000000000 Binary files a/helm/dbrepo/charts/keycloak-21.6.1.tgz and /dev/null differ diff --git a/helm/dbrepo/charts/keycloak-24.0.3.tgz b/helm/dbrepo/charts/keycloak-24.0.3.tgz new file mode 100644 index 0000000000000000000000000000000000000000..29a964b44168bec6c04969e16cf51c94b75952fc Binary files /dev/null and b/helm/dbrepo/charts/keycloak-24.0.3.tgz differ diff --git a/helm/dbrepo/charts/seaweedfs-4.2.1.tgz b/helm/dbrepo/charts/seaweedfs-4.2.1.tgz index 6fd5807b55c4d6ad8041d96ca5d4a39ed3795138..a463170406b9c62f8f33ba315ac440fe435ad93c 100644 Binary files a/helm/dbrepo/charts/seaweedfs-4.2.1.tgz and b/helm/dbrepo/charts/seaweedfs-4.2.1.tgz differ diff --git a/helm/dbrepo/files/01-setup-schema.sql b/helm/dbrepo/files/01-setup-schema.sql index c9ce89d1be71f4791c5e55dbb7c24f46e979355a..e2bde25ed6d64f69c4f8d6e897a49a672e3f9a71 100644 --- a/helm/dbrepo/files/01-setup-schema.sql +++ b/helm/dbrepo/files/01-setup-schema.sql @@ -3,10 +3,10 @@ BEGIN; CREATE TABLE IF NOT EXISTS `mdb_users` ( id character varying(36) NOT NULL, + keycloak_id character varying(36) NOT NULL, username character varying(255) NOT NULL, firstname character varying(255), lastname character varying(255), - email character varying(255) NOT NULL, orcid character varying(255), affiliation character varying(255), is_internal BOOLEAN NOT NULL DEFAULT FALSE, @@ -14,8 +14,8 @@ CREATE TABLE IF NOT EXISTS `mdb_users` theme character varying(255) NOT NULL default ('light'), language character varying(3) NOT NULL default ('en'), PRIMARY KEY (id), - UNIQUE (username), - UNIQUE (email) + UNIQUE (keycloak_id), + UNIQUE (username) ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_images` diff --git a/helm/dbrepo/files/create-event-listener.jar b/helm/dbrepo/files/create-event-listener.jar new file mode 100644 index 0000000000000000000000000000000000000000..9a9cd149f84ff92e5292a9fdc19a81edcc9ca7b7 Binary files /dev/null and b/helm/dbrepo/files/create-event-listener.jar differ diff --git a/helm/dbrepo/templates/auth-configmap.yaml b/helm/dbrepo/templates/auth-configmap.yaml index ffd14c4b1765cab2f20af5888c746fbf47a71a45..28ad32d66494ba0a284b73354af7e240bff48dd4 100644 --- a/helm/dbrepo/templates/auth-configmap.yaml +++ b/helm/dbrepo/templates/auth-configmap.yaml @@ -4,8 +4,11 @@ kind: ConfigMap metadata: name: auth-service-config namespace: {{ include "common.names.namespace" . | quote }} +binaryData: + create-event-listener.jar: |- + {{ .Files.Get "files/create-event-listener.jar" | b64enc }} data: - dbrepo-realm.json: | + dbrepo-realm.json: |- { "id" : "82c39861-d877-4667-a0f3-4daa2ee230e0", "realm" : "dbrepo", @@ -35,7 +38,7 @@ data: "oauth2DevicePollingInterval" : 5, "enabled" : true, "sslRequired" : "none", - "registrationAllowed" : false, + "registrationAllowed" : true, "registrationEmailAsUsername" : false, "rememberMe" : false, "verifyEmail" : true, @@ -46,6 +49,7 @@ data: "bruteForceProtected" : false, "permanentLockout" : false, "maxTemporaryLockouts" : 0, + "bruteForceStrategy" : "MULTIPLE", "maxFailureWaitSeconds" : 900, "minimumQuickLoginWaitSeconds" : 60, "waitIncrementSeconds" : 60, @@ -1316,8 +1320,8 @@ data: "protocol" : "openid-connect", "attributes" : { "realm_client" : "false", - "post.logout.redirect.uris" : "+", - "client.use.lightweight.access.token.enabled" : "true" + "client.use.lightweight.access.token.enabled" : "true", + "post.logout.redirect.uris" : "+" }, "authenticationFlowBindingOverrides" : { }, "fullScopeAllowed" : true, @@ -1391,6 +1395,38 @@ data: "fullScopeAllowed" : true, "nodeReRegistrationTimeout" : -1, "protocolMappers" : [ { + "id" : "266edf62-a19a-483b-b594-81428e4af792", + "name" : "orcid", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "ORCID", + "id.token.claim" : "true", + "lightweight.claim" : "false", + "access.token.claim" : "true", + "claim.name" : "orcid", + "jsonType.label" : "String" + } + }, { + "id" : "1a21798a-38b6-4df5-89f0-86942415246f", + "name" : "theme", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "THEME", + "id.token.claim" : "true", + "lightweight.claim" : "false", + "access.token.claim" : "true", + "claim.name" : "theme", + "jsonType.label" : "String" + } + }, { "id" : "da0b27c1-ae2e-4baa-bf78-db233e15c78d", "name" : "preferred_username", "protocol" : "openid-connect", @@ -1404,18 +1440,66 @@ data: "userinfo.token.claim" : "true" } }, { - "id" : "7c94de93-f60f-487b-b4b7-1891c67f74cc", - "name" : "aud", + "id" : "1bc6a1f4-4be2-439c-8c7f-b3fb0bb9956a", + "name" : "affiliation", "protocol" : "openid-connect", - "protocolMapper" : "oidc-hardcoded-claim-mapper", + "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "claim.value" : "dbrepo", + "introspection.token.claim" : "true", "userinfo.token.claim" : "true", + "user.attribute" : "AFFILIATION", "id.token.claim" : "true", + "lightweight.claim" : "false", "access.token.claim" : "true", - "claim.name" : "aud", - "access.tokenResponse.claim" : "false" + "claim.name" : "affiliation", + "jsonType.label" : "String" + } + }, { + "id" : "7cbf6dc6-653e-40a9-9974-0e5bf7a363c3", + "name" : "given name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "firstName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "given_name", + "jsonType.label" : "String" + } + }, { + "id" : "70bbd779-d085-4204-ac4b-3a40abab9d88", + "name" : "language", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "LANGUAGE", + "id.token.claim" : "true", + "lightweight.claim" : "false", + "access.token.claim" : "true", + "claim.name" : "language", + "jsonType.label" : "String" + } + }, { + "id" : "b817424d-7f91-43d8-b7d0-6a32582377fb", + "name" : "family name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "lastName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "family_name", + "jsonType.label" : "String" } }, { "id" : "030a1cd9-53d1-4a62-a375-94d50a2dc6fc", @@ -1432,9 +1516,26 @@ data: "access.token.claim" : "true", "claim.name" : "uid" } + }, { + "id" : "c304ed2f-5952-4772-838d-91998a45f154", + "name" : "aud", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-hardcoded-claim-mapper", + "consentRequired" : false, + "config" : { + "introspection.token.claim" : "true", + "claim.value" : "account", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "lightweight.claim" : "false", + "access.token.claim" : "true", + "claim.name" : "aud", + "jsonType.label" : "String", + "access.tokenResponse.claim" : "false" + } } ], - "defaultClientScopes" : [ "roles", "attributes", "basic" ], - "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ] + "defaultClientScopes" : [ "roles", "basic" ], + "optionalClientScopes" : [ "rabbitmq.read:*/*", "web-origins", "acr", "rabbitmq.write:*/*", "address", "phone", "offline_access", "profile", "attributes", "microprofile-jwt", "email", "rabbitmq.configure:*/*" ] }, { "id" : "25741f6b-4867-4138-8238-6345c6ba8702", "clientId" : "rabbitmq-client", @@ -1479,12 +1580,12 @@ data: "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "false", "user.attribute" : "username", "id.token.claim" : "false", "access.token.claim" : "true", "claim.name" : "client_id", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "false" } }, { "id" : "f1afc22d-f595-403b-ba2e-6ab19d98205e", @@ -1493,11 +1594,11 @@ data: "protocolMapper" : "oidc-hardcoded-claim-mapper", "consentRequired" : false, "config" : { - "claim.value" : "rabbitmq", - "userinfo.token.claim" : "false", "id.token.claim" : "false", "access.token.claim" : "true", "claim.name" : "aud", + "claim.value" : "rabbitmq", + "userinfo.token.claim" : "false", "access.tokenResponse.claim" : "false" } } ], @@ -1556,8 +1657,8 @@ data: "protocol" : "openid-connect", "attributes" : { "realm_client" : "false", - "post.logout.redirect.uris" : "+", "client.use.lightweight.access.token.enabled" : "true", + "post.logout.redirect.uris" : "+", "pkce.code.challenge.method" : "S256" }, "authenticationFlowBindingOverrides" : { }, @@ -1570,12 +1671,12 @@ data: "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "locale", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "locale", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } } ], "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], @@ -1599,8 +1700,8 @@ data: "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${emailScopeConsentText}" + "consent.screen.text" : "${emailScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "782819fe-ba5d-4ddb-9f95-cabb69d79c8d", @@ -1609,12 +1710,12 @@ data: "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "emailVerified", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "email_verified", - "jsonType.label" : "boolean" + "jsonType.label" : "boolean", + "userinfo.token.claim" : "true" } }, { "id" : "ca613fc8-bbf2-4240-8b33-a1874f1559f3", @@ -1623,12 +1724,12 @@ data: "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "email", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "email", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } } ] }, { @@ -1638,8 +1739,8 @@ data: "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${profileScopeConsentText}" + "consent.screen.text" : "${profileScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "84f0487a-1d7d-470c-9b8e-5835294ae235", @@ -1648,12 +1749,12 @@ data: "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "username", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "preferred_username", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "bbdcdb36-3ec0-443d-b1af-9993d40f0567", @@ -1662,12 +1763,12 @@ data: "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "gender", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "gender", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "9faa870b-5491-4ce9-b27d-c9ce07d6a95e", @@ -1676,12 +1777,12 @@ data: "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "birthdate", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "birthdate", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "f0e3c012-9523-4076-83ae-e466e2d08220", @@ -1701,12 +1802,12 @@ data: "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "profile", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "profile", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "18cfbf4b-0a8e-45c7-a832-c0f72c92f3f3", @@ -1715,12 +1816,12 @@ data: "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "updatedAt", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "updated_at", - "jsonType.label" : "long" + "jsonType.label" : "long", + "userinfo.token.claim" : "true" } }, { "id" : "841ea785-26ab-429a-a420-09ce3948924d", @@ -1729,12 +1830,12 @@ data: "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "lastName", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "family_name", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "bfba13ff-f952-4e89-bbb1-a693fdebfae8", @@ -1743,12 +1844,12 @@ data: "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "website", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "website", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "475f071d-5149-4379-b928-76482f5f519c", @@ -1757,12 +1858,12 @@ data: "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "zoneinfo", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "zoneinfo", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "b8bebfed-b5e9-4604-a0ee-9817f7d439ac", @@ -1771,12 +1872,12 @@ data: "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "middleName", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "middle_name", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "445232c8-6830-476c-a6f1-8bbef167595a", @@ -1785,12 +1886,12 @@ data: "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "picture", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "picture", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "65f2e474-6ede-4872-86e4-e49504dd0f2a", @@ -1799,12 +1900,12 @@ data: "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "locale", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "locale", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "16cd5a27-ccf3-453c-ae1e-8621813ab73c", @@ -1813,12 +1914,12 @@ data: "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "firstName", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "given_name", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "f9efedfc-3388-457c-b10a-1dff4525ff9b", @@ -1827,12 +1928,12 @@ data: "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "nickname", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "nickname", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } } ] }, { @@ -1866,12 +1967,12 @@ data: "protocolMapper" : "oidc-usermodel-property-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "username", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "upn", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } } ] }, { @@ -1913,8 +2014,8 @@ data: "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${phoneScopeConsentText}" + "consent.screen.text" : "${phoneScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "dae802fb-9138-408a-b80e-a40eb0f56814", @@ -1923,12 +2024,12 @@ data: "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "phoneNumber", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "phone_number", - "jsonType.label" : "String" + "jsonType.label" : "String", + "userinfo.token.claim" : "true" } }, { "id" : "feb06a8d-b0eb-4911-8464-368d93f566fa", @@ -1937,12 +2038,12 @@ data: "protocolMapper" : "oidc-usermodel-attribute-mapper", "consentRequired" : false, "config" : { - "userinfo.token.claim" : "true", "user.attribute" : "phoneNumberVerified", "id.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "phone_number_verified", - "jsonType.label" : "boolean" + "jsonType.label" : "boolean", + "userinfo.token.claim" : "true" } } ] }, { @@ -1952,8 +2053,8 @@ data: "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "false", - "display.on.consent.screen" : "false", - "consent.screen.text" : "" + "consent.screen.text" : "", + "display.on.consent.screen" : "false" }, "protocolMappers" : [ { "id" : "c6411e3b-6478-453d-b530-5fe175a4d786", @@ -2033,6 +2134,61 @@ data: "gui.order" : "", "consent.screen.text" : "" } + }, { + "id" : "aa5c6ca7-812d-4fff-80b9-f5095ca82ce6", + "name" : "service_account", + "description" : "Specific scope for a client enabled for service accounts", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "bb359b0f-97dc-4d6a-9a2f-89458b53c512", + "name" : "Client IP Address", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "clientAddress", + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "clientAddress", + "jsonType.label" : "String" + } + }, { + "id" : "7aa3a4d2-3dd1-48dd-8886-562906eadb2a", + "name" : "Client Host", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "clientHost", + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "clientHost", + "jsonType.label" : "String" + } + }, { + "id" : "c4882d39-e815-49f5-8a73-eb8b83572eae", + "name" : "Client ID", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "client_id", + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "client_id", + "jsonType.label" : "String" + } + } ] }, { "id" : "210cc792-6c07-45a6-a77e-827cdf3b41ba", "name" : "offline_access", @@ -2049,8 +2205,8 @@ data: "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${addressScopeConsentText}" + "consent.screen.text" : "${addressScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "8d4ffe4d-1d01-4ca1-8ff4-44eacca61b30", @@ -2123,8 +2279,8 @@ data: "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "false", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${rolesScopeConsentText}" + "consent.screen.text" : "${rolesScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "3b6b6914-8ad1-4a71-88ec-444f754aaacb", @@ -2140,11 +2296,15 @@ data: "protocolMapper" : "oidc-usermodel-realm-role-mapper", "consentRequired" : false, "config" : { + "introspection.token.claim" : "true", + "userinfo.token.claim" : "false", + "multivalued" : "true", "user.attribute" : "foo", + "id.token.claim" : "true", + "lightweight.claim" : "false", "access.token.claim" : "true", "claim.name" : "realm_access.roles", - "jsonType.label" : "String", - "multivalued" : "true" + "jsonType.label" : "String" } }, { "id" : "a7bd6723-e58e-47f7-95c0-2925ce99283d", @@ -2174,8 +2334,12 @@ data: "strictTransportSecurity" : "max-age=31536000; includeSubDomains" }, "smtpServer" : { }, + "loginTheme" : "keycloak.v2", + "accountTheme" : "", + "adminTheme" : "", + "emailTheme" : "", "eventsEnabled" : false, - "eventsListeners" : [ "jboss-logging" ], + "eventsListeners" : [ "create-event-listener", "jboss-logging" ], "enabledEventTypes" : [ "SEND_RESET_PASSWORD", "UPDATE_CONSENT_ERROR", "GRANT_CONSENT", "VERIFY_PROFILE_ERROR", "REMOVE_TOTP", "REVOKE_GRANT", "UPDATE_TOTP", "LOGIN_ERROR", "CLIENT_LOGIN", "RESET_PASSWORD_ERROR", "IMPERSONATE_ERROR", "CODE_TO_TOKEN_ERROR", "CUSTOM_REQUIRED_ACTION", "OAUTH2_DEVICE_CODE_TO_TOKEN_ERROR", "RESTART_AUTHENTICATION", "IMPERSONATE", "UPDATE_PROFILE_ERROR", "LOGIN", "OAUTH2_DEVICE_VERIFY_USER_CODE", "UPDATE_PASSWORD_ERROR", "CLIENT_INITIATED_ACCOUNT_LINKING", "TOKEN_EXCHANGE", "AUTHREQID_TO_TOKEN", "LOGOUT", "REGISTER", "DELETE_ACCOUNT_ERROR", "CLIENT_REGISTER", "IDENTITY_PROVIDER_LINK_ACCOUNT", "DELETE_ACCOUNT", "UPDATE_PASSWORD", "CLIENT_DELETE", "FEDERATED_IDENTITY_LINK_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN", "CLIENT_DELETE_ERROR", "VERIFY_EMAIL", "CLIENT_LOGIN_ERROR", "RESTART_AUTHENTICATION_ERROR", "EXECUTE_ACTIONS", "REMOVE_FEDERATED_IDENTITY_ERROR", "TOKEN_EXCHANGE_ERROR", "PERMISSION_TOKEN", "SEND_IDENTITY_PROVIDER_LINK_ERROR", "EXECUTE_ACTION_TOKEN_ERROR", "SEND_VERIFY_EMAIL", "OAUTH2_DEVICE_AUTH", "EXECUTE_ACTIONS_ERROR", "REMOVE_FEDERATED_IDENTITY", "OAUTH2_DEVICE_CODE_TO_TOKEN", "IDENTITY_PROVIDER_POST_LOGIN", "IDENTITY_PROVIDER_LINK_ACCOUNT_ERROR", "OAUTH2_DEVICE_VERIFY_USER_CODE_ERROR", "UPDATE_EMAIL", "REGISTER_ERROR", "REVOKE_GRANT_ERROR", "EXECUTE_ACTION_TOKEN", "LOGOUT_ERROR", "UPDATE_EMAIL_ERROR", "CLIENT_UPDATE_ERROR", "AUTHREQID_TO_TOKEN_ERROR", "UPDATE_PROFILE", "CLIENT_REGISTER_ERROR", "FEDERATED_IDENTITY_LINK", "SEND_IDENTITY_PROVIDER_LINK", "SEND_VERIFY_EMAIL_ERROR", "RESET_PASSWORD", "CLIENT_INITIATED_ACCOUNT_LINKING_ERROR", "OAUTH2_DEVICE_AUTH_ERROR", "UPDATE_CONSENT", "REMOVE_TOTP_ERROR", "VERIFY_EMAIL_ERROR", "SEND_RESET_PASSWORD_ERROR", "CLIENT_UPDATE", "CUSTOM_REQUIRED_ACTION_ERROR", "IDENTITY_PROVIDER_POST_LOGIN_ERROR", "UPDATE_TOTP_ERROR", "CODE_TO_TOKEN", "VERIFY_PROFILE", "GRANT_CONSENT_ERROR", "IDENTITY_PROVIDER_FIRST_LOGIN_ERROR" ], "adminEventsEnabled" : false, "adminEventsDetailsEnabled" : false, @@ -2223,7 +2387,7 @@ data: "subType" : "anonymous", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", "saml-role-list-mapper" ] + "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper", "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper" ] } }, { "id" : "1849e52a-b8c9-44a8-af3d-ee19376a1ed1", @@ -2249,7 +2413,15 @@ data: "subType" : "authenticated", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "oidc-address-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "saml-role-list-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper" ] + "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-address-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "oidc-sha256-pairwise-sub-mapper" ] + } + } ], + "org.keycloak.userprofile.UserProfileProvider" : [ { + "id" : "a407a1d6-a7f6-4a72-ba3a-149de03d5a43", + "providerId" : "declarative-user-profile", + "subComponents" : { }, + "config" : { + "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}],\"unmanagedAttributePolicy\":\"ENABLED\"}" ] } } ], "org.keycloak.storage.UserStorageProvider" : [ { @@ -2265,8 +2437,8 @@ data: "config" : { "ldap.attribute" : [ "createTimestamp" ], "is.mandatory.in.ldap" : [ "false" ], - "read.only" : [ "true" ], "always.read.value.from.ldap" : [ "true" ], + "read.only" : [ "true" ], "user.model.attribute" : [ "createTimestamp" ] } }, { @@ -2277,8 +2449,8 @@ data: "config" : { "ldap.attribute" : [ "sn" ], "is.mandatory.in.ldap" : [ "true" ], - "always.read.value.from.ldap" : [ "true" ], "read.only" : [ "false" ], + "always.read.value.from.ldap" : [ "true" ], "user.model.attribute" : [ "lastName" ] } }, { @@ -2301,8 +2473,8 @@ data: "config" : { "ldap.attribute" : [ "mail" ], "is.mandatory.in.ldap" : [ "false" ], - "read.only" : [ "false" ], "always.read.value.from.ldap" : [ "false" ], + "read.only" : [ "false" ], "user.model.attribute" : [ "email" ] } }, { @@ -2311,19 +2483,19 @@ data: "providerId" : "group-ldap-mapper", "subComponents" : { }, "config" : { + "mode" : [ "LDAP_ONLY" ], "membership.attribute.type" : [ "DN" ], + "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ], "group.name.ldap.attribute" : [ "cn" ], - "preserve.group.inheritance" : [ "false" ], "membership.user.ldap.attribute" : [ "uid" ], - "groups.dn" : [ "ou=users,{{ .Values.identityservice.global.ldapDomain }}" ], - "mode" : [ "LDAP_ONLY" ], - "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ], - "membership.ldap.attribute" : [ "member" ], "ignore.missing.groups" : [ "false" ], + "preserve.group.inheritance" : [ "false" ], + "membership.ldap.attribute" : [ "member" ], "memberof.ldap.attribute" : [ "memberOf" ], "group.object.classes" : [ "groupOfNames" ], - "drop.non.existing.groups.during.sync" : [ "false" ], - "groups.path" : [ "/" ] + "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ], + "groups.path" : [ "/" ], + "drop.non.existing.groups.during.sync" : [ "false" ] } }, { "id" : "b6ff3285-35af-4e86-8bb4-d94b8e0d70bb", @@ -2347,15 +2519,15 @@ data: "is.mandatory.in.ldap" : [ "true" ], "attribute.force.default" : [ "false" ], "is.binary.attribute" : [ "false" ], - "read.only" : [ "false" ], "always.read.value.from.ldap" : [ "false" ], + "read.only" : [ "false" ], "user.model.attribute" : [ "username" ] } } ] }, "config" : { - "pagination" : [ "false" ], "fullSyncPeriod" : [ "-1" ], + "pagination" : [ "false" ], "startTls" : [ "false" ], "connectionPooling" : [ "true" ], "usersDn" : [ "ou=users,{{ .Values.identityservice.global.ldapDomain }}" ], @@ -2363,15 +2535,15 @@ data: "useKerberosForPasswordAuthentication" : [ "false" ], "importEnabled" : [ "true" ], "enabled" : [ "true" ], + "bindCredential" : [ "{{ .Values.identityservice.global.adminPassword }}" ], "changedSyncPeriod" : [ "-1" ], - "bindDn" : [ "cn={{ .Values.identityservice.global.adminUser }},{{ .Values.identityservice.global.ldapDomain }}" ], "usernameLDAPAttribute" : [ "uid" ], - "bindCredential" : [ "{{ .Values.identityservice.global.adminPassword }}" ], + "bindDn" : [ "cn={{ .Values.identityservice.global.adminUser }},{{ .Values.identityservice.global.ldapDomain }}" ], "lastSync" : [ "1719252666" ], "vendor" : [ "other" ], "uuidLDAPAttribute" : [ "entryUUID" ], - "connectionUrl" : [ "ldap://identity-service:389" ], "allowKerberosAuthentication" : [ "false" ], + "connectionUrl" : [ "ldap://identity-service:389" ], "syncRegistrations" : [ "true" ], "authType" : [ "simple" ], "useTruststoreSpi" : [ "always" ], @@ -2383,14 +2555,6 @@ data: "validatePasswordPolicy" : [ "false" ] } } ], - "org.keycloak.userprofile.UserProfileProvider" : [ { - "id" : "a407a1d6-a7f6-4a72-ba3a-149de03d5a43", - "providerId" : "declarative-user-profile", - "subComponents" : { }, - "config" : { - "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}],\"unmanagedAttributePolicy\":\"ENABLED\"}" ] - } - } ], "org.keycloak.keys.KeyProvider" : [ { "id" : "2f53ccf3-37b0-4d34-83e7-ed497499ee51", "name" : "rsa-enc-generated", @@ -3003,10 +3167,12 @@ data: "actionTokenGeneratedByUserLifespan-idp-verify-account-via-email" : "", "parRequestUriLifespan" : "60", "clientSessionMaxLifespan" : "0", + "organizationsEnabled" : "false", "shortVerificationUri" : "" }, - "keycloakVersion" : "24.0.5", + "keycloakVersion" : "26.0.4", "userManagedAccessAllowed" : false, + "organizationsEnabled" : false, "clientProfiles" : { "profiles" : [ ] }, @@ -3014,7 +3180,7 @@ data: "policies" : [ ] } } - master-realm.json: | + master-realm.json: |- { "id" : "afe47bd0-61f8-40c3-95cb-04930407ebdd", "realm" : "master", @@ -3057,6 +3223,7 @@ data: "bruteForceProtected" : false, "permanentLockout" : false, "maxTemporaryLockouts" : 0, + "bruteForceStrategy" : "MULTIPLE", "maxFailureWaitSeconds" : 900, "minimumQuickLoginWaitSeconds" : 60, "waitIncrementSeconds" : 60, @@ -3681,8 +3848,8 @@ data: "protocol" : "openid-connect", "attributes" : { "realm_client" : "false", - "post.logout.redirect.uris" : "+", - "client.use.lightweight.access.token.enabled" : "true" + "client.use.lightweight.access.token.enabled" : "true", + "post.logout.redirect.uris" : "+" }, "authenticationFlowBindingOverrides" : { }, "fullScopeAllowed" : true, @@ -3800,8 +3967,8 @@ data: "protocol" : "openid-connect", "attributes" : { "realm_client" : "false", - "post.logout.redirect.uris" : "+", "client.use.lightweight.access.token.enabled" : "true", + "post.logout.redirect.uris" : "+", "pkce.code.challenge.method" : "S256" }, "authenticationFlowBindingOverrides" : { }, @@ -3833,8 +4000,8 @@ data: "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${addressScopeConsentText}" + "consent.screen.text" : "${addressScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "4aed5e41-0d8d-4c24-80a0-cd9822072756", @@ -3862,8 +4029,8 @@ data: "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${organizationScopeConsentText}" + "consent.screen.text" : "${organizationScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "5e80a7d2-c9d0-48e1-aadc-d8848ff90f92", @@ -3881,6 +4048,61 @@ data: "jsonType.label" : "String" } } ] + }, { + "id" : "1be1e284-2749-4bbb-890a-2d519cc1531c", + "name" : "service_account", + "description" : "Specific scope for a client enabled for service accounts", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "c913a673-cf66-4493-a2ed-14556c07617c", + "name" : "Client ID", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "client_id", + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "client_id", + "jsonType.label" : "String" + } + }, { + "id" : "5c244d68-5c63-4356-ac71-5a586f40c77e", + "name" : "Client IP Address", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "clientAddress", + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "clientAddress", + "jsonType.label" : "String" + } + }, { + "id" : "600285d4-ae51-4b39-a7be-bb83cf5870db", + "name" : "Client Host", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usersessionmodel-note-mapper", + "consentRequired" : false, + "config" : { + "user.session.note" : "clientHost", + "introspection.token.claim" : "true", + "userinfo.token.claim" : "true", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "clientHost", + "jsonType.label" : "String" + } + } ] }, { "id" : "0411ea86-a074-4781-850d-ea3ca94590a2", "name" : "offline_access", @@ -3932,8 +4154,8 @@ data: "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${profileScopeConsentText}" + "consent.screen.text" : "${profileScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "2d1400be-4053-4393-ba87-91b64f699054", @@ -4234,8 +4456,8 @@ data: "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "false", - "display.on.consent.screen" : "false", - "consent.screen.text" : "" + "consent.screen.text" : "", + "display.on.consent.screen" : "false" }, "protocolMappers" : [ { "id" : "635cbac1-7cab-43bd-99fc-f7084aca2fa2", @@ -4271,8 +4493,8 @@ data: "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "false", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${rolesScopeConsentText}" + "consent.screen.text" : "${rolesScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "2b5a3df4-1adb-402d-bc28-2bd43224e682", @@ -4281,12 +4503,12 @@ data: "protocolMapper" : "oidc-usermodel-realm-role-mapper", "consentRequired" : false, "config" : { - "introspection.token.claim" : "true", - "multivalued" : "true", "user.attribute" : "foo", + "introspection.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "realm_access.roles", - "jsonType.label" : "String" + "jsonType.label" : "String", + "multivalued" : "true" } }, { "id" : "f3b60071-ef26-48a7-9554-67f62f84d543", @@ -4295,12 +4517,12 @@ data: "protocolMapper" : "oidc-usermodel-client-role-mapper", "consentRequired" : false, "config" : { - "introspection.token.claim" : "true", - "multivalued" : "true", "user.attribute" : "foo", + "introspection.token.claim" : "true", "access.token.claim" : "true", "claim.name" : "resource_access.${client_id}.roles", - "jsonType.label" : "String" + "jsonType.label" : "String", + "multivalued" : "true" } }, { "id" : "b757200e-494a-4585-857e-e4c18aef7a0c", @@ -4320,8 +4542,8 @@ data: "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${emailScopeConsentText}" + "consent.screen.text" : "${emailScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "e18769b3-778b-47d8-be52-dd2769deebd1", @@ -4361,8 +4583,8 @@ data: "protocol" : "openid-connect", "attributes" : { "include.in.token.scope" : "true", - "display.on.consent.screen" : "true", - "consent.screen.text" : "${phoneScopeConsentText}" + "consent.screen.text" : "${phoneScopeConsentText}", + "display.on.consent.screen" : "true" }, "protocolMappers" : [ { "id" : "98cc724c-3f53-47f7-bf9f-baf2f7e08026", @@ -4448,7 +4670,7 @@ data: "subType" : "anonymous", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-usermodel-property-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "saml-user-property-mapper", "oidc-sha256-pairwise-sub-mapper" ] + "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "saml-user-property-mapper" ] } }, { "id" : "4b976576-c880-48a0-9b4d-2956cfd19b4a", @@ -4457,7 +4679,7 @@ data: "subType" : "authenticated", "subComponents" : { }, "config" : { - "allowed-protocol-mapper-types" : [ "saml-role-list-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-address-mapper" ] + "allowed-protocol-mapper-types" : [ "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper", "oidc-usermodel-property-mapper", "saml-user-attribute-mapper" ] } }, { "id" : "e1861ec9-2761-46fb-8048-149492269ff0", @@ -4487,6 +4709,14 @@ data: "allow-default-scopes" : [ "true" ] } } ], + "org.keycloak.userprofile.UserProfileProvider" : [ { + "id" : "34049725-5a66-456c-b895-87ca7c11bb6b", + "providerId" : "declarative-user-profile", + "subComponents" : { }, + "config" : { + "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}]}" ] + } + } ], "org.keycloak.storage.UserStorageProvider" : [ { "id" : "3a6f24e8-128b-4ac1-b3ab-694836db82fd", "name" : "Identity Service", @@ -4500,8 +4730,8 @@ data: "config" : { "ldap.attribute" : [ "mail" ], "is.mandatory.in.ldap" : [ "false" ], - "read.only" : [ "false" ], "always.read.value.from.ldap" : [ "false" ], + "read.only" : [ "false" ], "user.model.attribute" : [ "email" ] } }, { @@ -4512,8 +4742,8 @@ data: "config" : { "ldap.attribute" : [ "sn" ], "is.mandatory.in.ldap" : [ "true" ], - "read.only" : [ "false" ], "always.read.value.from.ldap" : [ "true" ], + "read.only" : [ "false" ], "user.model.attribute" : [ "lastName" ] } }, { @@ -4524,8 +4754,8 @@ data: "config" : { "ldap.attribute" : [ "modifyTimestamp" ], "is.mandatory.in.ldap" : [ "false" ], - "always.read.value.from.ldap" : [ "true" ], "read.only" : [ "true" ], + "always.read.value.from.ldap" : [ "true" ], "user.model.attribute" : [ "modifyTimestamp" ] } }, { @@ -4558,17 +4788,17 @@ data: "providerId" : "group-ldap-mapper", "subComponents" : { }, "config" : { + "mode" : [ "LDAP_ONLY" ], "membership.attribute.type" : [ "DN" ], + "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ], "group.name.ldap.attribute" : [ "cn" ], + "ignore.missing.groups" : [ "false" ], "membership.user.ldap.attribute" : [ "uid" ], "preserve.group.inheritance" : [ "false" ], - "groups.dn" : [ "ou=users,{{ .Values.identityservice.global.ldapDomain }}" ], - "mode" : [ "LDAP_ONLY" ], - "user.roles.retrieve.strategy" : [ "LOAD_GROUPS_BY_MEMBER_ATTRIBUTE" ], "membership.ldap.attribute" : [ "member" ], - "ignore.missing.groups" : [ "false" ], - "group.object.classes" : [ "groupOfNames" ], + "groups.dn" : [ "ou=users,dc=dbrepo,dc=at" ], "memberof.ldap.attribute" : [ "memberOf" ], + "group.object.classes" : [ "groupOfNames" ], "drop.non.existing.groups.during.sync" : [ "false" ], "groups.path" : [ "/" ] } @@ -4580,8 +4810,8 @@ data: "config" : { "ldap.attribute" : [ "createTimestamp" ], "is.mandatory.in.ldap" : [ "false" ], - "always.read.value.from.ldap" : [ "true" ], "read.only" : [ "true" ], + "always.read.value.from.ldap" : [ "true" ], "user.model.attribute" : [ "createTimestamp" ] } } ] @@ -4597,13 +4827,13 @@ data: "importEnabled" : [ "true" ], "enabled" : [ "true" ], "changedSyncPeriod" : [ "-1" ], + "usernameLDAPAttribute" : [ "uid" ], "bindCredential" : [ "{{ .Values.identityservice.global.adminPassword }}" ], "bindDn" : [ "cn={{ .Values.identityservice.global.adminUser }},{{ .Values.identityservice.global.ldapDomain }}" ], - "usernameLDAPAttribute" : [ "uid" ], "vendor" : [ "other" ], "uuidLDAPAttribute" : [ "entryUUID" ], "allowKerberosAuthentication" : [ "false" ], - "connectionUrl" : [ "ldap://identity-service:1389" ], + "connectionUrl" : [ "ldap://identity-service:389" ], "syncRegistrations" : [ "true" ], "authType" : [ "simple" ], "krbPrincipalAttribute" : [ "krb5PrincipalName" ], @@ -4617,14 +4847,6 @@ data: "validatePasswordPolicy" : [ "false" ] } } ], - "org.keycloak.userprofile.UserProfileProvider" : [ { - "id" : "34049725-5a66-456c-b895-87ca7c11bb6b", - "providerId" : "declarative-user-profile", - "subComponents" : { }, - "config" : { - "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}]}" ] - } - } ], "org.keycloak.keys.KeyProvider" : [ { "id" : "5b1052d2-fb71-47d2-86f9-908c869c8d1b", "name" : "hmac-generated-hs512", @@ -5236,10 +5458,12 @@ data: "parRequestUriLifespan" : "60", "clientSessionMaxLifespan" : "0", "frontendUrl" : "", + "organizationsEnabled" : "false", "acr.loa.map" : "{}" }, - "keycloakVersion" : "24.0.5", + "keycloakVersion" : "26.0.4", "userManagedAccessAllowed" : false, + "organizationsEnabled" : false, "clientProfiles" : { "profiles" : [ ] }, diff --git a/helm/dbrepo/templates/auth-secret.yaml b/helm/dbrepo/templates/auth-secret.yaml index a568ef25007e51d70bf4ad1ac186645e57499015..dca0f861f132ea1557a52b488c63e74e6b435917 100644 --- a/helm/dbrepo/templates/auth-secret.yaml +++ b/helm/dbrepo/templates/auth-secret.yaml @@ -11,6 +11,8 @@ stringData: AUTH_SERVICE_ENDPOINT: "{{ .Values.authservice.endpoint }}" METADATA_DB: "{{ .Values.metadatadb.db.name }}" METADATA_DB_PASSWORD: "{{ .Values.metadatadb.rootUser.password }}" + METADATA_SERVICE_ENDPOINT: "{{ .Values.metadataservice.endpoint }}/api/user" METADATA_USERNAME: "{{ .Values.metadatadb.rootUser.user }}" SYSTEM_USERNAME: "{{ .Values.identityservice.users }}" + SYSTEM_PASSWORD: "{{ .Values.identityservice.userPasswords }}" {{- end }} diff --git a/helm/dbrepo/templates/gateway-configmap.yaml b/helm/dbrepo/templates/gateway-configmap.yaml index aa314d3c65948076a4e7eaf977bf47b8735b153d..8ef358871523c80ac16ec128e54e116b3d57d52e 100644 --- a/helm/dbrepo/templates/gateway-configmap.yaml +++ b/helm/dbrepo/templates/gateway-configmap.yaml @@ -39,6 +39,24 @@ data: proxy_read_timeout 90; } + location /realms { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_pass https://auth-service; + proxy_read_timeout 90; + } + + location /resources { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_pass https://auth-service; + proxy_read_timeout 90; + } + location /api/search { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; diff --git a/helm/dbrepo/templates/ui-secret.yaml b/helm/dbrepo/templates/ui-secret.yaml index 5620e7b2da88226759723c4bbd24f2e5479bc444..a84ac8f5cef024c88fa41ce085f494cca396df9f 100644 --- a/helm/dbrepo/templates/ui-secret.yaml +++ b/helm/dbrepo/templates/ui-secret.yaml @@ -22,4 +22,13 @@ stringData: NUXT_PUBLIC_PID_DEFAULT_PUBLISHER: "{{ .Values.ui.public.pid.default.publisher }}" NUXT_PUBLIC_UPLOAD_CLIENT: "{{ .Values.ui.public.upload.client | default $uploadEndpoint }}" NUXT_PUBLIC_BROKER_CONNECTIONS: "{{ include "dbrepo.broker.connections" . }}" + NUXT_OIDC_PROVIDERS_KEYCLOAK_AUTHORIZATION_URL: "{{ .Values.gateway }}/realms/dbrepo/protocol/openid-connect/auth" + NUXT_OIDC_PROVIDERS_KEYCLOAK_BASE_URL: "{{ .Values.gateway }}/realms/dbrepo" + NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_ID: "{{ .Values.authservice.client.id }}" + NUXT_OIDC_PROVIDERS_KEYCLOAK_CLIENT_SECRET: "{{ .Values.authservice.client.secret }}" + NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_REDIRECT_URI: "{{ .Values.gateway }}" + NUXT_OIDC_PROVIDERS_KEYCLOAK_LOGOUT_URL: "{{ .Values.gateway }}/realms/dbrepo/protocol/openid-connect/logout" + NUXT_OIDC_PROVIDERS_KEYCLOAK_REDIRECT_URI: "{{ .Values.gateway }}/auth/keycloak/callback" + NUXT_OIDC_PROVIDERS_KEYCLOAK_TOKEN_URL: "{{ .Values.gateway }}/realms/dbrepo/protocol/openid-connect/token" + NUXT_OIDC_PROVIDERS_KEYCLOAK_USER_INFO_URL: "{{ .Values.gateway }}/realms/dbrepo/protocol/openid-connect/userinfo" {{- end }} diff --git a/helm/dbrepo/values.schema.json b/helm/dbrepo/values.schema.json index 9ade1b07493e1aa92d11a726d38f869b4ad69461..641287b434aff0bf533a2416081a9d6c0e447742 100644 --- a/helm/dbrepo/values.schema.json +++ b/helm/dbrepo/values.schema.json @@ -126,7 +126,7 @@ "endpoint": { "type": "string" }, - "extraEnvVarsCM": { + "extraEnvVarsSecret": { "type": "string" }, "extraVolumeMounts": { @@ -137,6 +137,9 @@ }, "name": { "type": "string" + }, + "subPath": { + "type": "string" } }, "type": "object" @@ -224,6 +227,9 @@ }, "type": "object" }, + "production": { + "type": "boolean" + }, "replicaCount": { "type": "integer" }, diff --git a/helm/dbrepo/values.yaml b/helm/dbrepo/values.yaml index 34db1f569f07dd9198c5247505b3ba45a52a19f8..7515778b33d38b5e427a85742d5aa0d71b9e6a3a 100644 --- a/helm/dbrepo/values.yaml +++ b/helm/dbrepo/values.yaml @@ -87,6 +87,8 @@ authservice: fullnameOverride: auth-db auth: postgresPassword: postgres + ## @param authservice.production Start Keycloak with production profile. + production: true ## @param authservice.resourcesPreset The container resource presets resourcesPreset: "small" jwt: @@ -116,7 +118,7 @@ authservice: setupJob: image: ## @skip authservice.setupJob.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/auth-service-init:1.6.1 + name: registry.datalab.tuwien.ac.at/dbrepo/auth-service-init:1.6.3 ## @param authservice.setupJob.resourcesPreset The container resource preset resourcesPreset: "nano" ## @param authservice.setupJob.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) @@ -127,8 +129,8 @@ authservice: ## limits: ## cpu: 500m ## memory: 1024Mi - ## @skip authservice.extraEnvVarsCM - extraEnvVarsCM: auth-service-config + ## @skip authservice.extraEnvVarsSecret + extraEnvVarsSecret: auth-service-secret ## @skip authservice.extraVolumes extraVolumes: - name: config-map @@ -140,7 +142,14 @@ authservice: ## @skip authservice.extraVolumeMounts extraVolumeMounts: - name: config-map - mountPath: /opt/keycloak/data/import + mountPath: /opt/keycloak/data/import/dbrepo-realm.json + subPath: dbrepo-realm.json + - name: config-map + mountPath: /opt/keycloak/data/import/master-realm.json + subPath: master-realm.json + - name: config-map + mountPath: /opt/bitnami/keycloak/providers/create-event-listener.jar + subPath: create-event-listener.jar - name: cache mountPath: /bitnami/keycloak/ ## @skip authservice.replicaCount The number of replicas. @@ -392,7 +401,7 @@ analyseservice: enabled: true image: ## @skip analyseservice.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.6.1 + name: registry.datalab.tuwien.ac.at/dbrepo/analyse-service:1.6.3 ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod podSecurityContext: ## @param analyseservice.podSecurityContext.enabled Enable pods' Security Context @@ -453,7 +462,7 @@ metadataservice: enabled: true image: ## @skip metadataservice.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.1 + name: registry.datalab.tuwien.ac.at/dbrepo/metadata-service:1.6.3 ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod podSecurityContext: ## @param metadataservice.podSecurityContext.enabled Enable pods' Security Context @@ -550,7 +559,7 @@ dataservice: endpoint: http://data-service image: ## @skip dataservice.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.6.1 + name: registry.datalab.tuwien.ac.at/dbrepo/data-service:1.6.3 ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod podSecurityContext: ## @param dataservice.podSecurityContext.enabled Enable pods' Security Context @@ -636,7 +645,7 @@ searchservice: endpoint: http://search-service image: ## @skip searchservice.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.6.1 + name: registry.datalab.tuwien.ac.at/dbrepo/search-service:1.6.3 ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod podSecurityContext: ## @param searchservice.podSecurityContext.enabled Enable pods' Security Context @@ -683,7 +692,7 @@ searchservice: init: image: ## @skip searchservice.init.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.6.1 + name: registry.datalab.tuwien.ac.at/dbrepo/search-service-init:1.6.3 ## @param searchservice.init.resourcesPreset The container resource preset resourcesPreset: "nano" ## @param searchservice.init.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads) @@ -744,7 +753,7 @@ storageservice: init: image: ## @skip storageservice.init.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.6.1 + name: registry.datalab.tuwien.ac.at/dbrepo/storage-service-init:1.6.3 s3: ## @param storageservice.init.s3.endpoint The S3-capable endpoint the microservice connects to. endpoint: http://storage-service-s3:8333 @@ -853,7 +862,7 @@ ui: enabled: true image: ## @skip ui.image.name - name: registry.datalab.tuwien.ac.at/dbrepo/ui:1.6.1 + name: registry.datalab.tuwien.ac.at/dbrepo/ui:1.6.3 ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod podSecurityContext: ## @param ui.podSecurityContext.enabled Enable pods' Security Context @@ -941,7 +950,7 @@ ui: ## @param ui.public.doi.endpoint The DOI proxy. endpoint: https://doi.org ## @param ui.replicaCount The number of replicas. - replicaCount: 2 + replicaCount: 1 ## @skip ui.extraVolumes extraVolumes: [ ] # - name: images-map diff --git a/helm/seaweedfs/Chart.lock b/helm/seaweedfs/Chart.lock index edcc38c41f0c6b2b35f8d740566918ddb16f17fc..96e5c8dce913d2f7a73bf8adc5d7f121fb2a3b70 100644 --- a/helm/seaweedfs/Chart.lock +++ b/helm/seaweedfs/Chart.lock @@ -1,12 +1,12 @@ dependencies: - name: mariadb repository: oci://registry-1.docker.io/bitnamicharts - version: 20.2.1 + version: 20.2.2 - name: postgresql repository: oci://registry-1.docker.io/bitnamicharts - version: 16.4.3 + version: 16.4.6 - name: common repository: oci://registry-1.docker.io/bitnamicharts - version: 2.29.0 -digest: sha256:4c967f771b303ca0db9ba2e355790152448c77a05d3f6c69eda6c234bc3f60c6 -generated: "2025-01-17T15:24:18.141765362+01:00" + version: 2.29.1 +digest: sha256:bc14ae7bbe7be291adc4a6329ae64835c367b09277a2678c4e10cc74b19ee491 +generated: "2025-02-04T22:22:11.88596441+01:00" diff --git a/helm/seaweedfs/charts/common-2.29.0.tgz b/helm/seaweedfs/charts/common-2.29.0.tgz deleted file mode 100644 index f36e9e24ec32ce1237d1ee774541c5586fce222d..0000000000000000000000000000000000000000 Binary files a/helm/seaweedfs/charts/common-2.29.0.tgz and /dev/null differ diff --git a/helm/seaweedfs/charts/common-2.29.1.tgz b/helm/seaweedfs/charts/common-2.29.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..8b9abbbc5b6c62a743cc0fb041d26b199c4313c8 Binary files /dev/null and b/helm/seaweedfs/charts/common-2.29.1.tgz differ diff --git a/helm/seaweedfs/charts/mariadb-20.2.1.tgz b/helm/seaweedfs/charts/mariadb-20.2.1.tgz deleted file mode 100644 index 9bba8eed49e866977396c0076b1a9c5946ec88b1..0000000000000000000000000000000000000000 Binary files a/helm/seaweedfs/charts/mariadb-20.2.1.tgz and /dev/null differ diff --git a/helm/seaweedfs/charts/mariadb-20.2.2.tgz b/helm/seaweedfs/charts/mariadb-20.2.2.tgz new file mode 100644 index 0000000000000000000000000000000000000000..a983469f30dfce693288215705891f387c517319 Binary files /dev/null and b/helm/seaweedfs/charts/mariadb-20.2.2.tgz differ diff --git a/helm/seaweedfs/charts/postgresql-16.4.3.tgz b/helm/seaweedfs/charts/postgresql-16.4.3.tgz deleted file mode 100644 index 429f7ed063f6655796792fbe711b027e147ddda4..0000000000000000000000000000000000000000 Binary files a/helm/seaweedfs/charts/postgresql-16.4.3.tgz and /dev/null differ diff --git a/helm/seaweedfs/charts/postgresql-16.4.6.tgz b/helm/seaweedfs/charts/postgresql-16.4.6.tgz new file mode 100644 index 0000000000000000000000000000000000000000..9016ba352dfd2b553e3cac4a8a80fb7c8c539d65 Binary files /dev/null and b/helm/seaweedfs/charts/postgresql-16.4.6.tgz differ diff --git a/install.sh b/install.sh index 710e9d55a1d65ba99d66a1540180548614464559..fa48d9bc35c83375ca02c9810b7e6a0ee780af21 100644 --- a/install.sh +++ b/install.sh @@ -1,7 +1,7 @@ #!/bin/bash # preset -VERSION="1.6.1" +VERSION="1.6.3" MIN_CPU=8 MIN_RAM=4 MIN_MAP_COUNT=262144 diff --git a/lib/python/Pipfile b/lib/python/Pipfile index b54561e5f8ff11eb4706050946f23f4a4004fdb5..62a93cc02a1d043464485a4506adcf65ca2160a2 100644 --- a/lib/python/Pipfile +++ b/lib/python/Pipfile @@ -13,6 +13,7 @@ pandas = "*" [dev-packages] build = "*" +pyyaml = "*" setuptools = "*" twine = "*" coverage = "*" diff --git a/lib/python/Pipfile.lock b/lib/python/Pipfile.lock index 836140fd7bff162440f0e8fdd3ab3ef5d2c4a316..52b7202c3e6e17d9651d8851a66dc925f010a4df 100644 --- a/lib/python/Pipfile.lock +++ b/lib/python/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "4fc272b993d5091dc8d60aee49575f17cd1de3145d916dc6aa82c09f7cefe4ee" + "sha256": "01e7f752292f6f3d558a9418f7172696f9bd200d00c7eed2745b74d08ef27eb4" }, "pipfile-spec": 6, "requires": { @@ -442,64 +442,64 @@ }, "numpy": { "hashes": [ - "sha256:059e6a747ae84fce488c3ee397cee7e5f905fd1bda5fb18c66bc41807ff119b2", - "sha256:08ef779aed40dbc52729d6ffe7dd51df85796a702afbf68a4f4e41fafdc8bda5", - "sha256:164a829b6aacf79ca47ba4814b130c4020b202522a93d7bff2202bfb33b61c60", - "sha256:26c9c4382b19fcfbbed3238a14abf7ff223890ea1936b8890f058e7ba35e8d71", - "sha256:27f5cdf9f493b35f7e41e8368e7d7b4bbafaf9660cba53fb21d2cd174ec09631", - "sha256:31b89fa67a8042e96715c68e071a1200c4e172f93b0fbe01a14c0ff3ff820fc8", - "sha256:32cb94448be47c500d2c7a95f93e2f21a01f1fd05dd2beea1ccd049bb6001cd2", - "sha256:360137f8fb1b753c5cde3ac388597ad680eccbbbb3865ab65efea062c4a1fd16", - "sha256:3683a8d166f2692664262fd4900f207791d005fb088d7fdb973cc8d663626faa", - "sha256:38efc1e56b73cc9b182fe55e56e63b044dd26a72128fd2fbd502f75555d92591", - "sha256:3d03883435a19794e41f147612a77a8f56d4e52822337844fff3d4040a142964", - "sha256:3ecc47cd7f6ea0336042be87d9e7da378e5c7e9b3c8ad0f7c966f714fc10d821", - "sha256:40f9e544c1c56ba8f1cf7686a8c9b5bb249e665d40d626a23899ba6d5d9e1484", - "sha256:4250888bcb96617e00bfa28ac24850a83c9f3a16db471eca2ee1f1714df0f957", - "sha256:4511d9e6071452b944207c8ce46ad2f897307910b402ea5fa975da32e0102800", - "sha256:45681fd7128c8ad1c379f0ca0776a8b0c6583d2f69889ddac01559dfe4390918", - "sha256:48fd472630715e1c1c89bf1feab55c29098cb403cc184b4859f9c86d4fcb6a95", - "sha256:4c86e2a209199ead7ee0af65e1d9992d1dce7e1f63c4b9a616500f93820658d0", - "sha256:4dfda918a13cc4f81e9118dea249e192ab167a0bb1966272d5503e39234d694e", - "sha256:5062dc1a4e32a10dc2b8b13cedd58988261416e811c1dc4dbdea4f57eea61b0d", - "sha256:51faf345324db860b515d3f364eaa93d0e0551a88d6218a7d61286554d190d73", - "sha256:526fc406ab991a340744aad7e25251dd47a6720a685fa3331e5c59fef5282a59", - "sha256:53c09385ff0b72ba79d8715683c1168c12e0b6e84fb0372e97553d1ea91efe51", - "sha256:55ba24ebe208344aa7a00e4482f65742969a039c2acfcb910bc6fcd776eb4355", - "sha256:5b6c390bfaef8c45a260554888966618328d30e72173697e5cabe6b285fb2348", - "sha256:5c5cc0cbabe9452038ed984d05ac87910f89370b9242371bd9079cb4af61811e", - "sha256:5edb4e4caf751c1518e6a26a83501fda79bff41cc59dac48d70e6d65d4ec4440", - "sha256:61048b4a49b1c93fe13426e04e04fdf5a03f456616f6e98c7576144677598675", - "sha256:676f4eebf6b2d430300f1f4f4c2461685f8269f94c89698d832cdf9277f30b84", - "sha256:67d4cda6fa6ffa073b08c8372aa5fa767ceb10c9a0587c707505a6d426f4e046", - "sha256:694f9e921a0c8f252980e85bce61ebbd07ed2b7d4fa72d0e4246f2f8aa6642ab", - "sha256:733585f9f4b62e9b3528dd1070ec4f52b8acf64215b60a845fa13ebd73cd0712", - "sha256:7671dc19c7019103ca44e8d94917eba8534c76133523ca8406822efdd19c9308", - "sha256:780077d95eafc2ccc3ced969db22377b3864e5b9a0ea5eb347cc93b3ea900315", - "sha256:7ba9cc93a91d86365a5d270dee221fdc04fb68d7478e6bf6af650de78a8339e3", - "sha256:89b16a18e7bba224ce5114db863e7029803c179979e1af6ad6a6b11f70545008", - "sha256:9036d6365d13b6cbe8f27a0eaf73ddcc070cae584e5ff94bb45e3e9d729feab5", - "sha256:93cf4e045bae74c90ca833cba583c14b62cb4ba2cba0abd2b141ab52548247e2", - "sha256:9ad014faa93dbb52c80d8f4d3dcf855865c876c9660cb9bd7553843dd03a4b1e", - "sha256:9b1d07b53b78bf84a96898c1bc139ad7f10fda7423f5fd158fd0f47ec5e01ac7", - "sha256:a7746f235c47abc72b102d3bce9977714c2444bdfaea7888d241b4c4bb6a78bf", - "sha256:aa3017c40d513ccac9621a2364f939d39e550c542eb2a894b4c8da92b38896ab", - "sha256:b34d87e8a3090ea626003f87f9392b3929a7bbf4104a05b6667348b6bd4bf1cd", - "sha256:b541032178a718c165a49638d28272b771053f628382d5e9d1c93df23ff58dbf", - "sha256:ba5511d8f31c033a5fcbda22dd5c813630af98c70b2661f2d2c654ae3cdfcfc8", - "sha256:bc8a37ad5b22c08e2dbd27df2b3ef7e5c0864235805b1e718a235bcb200cf1cb", - "sha256:bff7d8ec20f5f42607599f9994770fa65d76edca264a87b5e4ea5629bce12268", - "sha256:c1ad395cf254c4fbb5b2132fee391f361a6e8c1adbd28f2cd8e79308a615fe9d", - "sha256:f1d09e520217618e76396377c81fba6f290d5f926f50c35f3a5f72b01a0da780", - "sha256:f3eac17d9ec51be534685ba877b6ab5edc3ab7ec95c8f163e5d7b39859524716", - "sha256:f419290bc8968a46c4933158c91a0012b7a99bb2e465d5ef5293879742f8797e", - "sha256:f62aa6ee4eb43b024b0e5a01cf65a0bb078ef8c395e8713c6e8a12a697144528", - "sha256:f74e6fdeb9a265624ec3a3918430205dff1df7e95a230779746a6af78bc615af", - "sha256:f9b57eaa3b0cd8db52049ed0330747b0364e899e8a606a624813452b8203d5f7", - "sha256:fce4f615f8ca31b2e61aa0eb5865a21e14f5629515c9151850aa936c02a1ee51" + "sha256:02935e2c3c0c6cbe9c7955a8efa8908dd4221d7755644c59d1bba28b94fd334f", + "sha256:0349b025e15ea9d05c3d63f9657707a4e1d471128a3b1d876c095f328f8ff7f0", + "sha256:09d6a2032faf25e8d0cadde7fd6145118ac55d2740132c1d845f98721b5ebcfd", + "sha256:0bc61b307655d1a7f9f4b043628b9f2b721e80839914ede634e3d485913e1fb2", + "sha256:0eec19f8af947a61e968d5429f0bd92fec46d92b0008d0a6685b40d6adf8a4f4", + "sha256:106397dbbb1896f99e044efc90360d098b3335060375c26aa89c0d8a97c5f648", + "sha256:128c41c085cab8a85dc29e66ed88c05613dccf6bc28b3866cd16050a2f5448be", + "sha256:149d1113ac15005652e8d0d3f6fd599360e1a708a4f98e43c9c77834a28238cb", + "sha256:159ff6ee4c4a36a23fe01b7c3d07bd8c14cc433d9720f977fcd52c13c0098160", + "sha256:22ea3bb552ade325530e72a0c557cdf2dea8914d3a5e1fecf58fa5dbcc6f43cd", + "sha256:23ae9f0c2d889b7b2d88a3791f6c09e2ef827c2446f1c4a3e3e76328ee4afd9a", + "sha256:250c16b277e3b809ac20d1f590716597481061b514223c7badb7a0f9993c7f84", + "sha256:2ec6c689c61df613b783aeb21f945c4cbe6c51c28cb70aae8430577ab39f163e", + "sha256:2ffbb1acd69fdf8e89dd60ef6182ca90a743620957afb7066385a7bbe88dc748", + "sha256:3074634ea4d6df66be04f6728ee1d173cfded75d002c75fac79503a880bf3825", + "sha256:356ca982c188acbfa6af0d694284d8cf20e95b1c3d0aefa8929376fea9146f60", + "sha256:3fbe72d347fbc59f94124125e73fc4976a06927ebc503ec5afbfb35f193cd957", + "sha256:40c7ff5da22cd391944a28c6a9c638a5eef77fcf71d6e3a79e1d9d9e82752715", + "sha256:41184c416143defa34cc8eb9d070b0a5ba4f13a0fa96a709e20584638254b317", + "sha256:451e854cfae0febe723077bd0cf0a4302a5d84ff25f0bfece8f29206c7bed02e", + "sha256:4525b88c11906d5ab1b0ec1f290996c0020dd318af8b49acaa46f198b1ffc283", + "sha256:463247edcee4a5537841d5350bc87fe8e92d7dd0e8c71c995d2c6eecb8208278", + "sha256:4dbd80e453bd34bd003b16bd802fac70ad76bd463f81f0c518d1245b1c55e3d9", + "sha256:57b4012e04cc12b78590a334907e01b3a85efb2107df2b8733ff1ed05fce71de", + "sha256:5a8c863ceacae696aff37d1fd636121f1a512117652e5dfb86031c8d84836369", + "sha256:5acea83b801e98541619af398cc0109ff48016955cc0818f478ee9ef1c5c3dcb", + "sha256:642199e98af1bd2b6aeb8ecf726972d238c9877b0f6e8221ee5ab945ec8a2189", + "sha256:64bd6e1762cd7f0986a740fee4dff927b9ec2c5e4d9a28d056eb17d332158014", + "sha256:6d9fc9d812c81e6168b6d405bf00b8d6739a7f72ef22a9214c4241e0dc70b323", + "sha256:7079129b64cb78bdc8d611d1fd7e8002c0a2565da6a47c4df8062349fee90e3e", + "sha256:7dca87ca328f5ea7dafc907c5ec100d187911f94825f8700caac0b3f4c384b49", + "sha256:860fd59990c37c3ef913c3ae390b3929d005243acca1a86facb0773e2d8d9e50", + "sha256:8e6da5cffbbe571f93588f562ed130ea63ee206d12851b60819512dd3e1ba50d", + "sha256:8ec0636d3f7d68520afc6ac2dc4b8341ddb725039de042faf0e311599f54eb37", + "sha256:9491100aba630910489c1d0158034e1c9a6546f0b1340f716d522dc103788e39", + "sha256:97b974d3ba0fb4612b77ed35d7627490e8e3dff56ab41454d9e8b23448940576", + "sha256:995f9e8181723852ca458e22de5d9b7d3ba4da3f11cc1cb113f093b271d7965a", + "sha256:9dd47ff0cb2a656ad69c38da850df3454da88ee9a6fde0ba79acceee0e79daba", + "sha256:9fad446ad0bc886855ddf5909cbf8cb5d0faa637aaa6277fb4b19ade134ab3c7", + "sha256:a972cec723e0563aa0823ee2ab1df0cb196ed0778f173b381c871a03719d4826", + "sha256:ac9bea18d6d58a995fac1b2cb4488e17eceeac413af014b1dd26170b766d8467", + "sha256:b0531f0b0e07643eb089df4c509d30d72c9ef40defa53e41363eca8a8cc61495", + "sha256:b208cfd4f5fe34e1535c08983a1a6803fdbc7a1e86cf13dd0c61de0b51a0aadc", + "sha256:b3482cb7b3325faa5f6bc179649406058253d91ceda359c104dac0ad320e1391", + "sha256:b6fb9c32a91ec32a689ec6410def76443e3c750e7cfc3fb2206b985ffb2b85f0", + "sha256:b78ea78450fd96a498f50ee096f69c75379af5138f7881a51355ab0e11286c97", + "sha256:bd249bc894af67cbd8bad2c22e7cbcd46cf87ddfca1f1289d1e7e54868cc785c", + "sha256:c7d1fd447e33ee20c1f33f2c8e6634211124a9aabde3c617687d8b739aa69eac", + "sha256:d0bbe7dd86dca64854f4b6ce2ea5c60b51e36dfd597300057cf473d3615f2369", + "sha256:d6d6a0910c3b4368d89dde073e630882cdb266755565155bc33520283b2d9df8", + "sha256:da1eeb460ecce8d5b8608826595c777728cdf28ce7b5a5a8c8ac8d949beadcf2", + "sha256:e0c8854b09bc4de7b041148d8550d3bd712b5c21ff6a8ed308085f190235d7ff", + "sha256:e0d4142eb40ca6f94539e4db929410f2a46052a0fe7a2c1c59f6179c39938d2a", + "sha256:e9e82dcb3f2ebbc8cb5ce1102d5f1c5ed236bf8a11730fb45ba82e2841ec21df", + "sha256:ed6906f61834d687738d25988ae117683705636936cc605be0bb208b23df4d8f" ], "markers": "python_version == '3.11'", - "version": "==2.2.1" + "version": "==2.2.2" }, "paho-mqtt": { "hashes": [ @@ -655,11 +655,11 @@ }, "pydantic": { "hashes": [ - "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d", - "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06" + "sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff", + "sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53" ], "index": "pypi", - "version": "==2.10.4" + "version": "==2.10.5" }, "pydantic-core": { "hashes": [ @@ -824,11 +824,11 @@ }, "tzdata": { "hashes": [ - "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc", - "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd" + "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694", + "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639" ], "markers": "python_version >= '2'", - "version": "==2024.2" + "version": "==2025.1" }, "urllib3": { "hashes": [ @@ -1266,6 +1266,14 @@ "index": "pypi", "version": "==2024.8.6" }, + "id": { + "hashes": [ + "sha256:292cb8a49eacbbdbce97244f47a97b4c62540169c976552e497fd57df0734c1d", + "sha256:f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658" + ], + "markers": "python_version >= '3.8'", + "version": "==1.5.0" + }, "idna": { "hashes": [ "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", @@ -1284,11 +1292,11 @@ }, "importlib-metadata": { "hashes": [ - "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b", - "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7" + "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e", + "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580" ], "markers": "python_version < '3.12'", - "version": "==8.5.0" + "version": "==8.6.1" }, "iniconfig": { "hashes": [ @@ -1431,11 +1439,11 @@ }, "more-itertools": { "hashes": [ - "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef", - "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6" + "sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b", + "sha256:6eb054cb4b6db1473f6e15fcc676a08e4732548acd47c708f0e179c2c7c01e89" ], - "markers": "python_version >= '3.8'", - "version": "==10.5.0" + "markers": "python_version >= '3.9'", + "version": "==10.6.0" }, "nh3": { "hashes": [ @@ -1475,14 +1483,6 @@ "markers": "python_version >= '3.8'", "version": "==24.2" }, - "pkginfo": { - "hashes": [ - "sha256:8ad91a0445a036782b9366ef8b8c2c50291f83a553478ba8580c73d3215700cf", - "sha256:dcd589c9be4da8973eceffa247733c144812759aa67eaf4bbf97016a02f39088" - ], - "markers": "python_version >= '3.8'", - "version": "==1.12.0" - }, "pluggy": { "hashes": [ "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", @@ -1501,11 +1501,11 @@ }, "pygments": { "hashes": [ - "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", - "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a" + "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", + "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c" ], "markers": "python_version >= '3.8'", - "version": "==2.18.0" + "version": "==2.19.1" }, "pyproject-hooks": { "hashes": [ @@ -1532,6 +1532,65 @@ "index": "pypi", "version": "==0.6" }, + "pyyaml": { + "hashes": [ + "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", + "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", + "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", + "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", + "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", + "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", + "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", + "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", + "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", + "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", + "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", + "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", + "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", + "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", + "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", + "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", + "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", + "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", + "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", + "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", + "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", + "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", + "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", + "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", + "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", + "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", + "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", + "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", + "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", + "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", + "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", + "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", + "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", + "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", + "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", + "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", + "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", + "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", + "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", + "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", + "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", + "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", + "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", + "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", + "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", + "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", + "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", + "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", + "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", + "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", + "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", + "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", + "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" + ], + "index": "pypi", + "version": "==6.0.2" + }, "readme-renderer": { "hashes": [ "sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151", @@ -1590,11 +1649,11 @@ }, "setuptools": { "hashes": [ - "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6", - "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d" + "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6", + "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3" ], "index": "pypi", - "version": "==75.6.0" + "version": "==75.8.0" }, "snowballstemmer": { "hashes": [ @@ -1677,11 +1736,11 @@ }, "twine": { "hashes": [ - "sha256:36158b09df5406e1c9c1fb8edb24fc2be387709443e7376689b938531582ee27", - "sha256:9c6025b203b51521d53e200f4a08b116dee7500a38591668c6a6033117bdc218" + "sha256:a47f973caf122930bf0fbbf17f80b83bc1602c9ce393c7845f289a3001dc5384", + "sha256:be324f6272eff91d07ee93f251edf232fc647935dd585ac003539b42404a8dbd" ], "index": "pypi", - "version": "==6.0.1" + "version": "==6.1.0" }, "urllib3": { "hashes": [ diff --git a/lib/python/dbrepo/RestClient.py b/lib/python/dbrepo/RestClient.py index bc6940b7d034bcb85fec9f9c31c3b5a8aff0dcc3..a0b4bf60c43f2065ffd2f73f5010407fb0d20287 100644 --- a/lib/python/dbrepo/RestClient.py +++ b/lib/python/dbrepo/RestClient.py @@ -252,7 +252,7 @@ class RestClient: f'201 (CREATED): {response.text}') def update_user(self, user_id: str, theme: str, language: str, firstname: str = None, lastname: str = None, - affiliation: str = None, orcid: str = None) -> User: + affiliation: str = None, orcid: str = None) -> UserBrief: """ Updates a user with given user id. @@ -277,7 +277,7 @@ class RestClient: lastname=lastname, affiliation=affiliation, orcid=orcid)) if response.status_code == 202: body = response.json() - return User.model_validate(body) + return UserBrief.model_validate(body) if response.status_code == 400: raise MalformedError(f'Failed to update user: {response.text}') if response.status_code == 403: @@ -287,15 +287,13 @@ class RestClient: raise ResponseCodeError(f'Failed to update user: response code: {response.status_code} is not ' f'202 (ACCEPTED): {response.text}') - def update_user_password(self, user_id: str, password: str) -> User: + def update_user_password(self, user_id: str, password: str) -> None: """ Updates the password of a user with given user id. :param user_id: The user id of the user that should be updated. :param password: The updated user password. - :returns: The user, if successful. - :raises MalformedError: If the payload was rejected by the service. :raises ForbiddenError: If something went wrong with the authorization. :raises NotExistsError: If the user does not exist. @@ -306,8 +304,7 @@ class RestClient: url = f'/api/user/{user_id}/password' response = self._wrapper(method="put", url=url, force_auth=True, payload=UpdateUserPassword(password=password)) if response.status_code == 202: - body = response.json() - return User.model_validate(body) + return None if response.status_code == 400: raise MalformedError(f'Failed to update user password: {response.text}') if response.status_code == 403: @@ -617,7 +614,7 @@ class RestClient: def create_table(self, database_id: int, name: str, is_public: bool, is_schema_public: bool, columns: List[CreateTableColumn], constraints: CreateTableConstraints, - description: str = None) -> Table: + description: str = None) -> TableBrief: """ Updates the database owner of a database with given database id. @@ -645,7 +642,7 @@ class RestClient: description=description, columns=columns, constraints=constraints)) if response.status_code == 201: body = response.json() - return Table.model_validate(body) + return TableBrief.model_validate(body) if response.status_code == 400: raise MalformedError(f'Failed to create table: {response.text}') if response.status_code == 403: @@ -871,7 +868,7 @@ class RestClient: raise ResponseCodeError(f'Failed to find view: response code: {response.status_code} is not ' f'200 (OK): {response.text}') - def update_view(self, database_id: int, view_id: int, is_public: bool) -> View: + def update_view(self, database_id: int, view_id: int, is_public: bool) -> ViewBrief: """ Get a view of a database with given database id and view id. @@ -889,7 +886,7 @@ class RestClient: response = self._wrapper(method="put", url=url, payload=UpdateView(is_public=is_public)) if response.status_code == 202: body = response.json() - return View.model_validate(body) + return ViewBrief.model_validate(body) if response.status_code == 403: raise ForbiddenError(f'Failed to update view: not allowed') if response.status_code == 404: @@ -1091,7 +1088,7 @@ class RestClient: :raises ResponseCodeError: If something went wrong with the insert. """ url = f'/api/database/{database_id}/table/{table_id}/data' - response = self._wrapper(method="post", url=url, force_auth=True, payload=CreateData(data=data)) + response = self._wrapper(method="post", url=url, force_auth=True, payload=Tuple(data=data)) if response.status_code == 201: return if response.status_code == 400: @@ -1279,7 +1276,7 @@ class RestClient: :raises ResponseCodeError: If something went wrong with the update. """ url = f'/api/database/{database_id}/table/{table_id}/data' - response = self._wrapper(method="put", url=url, force_auth=True, payload=UpdateData(data=data, keys=keys)) + response = self._wrapper(method="put", url=url, force_auth=True, payload=TupleUpdate(data=data, keys=keys)) if response.status_code == 202: return if response.status_code == 400: @@ -1309,7 +1306,7 @@ class RestClient: :raises ResponseCodeError: If something went wrong with the deletion. """ url = f'/api/database/{database_id}/table/{table_id}/data' - response = self._wrapper(method="delete", url=url, force_auth=True, payload=DeleteData(keys=keys)) + response = self._wrapper(method="delete", url=url, force_auth=True, payload=TupleDelete(keys=keys)) if response.status_code == 202: return if response.status_code == 400: @@ -1770,13 +1767,13 @@ class RestClient: raise ResponseCodeError(f'Failed to update query: response code: {response.status_code} is not ' f'202 (ACCEPTED): {response.text}') - def create_identifier(self, database_id: int, type: IdentifierType, titles: List[CreateIdentifierTitle], + def create_identifier(self, database_id: int, type: IdentifierType, titles: List[SaveIdentifierTitle], publisher: str, creators: List[CreateIdentifierCreator], publication_year: int, - descriptions: List[CreateIdentifierDescription] = None, - funders: List[CreateIdentifierFunder] = None, licenses: List[License] = None, + descriptions: List[SaveIdentifierDescription] = None, + funders: List[SaveIdentifierFunder] = None, licenses: List[License] = None, language: Language = None, subset_id: int = None, view_id: int = None, table_id: int = None, publication_day: int = None, publication_month: int = None, - related_identifiers: List[CreateRelatedIdentifier] = None) -> Identifier: + related_identifiers: List[SaveRelatedIdentifier] = None) -> Identifier: """ Create an identifier draft. @@ -1831,12 +1828,12 @@ class RestClient: f'201 (CREATED): {response.text}') def save_identifier(self, identifier_id: int, database_id: int, type: IdentifierType, - titles: List[CreateIdentifierTitle], publisher: str, creators: List[CreateIdentifierCreator], - publication_year: int, descriptions: List[CreateIdentifierDescription] = None, - funders: List[CreateIdentifierFunder] = None, licenses: List[License] = None, + titles: List[SaveIdentifierTitle], publisher: str, creators: List[CreateIdentifierCreator], + publication_year: int, descriptions: List[SaveIdentifierDescription] = None, + funders: List[SaveIdentifierFunder] = None, licenses: List[License] = None, language: Language = None, subset_id: int = None, view_id: int = None, table_id: int = None, publication_day: int = None, publication_month: int = None, - related_identifiers: List[CreateRelatedIdentifier] = None) -> Identifier: + related_identifiers: List[SaveRelatedIdentifier] = None) -> Identifier: """ Save an existing identifier and update the metadata attached to it. diff --git a/lib/python/dbrepo/api/dto.py b/lib/python/dbrepo/api/dto.py index fa7eb063fc453c3dd8fabef04f141d07012c94a3..bd0d13dc1894d1a83891abdcdd6fb438de27f3f4 100644 --- a/lib/python/dbrepo/api/dto.py +++ b/lib/python/dbrepo/api/dto.py @@ -113,18 +113,18 @@ class ContainerBrief(BaseModel): class ColumnBrief(BaseModel): id: int name: str - alias: str database_id: int table_id: int internal_name: str type: ColumnType + alias: Optional[str] = None class TableBrief(BaseModel): id: int database_id: int name: str - description: Optional[str] + description: Optional[str] = None internal_name: str is_versioned: bool is_public: bool @@ -419,7 +419,7 @@ class IdentifierTitle(BaseModel): type: Optional[TitleType] = None -class CreateIdentifierTitle(BaseModel): +class SaveIdentifierTitle(BaseModel): title: str language: Optional[Language] = None type: Optional[TitleType] = None @@ -432,7 +432,7 @@ class IdentifierDescription(BaseModel): type: Optional[DescriptionType] = None -class CreateIdentifierDescription(BaseModel): +class SaveIdentifierDescription(BaseModel): description: str language: Optional[Language] = None type: Optional[DescriptionType] = None @@ -448,7 +448,7 @@ class IdentifierFunder(BaseModel): award_title: Optional[str] = None -class CreateIdentifierFunder(BaseModel): +class SaveIdentifierFunder(BaseModel): funder_name: str funder_identifier: Optional[str] = None funder_identifier_type: Optional[str] = None @@ -463,16 +463,16 @@ class License(BaseModel): description: str -class CreateData(BaseModel): +class Tuple(BaseModel): data: dict -class UpdateData(BaseModel): +class TupleUpdate(BaseModel): data: dict keys: dict -class DeleteData(BaseModel): +class TupleDelete(BaseModel): keys: dict @@ -511,6 +511,7 @@ class CreateTableColumn(BaseModel): name: str type: ColumnType null_allowed: bool + description: Optional[str] = None concept_uri: Optional[str] = None unit_uri: Optional[str] = None index_length: Optional[int] = None @@ -527,7 +528,26 @@ class CreateTableConstraints(BaseModel): foreign_keys: List[CreateForeignKey] = field(default_factory=list) -class IdentifierCreator(BaseModel): +class NameIdentifierSchemeType(str, Enum): + """ + Enumeration of name identifier scheme types. + """ + ORCID = "ORCID" + ROR = "ROR" + ISNI = "ISNI" + GRID = "GRID" + + +class AffiliationIdentifierSchemeType(str, Enum): + """ + Enumeration of affiliation identifier scheme types. + """ + ROR = "ROR" + ISNI = "ISNI" + GRID = "GRID" + + +class Creator(BaseModel): id: int creator_name: str firstname: Optional[str] = None @@ -535,13 +555,24 @@ class IdentifierCreator(BaseModel): affiliation: Optional[str] = None name_type: Optional[str] = None name_identifier: Optional[str] = None - name_identifier_scheme: Optional[str] = None + name_identifier_scheme: Optional[NameIdentifierSchemeType] = None name_identifier_scheme_uri: Optional[str] = None affiliation_identifier: Optional[str] = None affiliation_identifier_scheme: Optional[str] = None affiliation_identifier_scheme_uri: Optional[str] = None +class CreatorBrief(BaseModel): + id: int + creator_name: str + affiliation: Optional[str] = None + name_type: Optional[str] = None + name_identifier: Optional[str] = None + name_identifier_scheme: Optional[NameIdentifierSchemeType] = None + affiliation_identifier: Optional[str] = None + affiliation_identifier_scheme: Optional[str] = None + + class CreateIdentifierCreator(BaseModel): creator_name: str firstname: Optional[str] = None @@ -563,7 +594,7 @@ class RelatedIdentifier(BaseModel): relation: RelatedIdentifierRelation -class CreateRelatedIdentifier(BaseModel): +class SaveRelatedIdentifier(BaseModel): value: str type: RelatedIdentifierType relation: RelatedIdentifierRelation @@ -575,9 +606,9 @@ class CreateIdentifier(BaseModel): creators: List[CreateIdentifierCreator] publication_year: int publisher: str - titles: List[CreateIdentifierTitle] - descriptions: List[CreateIdentifierDescription] - funders: Optional[List[CreateIdentifierFunder]] = field(default_factory=list) + titles: List[SaveIdentifierTitle] + descriptions: List[SaveIdentifierDescription] + funders: Optional[List[SaveIdentifierFunder]] = field(default_factory=list) doi: Optional[str] = None language: Optional[str] = None licenses: Optional[List[License]] = field(default_factory=list) @@ -587,7 +618,7 @@ class CreateIdentifier(BaseModel): query: Optional[str] = None query_normalized: Optional[str] = None execution: Optional[str] = None - related_identifiers: Optional[List[CreateRelatedIdentifier]] = field(default_factory=list) + related_identifiers: Optional[List[SaveRelatedIdentifier]] = field(default_factory=list) result_hash: Optional[str] = None result_number: Optional[int] = None publication_day: Optional[int] = None @@ -602,7 +633,7 @@ class Identifier(BaseModel): status: IdentifierStatusType publication_year: int publisher: str - creators: List[IdentifierCreator] + creators: List[Creator] titles: List[IdentifierTitle] descriptions: List[IdentifierDescription] funders: Optional[List[IdentifierFunder]] = field(default_factory=list) @@ -622,6 +653,21 @@ class Identifier(BaseModel): publication_month: Optional[int] = None +class IdentifierBrief(BaseModel): + id: int + database_id: int + type: IdentifierType + owned_by: str + status: IdentifierStatusType + publication_year: int + publisher: str + titles: List[IdentifierTitle] + doi: Optional[str] = None + query_id: Optional[int] = None + table_id: Optional[int] = None + view_id: Optional[int] = None + + class View(BaseModel): id: int database_id: int @@ -856,7 +902,7 @@ class Query(BaseModel): result_hash: str query_normalized: str result_number: Optional[int] = None - identifiers: List[Identifier] = field(default_factory=list) + identifiers: List[IdentifierBrief] = field(default_factory=list) class UpdateQuery(BaseModel): @@ -950,15 +996,17 @@ class Table(BaseModel): avg_row_length: Optional[int] = None -class TableMinimal(BaseModel): - id: int - database_id: int - - -class ColumnMinimal(BaseModel): +class DatabaseBrief(BaseModel): id: int - table_id: int - database_id: int + name: str + contact: UserBrief + owner_id: str + internal_name: str + is_public: bool + is_schema_public: bool + identifiers: Optional[List[IdentifierBrief]] = field(default_factory=list) + preview_image: Optional[str] = None + description: Optional[str] = None class Database(BaseModel): @@ -973,37 +1021,25 @@ class Database(BaseModel): container: ContainerBrief identifiers: Optional[List[Identifier]] = field(default_factory=list) subsets: Optional[List[Identifier]] = field(default_factory=list) + preview_image: Optional[str] = None description: Optional[str] = None tables: Optional[List[Table]] = field(default_factory=list) views: Optional[List[View]] = field(default_factory=list) - image: Optional[str] = None accesses: Optional[List[DatabaseAccess]] = field(default_factory=list) - exchange_type: Optional[str] = None - - -class DatabaseBrief(BaseModel): - id: int - name: str - internal_name: str - description: Optional[str] = None - is_public: bool - is_schema_public: bool - identifiers: Optional[List[Identifier]] = field(default_factory=list) - contact: UserBrief - owner_id: str + exchange_name: Optional[str] = None class Unique(BaseModel): id: int - table: TableMinimal - columns: List[ColumnMinimal] + table: TableBrief + columns: List[ColumnBrief] class ForeignKeyReference(BaseModel): id: int - foreign_key: ForeignKeyMinimal - column: ColumnMinimal - referenced_column: ColumnMinimal + foreign_key: ForeignKeyBrief + column: ColumnBrief + referenced_column: ColumnBrief class ReferenceType(str, Enum): @@ -1017,7 +1053,7 @@ class ReferenceType(str, Enum): SET_DEFAULT = "set_default" -class ForeignKeyMinimal(BaseModel): +class ForeignKeyBrief(BaseModel): id: int @@ -1025,8 +1061,8 @@ class ForeignKey(BaseModel): id: int name: str references: List[ForeignKeyReference] - table: TableMinimal - referenced_table: TableMinimal + table: TableBrief + referenced_table: TableBrief on_update: Optional[ReferenceType] = None on_delete: Optional[ReferenceType] = None @@ -1041,8 +1077,8 @@ class CreateForeignKey(BaseModel): class PrimaryKey(BaseModel): id: int - table: TableMinimal - column: ColumnMinimal + table: TableBrief + column: ColumnBrief class Constraints(BaseModel): diff --git a/lib/python/docs/index.rst b/lib/python/docs/index.rst index 0a989f321fa9dbb644fba8c668cff807a1232826..b3c05fe3645e558aaa92a470c19be4d27db46add 100644 --- a/lib/python/docs/index.rst +++ b/lib/python/docs/index.rst @@ -6,7 +6,7 @@ Pandas `DataFrame <https://pandas.pydata.org/docs/reference/api/pandas.DataFrame provides an object-oriented API as well as low-level access to DBRepo services. .. note:: - The SDK has been implemented and documented for DBRepo version 1.6.1, earlier versions may be supported but are not tested for compatibility. + The SDK has been implemented and documented for DBRepo version 1.6.3, earlier versions may be supported but are not tested for compatibility. Quickstart ---------- diff --git a/lib/python/pyproject.toml b/lib/python/pyproject.toml index 33d1e52cc0a967a56e7e0a9ce639e5ceb53b42c6..99f62c9a44dcdb10f63d03c97048a0676a1b1d02 100644 --- a/lib/python/pyproject.toml +++ b/lib/python/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "dbrepo" -version = "1.6.1" +version = "1.6.3" description = "DBRepo Python Library" keywords = [ "DBRepo", diff --git a/lib/python/setup.py b/lib/python/setup.py index 027b8a5bb628da1cd03378d59d44ff8dc507c9a7..dfe9a897cab556846dbf7dfb6ffb5303d0e77b03 100644 --- a/lib/python/setup.py +++ b/lib/python/setup.py @@ -2,7 +2,7 @@ from distutils.core import setup setup(name="dbrepo", - version="1.6.1", + version="1.6.3", description="A library for communicating with DBRepo", url="https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6/", author="Martin Weise", diff --git a/lib/python/tests/conftest.py b/lib/python/tests/conftest.py deleted file mode 100644 index 5270a5bfba0c614fc3e16b559879dd6209f440dc..0000000000000000000000000000000000000000 --- a/lib/python/tests/conftest.py +++ /dev/null @@ -1,37 +0,0 @@ -import logging -import uuid - -import pytest - -from dbrepo.RestClient import RestClient -from dbrepo.api.dto import Database - -logging.basicConfig(level=logging.DEBUG) - - -def pytest_configure(config): - TestKeyValue.username = str(uuid.uuid4()).replace("-", "")[0:10] - TestKeyValue.password = str(uuid.uuid4()).replace("-", "")[0:10] - - -@pytest.fixture(scope='session', name='rest_client') -def user_rest_client() -> RestClient: - TestKeyValue.user_id = RestClient().create_user(username=f'{TestKeyValue.username}', - password=f'{TestKeyValue.password}', - email=f'{TestKeyValue.username}@example.com').id - return RestClient(username=TestKeyValue.username, password=TestKeyValue.password) - - -@pytest.fixture(scope='session', name='database') -def database() -> Database: - name = str(uuid.uuid4()).replace("-", "")[0:10] - return RestClient(username=TestKeyValue.username, - password=TestKeyValue.password).create_database(name=name, container_id=1, is_public=True, - is_schema_public=True) - - -class TestKeyValue: - user_id: str = None - username: str = None - password: str = None - database_name: str = None diff --git a/lib/python/tests/test_dtos.py b/lib/python/tests/test_dtos.py new file mode 100644 index 0000000000000000000000000000000000000000..3f05e24081b45deb662afed4a3b342803b6ce56a --- /dev/null +++ b/lib/python/tests/test_dtos.py @@ -0,0 +1,94 @@ +import inspect +import logging +import sys +import unittest +from logging.config import dictConfig +from math import floor + +from yaml import safe_load + +from dbrepo.api import dto + +logging.addLevelName(level=logging.NOTSET, levelName='TRACE') +logging.basicConfig(level=logging.DEBUG) + +# logging configuration +dictConfig({ + 'version': 1, + 'formatters': { + 'default': { + 'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s', + }, + 'simple': { + 'format': '[%(asctime)s] %(levelname)s: %(message)s', + }, + }, + 'handlers': {'console': { + 'class': 'logging.StreamHandler', + 'stream': 'ext://sys.stdout', + 'formatter': 'simple' # default + }}, + 'root': { + 'level': 'DEBUG', + 'handlers': ['console'] + } +}) + + +class AnalyseUnitTest(unittest.TestCase): + schemas = None + models: [()] = [] + found: int = 0 + skipped: [str] = [] + + def setUp(self): + with open('../../.docs/.openapi/api.yaml') as fh: + self.schemas = safe_load(fh)['components']['schemas'] + for name, obj in inspect.getmembers(sys.modules[dto.__name__]): + self.found += 1 + if not inspect.isclass(obj): + continue + if f'{name}Dto' not in self.schemas: + logging.debug(f'skip model {name}: OpenAPI schema definition {name}Dto not found') + self.skipped.append(f'{name}Dto') + continue + self.models.append((name, obj)) + + def build_model(self, name: str, obj: any, definition: any) -> dict: + model_dict = dict() + for property in definition['properties']: + if 'example' in definition['properties'][property]: + if '$ref' not in definition['properties'][property]: + model_dict[property] = definition['properties'][property]['example'] + continue + ref = definition['properties'][property]['$ref'][len('#/components/schemas/'):-3] + # recursive call + model_dict[property] = self.build_model(ref, self.get_model(ref), self.schemas[f'{ref}Dto']) + continue + if 'items' in definition['properties'][property]: + if '$ref' not in definition['properties'][property]['items']: + continue + ref = definition['properties'][property]['items']['$ref'][len('#/components/schemas/'):-3] + # recursive call + model_dict[property] = [self.build_model(ref, self.get_model(ref), self.schemas[f'{ref}Dto'])] + continue + if '$ref' in definition['properties'][property]: + ref = definition['properties'][property]['$ref'][len('#/components/schemas/'):-3] + # recursive call + model_dict[property] = self.build_model(ref, self.get_model(ref), self.schemas[f'{ref}Dto']) + return model_dict + + def get_model(self, ref: str): + for name, obj in self.models: + if name == ref: + return obj + return None + + def test_dtos_succeeds(self): + logging.info(f'Found {self.found} model(s) in {dto.__name__}') + for name, obj in self.models: + logging.debug(f'building model: {name} against OpenAPI schema definition {name}Dto') + model = obj(**self.build_model(name, obj, self.schemas[f'{name}Dto'])) + logging.warning(f'Unable to find {len(self.skipped)} OpenAPI schema definition(s): {self.skipped}') + logging.info(f'Coverage: {floor((1 - len(self.skipped) / self.found) * 100)}%') + pass diff --git a/lib/python/tests/test_system_database.py b/lib/python/tests/test_system_database.py deleted file mode 100644 index 902b95435b09c755fa33cd592fbd7a9c9ddc81ee..0000000000000000000000000000000000000000 --- a/lib/python/tests/test_system_database.py +++ /dev/null @@ -1,34 +0,0 @@ -import unittest -import uuid - -import pytest - - -class UserUnitTest(unittest.TestCase): - - @pytest.fixture(autouse=True) - def prepare_fixture(self, rest_client, database): - self.rest_client = rest_client - self.database = database - - @pytest.mark.usefixtures("rest_client") - def test_create_database_succeeds(self): - name = str(uuid.uuid4()).replace("-", "")[0:10] - # test - response = self.rest_client.create_database(name=name, container_id=1, - is_public=True, is_schema_public=True) - self.assertEqual(True, response.is_public) - self.assertEqual(True, response.is_schema_public) - self.assertEqual(None, response.description) - - @pytest.mark.usefixtures("rest_client", "database") - def test_update_database_visibility_succeeds(self): - # test - response = self.rest_client.update_database_visibility(database_id=self.database.id, is_public=False, - is_schema_public=False) - self.assertEqual(False, response.is_public) - self.assertEqual(False, response.is_schema_public) - - -if __name__ == "__main__": - unittest.main() diff --git a/lib/python/tests/test_system_user.py b/lib/python/tests/test_system_user.py deleted file mode 100644 index 350b34110274b4697f58cf6ce96168fb6682315c..0000000000000000000000000000000000000000 --- a/lib/python/tests/test_system_user.py +++ /dev/null @@ -1,42 +0,0 @@ -import unittest -import uuid - -import pytest - -from conftest import TestKeyValue -from dbrepo.RestClient import RestClient - - -class UserUnitTest(unittest.TestCase): - - @pytest.fixture(autouse=True) - def prepare_fixture(self, rest_client): - self.rest_client = rest_client - - def test_get_users_succeeds(self): - # test - response = RestClient().get_users() - - def test_create_user_succeeds(self): - username = str(uuid.uuid4()).replace("-", "")[0:10] - password = str(uuid.uuid4()).replace("-", "")[0:10] - # test - response = RestClient().create_user(username=f'{username}', password=f'{password}', - email=f'{username}@example.com') - self.assertEqual(username, response.username) - - @pytest.mark.usefixtures("rest_client") - def test_update_user_succeeds(self): - # test - response = self.rest_client.update_user(user_id=TestKeyValue.user_id, theme='dark', language='de', - firstname='Foo', lastname='Bar', affiliation='TU Wien', - orcid='https://orcid.org/0000-0003-4216-302X') - self.assertEqual('dark', response.attributes.theme) - self.assertEqual('Foo', response.given_name) - self.assertEqual('Bar', response.family_name) - self.assertEqual('TU Wien', response.attributes.affiliation) - self.assertEqual('https://orcid.org/0000-0003-4216-302X', response.attributes.orcid) - - -if __name__ == "__main__": - unittest.main() diff --git a/lib/python/tests/test_unit_analyse.py b/lib/python/tests/test_unit_analyse.py index a26d7aa8441fd716640ca1d71c65a26f45f154ff..5ca2b8301cbb04f9e896436909c97b4873842612 100644 --- a/lib/python/tests/test_unit_analyse.py +++ b/lib/python/tests/test_unit_analyse.py @@ -1,6 +1,5 @@ import unittest import requests_mock -import dataclasses from dbrepo.RestClient import RestClient diff --git a/lib/python/tests/test_unit_database.py b/lib/python/tests/test_unit_database.py index eeeea68832ac33e2f013a3c2deaa3d4eec33122c..203c296b9c86d9bca0fce4f3b433af298f6cd251 100644 --- a/lib/python/tests/test_unit_database.py +++ b/lib/python/tests/test_unit_database.py @@ -4,7 +4,7 @@ import requests_mock from pydantic_core import ValidationError from dbrepo.RestClient import RestClient -from dbrepo.api.dto import Database, Container, Image, DatabaseAccess, AccessType, DatabaseBrief, UserBrief, \ +from dbrepo.api.dto import Database, DatabaseAccess, AccessType, DatabaseBrief, UserBrief, \ ContainerBrief, ImageBrief from dbrepo.api.exceptions import ResponseCodeError, NotExistsError, ForbiddenError, MalformedError, AuthenticationError @@ -28,7 +28,19 @@ class DatabaseUnitTest(unittest.TestCase): contact=UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise'), internal_name='test_abcd', is_public=True, - is_schema_public=True) + is_schema_public=True, + container=ContainerBrief( + id=1, + name='MariaDB Galera 11.1.3', + internal_name='mariadb', + image=ImageBrief( + id=1, + name='mariadb', + version='11.2.2', + jdbc_method='mariadb' + ) + ) + ) ] with requests_mock.Mocker() as mock: # mock diff --git a/lib/python/tests/test_unit_identifier.py b/lib/python/tests/test_unit_identifier.py index 45b0a919e74d79d2420669a7036fcc87ae02b92a..8726d05ef23108c2a0a8fb9e8c4cd65052e19b1e 100644 --- a/lib/python/tests/test_unit_identifier.py +++ b/lib/python/tests/test_unit_identifier.py @@ -1,14 +1,12 @@ import unittest import requests_mock -import datetime from dbrepo.RestClient import RestClient - -from dbrepo.api.dto import Identifier, IdentifierType, CreateIdentifierTitle, CreateIdentifierCreator, \ - IdentifierCreator, IdentifierTitle, IdentifierDescription, CreateIdentifierDescription, Language, \ - CreateIdentifierFunder, CreateRelatedIdentifier, RelatedIdentifierRelation, RelatedIdentifierType, IdentifierFunder, \ - RelatedIdentifier, UserBrief, IdentifierStatusType +from dbrepo.api.dto import Identifier, IdentifierType, SaveIdentifierTitle, Creator, IdentifierTitle, \ + IdentifierDescription, SaveIdentifierDescription, Language, SaveIdentifierFunder, SaveRelatedIdentifier, \ + RelatedIdentifierRelation, RelatedIdentifierType, IdentifierFunder, RelatedIdentifier, UserBrief, \ + IdentifierStatusType, CreateIdentifierCreator from dbrepo.api.exceptions import MalformedError, ForbiddenError, NotExistsError, AuthenticationError @@ -29,7 +27,7 @@ class IdentifierUnitTest(unittest.TestCase): related_identifiers=[ RelatedIdentifier(id=7, value='10.12345/abc', relation=RelatedIdentifierRelation.CITES, type=RelatedIdentifierType.DOI)], - creators=[IdentifierCreator(id=5, creator_name='Carberry, Josiah')], + creators=[Creator(id=5, creator_name='Carberry, Josiah')], status=IdentifierStatusType.PUBLISHED, owner=UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise')) # mock @@ -38,14 +36,14 @@ class IdentifierUnitTest(unittest.TestCase): client = RestClient(username="a", password="b") response = client.create_identifier( database_id=1, type=IdentifierType.VIEW, - titles=[CreateIdentifierTitle(title='Test Title')], + titles=[SaveIdentifierTitle(title='Test Title')], publisher='TU Wien', publication_year=2024, language=Language.EN, - funders=[CreateIdentifierFunder(funder_name='FWF')], - related_identifiers=[CreateRelatedIdentifier(value='10.12345/abc', - relation=RelatedIdentifierRelation.CITES, - type=RelatedIdentifierType.DOI)], - descriptions=[CreateIdentifierDescription(description='Test Description')], + funders=[SaveIdentifierFunder(funder_name='FWF')], + related_identifiers=[SaveRelatedIdentifier(value='10.12345/abc', + relation=RelatedIdentifierRelation.CITES, + type=RelatedIdentifierType.DOI)], + descriptions=[SaveIdentifierDescription(description='Test Description')], creators=[CreateIdentifierCreator(creator_name='Carberry, Josiah')]) self.assertEqual(exp, response) @@ -58,8 +56,8 @@ class IdentifierUnitTest(unittest.TestCase): client = RestClient(username="a", password="b") response = client.create_identifier( database_id=1, type=IdentifierType.VIEW, - titles=[CreateIdentifierTitle(title='Test Title')], - descriptions=[CreateIdentifierDescription(description='Test')], + titles=[SaveIdentifierTitle(title='Test Title')], + descriptions=[SaveIdentifierDescription(description='Test')], publisher='TU Wien', publication_year=2024, creators=[CreateIdentifierCreator(creator_name='Carberry, Josiah')]) except MalformedError: @@ -74,8 +72,8 @@ class IdentifierUnitTest(unittest.TestCase): client = RestClient(username="a", password="b") response = client.create_identifier( database_id=1, type=IdentifierType.VIEW, - titles=[CreateIdentifierTitle(title='Test Title')], - descriptions=[CreateIdentifierDescription(description='Test')], + titles=[SaveIdentifierTitle(title='Test Title')], + descriptions=[SaveIdentifierDescription(description='Test')], publisher='TU Wien', publication_year=2024, creators=[CreateIdentifierCreator(creator_name='Carberry, Josiah')]) except ForbiddenError: @@ -90,8 +88,8 @@ class IdentifierUnitTest(unittest.TestCase): client = RestClient(username="a", password="b") response = client.create_identifier( database_id=1, type=IdentifierType.VIEW, - titles=[CreateIdentifierTitle(title='Test Title')], - descriptions=[CreateIdentifierDescription(description='Test')], + titles=[SaveIdentifierTitle(title='Test Title')], + descriptions=[SaveIdentifierDescription(description='Test')], publisher='TU Wien', publication_year=2024, creators=[CreateIdentifierCreator(creator_name='Carberry, Josiah')]) except NotExistsError: @@ -105,8 +103,8 @@ class IdentifierUnitTest(unittest.TestCase): try: response = RestClient().create_identifier( database_id=1, type=IdentifierType.VIEW, - titles=[CreateIdentifierTitle(title='Test Title')], - descriptions=[CreateIdentifierDescription(description='Test')], + titles=[SaveIdentifierTitle(title='Test Title')], + descriptions=[SaveIdentifierDescription(description='Test')], publisher='TU Wien', publication_year=2024, creators=[CreateIdentifierCreator(creator_name='Carberry, Josiah')]) except AuthenticationError: @@ -127,7 +125,7 @@ class IdentifierUnitTest(unittest.TestCase): related_identifiers=[RelatedIdentifier(id=7, value='10.12345/abc', relation=RelatedIdentifierRelation.CITES, type=RelatedIdentifierType.DOI)], - creators=[IdentifierCreator(id=5, creator_name='Carberry, Josiah')], + creators=[Creator(id=5, creator_name='Carberry, Josiah')], status=IdentifierStatusType.PUBLISHED, owner=UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise'))] # mock diff --git a/lib/python/tests/test_unit_table.py b/lib/python/tests/test_unit_table.py index 4c4ad2af6aabbe6a36689fe3a44b50b8f6f625dc..eccf8c2a59ee45c3341c4116678301e438f0089b 100644 --- a/lib/python/tests/test_unit_table.py +++ b/lib/python/tests/test_unit_table.py @@ -6,7 +6,7 @@ from pandas import DataFrame from dbrepo.RestClient import RestClient from dbrepo.api.dto import Table, CreateTableConstraints, Column, Constraints, ColumnType, ConceptBrief, UnitBrief, \ - TableStatistics, ColumnStatistic, PrimaryKey, TableMinimal, ColumnMinimal, TableBrief, UserBrief + TableStatistics, ColumnStatistic, PrimaryKey, ColumnBrief, TableBrief, UserBrief from dbrepo.api.exceptions import MalformedError, ForbiddenError, NotExistsError, NameExistsError, \ AuthenticationError, ExternalSystemError @@ -14,35 +14,15 @@ from dbrepo.api.exceptions import MalformedError, ForbiddenError, NotExistsError class TableUnitTest(unittest.TestCase): def test_create_table_succeeds(self): - exp = Table(id=2, - name="Test", - description="Test Table", - database_id=1, - internal_name="test", - owner=UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise'), - is_versioned=True, - queue_name='test', - routing_key='dbrepo.test_database_1234.test', - is_public=True, - is_schema_public=True, - constraints=Constraints(uniques=[], - foreign_keys=[], - checks=[], - primary_key=[PrimaryKey(id=1, - table=TableMinimal(id=2, database_id=1), - column=ColumnMinimal(id=1, table_id=2, - database_id=1))]), - columns=[Column(id=1, - ord=0, - name="ID", - database_id=1, - table_id=2, - internal_name="id", - auto_generated=True, - is_primary_key=True, - type=ColumnType.BIGINT, - is_public=True, - is_null_allowed=False)]) + exp = TableBrief(id=2, + database_id=1, + name="Test", + description="Test Table", + internal_name="test", + owned_by='8638c043-5145-4be8-a3e4-4b79991b0a16', + is_versioned=True, + is_public=True, + is_schema_public=True) with requests_mock.Mocker() as mock: # mock mock.post('/api/database/1/table', json=exp.model_dump(), status_code=201) @@ -159,9 +139,20 @@ class TableUnitTest(unittest.TestCase): foreign_keys=[], checks=[], primary_key=[PrimaryKey(id=1, - table=TableMinimal(id=2, database_id=1), - column=ColumnMinimal(id=1, table_id=2, - database_id=1))]), + table=TableBrief(id=2, database_id=1, + name='Other', + internal_name='other', + description=None, + is_versioned=True, + is_public=True, + is_schema_public=True, + owned_by='8638c043-5145-4be8-a3e4-4b79991b0a16'), + column=ColumnBrief(id=1, table_id=2, + database_id=1, + name='id', + alias=None, + internal_name='id', + type=ColumnType.BIGINT))]), columns=[Column(id=1, name="ID", ord=0, diff --git a/lib/python/tests/test_unit_user.py b/lib/python/tests/test_unit_user.py index 0d1e72088573af1921028daf9af1b3e1f092cac2..0e846b1b42e6ba935a2f204d09aa0920dce69626 100644 --- a/lib/python/tests/test_unit_user.py +++ b/lib/python/tests/test_unit_user.py @@ -125,8 +125,8 @@ class UserUnitTest(unittest.TestCase): def test_update_user_succeeds(self): with requests_mock.Mocker() as mock: - exp = User(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise', given_name='Martin', - attributes=UserAttributes(theme='dark')) + exp = UserBrief(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise', given_name='Martin', + attributes=UserAttributes(theme='dark')) # mock mock.put('http://localhost/api/user/8638c043-5145-4be8-a3e4-4b79991b0a16', status_code=202, json=exp.model_dump()) @@ -173,16 +173,12 @@ class UserUnitTest(unittest.TestCase): def test_update_user_password_succeeds(self): with requests_mock.Mocker() as mock: - exp = User(id='8638c043-5145-4be8-a3e4-4b79991b0a16', username='mweise', given_name='Martin', - attributes=UserAttributes(theme='dark')) # mock - mock.put('http://localhost/api/user/8638c043-5145-4be8-a3e4-4b79991b0a16/password', status_code=202, - json=exp.model_dump()) + mock.put('http://localhost/api/user/8638c043-5145-4be8-a3e4-4b79991b0a16/password', status_code=202) # test client = RestClient(username="a", password="b") response = client.update_user_password(user_id='8638c043-5145-4be8-a3e4-4b79991b0a16', password='s3cr3t1n0rm4t10n') - self.assertEqual(exp, response) def test_update_user_password_not_allowed_fails(self): with requests_mock.Mocker() as mock: diff --git a/make/build.mk b/make/build.mk index 7311ed27167f72e4ffa4b8b7659127b90679d471..270b2cee6fd80b9dea9a475399081ae34ad65c91 100644 --- a/make/build.mk +++ b/make/build.mk @@ -14,23 +14,27 @@ build-data-service: ## Build the Data Service. build-metadata-service: ## Build the Metadata Service. mvn -f ./dbrepo-metadata-service/pom.xml clean package -DskipTests +.PHONY: build-auth-event-listener +build-auth-event-listener: ## Build the Auth Service Event Listener. + mvn -f ./dbrepo-auth-service/listeners/pom.xml clean package -DskipTests + .PHONY: build-ui build-ui: ## Build the UI. bun --cwd ./dbrepo-ui build .PHONY: build-lib build-lib: ## Build the Python Library. - rm -f ./dbrepo-analyse-service/lib/dbrepo-${APP_VERSION}.tar.gz - rm -f ./dbrepo-search-service/lib/dbrepo-${APP_VERSION}.tar.gz - rm -f ./dbrepo-search-service/init/lib/dbrepo-${APP_VERSION}.tar.gz + rm -rf ./dbrepo-analyse-service/venv/ ./dbrepo-analyse-service/Pipfile.lock ./dbrepo-analyse-service/lib/dbrepo-${APP_VERSION}* + rm -rf ./dbrepo-search-service/venv/ ./dbrepo-search-service/Pipfile.lock ./dbrepo-search-service/lib/dbrepo-${APP_VERSION}* + rm -rf ./dbrepo-search-service/init/venv/ ./dbrepo-search-service/init/Pipfile.lock ./dbrepo-search-service/init/lib/dbrepo-${APP_VERSION}* python3 -m build --sdist ./lib/python python3 -m build --wheel ./lib/python - cp ./lib/python/dist/dbrepo-${APP_VERSION}.tar.gz ./dbrepo-analyse-service/lib/dbrepo-${APP_VERSION}.tar.gz - (cd ./dbrepo-analyse-service && PIPENV_IGNORE_VIRTUALENVS=1 pipenv lock) - cp ./lib/python/dist/dbrepo-${APP_VERSION}.tar.gz ./dbrepo-search-service/lib/dbrepo-${APP_VERSION}.tar.gz - (cd ./dbrepo-search-service && PIPENV_IGNORE_VIRTUALENVS=1 pipenv lock) - cp ./lib/python/dist/dbrepo-${APP_VERSION}.tar.gz ./dbrepo-search-service/init/lib/dbrepo-${APP_VERSION}.tar.gz - (cd ./dbrepo-search-service/init && PIPENV_IGNORE_VIRTUALENVS=1 pipenv lock) + cp -r ./lib/python/dist/dbrepo-${APP_VERSION}* ./dbrepo-analyse-service/lib + (cd ./dbrepo-analyse-service && python3 -m venv venv && PIPENV_IGNORE_VIRTUALENVS=1 pipenv install --dev) + cp -r ./lib/python/dist/dbrepo-${APP_VERSION}* ./dbrepo-search-service/lib + (cd ./dbrepo-search-service && python3 -m venv venv && PIPENV_IGNORE_VIRTUALENVS=1 pipenv install --dev) + cp -r ./lib/python/dist/dbrepo-${APP_VERSION}* ./dbrepo-search-service/init/lib + (cd ./dbrepo-search-service/init && python3 -m venv venv && PIPENV_IGNORE_VIRTUALENVS=1 pipenv install --dev) .PHONY: build-helm build-helm: ## Build the DBRepo and DBRepo MariaDB Galera Helm Charts. diff --git a/make/dev.mk b/make/dev.mk index 0282dbbce287356e207822fdc9dbf1be7e26e0b8..d8da31086b3dfcba7f85aeeaa6db64564b87c036 100644 --- a/make/dev.mk +++ b/make/dev.mk @@ -1,7 +1,7 @@ ##@ Development .PHONY: start-dev -start-dev: build-images ## Start the development deployment. +start-dev: build-images build-auth-event-listener ## Start the development deployment. docker container stop dbrepo-gateway-service || true docker container rm dbrepo-gateway-service || true docker compose up -d diff --git a/make/gen.mk b/make/gen.mk index ed10c7e123e292816bd550aba66faf214dcfb81b..308a307b95534ea6bbf0f497244b64a5597061ae 100644 --- a/make/gen.mk +++ b/make/gen.mk @@ -1,11 +1,11 @@ ##@ Generate -.PHONY: gen-swagger-doc -gen-swagger-doc: build-images ## Generate Swagger documentation and fetch. +.PHONY: gen-openapi-doc +gen-openapi-doc: build-images ## Generate Swagger documentation and fetch. docker compose up -d - bash .docs/.swagger/swagger-generate.sh + bash .docs/.openapi/openapi-generate.sh docker compose down - openapi-merge-cli --config .docs/.swagger/openapi-merge.json + openapi-merge-cli --config .docs/.openapi/openapi-merge.json .PHONY: gen-helm-doc gen-helm-doc: build-helm ## Generate Helm documentation and schema diff --git a/sonar-project.properties b/sonar-project.properties index d354d54608a75063e0000cd577469dba69ae5eec..4442bf46ff84667faa8f20672f21d14be29fef3e 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -2,7 +2,7 @@ sonar.projectKey=fair-data-austria-db-repository_fda-services_a57fa043-ab99-4cdd-a721-162d9a916d77 sonar.host.url=https://s39.datalab.tuwien.ac.at # project -sonar.projectVersion=1.6.1 +sonar.projectVersion=1.6.3 # general sonar.qualitygate.wait=true sonar.projectCreation.mainBranchName=master diff --git a/yq b/yq new file mode 100644 index 0000000000000000000000000000000000000000..5578822fb407e254544a2b532ef439174956ea45 --- /dev/null +++ b/yq @@ -0,0 +1,7043 @@ +openapi: 3.0.1 +info: + title: Database Repository Metadata Service API + description: Service that manages the metadata + contact: + name: Prof. Andreas Rauber + email: andreas.rauber@tuwien.ac.at + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0 + version: 1.6.2 +externalDocs: + description: Sourcecode Documentation + url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.6.2/system-services-metadata/ +servers: +- url: http://localhost + description: Development instance +- url: https://test.dbrepo.tuwien.ac.at + description: Staging instance +paths: + /api/database: + get: + tags: + - database-endpoint + summary: List databases + description: "Lists all databases in the metadata database. Requests with HTTP\ + \ method **GET** return the list of databases, requests with HTTP method **HEAD**\ + \ only the number in the `X-Count` header." + operationId: list + parameters: + - name: internal_name + in: query + required: false + schema: + type: string + responses: + "200": + description: List of databases + headers: + Access-Control-Expose-Headers: + description: Expose `X-Count` custom header + required: true + style: simple + X-Count: + description: Number of databases + required: true + style: simple + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/DatabaseBriefDto" + post: + tags: + - database-endpoint + summary: Create database + description: Creates a database in the container with id. Requires roles `create-database`. + operationId: create_5 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseCreateDto" + required: true + responses: + "409": + description: Query store could not be created + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Database create query is malformed or image is not supported + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "423": + description: Database quota exceeded + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Database create permission is missing or grant permissions + at broker service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to fin container/user/database in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "201": + description: Created a new database + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseBriefDto" + security: + - bearerAuth: [] + - basicAuth: [] + head: + tags: + - database-endpoint + summary: List databases + description: "Lists all databases in the metadata database. Requests with HTTP\ + \ method **GET** return the list of databases, requests with HTTP method **HEAD**\ + \ only the number in the `X-Count` header." + operationId: list_1 + parameters: + - name: internal_name + in: query + required: false + schema: + type: string + responses: + "200": + description: List of databases + headers: + Access-Control-Expose-Headers: + description: Expose `X-Count` custom header + required: true + style: simple + X-Count: + description: Number of databases + required: true + style: simple + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/DatabaseBriefDto" + /api/database/{databaseId}/access/{userId}: + get: + tags: + - access-endpoint + summary: Find/Check access + description: "Finds or checks access of a user with given id to a database with\ + \ given id. Requests with HTTP method **GET** return the access object, requests\ + \ with HTTP method **HEAD** only the status. When the user has at least *READ*\ + \ access, the status 200 is returned, 403 otherwise. Requires role `check-database-access`\ + \ or `check-foreign-database-access`." + operationId: find + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: userId + in: path + required: true + schema: + type: string + format: uuid + responses: + "403": + description: No access to this database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Database not found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Found database access + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseAccessDto" + security: + - bearerAuth: [] + - basicAuth: [] + put: + tags: + - access-endpoint + summary: Modify access + description: Modifies access of a user with given id to database with given + id. Requires role `update-database-access`. + operationId: update_5 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: userId + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UpdateDatabaseAccessDto" + required: true + responses: + "404": + description: Database or user not found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Modify access not permitted when no access is granted in the + first place + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Access could not be updated in the data service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Modified access + "502": + description: Access could not be updated due to connection error in the + data service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Modify access query or database connection is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + post: + tags: + - access-endpoint + summary: Give access + description: Give a user with given id access to some database with given id. + Requires role `create-database-access`. + operationId: create_8 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: userId + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UpdateDatabaseAccessDto" + required: true + responses: + "404": + description: Database or user not found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Access could not be created in the data service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Failed giving access + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Granting access succeeded + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseAccessDto" + "400": + description: Granting access query or database connection is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Access could not be created due to connection error + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + delete: + tags: + - access-endpoint + summary: Delete access + description: Delete access of a user with id to a database with id. Requires + role `delete-database-access`. + operationId: revoke + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: userId + in: path + required: true + schema: + type: string + format: uuid + responses: + "403": + description: Revoke of access not permitted as no access was found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Deleted access + "502": + description: Access could not be created due to connection error + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: "User, database with access was not found" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Access could not be revoked in the data service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Modify access query or database connection is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + head: + tags: + - access-endpoint + summary: Find/Check access + description: "Finds or checks access of a user with given id to a database with\ + \ given id. Requests with HTTP method **GET** return the access object, requests\ + \ with HTTP method **HEAD** only the status. When the user has at least *READ*\ + \ access, the status 200 is returned, 403 otherwise. Requires role `check-database-access`\ + \ or `check-foreign-database-access`." + operationId: find_1 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: userId + in: path + required: true + schema: + type: string + format: uuid + responses: + "403": + description: No access to this database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Database not found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Found database access + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseAccessDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/user/{userId}: + get: + tags: + - user-endpoint + summary: Get user + description: Gets own user information from the metadata database. Requires + authentication. Foreign user information can only be obtained if additional + role `find-foreign-user` is present. Finding information about internal users + results in a 404 error. + operationId: find_2 + parameters: + - name: userId + in: path + required: true + schema: + type: string + format: uuid + responses: + "404": + description: User was not found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Found user + content: + application/json: + schema: + $ref: "#/components/schemas/UserDto" + "403": + description: Find user is not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + put: + tags: + - user-endpoint + summary: Update user + description: Updates user with id. Requires role `modify-user-information`. + operationId: modify + parameters: + - name: userId + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UserUpdateDto" + required: true + responses: + "202": + description: Modified user information + content: + application/json: + schema: + $ref: "#/components/schemas/UserDto" + "404": + description: Failed to find database/user in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Modify user query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Not allowed to modify user metadata + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/user/{userId}/password: + put: + tags: + - user-endpoint + summary: Update user password + description: Updates password of user with id. Requires authentication. + operationId: password + parameters: + - name: userId + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UserPasswordDto" + required: true + responses: + "400": + description: Invalid password payload + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Modified user password + "403": + description: Not allowed to change foreign user password + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to get user in auth service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database/user in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to auth service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/user/token: + put: + tags: + - user-endpoint + summary: Refresh token + description: Refreshes user token by refresh token. + operationId: refreshToken + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/RefreshTokenRequestDto" + required: true + responses: + "202": + description: Refreshed user token + content: + application/json: + schema: + $ref: "#/components/schemas/TokenDto" + "403": + description: Not allowed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Invalid refresh token + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to auth service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + post: + tags: + - user-endpoint + summary: Create token + description: Creates a user token via the Auth Service. + operationId: getToken + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/LoginRequestDto" + required: true + responses: + "400": + description: Invalid login request + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Not allowed to get token + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find user in auth database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to get user in auth service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Obtained user token + content: + application/json: + schema: + $ref: "#/components/schemas/TokenDto" + "428": + description: Account is not fully setup in auth service (requires password + change?) + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to auth service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + /api/ontology/{ontologyId}: + get: + tags: + - ontology-endpoint + summary: Find ontology + description: Finds an ontology with id in the metadata database. + operationId: find_3 + parameters: + - name: ontologyId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "404": + description: Could not find ontology + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Find one ontology + content: + application/json: + schema: + $ref: "#/components/schemas/OntologyDto" + put: + tags: + - ontology-endpoint + summary: Update ontology + description: Updates an ontology with id. Requires role `update-ontology`. + operationId: update + parameters: + - name: ontologyId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/OntologyModifyDto" + required: true + responses: + "404": + description: Could not find ontology + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Updated ontology successfully + content: + application/json: + schema: + $ref: "#/components/schemas/OntologyDto" + security: + - bearerAuth: [] + - basicAuth: [] + delete: + tags: + - ontology-endpoint + summary: Delete ontology + description: Deletes an ontology with given id. Requires role `delete-ontology`. + operationId: delete + parameters: + - name: ontologyId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "202": + description: Deleted ontology successfully + content: + application/json: {} + "404": + description: Could not find ontology + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/message/{messageId}: + put: + tags: + - message-endpoint + summary: Update message + description: Updates a message with id. Requires role `update-maintenance-message`. + operationId: update_1 + parameters: + - name: messageId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/BannerMessageUpdateDto" + required: true + responses: + "202": + description: Updated message + content: + application/json: + schema: + $ref: "#/components/schemas/BannerMessageBriefDto" + "404": + description: Could not find message + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + delete: + tags: + - message-endpoint + summary: Delete message + description: Deletes a message with id. Requires role `delete-maintenance-message`. + operationId: delete_1 + parameters: + - name: messageId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "404": + description: Could not find message + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Deleted message + content: + application/json: {} + security: + - bearerAuth: [] + - basicAuth: [] + /api/image/{imageId}: + get: + tags: + - image-endpoint + summary: Find image + description: Finds a container image in the metadata database. + operationId: findById + parameters: + - name: imageId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "404": + description: Image could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Found image + content: + application/json: + schema: + $ref: "#/components/schemas/ImageDto" + put: + tags: + - image-endpoint + summary: Update image + description: Updates container image in the metadata database. Requires role + `modify-image`. + operationId: update_2 + parameters: + - name: imageId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ImageChangeDto" + required: true + responses: + "404": + description: Image could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Updated image successfully + content: + application/json: + schema: + $ref: "#/components/schemas/ImageDto" + security: + - bearerAuth: [] + - basicAuth: [] + delete: + tags: + - image-endpoint + summary: Delete image + description: Deletes a container image in the metadata database. Requires role + `delete-image`. + operationId: delete_2 + parameters: + - name: imageId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "202": + description: Deleted image successfully + "404": + description: Image could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/identifier/{identifierId}: + get: + tags: + - identifier-endpoint + summary: Find identifier + description: Finds an identifier with id. The response format depends on the + HTTP `Accept` header set on the request. + operationId: find_6 + parameters: + - name: identifierId + in: path + required: true + schema: + type: integer + format: int64 + - name: Accept + in: header + required: true + schema: + type: string + responses: + "200": + description: Found identifier successfully + content: + application/json: + schema: + $ref: "#/components/schemas/IdentifierDto" + application/ld+json: + schema: + $ref: "#/components/schemas/LdDatasetDto" + text/csv: {} + text/xml: {} + text/bibliography: {} + text/bibliography; style=apa: {} + text/bibliography; style=ieee: {} + text/bibliography; style=bibtex: {} + "502": + description: Connection to data service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: "Identifier could not be exported, the requested style is not\ + \ known" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "409": + description: Exported resource was not found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "410": + description: Failed to retrieve from S3 endpoint + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Identifier could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "406": + description: Failed to find acceptable representation + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to find in data service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + put: + tags: + - identifier-endpoint + summary: Save identifier + description: Saves an identifier with id as a draft identifier. Identifiers + can only be created for objects the user has at least *READ* access in the + associated database (requires role `create-identifier`) or for any object + in any database (requires role `create-foreign-identifier`). + operationId: save + parameters: + - name: identifierId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/IdentifierSaveDto" + required: true + responses: + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: "Failed to find database, table or view" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Identifier form contains invalid request data + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Saved identifier + content: + application/json: + schema: + $ref: "#/components/schemas/IdentifierDto" + "403": + description: Insufficient access rights or authorities + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + delete: + tags: + - identifier-endpoint + summary: Delete identifier + description: Deletes an identifier with id. Requires role `delete-identifier`. + operationId: delete_3 + parameters: + - name: identifierId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to delete in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Identifier or database could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Deleted identifier + "403": + description: Deleting identifier not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/identifier/{identifierId}/publish: + put: + tags: + - identifier-endpoint + summary: Publish identifier + description: Publishes an identifier with id. A published identifier cannot + be changed anymore. Requires role `publish-identifier`. + operationId: publish + parameters: + - name: identifierId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: "Failed to find database, table or view" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Published identifier + content: + application/json: + schema: + $ref: "#/components/schemas/IdentifierDto" + "400": + description: Identifier form contains invalid request data + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Insufficient access rights or authorities + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/visibility: + put: + tags: + - database-endpoint + summary: Update database visibility + description: Updates the database with id on the visibility. Only the database + owner can perform this operation. Requires role `modify-database-visibility`. + operationId: visibility + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseModifyVisibilityDto" + required: true + responses: + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Visibility modified successfully + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseBriefDto" + "400": + description: The visibility payload is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Visibility modification is not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/view/{viewId}: + get: + tags: + - view-endpoint + summary: Get view + description: Gets a view with id in the metadata database. + operationId: find_7 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: viewId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "403": + description: Find view is not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: "Database, view or user could not be found" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Find view successfully + headers: + X-Username: + description: The authentication username + style: simple + Access-Control-Expose-Headers: + description: Expose custom headers + style: simple + X-Type: + description: The JDBC connection type + style: simple + X-View: + description: The view internal name + style: simple + X-Database: + description: The database internal name + style: simple + X-Password: + description: The authentication password + style: simple + X-Host: + description: The database hostname + style: simple + X-Port: + description: The database port number + style: simple + content: + application/json: + schema: + $ref: "#/components/schemas/ViewDto" + security: + - bearerAuth: [] + - basicAuth: [] + put: + tags: + - view-endpoint + summary: Update view + description: Updates a view with id. This can only be performed by the view + owner or database owner. Requires role `create-database-view`. + operationId: update_3 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: viewId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ViewUpdateDto" + required: true + responses: + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Database or View could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Update not allowed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Update view query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Update view successfully + content: + '*/*': + schema: + $ref: "#/components/schemas/ViewDto" + security: + - bearerAuth: [] + - basicAuth: [] + delete: + tags: + - view-endpoint + summary: Delete view + description: Deletes a view with id. Requires role `delete-database-view`. + operationId: delete_4 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: viewId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "423": + description: Delete view resulted in an invalid query statement + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: "Database, view or user could not be found" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Delete view successfully + content: + '*/*': + schema: + type: object + "400": + description: Delete view query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Deletion not allowed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/table/{tableId}: + get: + tags: + - table-endpoint + summary: Find table + description: "Finds a table with id. When a table is hidden (i.e. when `is_public`\ + \ is `false`), then the user needs to have at least read access and the role\ + \ `find-table`. When the `system` role is present, the endpoint responds with\ + \ additional connection metadata in the header." + operationId: findById_2 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: Find table successfully + headers: + X-Username: + description: The authentication username + style: simple + X-Table: + description: The table internal name + style: simple + Access-Control-Expose-Headers: + description: Expose custom headers + style: simple + X-Type: + description: The JDBC connection type + style: simple + X-Database: + description: The database internal name + style: simple + X-Password: + description: The authentication password + style: simple + X-Host: + description: The database hostname + style: simple + X-Port: + description: The database port number + style: simple + content: + application/json: + schema: + $ref: "#/components/schemas/TableDto" + "503": + description: Failed to obtain queue information from broker service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Access to the database is forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Failed to establish connection with broker service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: "Table, database or container could not be found" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + put: + tags: + - table-endpoint + summary: Update table + description: Updates a table in the database with id. Requires role `update-table`. + operationId: update_4 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/TableUpdateDto" + required: true + responses: + "403": + description: Update table visibility not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Table could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Updated the table + content: + application/json: + schema: + $ref: "#/components/schemas/TableBriefDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Update table visibility payload is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + delete: + tags: + - table-endpoint + summary: Delete table + description: Deletes a table with id. Only the owner of a table can perform + this action (requires role `delete-table`) or anyone can delete a table (requires + role `delete-foreign-table`). + operationId: delete_5 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Access to the database is forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Delete table successfully + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Delete table query resulted in an invalid query statement + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: "Table, database or container could not be found" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/table/{tableId}/statistic: + put: + tags: + - table-endpoint + summary: Update statistics + description: "Updates basic statistical properties (min, max, mean, median,\ + \ std.dev) for numerical columns in a table with id. This action can only\ + \ be performed by the table owner. Requires role `update-table-statistic`." + operationId: updateStatistic + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Failed to map column statistic to known columns + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database/table in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Not the owner + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Updated table statistics successfully + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/table/{tableId}/column/{columnId}: + put: + tags: + - table-endpoint + summary: Update semantics + description: Updates column semantics of a table column with id. Only the table + owner with at least *READ* access to the associated database can update the + column semantics (requires role `modify-table-column-semantics`) or foreign + table columns if role `modify-foreign-table-column-semantics`. + operationId: updateColumn + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + - name: columnId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ColumnSemanticsUpdateDto" + required: true + responses: + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Access to the database is forbidden + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find user/table/database/ontology in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Updated column semantics successfully + content: + application/json: + schema: + $ref: "#/components/schemas/ColumnDto" + "400": + description: Update semantic concept query is malformed or update unit of + measurement query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/owner: + put: + tags: + - database-endpoint + summary: Update database owner + description: Updates the database with id on the owner. Only the database owner + can perform this operation. Requires role `modify-database-owner`. + operationId: transfer + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseTransferDto" + required: true + responses: + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Transfer of ownership was successful + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseBriefDto" + "403": + description: Transfer of ownership is not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Database or user could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Owner payload is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/metadata/view: + put: + tags: + - database-endpoint + summary: Update database view schemas + description: Updates the database with id with generated metadata from view + that are not yet known to the database. Only the database owner can perform + this operation. Requires role `find-database`. + operationId: refreshViewMetadata + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Refreshed database views metadata + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseBriefDto" + "403": + description: Refresh view metadata is not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/metadata/table: + put: + tags: + - database-endpoint + summary: Update database table schemas + description: Updates the database with id with generated metadata from tables + that are not yet known to the database. Only the database owner can perform + this operation. Requires role `find-database`. + operationId: refreshTableMetadata + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "403": + description: Not allowed to refresh table metadata + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to fin user/database in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Refreshed database tables metadata + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseBriefDto" + "400": + description: Failed to parse payload at search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/image: + get: + tags: + - database-endpoint + summary: Get database preview image + description: Gets the database with id on the preview image. + operationId: findPreviewImage + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "404": + description: Database or user could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: View of image was successful + content: + '*/*': + schema: + type: array + items: + type: string + format: byte + security: + - bearerAuth: [] + - basicAuth: [] + put: + tags: + - database-endpoint + summary: Update database preview image + description: Updates the database with id on the preview image. Only the database + owner can perform this operation. Requires role `modify-database-image`. + operationId: modifyImage + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseModifyImageDto" + required: true + responses: + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Modify of image was successful + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseBriefDto" + "410": + description: File was not found in the Storage Service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Database could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Modify of image is not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/user: + get: + tags: + - user-endpoint + summary: List users + description: "Lists users known to the metadata database. Internal users are\ + \ omitted from the result list. If the optional query parameter `username`\ + \ is present, the result list can be filtered by matching this exact username." + operationId: findAll + parameters: + - name: username + in: query + required: false + schema: + type: string + responses: + "200": + description: List users + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/UserBriefDto" + post: + tags: + - user-endpoint + summary: Create user + description: Creates a user in the auth service and metadata database. Requires + that no credentials are sent in the request. + operationId: create + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/SignupRequestDto" + required: true + responses: + "403": + description: Internal authentication to the auth service is invalid + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Parameters are not well-formed (likely email) + content: + application/json: {} + "409": + description: User with username already exists + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "417": + description: User with e-mail already exists + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to create in auth service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "201": + description: Created user + content: + application/json: + schema: + $ref: "#/components/schemas/UserDto" + "502": + description: Failed to create in auth service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Default role not found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + /api/ontology: + get: + tags: + - ontology-endpoint + summary: List ontologies + description: Lists all ontologies known to the metadata database. + operationId: findAll_2 + responses: + "200": + description: List ontologies + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/OntologyBriefDto" + post: + tags: + - ontology-endpoint + summary: Create ontology + description: Creates an ontology in the metadata database. Requires role `create-ontology`. + operationId: create_1 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/OntologyCreateDto" + required: true + responses: + "201": + description: Registered ontology successfully + content: + application/json: + schema: + $ref: "#/components/schemas/OntologyDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/message: + get: + tags: + - message-endpoint + summary: List messages + description: "Lists messages known to the metadata database. Messages can be\ + \ filtered be filtered with the optional `active` parameter. If set to *true*,\ + \ only active messages (that is, messages whose end time has not been reached)\ + \ will be returned. Otherwise only inactive messages are returned. If not\ + \ set, active and inactive messages are returned." + operationId: list_2 + parameters: + - name: active + in: query + required: false + schema: + type: boolean + responses: + "200": + description: List messages + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/BannerMessageDto" + post: + tags: + - message-endpoint + summary: Create message + description: Creates a message in the metadata database. Requires role `create-maintenance-message`. + operationId: create_2 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/BannerMessageCreateDto" + required: true + responses: + "201": + description: Created message + content: + application/json: + schema: + $ref: "#/components/schemas/BannerMessageBriefDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/image: + get: + tags: + - image-endpoint + summary: List images + description: Lists all container images known to the metadata database. + operationId: findAll_3 + responses: + "200": + description: List images + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/ImageBriefDto" + post: + tags: + - image-endpoint + summary: Create image + description: Creates a container image in the metadata database. Requires role + `create-image`. + operationId: create_3 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ImageCreateDto" + required: true + responses: + "409": + description: Image already exists + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Image specification is invalid + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "201": + description: Created image + content: + application/json: + schema: + $ref: "#/components/schemas/ImageDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/identifier: + get: + tags: + - identifier-endpoint + summary: List identifiers + description: Lists all identifiers known to the metadata database + operationId: findAll_4 + parameters: + - name: dbid + in: query + required: false + schema: + type: integer + format: int64 + - name: qid + in: query + required: false + schema: + type: integer + format: int64 + - name: vid + in: query + required: false + schema: + type: integer + format: int64 + - name: tid + in: query + required: false + schema: + type: integer + format: int64 + - name: Accept + in: header + required: true + schema: + type: string + responses: + "200": + description: Found identifiers successfully + content: + application/json: + schema: + type: array + items: + type: string + application/ld+json: + schema: + type: array + items: + $ref: "#/components/schemas/LdDatasetDto" + "406": + description: "Identifier could not be exported, the requested style is not\ + \ known" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + post: + tags: + - identifier-endpoint + summary: Create identifier + description: Create an identifier with id to create a draft identifier. Identifiers + can only be created for objects the user has at least *READ* access in the + associated database (requires role `create-identifier`) or for any object + in any database (requires role `create-foreign-identifier`). + operationId: create_4 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/IdentifierCreateDto" + required: true + responses: + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "201": + description: Drafted identifier + content: + application/json: + schema: + $ref: "#/components/schemas/IdentifierDto" + "404": + description: "Failed to find database, table or view" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Identifier form contains invalid request data + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Insufficient access rights or authorities + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/view: + get: + tags: + - view-endpoint + summary: List views + description: Lists views known to the metadata database. + operationId: findAll_5 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: Find views successfully + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/ViewBriefDto" + "404": + description: Database or user could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + post: + tags: + - view-endpoint + summary: Create view + description: Creates a view. This can only be performed by the database owner. + Requires role `create-database-view`. + operationId: create_6 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ViewCreateDto" + required: true + responses: + "423": + description: Create view resulted in an invalid query statement + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "201": + description: Create view successfully + content: + application/json: + schema: + $ref: "#/components/schemas/ViewBriefDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Credentials missing + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database/user in metadata database. + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Create view query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/table: + get: + tags: + - table-endpoint + summary: List tables + description: "Lists all tables known to the metadata database. When a database\ + \ has a hidden schema (i.e. when `is_schema_public` is `false`), then the\ + \ user needs to have at least read access and the role `list-tables`." + operationId: list_4 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "403": + description: List tables not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Database could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: List tables + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/TableBriefDto" + security: + - bearerAuth: [] + - basicAuth: [] + post: + tags: + - table-endpoint + summary: Create table + description: Creates a table in the database with id. Requires role `create-table`. + operationId: create_7 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/TableCreateDto" + required: true + responses: + "502": + description: Connection to search service failed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Create table not permitted + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "201": + description: Created a new table + content: + application/json: + schema: + $ref: "#/components/schemas/TableBriefDto" + "409": + description: Create table conflicts with existing table name + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: "Database, container or user could not be found" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "503": + description: Failed to save in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Create table query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/container: + get: + tags: + - container-endpoint + summary: List containers + description: List all containers in the metadata database. + operationId: findAll_6 + parameters: + - name: limit + in: query + required: false + schema: + type: integer + format: int32 + responses: + "200": + description: List containers + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/ContainerBriefDto" + post: + tags: + - container-endpoint + summary: Create container + description: Creates a container in the metadata database. Requires role `create-container`. + operationId: create_9 + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ContainerCreateDto" + required: true + responses: + "400": + description: Container payload malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Container image or user could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "409": + description: Container name already exists + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "201": + description: Created a new container + content: + application/json: + schema: + $ref: "#/components/schemas/ContainerDto" + "403": + description: "Create container not permitted, need authority `create-container`" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/unit: + get: + tags: + - unit-endpoint + summary: List units + description: Lists units known to the metadata database. + operationId: findAll_1 + responses: + "200": + description: Find all semantic units + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/UnitDto" + /api/ontology/{ontologyId}/entity: + get: + tags: + - ontology-endpoint + summary: Find entities + description: Finds semantic entities by label or uri in an ontology with id. + Requires role `execute-semantic-query`. + operationId: find_4 + parameters: + - name: ontologyId + in: path + required: true + schema: + type: integer + format: int64 + - name: label + in: query + required: false + schema: + type: string + - name: uri + in: query + required: false + schema: + type: string + responses: + "400": + description: Filter params are invalid + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Found entities + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/EntityDto" + "404": + description: Could not find ontology + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "422": + description: Ontology does not have rdf or sparql endpoint + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "417": + description: Generated query or uri is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/oai: + get: + tags: + - metadata-endpoint + summary: Get record + operationId: identify_1_1_1_1 + parameters: + - name: verb + in: query + - name: parameters + in: query + required: true + schema: + $ref: "#/components/schemas/OaiListIdentifiersParameters" + responses: + "200": + description: List containers + content: + text/xml: {} + /api/message/message/{messageId}: + get: + tags: + - message-endpoint + summary: Find message + description: Finds a message with id in the metadata database. + operationId: find_5 + parameters: + - name: messageId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: Get messages + content: + application/json: + schema: + $ref: "#/components/schemas/BannerMessageDto" + "404": + description: Could not find message + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + /api/license: + get: + tags: + - license-endpoint + summary: List licenses + description: Lists licenses known to the metadata database. + operationId: list_3 + responses: + "200": + description: List of licenses + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/LicenseDto" + /api/identifier/retrieve: + get: + tags: + - identifier-endpoint + summary: Retrieve PID metadata + description: "Retrieves Persistent Identifier (PID) metadata from external endpoints.\ + \ Supported PIDs are: ORCID, ROR, DOI." + operationId: retrieve + parameters: + - name: url + in: query + required: true + schema: + type: string + responses: + "200": + description: Retrieved metadata from identifier + content: + application/json: + schema: + $ref: "#/components/schemas/IdentifierDto" + "404": + description: Failed to find metadata for identifier + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + /api/database/{databaseId}: + get: + tags: + - database-endpoint + summary: Find database + description: Finds a database with id. + operationId: findById_1 + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "503": + description: Failed to find queue information in broker service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "502": + description: Connection to the broker service could not be established + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Database found successfully + headers: + X-Username: + description: The authentication username + style: simple + Access-Control-Expose-Headers: + description: Expose custom headers + style: simple + X-Password: + description: The authentication password + style: simple + content: + application/json: + schema: + $ref: "#/components/schemas/DatabaseBriefDto" + "403": + description: Not allowed to view database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: "Database, user or exchange could not be found" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/table/{tableId}/suggest: + get: + tags: + - table-endpoint + summary: Suggest semantics + description: Suggests semantic concepts for a table. This action can only be + performed by the table owner. Requires role `table-semantic-analyse`. + operationId: analyseTable + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "417": + description: Generated query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "422": + description: Ontology does not have rdf or sparql endpoint + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "400": + description: Failed to parse statistic in search service + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "403": + description: Not the table owner. + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "404": + description: Failed to find database/table in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Suggested table semantics successfully + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/EntityDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/database/{databaseId}/table/{tableId}/column/{columnId}/suggest: + get: + tags: + - table-endpoint + summary: Suggest semantics + description: Suggests column semantics. Requires role `table-semantic-analyse`. + operationId: analyseTableColumn + parameters: + - name: databaseId + in: path + required: true + schema: + type: integer + format: int64 + - name: tableId + in: path + required: true + schema: + type: integer + format: int64 + - name: columnId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "400": + description: Generated query is malformed + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "422": + description: Ontology does not have rdf or sparql endpoint + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "200": + description: Suggested table column semantics successfully + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/TableColumnEntityDto" + "404": + description: Failed to find database/table in metadata database + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/container/{containerId}: + get: + tags: + - container-endpoint + summary: Find container + description: Finds a container in the metadata database. + operationId: findById_3 + parameters: + - name: containerId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: Found container + content: + application/json: + schema: + $ref: "#/components/schemas/ContainerDto" + "404": + description: Container image could not be found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + delete: + tags: + - container-endpoint + summary: Delete container + description: Deletes a container in the metadata database. Requires role `delete-container`. + operationId: delete_6 + parameters: + - name: containerId + in: path + required: true + schema: + type: integer + format: int64 + responses: + "404": + description: Container not found + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + "202": + description: Deleted container + "403": + description: "Create container not permitted, need authority `delete-container`" + content: + application/json: + schema: + $ref: "#/components/schemas/ApiErrorDto" + security: + - bearerAuth: [] + - basicAuth: [] + /api/concept: + get: + tags: + - concept-endpoint + summary: List concepts + description: List all semantic concepts known to the metadata database + operationId: findAll_7 + responses: + "200": + description: List concepts + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/ConceptDto" +components: + schemas: + DatabaseBriefDto: + required: + - contact + - id + - internal_name + - is_public + - is_schema_public + - name + - owner_id + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + example: Air Quality + description: + type: string + example: Air Quality + identifiers: + type: array + items: + $ref: "#/components/schemas/IdentifierBriefDto" + contact: + $ref: "#/components/schemas/UserBriefDto" + internal_name: + type: string + example: air_quality + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + owner_id: + type: string + format: uuid + preview_image: + type: string + IdentifierBriefDto: + required: + - created_by + - database_id + - id + - publication_year + - publisher + - titles + - type + type: object + properties: + id: + type: integer + format: int64 + type: + type: string + enum: + - database + - subset + - table + - view + titles: + type: array + items: + $ref: "#/components/schemas/IdentifierTitleDto" + doi: + type: string + example: 10.1038/nphys1170 + publisher: + type: string + example: TU Wien + status: + type: string + enum: + - draft + - published + database_id: + type: integer + format: int64 + example: 1 + query_id: + type: integer + format: int64 + example: 1 + table_id: + type: integer + format: int64 + example: 1 + view_id: + type: integer + format: int64 + example: 1 + publication_year: + type: integer + format: int32 + example: 2022 + created_by: + type: string + format: uuid + IdentifierTitleDto: + required: + - id + type: object + properties: + id: + type: integer + format: int64 + title: + type: string + example: Airquality Demonstrator + language: + type: string + example: en + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - "no" + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + type: + type: string + enum: + - AlternativeTitle + - Subtitle + - TranslatedTitle + - Other + UserBriefDto: + required: + - id + - username + type: object + properties: + id: + type: string + format: uuid + example: 1ffc7b0e-9aeb-4e8b-b8f1-68f3936155b4 + username: + type: string + description: Only contains lowercase characters + example: jcarberry + name: + type: string + example: Josiah Carberry + orcid: + type: string + example: 0000-0002-1825-0097 + qualified_name: + type: string + example: Josiah Carberry — @jcarberry + given_name: + type: string + example: Josiah + family_name: + type: string + example: Carberry + ApiErrorDto: + required: + - code + - message + - status + type: object + properties: + status: + type: string + example: NOT_FOUND + enum: + - 100 CONTINUE + - 101 SWITCHING_PROTOCOLS + - 102 PROCESSING + - 103 EARLY_HINTS + - 103 CHECKPOINT + - 200 OK + - 201 CREATED + - 202 ACCEPTED + - 203 NON_AUTHORITATIVE_INFORMATION + - 204 NO_CONTENT + - 205 RESET_CONTENT + - 206 PARTIAL_CONTENT + - 207 MULTI_STATUS + - 208 ALREADY_REPORTED + - 226 IM_USED + - 300 MULTIPLE_CHOICES + - 301 MOVED_PERMANENTLY + - 302 FOUND + - 302 MOVED_TEMPORARILY + - 303 SEE_OTHER + - 304 NOT_MODIFIED + - 305 USE_PROXY + - 307 TEMPORARY_REDIRECT + - 308 PERMANENT_REDIRECT + - 400 BAD_REQUEST + - 401 UNAUTHORIZED + - 402 PAYMENT_REQUIRED + - 403 FORBIDDEN + - 404 NOT_FOUND + - 405 METHOD_NOT_ALLOWED + - 406 NOT_ACCEPTABLE + - 407 PROXY_AUTHENTICATION_REQUIRED + - 408 REQUEST_TIMEOUT + - 409 CONFLICT + - 410 GONE + - 411 LENGTH_REQUIRED + - 412 PRECONDITION_FAILED + - 413 PAYLOAD_TOO_LARGE + - 413 REQUEST_ENTITY_TOO_LARGE + - 414 URI_TOO_LONG + - 414 REQUEST_URI_TOO_LONG + - 415 UNSUPPORTED_MEDIA_TYPE + - 416 REQUESTED_RANGE_NOT_SATISFIABLE + - 417 EXPECTATION_FAILED + - 418 I_AM_A_TEAPOT + - 419 INSUFFICIENT_SPACE_ON_RESOURCE + - 420 METHOD_FAILURE + - 421 DESTINATION_LOCKED + - 422 UNPROCESSABLE_ENTITY + - 423 LOCKED + - 424 FAILED_DEPENDENCY + - 425 TOO_EARLY + - 426 UPGRADE_REQUIRED + - 428 PRECONDITION_REQUIRED + - 429 TOO_MANY_REQUESTS + - 431 REQUEST_HEADER_FIELDS_TOO_LARGE + - 451 UNAVAILABLE_FOR_LEGAL_REASONS + - 500 INTERNAL_SERVER_ERROR + - 501 NOT_IMPLEMENTED + - 502 BAD_GATEWAY + - 503 SERVICE_UNAVAILABLE + - 504 GATEWAY_TIMEOUT + - 505 HTTP_VERSION_NOT_SUPPORTED + - 506 VARIANT_ALSO_NEGOTIATES + - 507 INSUFFICIENT_STORAGE + - 508 LOOP_DETECTED + - 509 BANDWIDTH_LIMIT_EXCEEDED + - 510 NOT_EXTENDED + - 511 NETWORK_AUTHENTICATION_REQUIRED + message: + type: string + example: Error message + code: + type: string + example: error.service.code + DatabaseAccessDto: + required: + - type + - user + type: object + properties: + user: + $ref: "#/components/schemas/UserBriefDto" + type: + type: string + enum: + - read + - write_own + - write_all + UserUpdateDto: + required: + - language + - theme + type: object + properties: + firstname: + type: string + example: Josiah + lastname: + type: string + example: Carberry + affiliation: + type: string + example: Brown University + orcid: + type: string + example: 0000-0002-1825-0097 + theme: + type: string + example: dark + language: + type: string + example: en + UserAttributesDto: + required: + - language + - theme + type: object + properties: + theme: + type: string + example: light + orcid: + type: string + example: https://orcid.org/0000-0002-1825-0097 + affiliation: + type: string + example: Brown University + language: + type: string + example: en + UserDto: + required: + - attributes + - id + type: object + properties: + id: + type: string + format: uuid + example: 1ffc7b0e-9aeb-4e8b-b8f1-68f3936155b4 + name: + type: string + example: Josiah Carberry + attributes: + $ref: "#/components/schemas/UserAttributesDto" + last_retrieved: + type: string + format: date-time + qualified_name: + type: string + example: Josiah Carberry — @jcarberry + given_name: + type: string + example: Josiah + family_name: + type: string + example: Carberry + UserPasswordDto: + required: + - password + type: object + properties: + password: + type: string + RefreshTokenRequestDto: + required: + - refresh_token + type: object + properties: + refresh_token: + type: string + example: refresh_token + TokenDto: + required: + - access_token + - expires_in + - id_token + - not-before-policy + - refresh_expires_in + - refresh_token + - scope + - session_state + - token_type + type: object + properties: + scope: + type: string + access_token: + type: string + expires_in: + type: integer + format: int64 + refresh_token: + type: string + refresh_expires_in: + type: integer + format: int64 + id_token: + type: string + session_state: + type: string + token_type: + type: string + not-before-policy: + type: integer + format: int64 + OntologyModifyDto: + required: + - prefix + - uri + type: object + properties: + uri: + type: string + example: Ontology URI + prefix: + type: string + example: Ontology prefix + sparql_endpoint: + type: string + example: Ontology SPARQL endpoint + rdf_path: + type: string + example: rdf/om-2.0.rdf + OntologyDto: + required: + - id + - prefix + - rdf + - sparql + - uri + type: object + properties: + id: + type: integer + format: int64 + uri: + type: string + example: http://www.wikidata.org/ + prefix: + type: string + example: wd + sparql: + type: boolean + example: true + rdf: + type: boolean + example: false + uri_pattern: + type: string + example: http://www.wikidata.org/entity/.* + sparql_endpoint: + type: string + example: https://query.wikidata.org/sparql + rdf_path: + type: string + example: rdf/om-2.0.rdf + BannerMessageUpdateDto: + required: + - message + - type + type: object + properties: + type: + type: string + enum: + - error + - warning + - info + message: + type: string + example: Maintenance starts on 8am on Monday + link: + type: string + example: https://example.com + link_text: + type: string + example: More + display_start: + type: string + format: date-time + example: 2021-03-12T15:26:21Z + display_end: + type: string + format: date-time + example: 2021-03-12T15:26:21Z + BannerMessageBriefDto: + required: + - message + - type + type: object + properties: + type: + type: string + enum: + - error + - warning + - info + message: + type: string + example: Maintenance starts on 8am on Monday + link: + type: string + example: https://example.com + link_text: + type: string + example: More + ImageChangeDto: + required: + - dialect + - driver_class + - jdbc_method + - registry + type: object + properties: + registry: + type: string + example: docker.io/library + defaultPort: + maximum: 65535 + minimum: 1024 + type: integer + format: int32 + example: 5432 + dialect: + type: string + example: Postgres + driver_class: + type: string + example: org.postgresql.Driver + jdbc_method: + type: string + example: postgresql + DataTypeDto: + required: + - display_name + - documentation + - is_buildable + - is_quoted + - value + type: object + properties: + value: + type: string + example: time + documentation: + type: string + example: https://mariadb.com/kb/en/time/ + display_name: + type: string + example: TIME(fsp) + size_min: + type: integer + format: int32 + example: 0 + size_max: + type: integer + format: int32 + example: 6 + size_default: + type: integer + format: int32 + example: 0 + size_required: + type: boolean + example: false + d_min: + type: integer + format: int32 + d_max: + type: integer + format: int32 + d_default: + type: integer + format: int32 + d_required: + type: boolean + data_hint: + type: string + example: "e.g. HH:MM:SS, HH:MM, HHMMSS, H:M:S" + type_hint: + type: string + example: "fsp=microsecond precision, min. 0, max. 6" + is_quoted: + type: boolean + description: frontend needs to quote this data type + example: false + is_buildable: + type: boolean + description: frontend can build this data type + example: true + ImageDto: + required: + - data_types + - default + - default_port + - dialect + - driver_class + - id + - jdbc_method + - name + - operators + - registry + - version + type: object + properties: + id: + type: integer + format: int64 + registry: + type: string + example: docker.io/library + name: + type: string + example: mariadb + version: + type: string + example: "10.5" + dialect: + type: string + example: org.hibernate.dialect.MariaDBDialect + operators: + type: array + items: + $ref: "#/components/schemas/OperatorDto" + driver_class: + type: string + example: org.mariadb.jdbc.Driver + jdbc_method: + type: string + example: mariadb + default: + type: boolean + example: false + default_port: + type: integer + format: int32 + example: 3306 + data_types: + type: array + items: + $ref: "#/components/schemas/DataTypeDto" + OperatorDto: + required: + - display_name + - documentation + - value + type: object + properties: + id: + type: integer + format: int64 + value: + type: string + example: XOR + documentation: + type: string + example: https://mariadb.com/kb/en/xor/ + display_name: + type: string + example: XOR + CreatorSaveDto: + required: + - creator_name + - id + type: object + properties: + id: + type: integer + format: int64 + example: 1 + firstname: + type: string + example: Josiah + lastname: + type: string + example: Carberry + affiliation: + type: string + example: Wesleyan University + creator_name: + type: string + example: "Carberry, Josiah" + name_type: + type: string + example: Personal + enum: + - Personal + - Organizational + name_identifier: + type: string + example: 0000-0002-1825-0097 + name_identifier_scheme: + type: string + example: ORCID + enum: + - ORCID + - ROR + - ISNI + - GRID + affiliation_identifier: + type: string + example: https://ror.org/04d836q62 + affiliation_identifier_scheme: + type: string + example: ROR + enum: + - ROR + - GRID + - ISNI + IdentifierFunderSaveDto: + required: + - funder_name + - id + type: object + properties: + id: + type: integer + format: int64 + example: 1 + funder_name: + type: string + example: European Commission + funder_identifier: + type: string + example: http://doi.org/10.13039/501100000780 + funder_identifier_type: + type: string + example: Crossref Funder ID + enum: + - Crossref Funder ID + - ROR + - GND + - ISNI + - Other + scheme_uri: + type: string + example: http://doi.org/ + award_number: + type: string + example: "824087" + award_title: + type: string + example: EOSC-Life + IdentifierSaveDescriptionDto: + required: + - description + - id + type: object + properties: + id: + type: integer + format: int64 + example: 1 + description: + type: string + example: "Air quality reports at Stephansplatz, Vienna" + language: + type: string + example: en + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - "no" + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + type: + type: string + example: Abstract + enum: + - Abstract + - Methods + - SeriesInformation + - TableOfContents + - TechnicalInfo + - Other + IdentifierSaveDto: + required: + - creators + - database_id + - id + - publication_year + - publisher + - titles + - type + type: object + properties: + id: + type: integer + format: int64 + example: 1 + type: + type: string + example: database + enum: + - database + - subset + - table + - view + doi: + type: string + example: 10.1111/11111111 + titles: + type: array + items: + $ref: "#/components/schemas/IdentifierSaveTitleDto" + descriptions: + type: array + items: + $ref: "#/components/schemas/IdentifierSaveDescriptionDto" + funders: + type: array + items: + $ref: "#/components/schemas/IdentifierFunderSaveDto" + licenses: + type: array + items: + $ref: "#/components/schemas/LicenseDto" + publisher: + type: string + example: TU Wien + language: + type: string + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - "no" + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + creators: + type: array + items: + $ref: "#/components/schemas/CreatorSaveDto" + database_id: + type: integer + format: int64 + example: 1 + query_id: + type: integer + format: int64 + view_id: + type: integer + format: int64 + table_id: + type: integer + format: int64 + publication_day: + type: integer + format: int32 + example: 15 + publication_month: + type: integer + format: int32 + example: 12 + publication_year: + type: integer + format: int32 + example: 2022 + related_identifiers: + type: array + items: + $ref: "#/components/schemas/RelatedIdentifierSaveDto" + IdentifierSaveTitleDto: + required: + - id + - title + type: object + properties: + id: + type: integer + format: int64 + example: 1 + title: + type: string + example: Airquality Demonstrator + language: + type: string + example: en + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - "no" + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + type: + type: string + example: Subtitle + enum: + - AlternativeTitle + - Subtitle + - TranslatedTitle + - Other + LicenseDto: + required: + - identifier + - uri + type: object + properties: + identifier: + type: string + example: MIT + uri: + type: string + example: https://opensource.org/licenses/MIT + description: + type: string + example: "A short and simple permissive license with conditions only requiring\ + \ preservation of copyright and license notices. Licensed works, modifications,\ + \ and larger works may be distributed under different terms and without\ + \ source code." + RelatedIdentifierSaveDto: + required: + - id + - relation + - type + - value + type: object + properties: + id: + type: integer + format: int64 + example: 1 + value: + type: string + example: 10.70124/dc4zh-9ce78 + type: + type: string + example: DOI + enum: + - DOI + - URL + - URN + - ARK + - arXiv + - bibcode + - EAN13 + - EISSN + - Handle + - IGSN + - ISBN + - ISTC + - LISSN + - LSID + - PMID + - PURL + - UPC + - w3id + relation: + type: string + example: Cites + enum: + - IsCitedBy + - Cites + - IsSupplementTo + - IsSupplementedBy + - IsContinuedBy + - Continues + - IsDescribedBy + - Describes + - HasMetadata + - IsMetadataFor + - HasVersion + - IsVersionOf + - IsNewVersionOf + - IsPreviousVersionOf + - IsPartOf + - HasPart + - IsPublishedIn + - IsReferencedBy + - References + - IsDocumentedBy + - Documents + - IsCompiledBy + - Compiles + - IsVariantFormOf + - IsOriginalFormOf + - IsIdenticalTo + - IsReviewedBy + - Reviews + - IsDerivedFrom + - IsSourceOf + - IsRequiredBy + - Requires + - IsObsoletedBy + - Obsoletes + CreatorDto: + required: + - creator_name + - id + type: object + properties: + id: + type: integer + format: int64 + firstname: + type: string + example: Josiah + lastname: + type: string + example: Carberry + affiliation: + type: string + example: Brown University + creator_name: + type: string + example: "Carberry, Josiah" + name_type: + type: string + example: Personal + enum: + - Personal + - Organizational + name_identifier: + type: string + example: 0000-0002-1825-0097 + name_identifier_scheme: + type: string + example: ORCID + enum: + - ORCID + - ROR + - ISNI + - GRID + name_identifier_scheme_uri: + type: string + example: https://orcid.org/ + affiliation_identifier: + type: string + example: https://ror.org/05gq02987 + affiliation_identifier_scheme: + type: string + example: ROR + enum: + - ROR + - GRID + - ISNI + affiliation_identifier_scheme_uri: + type: string + example: https://ror.org/ + IdentifierDescriptionDto: + required: + - id + type: object + properties: + id: + type: integer + format: int64 + description: + type: string + example: "Air quality reports at Stephansplatz, Vienna" + language: + type: string + example: en + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - "no" + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + type: + type: string + example: Abstract + enum: + - Abstract + - Methods + - SeriesInformation + - TableOfContents + - TechnicalInfo + - Other + IdentifierDto: + required: + - creators + - database_id + - id + - owner + - publication_year + - publisher + - query + - query_hash + - query_normalized + - titles + - type + type: object + properties: + id: + type: integer + format: int64 + type: + type: string + enum: + - database + - subset + - table + - view + titles: + type: array + items: + $ref: "#/components/schemas/IdentifierTitleDto" + descriptions: + type: array + items: + $ref: "#/components/schemas/IdentifierDescriptionDto" + funders: + type: array + items: + $ref: "#/components/schemas/IdentifierFunderDto" + query: + type: string + example: "SELECT `id`, `value`, `location` FROM `air_quality` WHERE `location`\ + \ = \"09:STEF\"" + execution: + type: string + format: date-time + example: 2021-03-12T15:26:21Z + doi: + type: string + example: 10.1038/nphys1170 + publisher: + type: string + example: TU Wien + owner: + $ref: "#/components/schemas/UserBriefDto" + language: + type: string + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - "no" + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + licenses: + type: array + items: + $ref: "#/components/schemas/LicenseDto" + creators: + type: array + items: + $ref: "#/components/schemas/CreatorDto" + status: + type: string + enum: + - draft + - published + database_id: + type: integer + format: int64 + example: 1 + query_id: + type: integer + format: int64 + example: 1 + table_id: + type: integer + format: int64 + example: 1 + view_id: + type: integer + format: int64 + example: 1 + query_normalized: + type: string + example: "SELECT `id`, `value`, `location` FROM `air_quality` WHERE `location`\ + \ = \"09:STEF\"" + related_identifiers: + type: array + items: + $ref: "#/components/schemas/RelatedIdentifierDto" + query_hash: + type: string + description: query hash in sha512 + result_hash: + type: string + example: 34fe82cda2c53f13f8d90cfd7a3469e3a939ff311add50dce30d9136397bf8e5 + result_number: + type: integer + format: int64 + example: 1 + publication_day: + type: integer + format: int32 + example: 15 + publication_month: + type: integer + format: int32 + example: 12 + publication_year: + type: integer + format: int32 + example: 2022 + IdentifierFunderDto: + required: + - funder_name + - id + type: object + properties: + id: + type: integer + format: int64 + funder_name: + type: string + example: European Commission + funder_identifier: + type: string + example: http://doi.org/10.13039/501100000780 + funder_identifier_type: + type: string + example: Crossref Funder ID + enum: + - Crossref Funder ID + - ROR + - GND + - ISNI + - Other + scheme_uri: + type: string + example: http://doi.org/ + award_number: + type: string + example: "824087" + award_title: + type: string + example: EOSC-Life + RelatedIdentifierDto: + required: + - id + - relation + - type + - value + type: object + properties: + id: + type: integer + format: int64 + value: + type: string + example: 10.70124/dc4zh-9ce78 + type: + type: string + example: DOI + enum: + - DOI + - URL + - URN + - ARK + - arXiv + - bibcode + - EAN13 + - EISSN + - Handle + - IGSN + - ISBN + - ISTC + - LISSN + - LSID + - PMID + - PURL + - UPC + - w3id + relation: + type: string + example: Cites + enum: + - IsCitedBy + - Cites + - IsSupplementTo + - IsSupplementedBy + - IsContinuedBy + - Continues + - IsDescribedBy + - Describes + - HasMetadata + - IsMetadataFor + - HasVersion + - IsVersionOf + - IsNewVersionOf + - IsPreviousVersionOf + - IsPartOf + - HasPart + - IsPublishedIn + - IsReferencedBy + - References + - IsDocumentedBy + - Documents + - IsCompiledBy + - Compiles + - IsVariantFormOf + - IsOriginalFormOf + - IsIdenticalTo + - IsReviewedBy + - Reviews + - IsDerivedFrom + - IsSourceOf + - IsRequiredBy + - Requires + - IsObsoletedBy + - Obsoletes + DatabaseModifyVisibilityDto: + required: + - is_public + - is_schema_public + type: object + properties: + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + ViewUpdateDto: + required: + - is_public + - is_schema_public + type: object + properties: + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + ViewColumnDto: + required: + - auto_generated + - database_id + - id + - internal_name + - is_null_allowed + - name + - ord + - type + type: object + properties: + id: + type: integer + format: int64 + name: + maxLength: 64 + minLength: 0 + type: string + example: Date + size: + type: integer + format: int64 + example: 255 + d: + type: integer + format: int64 + example: 0 + description: + maxLength: 2048 + minLength: 0 + type: string + example: Column comment + database_id: + type: integer + format: int64 + ord: + type: integer + format: int32 + example: 0 + internal_name: + maxLength: 64 + minLength: 0 + type: string + example: mdb_date + auto_generated: + type: boolean + example: false + index_length: + type: integer + format: int64 + length: + type: integer + format: int64 + type: + type: string + example: string + enum: + - char + - varchar + - binary + - varbinary + - tinyblob + - tinytext + - text + - blob + - mediumtext + - mediumblob + - longtext + - longblob + - enum + - set + - serial + - bit + - tinyint + - bool + - smallint + - mediumint + - int + - bigint + - float + - double + - decimal + - date + - datetime + - timestamp + - time + - year + is_null_allowed: + type: boolean + example: false + ViewDto: + required: + - columns + - database_id + - id + - internal_name + - name + - owner + - query + - query_hash + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + example: Air Quality + identifiers: + type: array + items: + $ref: "#/components/schemas/IdentifierDto" + query: + type: string + example: SELECT `id` FROM `air_quality` ORDER BY `value` DESC + owner: + $ref: "#/components/schemas/UserBriefDto" + columns: + type: array + items: + $ref: "#/components/schemas/ViewColumnDto" + last_retrieved: + type: string + format: date-time + database_id: + type: integer + format: int64 + internal_name: + type: string + example: air_quality + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + initial_view: + type: boolean + description: True if it is the default view for the database + example: true + query_hash: + type: string + example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916 + TableUpdateDto: + required: + - is_public + - is_schema_public + type: object + properties: + description: + maxLength: 180 + minLength: 0 + type: string + example: Air Quality in Austria + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + TableBriefDto: + required: + - database_id + - id + - internal_name + - is_public + - is_schema_public + - is_versioned + - name + - owned_by + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + example: Air Quality + description: + type: string + example: Air Quality in Austria + database_id: + type: integer + format: int64 + internal_name: + type: string + example: air_quality + is_versioned: + type: boolean + example: true + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + owned_by: + type: string + format: uuid + ColumnSemanticsUpdateDto: + type: object + properties: + concept_uri: + type: string + unit_uri: + type: string + ColumnDto: + required: + - database_id + - id + - internal_name + - is_null_allowed + - name + - ord + - table_id + - type + type: object + properties: + id: + type: integer + format: int64 + example: 1 + name: + maxLength: 64 + minLength: 0 + type: string + example: Given Name + alias: + type: string + example: firstname + size: + type: integer + format: int64 + example: 255 + d: + type: integer + format: int64 + example: 0 + mean: + type: number + example: 45.4 + median: + type: number + example: 51 + concept: + $ref: "#/components/schemas/ConceptBriefDto" + unit: + $ref: "#/components/schemas/UnitBriefDto" + description: + maxLength: 2048 + minLength: 0 + type: string + example: Column comment + enums: + type: array + items: + type: string + sets: + type: array + items: + type: string + database_id: + type: integer + format: int64 + example: 2 + table_id: + type: integer + format: int64 + example: 3 + ord: + type: integer + format: int32 + example: 0 + internal_name: + maxLength: 64 + minLength: 0 + type: string + example: given_name + index_length: + type: integer + format: int64 + example: 255 + length: + type: integer + format: int64 + example: 255 + type: + type: string + example: varchar + enum: + - char + - varchar + - binary + - varbinary + - tinyblob + - tinytext + - text + - blob + - mediumtext + - mediumblob + - longtext + - longblob + - enum + - set + - serial + - bit + - tinyint + - bool + - smallint + - mediumint + - int + - bigint + - float + - double + - decimal + - date + - datetime + - timestamp + - time + - year + data_length: + type: integer + format: int64 + example: 34300 + max_data_length: + type: integer + format: int64 + example: 34300 + num_rows: + type: integer + format: int64 + example: 32 + val_min: + type: number + example: 0 + val_max: + type: number + example: 100 + std_dev: + type: number + example: 5.32 + is_null_allowed: + type: boolean + example: false + ConceptBriefDto: + required: + - id + - uri + type: object + properties: + id: + type: integer + format: int64 + example: 23 + uri: + type: string + example: http://www.wikidata.org/entity/Q202444 + name: + type: string + example: given name + description: + type: string + example: "name typically used to differentiate people from the same family,\ + \ clan, or other social group who have a common last name" + UnitBriefDto: + required: + - id + - uri + type: object + properties: + id: + type: integer + format: int64 + example: 34 + uri: + type: string + example: http://www.wikidata.org/entity/Q1422583 + name: + type: string + example: importance + description: + type: string + example: "subjective magnitude of value, meaning, or purpose" + DatabaseTransferDto: + required: + - id + type: object + properties: + id: + type: string + format: uuid + DatabaseModifyImageDto: + type: object + properties: + key: + type: string + UpdateDatabaseAccessDto: + required: + - type + type: object + properties: + type: + type: string + enum: + - read + - write_own + - write_all + SignupRequestDto: + required: + - email + - password + - username + type: object + properties: + username: + pattern: "^[a-z0-9]{3,}$" + type: string + example: user + email: + type: string + example: user@example.com + password: + type: string + LoginRequestDto: + required: + - password + - username + type: object + properties: + username: + type: string + example: user + password: + type: string + OntologyCreateDto: + required: + - prefix + - uri + type: object + properties: + uri: + type: string + example: Ontology URI + prefix: + type: string + example: Ontology prefix + sparql_endpoint: + type: string + example: Ontology SPARQL endpoint + BannerMessageCreateDto: + required: + - message + - type + type: object + properties: + type: + type: string + enum: + - error + - warning + - info + message: + type: string + example: Maintenance starts on 8am on Monday + link: + type: string + example: https://example.com + link_text: + type: string + example: More + display_start: + type: string + format: date-time + example: 2021-03-12T15:26:21Z + display_end: + type: string + format: date-time + example: 2021-03-12T15:26:21Z + ImageCreateDto: + required: + - default_port + - dialect + - driver_class + - is_default + - jdbc_method + - name + - registry + - version + type: object + properties: + registry: + type: string + example: docker.io/library + name: + type: string + example: mariadb + version: + type: string + dialect: + type: string + is_default: + type: boolean + example: false + driver_class: + type: string + jdbc_method: + type: string + default_port: + maximum: 65535 + minimum: 1024 + type: integer + format: int32 + IdentifierCreateDto: + required: + - creators + - database_id + - publication_year + - publisher + - titles + - type + type: object + properties: + type: + type: string + example: database + enum: + - database + - subset + - table + - view + doi: + type: string + example: 10.1111/11111111 + titles: + type: array + items: + $ref: "#/components/schemas/IdentifierSaveTitleDto" + descriptions: + type: array + items: + $ref: "#/components/schemas/IdentifierSaveDescriptionDto" + funders: + type: array + items: + $ref: "#/components/schemas/IdentifierFunderSaveDto" + licenses: + type: array + items: + $ref: "#/components/schemas/LicenseDto" + publisher: + type: string + example: TU Wien + language: + type: string + enum: + - ab + - aa + - af + - ak + - sq + - am + - ar + - an + - hy + - as + - av + - ae + - ay + - az + - bm + - ba + - eu + - be + - bn + - bh + - bi + - bs + - br + - bg + - my + - ca + - km + - ch + - ce + - ny + - zh + - cu + - cv + - kw + - co + - cr + - hr + - cs + - da + - dv + - nl + - dz + - en + - eo + - et + - ee + - fo + - fj + - fi + - fr + - ff + - gd + - gl + - lg + - ka + - de + - ki + - el + - kl + - gn + - gu + - ht + - ha + - he + - hz + - hi + - ho + - hu + - is + - io + - ig + - id + - ia + - ie + - iu + - ik + - ga + - it + - ja + - jv + - kn + - kr + - ks + - kk + - rw + - kv + - kg + - ko + - kj + - ku + - ky + - lo + - la + - lv + - lb + - li + - ln + - lt + - lu + - mk + - mg + - ms + - ml + - mt + - gv + - mi + - mr + - mh + - ro + - mn + - na + - nv + - nd + - ng + - ne + - se + - "no" + - nb + - nn + - ii + - oc + - oj + - or + - om + - os + - pi + - pa + - ps + - fa + - pl + - pt + - qu + - rm + - rn + - ru + - sm + - sg + - sa + - sc + - sr + - sn + - sd + - si + - sk + - sl + - so + - st + - nr + - es + - su + - sw + - ss + - sv + - tl + - ty + - tg + - ta + - tt + - te + - th + - bo + - ti + - to + - ts + - tn + - tr + - tk + - tw + - ug + - uk + - ur + - uz + - ve + - vi + - vo + - wa + - cy + - fy + - wo + - xh + - yi + - yo + - za + - zu + creators: + type: array + items: + $ref: "#/components/schemas/CreatorSaveDto" + database_id: + type: integer + format: int64 + example: 1 + query_id: + type: integer + format: int64 + view_id: + type: integer + format: int64 + table_id: + type: integer + format: int64 + publication_day: + type: integer + format: int32 + example: 15 + publication_month: + type: integer + format: int32 + example: 12 + publication_year: + type: integer + format: int32 + example: 2022 + related_identifiers: + type: array + items: + $ref: "#/components/schemas/RelatedIdentifierSaveDto" + DatabaseCreateDto: + required: + - container_id + - is_public + - is_schema_public + - name + type: object + properties: + name: + type: string + example: Air Quality + container_id: + type: integer + format: int64 + example: 1 + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + ViewCreateDto: + required: + - is_public + - is_schema_public + - name + - query + type: object + properties: + name: + maxLength: 63 + minLength: 1 + type: string + example: Air Quality + query: + type: string + example: SELECT `id` FROM `air_quality` + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + ViewBriefDto: + required: + - database_id + - id + - internal_name + - name + - query + - query_hash + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + example: Air Quality + query: + type: string + example: SELECT `id` FROM `air_quality` ORDER BY `value` DESC + database_id: + type: integer + format: int64 + internal_name: + type: string + example: air_quality + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + initial_view: + type: boolean + description: True if it is the default view for the database + example: true + query_hash: + type: string + example: 7de03e818900b6ea6d58ad0306d4a741d658c6df3d1964e89ed2395d8c7e7916 + owned_by: + type: string + format: uuid + ColumnCreateDto: + required: + - name + - null_allowed + - type + type: object + properties: + name: + type: string + example: Date + type: + type: string + example: string + enum: + - char + - varchar + - binary + - varbinary + - tinyblob + - tinytext + - text + - blob + - mediumtext + - mediumblob + - longtext + - longblob + - enum + - set + - serial + - bit + - tinyint + - bool + - smallint + - mediumint + - int + - bigint + - float + - double + - decimal + - date + - datetime + - timestamp + - time + - year + size: + type: integer + format: int64 + example: 255 + d: + type: integer + format: int64 + example: 0 + description: + maxLength: 2048 + minLength: 0 + type: string + example: Formatted as YYYY-MM-dd + enums: + type: array + description: "enum values, only considered when type = ENUM" + items: + type: string + description: "enum values, only considered when type = ENUM" + sets: + type: array + description: "set values, only considered when type = SET" + items: + type: string + description: "set values, only considered when type = SET" + index_length: + type: integer + format: int64 + null_allowed: + type: boolean + example: true + concept_uri: + type: string + unit_uri: + type: string + ConstraintsCreateDto: + required: + - checks + - foreign_keys + - primary_key + - uniques + type: object + properties: + uniques: + type: array + items: + type: array + items: + type: string + checks: + uniqueItems: true + type: array + items: + type: string + foreign_keys: + type: array + items: + $ref: "#/components/schemas/ForeignKeyCreateDto" + primary_key: + uniqueItems: true + type: array + items: + type: string + ForeignKeyCreateDto: + required: + - columns + - referenced_columns + - referenced_table + type: object + properties: + columns: + type: array + items: + type: string + referenced_table: + type: string + referenced_columns: + type: array + items: + type: string + on_update: + type: string + enum: + - restrict + - cascade + - set_null + - no_action + - set_default + on_delete: + type: string + enum: + - restrict + - cascade + - set_null + - no_action + - set_default + TableCreateDto: + required: + - columns + - constraints + - is_public + - is_schema_public + - name + type: object + properties: + name: + maxLength: 64 + minLength: 1 + type: string + example: Air Quality + description: + maxLength: 180 + minLength: 0 + type: string + example: Air Quality in Austria + columns: + type: array + items: + $ref: "#/components/schemas/ColumnCreateDto" + constraints: + $ref: "#/components/schemas/ConstraintsCreateDto" + is_public: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + ContainerCreateDto: + required: + - host + - image_id + - name + - privileged_password + - privileged_username + - quota + type: object + properties: + name: + type: string + example: Air Quality + host: + type: string + description: Hostname of container + port: + type: integer + description: Port of container + format: int32 + quota: + type: integer + format: int64 + example: 50 + image_id: + type: integer + description: Image ID + format: int64 + ui_host: + type: string + ui_port: + type: integer + format: int32 + privileged_username: + type: string + description: Username of privileged user + example: root + privileged_password: + type: string + description: Password of privileged user + ContainerDto: + required: + - count + - id + - image + - internal_name + - name + - quota + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + example: Air Quality + image: + $ref: "#/components/schemas/ImageDto" + quota: + type: integer + format: int64 + example: 50 + count: + type: integer + format: int64 + example: 10 + last_retrieved: + type: string + format: date-time + internal_name: + type: string + example: data-db + ui_host: + type: string + ui_port: + type: integer + format: int32 + ColumnBriefDto: + required: + - column_type + - database_id + - id + - internal_name + - name + - table_id + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + example: date + alias: + type: string + database_id: + type: integer + format: int64 + table_id: + type: integer + format: int64 + internal_name: + type: string + example: mdb_date + column_type: + type: string + example: date + enum: + - char + - varchar + - binary + - varbinary + - tinyblob + - tinytext + - text + - blob + - mediumtext + - mediumblob + - longtext + - longblob + - enum + - set + - serial + - bit + - tinyint + - bool + - smallint + - mediumint + - int + - bigint + - float + - double + - decimal + - date + - datetime + - timestamp + - time + - year + UnitDto: + required: + - columns + - id + - uri + type: object + properties: + id: + type: integer + format: int64 + uri: + type: string + name: + type: string + description: + type: string + columns: + type: array + items: + $ref: "#/components/schemas/ColumnBriefDto" + OntologyBriefDto: + required: + - id + - prefix + - rdf + - sparql + - uri + type: object + properties: + id: + type: integer + format: int64 + uri: + type: string + example: http://www.wikidata.org/ + prefix: + type: string + example: wd + sparql: + type: boolean + example: true + rdf: + type: boolean + example: false + uri_pattern: + type: string + example: http://www.wikidata.org/entity/.* + EntityDto: + required: + - label + - uri + type: object + properties: + uri: + type: string + example: https://www.wikidata.org/entity/Q1686799 + label: + type: string + example: Apache Jena + description: + type: string + example: open source semantic web framework for Java + OaiListIdentifiersParameters: + type: object + properties: + metadataPrefix: + type: string + from: + type: string + until: + type: string + set: + type: string + resumptionToken: + type: string + fromDate: + type: string + format: date-time + untilDate: + type: string + format: date-time + parametersString: + type: string + BannerMessageDto: + required: + - id + - message + - type + type: object + properties: + id: + type: integer + format: int64 + type: + type: string + enum: + - error + - warning + - info + message: + type: string + example: Maintenance starts on 8am on Monday + link: + type: string + example: https://example.com + link_text: + type: string + example: More + display_start: + type: string + format: date-time + example: 2021-03-12T15:26:21Z + display_end: + type: string + format: date-time + example: 2021-03-12T15:26:21Z + ImageBriefDto: + required: + - default + - id + - jdbc_method + - name + - version + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + example: mariadb + version: + type: string + example: "10.5" + jdbc_method: + type: string + example: mariadb + default: + type: boolean + example: false + LdCreatorDto: + required: + - '@type' + - name + type: object + properties: + name: + type: string + sameAs: + type: string + givenName: + type: string + familyName: + type: string + '@type': + type: string + LdDatasetDto: + required: + - '@context' + - '@type' + - citation + - creator + - description + - hasPart + - identifier + - name + - temporalCoverage + - url + - version + type: object + properties: + name: + type: string + description: + type: string + url: + type: string + identifier: + type: array + items: + type: string + license: + type: string + creator: + type: array + items: + $ref: "#/components/schemas/LdCreatorDto" + citation: + type: string + hasPart: + type: array + items: + $ref: "#/components/schemas/LdDatasetDto" + temporalCoverage: + type: string + version: + type: string + format: date-time + '@context': + type: string + '@type': + type: string + ConstraintsDto: + type: object + properties: + uniques: + type: array + items: + $ref: "#/components/schemas/UniqueDto" + checks: + uniqueItems: true + type: array + items: + type: string + foreign_keys: + type: array + items: + $ref: "#/components/schemas/ForeignKeyDto" + primary_key: + uniqueItems: true + type: array + items: + $ref: "#/components/schemas/PrimaryKeyDto" + ForeignKeyBriefDto: + type: object + properties: + id: + type: integer + format: int64 + ForeignKeyDto: + required: + - name + - referenced_table + - references + - table + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + references: + type: array + items: + $ref: "#/components/schemas/ForeignKeyReferenceDto" + table: + $ref: "#/components/schemas/TableBriefDto" + referenced_table: + $ref: "#/components/schemas/TableBriefDto" + on_update: + type: string + enum: + - restrict + - cascade + - set_null + - no_action + - set_default + on_delete: + type: string + enum: + - restrict + - cascade + - set_null + - no_action + - set_default + ForeignKeyReferenceDto: + required: + - column + - foreign_key + - referenced_column + type: object + properties: + id: + type: integer + format: int64 + column: + $ref: "#/components/schemas/ColumnBriefDto" + foreign_key: + $ref: "#/components/schemas/ForeignKeyBriefDto" + referenced_column: + $ref: "#/components/schemas/ColumnBriefDto" + PrimaryKeyDto: + required: + - column + - table + type: object + properties: + id: + type: integer + format: int64 + table: + $ref: "#/components/schemas/TableBriefDto" + column: + $ref: "#/components/schemas/ColumnBriefDto" + TableDto: + required: + - columns + - constraints + - database_id + - id + - internal_name + - is_public + - is_schema_public + - is_versioned + - name + - owner + - queue_name + - routing_key + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + example: Air Quality + alias: + type: string + identifiers: + type: array + items: + $ref: "#/components/schemas/IdentifierDto" + owner: + $ref: "#/components/schemas/UserBriefDto" + description: + maxLength: 2048 + minLength: 0 + type: string + example: Air Quality in Austria + columns: + type: array + items: + $ref: "#/components/schemas/ColumnDto" + constraints: + $ref: "#/components/schemas/ConstraintsDto" + last_retrieved: + type: string + format: date-time + database_id: + type: integer + format: int64 + internal_name: + type: string + example: air_quality + is_versioned: + type: boolean + example: true + is_schema_public: + type: boolean + example: true + queue_name: + type: string + example: air_quality + queue_type: + type: string + example: quorum + routing_key: + type: string + example: dbrepo.1.2 + is_public: + type: boolean + example: true + num_rows: + type: integer + format: int64 + example: 5 + data_length: + type: integer + description: in bytes + format: int64 + example: 16384 + max_data_length: + type: integer + description: in bytes + format: int64 + example: 0 + avg_row_length: + type: integer + description: in bytes + format: int64 + example: 3276 + UniqueDto: + required: + - columns + - id + - name + - table + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + table: + $ref: "#/components/schemas/TableBriefDto" + columns: + type: array + items: + $ref: "#/components/schemas/ColumnDto" + TableColumnEntityDto: + required: + - column_id + - database_id + - table_id + - uri + type: object + properties: + uri: + type: string + example: https://www.wikidata.org/entity/Q1686799 + label: + type: string + example: Apache Jena + description: + type: string + example: open source semantic web framework for Java + database_id: + type: integer + format: int64 + example: 1 + table_id: + type: integer + format: int64 + example: 1 + column_id: + type: integer + format: int64 + example: 1 + ContainerBriefDto: + required: + - count + - hash + - id + - image + - internal_name + - name + - quota + type: object + properties: + id: + type: integer + format: int64 + hash: + type: string + example: f829dd8a884182d0da846f365dee1221fd16610a14c81b8f9f295ff162749e50 + name: + type: string + example: Air Quality + image: + $ref: "#/components/schemas/ImageBriefDto" + quota: + type: integer + format: int32 + example: 50 + count: + type: integer + format: int32 + example: 10 + internal_name: + type: string + example: air-quality + ConceptDto: + required: + - columns + - id + - uri + type: object + properties: + id: + type: integer + format: int64 + uri: + type: string + name: + type: string + description: + type: string + columns: + type: array + items: + $ref: "#/components/schemas/ColumnBriefDto" + securitySchemes: + basicAuth: + type: http + scheme: basic + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT